diff options
Diffstat (limited to 'libs/hwui/PixelBuffer.cpp')
-rw-r--r-- | libs/hwui/PixelBuffer.cpp | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/libs/hwui/PixelBuffer.cpp b/libs/hwui/PixelBuffer.cpp new file mode 100644 index 0000000..8280370 --- /dev/null +++ b/libs/hwui/PixelBuffer.cpp @@ -0,0 +1,163 @@ +/* + * 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 "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); + mAccessMode = mode; + } + + return mMappedPointer; +} + +void GpuPixelBuffer::unmap() { + if (mAccessMode != kAccessMode_None) { + if (mMappedPointer) { + mCaches.bindPixelBuffer(mBuffer); + glUnmapBuffer(GL_PIXEL_UNPACK_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, (void*) offset); +} + +/////////////////////////////////////////////////////////////////////////////// +// Factory +/////////////////////////////////////////////////////////////////////////////// + +PixelBuffer* PixelBuffer::create(GLenum format, uint32_t width, uint32_t height, BufferType type) { + bool gpuBuffer = type == kBufferType_Auto && Extensions::getInstance().getMajorGlVersion() >= 3; + if (gpuBuffer) { + char property[PROPERTY_VALUE_MAX]; + if (property_get(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, property, "false") > 0) { + if (!strcmp(property, "true")) { + return new GpuPixelBuffer(format, width, height); + } + } + } + return new CpuPixelBuffer(format, width, height); +} + +}; // namespace uirenderer +}; // namespace android |