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 #define LOG_TAG "OpenGLRenderer" 18 19 #include <utils/Log.h> 20 21 #include "Caches.h" 22 #include "Extensions.h" 23 #include "PixelBuffer.h" 24 #include "Properties.h" 25 26 namespace android { 27 namespace uirenderer { 28 29 /////////////////////////////////////////////////////////////////////////////// 30 // CPU pixel buffer 31 /////////////////////////////////////////////////////////////////////////////// 32 33 class CpuPixelBuffer: public PixelBuffer { 34 public: 35 CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height); 36 ~CpuPixelBuffer(); 37 38 uint8_t* map(AccessMode mode = kAccessMode_ReadWrite); 39 void unmap(); 40 41 uint8_t* getMappedPointer() const; 42 43 void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset); 44 45 private: 46 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 CpuPixelBuffer::~CpuPixelBuffer() { 55 delete[] mBuffer; 56 } 57 58 uint8_t* CpuPixelBuffer::map(AccessMode mode) { 59 if (mAccessMode == kAccessMode_None) { 60 mAccessMode = mode; 61 } 62 return mBuffer; 63 } 64 65 void CpuPixelBuffer::unmap() { 66 mAccessMode = kAccessMode_None; 67 } 68 69 uint8_t* CpuPixelBuffer::getMappedPointer() const { 70 return mAccessMode == kAccessMode_None ? NULL : mBuffer; 71 } 72 73 void CpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) { 74 glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, 75 mFormat, GL_UNSIGNED_BYTE, mBuffer + offset); 76 } 77 78 /////////////////////////////////////////////////////////////////////////////// 79 // GPU pixel buffer 80 /////////////////////////////////////////////////////////////////////////////// 81 82 class GpuPixelBuffer: public PixelBuffer { 83 public: 84 GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height); 85 ~GpuPixelBuffer(); 86 87 uint8_t* map(AccessMode mode = kAccessMode_ReadWrite); 88 void unmap(); 89 90 uint8_t* getMappedPointer() const; 91 92 void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset); 93 94 private: 95 GLuint mBuffer; 96 uint8_t* mMappedPointer; 97 Caches& mCaches; 98 }; 99 100 GpuPixelBuffer::GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height): 101 PixelBuffer(format, width, height), mMappedPointer(0), mCaches(Caches::getInstance()) { 102 glGenBuffers(1, &mBuffer); 103 mCaches.bindPixelBuffer(mBuffer); 104 glBufferData(GL_PIXEL_UNPACK_BUFFER, getSize(), NULL, GL_DYNAMIC_DRAW); 105 mCaches.unbindPixelBuffer(); 106 } 107 108 GpuPixelBuffer::~GpuPixelBuffer() { 109 glDeleteBuffers(1, &mBuffer); 110 } 111 112 uint8_t* GpuPixelBuffer::map(AccessMode mode) { 113 if (mAccessMode == kAccessMode_None) { 114 mCaches.bindPixelBuffer(mBuffer); 115 mMappedPointer = (uint8_t*) glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, getSize(), mode); 116 mAccessMode = mode; 117 } 118 119 return mMappedPointer; 120 } 121 122 void GpuPixelBuffer::unmap() { 123 if (mAccessMode != kAccessMode_None) { 124 if (mMappedPointer) { 125 mCaches.bindPixelBuffer(mBuffer); 126 glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); 127 } 128 mAccessMode = kAccessMode_None; 129 mMappedPointer = NULL; 130 } 131 } 132 133 uint8_t* GpuPixelBuffer::getMappedPointer() const { 134 return mMappedPointer; 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.bindPixelBuffer(mBuffer); 140 unmap(); 141 glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat, 142 GL_UNSIGNED_BYTE, (void*) offset); 143 } 144 145 /////////////////////////////////////////////////////////////////////////////// 146 // Factory 147 /////////////////////////////////////////////////////////////////////////////// 148 149 PixelBuffer* PixelBuffer::create(GLenum format, uint32_t width, uint32_t height, BufferType type) { 150 bool gpuBuffer = type == kBufferType_Auto && Extensions::getInstance().getMajorGlVersion() >= 3; 151 if (gpuBuffer) { 152 char property[PROPERTY_VALUE_MAX]; 153 if (property_get(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, property, "false") > 0) { 154 if (!strcmp(property, "true")) { 155 return new GpuPixelBuffer(format, width, height); 156 } 157 } 158 } 159 return new CpuPixelBuffer(format, width, height); 160 } 161 162 }; // namespace uirenderer 163 }; // namespace android 164