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 #include "utils/GLUtils.h" 24 25 #include <utils/Log.h> 26 27 namespace android { 28 namespace uirenderer { 29 30 /////////////////////////////////////////////////////////////////////////////// 31 // CPU pixel buffer 32 /////////////////////////////////////////////////////////////////////////////// 33 34 class CpuPixelBuffer : public PixelBuffer { 35 public: 36 CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height); 37 38 uint8_t* map(AccessMode mode = kAccessMode_ReadWrite) override; 39 40 void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) override; 41 42 protected: 43 void unmap() override; 44 45 private: 46 std::unique_ptr<uint8_t[]> mBuffer; 47 }; 48 49 CpuPixelBuffer::CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height) 50 : PixelBuffer(format, width, height) 51 , mBuffer(new uint8_t[width * height * formatSize(format)]) {} 52 53 uint8_t* CpuPixelBuffer::map(AccessMode mode) { 54 if (mAccessMode == kAccessMode_None) { 55 mAccessMode = mode; 56 } 57 return mBuffer.get(); 58 } 59 60 void CpuPixelBuffer::unmap() { 61 mAccessMode = kAccessMode_None; 62 } 63 64 void CpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) { 65 glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat, GL_UNSIGNED_BYTE, 66 &mBuffer[offset]); 67 } 68 69 /////////////////////////////////////////////////////////////////////////////// 70 // GPU pixel buffer 71 /////////////////////////////////////////////////////////////////////////////// 72 73 class GpuPixelBuffer : public PixelBuffer { 74 public: 75 GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height); 76 ~GpuPixelBuffer(); 77 78 uint8_t* map(AccessMode mode = kAccessMode_ReadWrite) override; 79 80 void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) override; 81 82 protected: 83 void unmap() override; 84 85 private: 86 GLuint mBuffer; 87 uint8_t* mMappedPointer; 88 Caches& mCaches; 89 }; 90 91 GpuPixelBuffer::GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height) 92 : PixelBuffer(format, width, height) 93 , mMappedPointer(nullptr) 94 , mCaches(Caches::getInstance()) { 95 glGenBuffers(1, &mBuffer); 96 97 mCaches.pixelBufferState().bind(mBuffer); 98 glBufferData(GL_PIXEL_UNPACK_BUFFER, getSize(), nullptr, GL_DYNAMIC_DRAW); 99 mCaches.pixelBufferState().unbind(); 100 } 101 102 GpuPixelBuffer::~GpuPixelBuffer() { 103 glDeleteBuffers(1, &mBuffer); 104 } 105 106 uint8_t* GpuPixelBuffer::map(AccessMode mode) { 107 if (mAccessMode == kAccessMode_None) { 108 mCaches.pixelBufferState().bind(mBuffer); 109 mMappedPointer = (uint8_t*)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, getSize(), mode); 110 if (CC_UNLIKELY(!mMappedPointer)) { 111 GLUtils::dumpGLErrors(); 112 LOG_ALWAYS_FATAL("Failed to map PBO"); 113 } 114 mAccessMode = mode; 115 mCaches.pixelBufferState().unbind(); 116 } 117 118 return mMappedPointer; 119 } 120 121 void GpuPixelBuffer::unmap() { 122 if (mAccessMode != kAccessMode_None) { 123 if (mMappedPointer) { 124 mCaches.pixelBufferState().bind(mBuffer); 125 GLboolean status = glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); 126 if (status == GL_FALSE) { 127 ALOGE("Corrupted GPU pixel buffer"); 128 } 129 } 130 mAccessMode = kAccessMode_None; 131 mMappedPointer = nullptr; 132 } 133 } 134 135 void GpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) { 136 // If the buffer is not mapped, unmap() will not bind it 137 mCaches.pixelBufferState().bind(mBuffer); 138 unmap(); 139 glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat, GL_UNSIGNED_BYTE, 140 reinterpret_cast<void*>(offset)); 141 mCaches.pixelBufferState().unbind(); 142 } 143 144 /////////////////////////////////////////////////////////////////////////////// 145 // Factory 146 /////////////////////////////////////////////////////////////////////////////// 147 148 PixelBuffer* PixelBuffer::create(GLenum format, uint32_t width, uint32_t height, BufferType type) { 149 if (type == kBufferType_Auto && Caches::getInstance().gpuPixelBuffersEnabled) { 150 return new GpuPixelBuffer(format, width, height); 151 } 152 return new CpuPixelBuffer(format, width, height); 153 } 154 155 }; // namespace uirenderer 156 }; // namespace android 157