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 27namespace android { 28namespace uirenderer { 29 30/////////////////////////////////////////////////////////////////////////////// 31// CPU pixel buffer 32/////////////////////////////////////////////////////////////////////////////// 33 34class CpuPixelBuffer : public PixelBuffer { 35public: 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 42protected: 43 void unmap() override; 44 45private: 46 std::unique_ptr<uint8_t[]> mBuffer; 47}; 48 49CpuPixelBuffer::CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height) 50 : PixelBuffer(format, width, height) 51 , mBuffer(new uint8_t[width * height * formatSize(format)]) {} 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 64void 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 73class GpuPixelBuffer : public PixelBuffer { 74public: 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 82protected: 83 void unmap() override; 84 85private: 86 GLuint mBuffer; 87 uint8_t* mMappedPointer; 88 Caches& mCaches; 89}; 90 91GpuPixelBuffer::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 102GpuPixelBuffer::~GpuPixelBuffer() { 103 glDeleteBuffers(1, &mBuffer); 104} 105 106uint8_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 121void 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 135void 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 148PixelBuffer* 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