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