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