|  | /* | 
|  | * Copyright (C) 2013 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | #define LOG_TAG "OpenGLRenderer" | 
|  |  | 
|  | #include <utils/Log.h> | 
|  |  | 
|  | #include "Caches.h" | 
|  | #include "Debug.h" | 
|  | #include "Extensions.h" | 
|  | #include "PixelBuffer.h" | 
|  | #include "Properties.h" | 
|  |  | 
|  | namespace android { | 
|  | namespace uirenderer { | 
|  |  | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  | // CPU pixel buffer | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | class CpuPixelBuffer: public PixelBuffer { | 
|  | public: | 
|  | CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height); | 
|  | ~CpuPixelBuffer(); | 
|  |  | 
|  | uint8_t* map(AccessMode mode = kAccessMode_ReadWrite); | 
|  | void unmap(); | 
|  |  | 
|  | uint8_t* getMappedPointer() const; | 
|  |  | 
|  | void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset); | 
|  |  | 
|  | private: | 
|  | uint8_t* mBuffer; | 
|  | }; | 
|  |  | 
|  | CpuPixelBuffer::CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height): | 
|  | PixelBuffer(format, width, height) { | 
|  | mBuffer = new uint8_t[width * height * formatSize(format)]; | 
|  | } | 
|  |  | 
|  | CpuPixelBuffer::~CpuPixelBuffer() { | 
|  | delete[] mBuffer; | 
|  | } | 
|  |  | 
|  | uint8_t* CpuPixelBuffer::map(AccessMode mode) { | 
|  | if (mAccessMode == kAccessMode_None) { | 
|  | mAccessMode = mode; | 
|  | } | 
|  | return mBuffer; | 
|  | } | 
|  |  | 
|  | void CpuPixelBuffer::unmap() { | 
|  | mAccessMode = kAccessMode_None; | 
|  | } | 
|  |  | 
|  | uint8_t* CpuPixelBuffer::getMappedPointer() const { | 
|  | return mAccessMode == kAccessMode_None ? NULL : mBuffer; | 
|  | } | 
|  |  | 
|  | void CpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) { | 
|  | glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, | 
|  | mFormat, GL_UNSIGNED_BYTE, mBuffer + offset); | 
|  | } | 
|  |  | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  | // GPU pixel buffer | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | class GpuPixelBuffer: public PixelBuffer { | 
|  | public: | 
|  | GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height); | 
|  | ~GpuPixelBuffer(); | 
|  |  | 
|  | uint8_t* map(AccessMode mode = kAccessMode_ReadWrite); | 
|  | void unmap(); | 
|  |  | 
|  | uint8_t* getMappedPointer() const; | 
|  |  | 
|  | void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset); | 
|  |  | 
|  | private: | 
|  | GLuint mBuffer; | 
|  | uint8_t* mMappedPointer; | 
|  | Caches& mCaches; | 
|  | }; | 
|  |  | 
|  | GpuPixelBuffer::GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height): | 
|  | PixelBuffer(format, width, height), mMappedPointer(0), mCaches(Caches::getInstance()) { | 
|  | glGenBuffers(1, &mBuffer); | 
|  | mCaches.bindPixelBuffer(mBuffer); | 
|  | glBufferData(GL_PIXEL_UNPACK_BUFFER, getSize(), NULL, GL_DYNAMIC_DRAW); | 
|  | mCaches.unbindPixelBuffer(); | 
|  | } | 
|  |  | 
|  | GpuPixelBuffer::~GpuPixelBuffer() { | 
|  | glDeleteBuffers(1, &mBuffer); | 
|  | } | 
|  |  | 
|  | uint8_t* GpuPixelBuffer::map(AccessMode mode) { | 
|  | if (mAccessMode == kAccessMode_None) { | 
|  | mCaches.bindPixelBuffer(mBuffer); | 
|  | mMappedPointer = (uint8_t*) glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, getSize(), mode); | 
|  | #if DEBUG_OPENGL | 
|  | if (!mMappedPointer) { | 
|  | GLenum status = GL_NO_ERROR; | 
|  | while ((status = glGetError()) != GL_NO_ERROR) { | 
|  | ALOGE("Could not map GPU pixel buffer: 0x%x", status); | 
|  | } | 
|  | } | 
|  | #endif | 
|  | mAccessMode = mode; | 
|  | } | 
|  |  | 
|  | return mMappedPointer; | 
|  | } | 
|  |  | 
|  | void GpuPixelBuffer::unmap() { | 
|  | if (mAccessMode != kAccessMode_None) { | 
|  | if (mMappedPointer) { | 
|  | mCaches.bindPixelBuffer(mBuffer); | 
|  | GLboolean status = glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); | 
|  | if (status == GL_FALSE) { | 
|  | ALOGE("Corrupted GPU pixel buffer"); | 
|  | } | 
|  | } | 
|  | mAccessMode = kAccessMode_None; | 
|  | mMappedPointer = NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | uint8_t* GpuPixelBuffer::getMappedPointer() const { | 
|  | return mMappedPointer; | 
|  | } | 
|  |  | 
|  | void GpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) { | 
|  | // If the buffer is not mapped, unmap() will not bind it | 
|  | mCaches.bindPixelBuffer(mBuffer); | 
|  | unmap(); | 
|  | glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat, | 
|  | GL_UNSIGNED_BYTE, reinterpret_cast<void*>(offset)); | 
|  | } | 
|  |  | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  | // Factory | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | PixelBuffer* PixelBuffer::create(GLenum format, uint32_t width, uint32_t height, BufferType type) { | 
|  | if (type == kBufferType_Auto && Caches::getInstance().gpuPixelBuffersEnabled) { | 
|  | return new GpuPixelBuffer(format, width, height); | 
|  | } | 
|  | return new CpuPixelBuffer(format, width, height); | 
|  | } | 
|  |  | 
|  | }; // namespace uirenderer | 
|  | }; // namespace android |