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 uint8_t* CpuPixelBuffer::map(AccessMode mode) {
     54     if (mAccessMode == kAccessMode_None) {
     55         mAccessMode = mode;
     56     }
     57     return mBuffer.get();
     58 }
     59 
     60 void CpuPixelBuffer::unmap() {
     61     mAccessMode = kAccessMode_None;
     62 }
     63 
     64 void 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 
     73 class GpuPixelBuffer : public PixelBuffer {
     74 public:
     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 
     82 protected:
     83     void unmap() override;
     84 
     85 private:
     86     GLuint mBuffer;
     87     uint8_t* mMappedPointer;
     88     Caches& mCaches;
     89 };
     90 
     91 GpuPixelBuffer::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 
    102 GpuPixelBuffer::~GpuPixelBuffer() {
    103     glDeleteBuffers(1, &mBuffer);
    104 }
    105 
    106 uint8_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 
    121 void 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 
    135 void 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 
    148 PixelBuffer* 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