blob: 910a9889db1fc8ad2f24a22b2aa76d1e097a163b [file] [log] [blame]
Stan Ilieva683eb32018-09-04 15:42:18 +00001/*
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