Home | History | Annotate | Download | only in hwui
      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