PixelBuffer.cpp revision 5a4690bf26932c0d6940e4af8516d920e09ae81a
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "PixelBuffer.h" 18 19#include "Debug.h" 20#include "Extensions.h" 21#include "Properties.h" 22#include "renderstate/RenderState.h" 23 24#include <utils/Log.h> 25 26namespace android { 27namespace uirenderer { 28 29/////////////////////////////////////////////////////////////////////////////// 30// CPU pixel buffer 31/////////////////////////////////////////////////////////////////////////////// 32 33class CpuPixelBuffer: public PixelBuffer { 34public: 35 CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height); 36 37 uint8_t* map(AccessMode mode = kAccessMode_ReadWrite) override; 38 void unmap() override; 39 40 uint8_t* getMappedPointer() const override; 41 42 void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) override; 43 44private: 45 std::unique_ptr<uint8_t[]> mBuffer; 46}; 47 48CpuPixelBuffer::CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height) 49 : PixelBuffer(format, width, height) 50 , mBuffer(new uint8_t[width * height * formatSize(format)]) { 51} 52 53uint8_t* CpuPixelBuffer::map(AccessMode mode) { 54 if (mAccessMode == kAccessMode_None) { 55 mAccessMode = mode; 56 } 57 return mBuffer.get(); 58} 59 60void CpuPixelBuffer::unmap() { 61 mAccessMode = kAccessMode_None; 62} 63 64uint8_t* CpuPixelBuffer::getMappedPointer() const { 65 return mAccessMode == kAccessMode_None ? nullptr : mBuffer.get(); 66} 67 68void CpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) { 69 glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, 70 mFormat, GL_UNSIGNED_BYTE, &mBuffer[offset]); 71} 72 73/////////////////////////////////////////////////////////////////////////////// 74// GPU pixel buffer 75/////////////////////////////////////////////////////////////////////////////// 76 77class GpuPixelBuffer: public PixelBuffer { 78public: 79 GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height); 80 ~GpuPixelBuffer(); 81 82 uint8_t* map(AccessMode mode = kAccessMode_ReadWrite) override; 83 void unmap() override; 84 85 uint8_t* getMappedPointer() const override; 86 87 void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) override; 88 89private: 90 GLuint mBuffer; 91 uint8_t* mMappedPointer; 92 Caches& mCaches; 93}; 94 95GpuPixelBuffer::GpuPixelBuffer(GLenum format, 96 uint32_t width, uint32_t height) 97 : PixelBuffer(format, width, height) 98 , mMappedPointer(nullptr) 99 , mCaches(Caches::getInstance()){ 100 glGenBuffers(1, &mBuffer); 101 102 mCaches.pixelBufferState().bind(mBuffer); 103 glBufferData(GL_PIXEL_UNPACK_BUFFER, getSize(), nullptr, GL_DYNAMIC_DRAW); 104 mCaches.pixelBufferState().unbind(); 105} 106 107GpuPixelBuffer::~GpuPixelBuffer() { 108 glDeleteBuffers(1, &mBuffer); 109} 110 111uint8_t* GpuPixelBuffer::map(AccessMode mode) { 112 if (mAccessMode == kAccessMode_None) { 113 mCaches.pixelBufferState().bind(mBuffer); 114 mMappedPointer = (uint8_t*) glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, getSize(), mode); 115#if DEBUG_OPENGL 116 if (!mMappedPointer) { 117 GLenum status = GL_NO_ERROR; 118 while ((status = glGetError()) != GL_NO_ERROR) { 119 ALOGE("Could not map GPU pixel buffer: 0x%x", status); 120 } 121 } 122#endif 123 mAccessMode = mode; 124 } 125 126 return mMappedPointer; 127} 128 129void GpuPixelBuffer::unmap() { 130 if (mAccessMode != kAccessMode_None) { 131 if (mMappedPointer) { 132 mCaches.pixelBufferState().bind(mBuffer); 133 GLboolean status = glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); 134 if (status == GL_FALSE) { 135 ALOGE("Corrupted GPU pixel buffer"); 136 } 137 } 138 mAccessMode = kAccessMode_None; 139 mMappedPointer = nullptr; 140 } 141} 142 143uint8_t* GpuPixelBuffer::getMappedPointer() const { 144 return mMappedPointer; 145} 146 147void GpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) { 148 // If the buffer is not mapped, unmap() will not bind it 149 mCaches.pixelBufferState().bind(mBuffer); 150 unmap(); 151 glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat, 152 GL_UNSIGNED_BYTE, reinterpret_cast<void*>(offset)); 153} 154 155/////////////////////////////////////////////////////////////////////////////// 156// Factory 157/////////////////////////////////////////////////////////////////////////////// 158 159PixelBuffer* PixelBuffer::create(GLenum format, 160 uint32_t width, uint32_t height, BufferType type) { 161 if (type == kBufferType_Auto && Caches::getInstance().gpuPixelBuffersEnabled) { 162 return new GpuPixelBuffer(format, width, height); 163 } 164 return new CpuPixelBuffer(format, width, height); 165} 166 167}; // namespace uirenderer 168}; // namespace android 169