1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "gpu_buffer_gles.h"
17
18 #if (RENDER_PERF_ENABLED == 1)
19 #include <core/implementation_uids.h>
20 #include <core/perf/intf_performance_data_manager.h>
21 #endif
22 #include <render/namespace.h>
23
24 #include "gles/device_gles.h"
25 #include "gles/gl_functions.h"
26 #include "util/log.h"
27
28 #define IS_BIT(value, bit) ((((value) & (bit)) == (bit)) ? (GLboolean)GL_TRUE : (GLboolean)GL_FALSE)
29
30 RENDER_BEGIN_NAMESPACE()
31 namespace {
32 #if (RENDER_PERF_ENABLED == 1)
RecordAllocation(const int64_t alignedByteSize)33 void RecordAllocation(const int64_t alignedByteSize)
34 {
35 if (auto* inst = CORE_NS::GetInstance<CORE_NS::IPerformanceDataManagerFactory>(CORE_NS::UID_PERFORMANCE_FACTORY);
36 inst) {
37 CORE_NS::IPerformanceDataManager* pdm = inst->Get("Memory");
38 pdm->UpdateData("AllGpuBuffers", "GPU_BUFFER", alignedByteSize,
39 CORE_NS::IPerformanceDataManager::PerformanceTimingData::DataType::BYTES);
40 }
41 }
42 #endif
43
44 constexpr GLenum INIT_TARGET = GL_COPY_WRITE_BUFFER;
45
MakeFlags(uint32_t requiredFlags)46 constexpr uint32_t MakeFlags(uint32_t requiredFlags)
47 {
48 uint32_t flags = 0;
49 if ((requiredFlags & CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == 0) {
50 // allow non device local (non gpu) memory (since device_local not set)
51 flags |= GL_CLIENT_STORAGE_BIT_EXT;
52 }
53 if (requiredFlags & CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
54 // can be mapped (reads?)
55 flags |= GL_MAP_WRITE_BIT;
56 }
57 if (requiredFlags & CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
58 // no need to flush
59 flags |= GL_MAP_COHERENT_BIT_EXT;
60 }
61 if (flags & GL_MAP_COHERENT_BIT_EXT) {
62 // It is an error to specify MAP_COHERENT_BIT_EXT without also specifying MAP_PERSISTENT_BIT_EXT.
63 flags |= GL_MAP_PERSISTENT_BIT_EXT;
64 }
65 if (flags & GL_MAP_PERSISTENT_BIT_EXT) {
66 // If <flags> contains MAP_PERSISTENT_BIT_EXT, it must also contain at least one of
67 // MAP_READ_BIT or MAP_WRITE_BIT.
68 flags |= GL_MAP_WRITE_BIT;
69 }
70 return flags;
71 }
72
73 class ActivateDevice final {
74 public:
ActivateDevice(DeviceGLES & device)75 ActivateDevice(DeviceGLES& device) : device_(device), isActive_(device.IsActive())
76 {
77 if (!isActive_) {
78 device_.Activate();
79 }
80 }
81
~ActivateDevice()82 ~ActivateDevice()
83 {
84 if (!isActive_) {
85 device_.Deactivate();
86 }
87 }
88
89 ActivateDevice(const ActivateDevice&) = delete;
90 ActivateDevice(ActivateDevice&&) noexcept = delete;
91
92 private:
93 DeviceGLES& device_;
94 bool isActive_ { false };
95 };
96 } // namespace
97
GpuBufferGLES(Device & device,const GpuBufferDesc & desc)98 GpuBufferGLES::GpuBufferGLES(Device& device, const GpuBufferDesc& desc)
99 : device_((DeviceGLES&)device), plat_({ {}, 0u, 0u, desc.byteSize, 0u, desc.byteSize }), desc_(desc),
100 isPersistantlyMapped_((desc.memoryPropertyFlags & CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT) &&
101 (desc.memoryPropertyFlags & CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT)),
102 // At some point see if other memory property flags should be used.
103 isMappable_(IS_BIT(desc.memoryPropertyFlags, CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT))
104 {
105 PLUGIN_ASSERT(device_.IsActive());
106 glGenBuffers(1, &plat_.buffer);
107
108 // we need to handle the alignment only for mappable uniform buffers due to binding offset
109 GLint minAlignment = sizeof(float) * 4u; // NOTE: un-educated guess here.
110 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &minAlignment);
111
112 minAlignment = minAlignment > 0 ? minAlignment : 1;
113 plat_.alignedBindByteSize = ((plat_.bindMemoryByteSize + (minAlignment - 1)) / minAlignment) * minAlignment;
114 plat_.alignedByteSize = plat_.alignedBindByteSize;
115
116 if (desc.engineCreationFlags & CORE_ENGINE_BUFFER_CREATION_DYNAMIC_RING_BUFFER) {
117 isRingBuffer_ = true;
118 plat_.alignedByteSize *= device_.GetCommandBufferingCount();
119 }
120
121 const auto oldBind = device_.BoundBuffer(INIT_TARGET);
122 device_.BindBuffer(INIT_TARGET, plat_.buffer);
123
124 // check for the extension
125 if (const bool hasBufferStorageEXT = device_.HasExtension("GL_EXT_buffer_storage"); hasBufferStorageEXT) {
126 uint32_t flags = MakeFlags(desc.memoryPropertyFlags);
127 glBufferStorageEXT(INIT_TARGET, static_cast<GLsizeiptr>(plat_.alignedByteSize), nullptr, flags);
128 if (isPersistantlyMapped_) {
129 // make the persistant mapping..
130 flags = flags & (~GL_CLIENT_STORAGE_BIT_EXT); // not valid for map buffer..
131 data_ = reinterpret_cast<uint8_t*>(
132 glMapBufferRange(INIT_TARGET, 0, static_cast<GLsizeiptr>(plat_.alignedByteSize), flags));
133 }
134 } else {
135 // glBufferStorageEXT not found, so persistant mapping is not possible.
136 isPersistantlyMapped_ = false;
137 // legacy path, no glbufferStorage extension.
138 if (desc_.engineCreationFlags & EngineBufferCreationFlagBits::CORE_ENGINE_BUFFER_CREATION_SINGLE_SHOT_STAGING) {
139 // single shot staging buffer so give the driver more hints. (cpu write once, gpu read few times)
140 glBufferData(INIT_TARGET, static_cast<GLsizeiptr>(plat_.alignedByteSize), nullptr, GL_STREAM_DRAW);
141 } else {
142 if (isMappable_) {
143 // modified repeatedly , used many times.
144 glBufferData(INIT_TARGET, static_cast<GLsizeiptr>(plat_.alignedByteSize), nullptr, GL_DYNAMIC_DRAW);
145 } else {
146 // modified once, used many times.
147 glBufferData(INIT_TARGET, static_cast<GLsizeiptr>(plat_.alignedByteSize), nullptr, GL_STATIC_DRAW);
148 }
149 }
150 }
151 device_.BindBuffer(INIT_TARGET, oldBind);
152
153 #if (RENDER_PERF_ENABLED == 1)
154 RecordAllocation(static_cast<int64_t>(plat_.alignedByteSize));
155 #endif
156
157 #if (RENDER_DEBUG_GPU_RESOURCE_IDS == 1)
158 PLUGIN_LOG_E("gpu buffer >: %u", plat_.buffer);
159 #endif
160 }
161
GpuBufferGLES(Device & device,const GpuBufferDesc & desc,const GpuBufferPlatformData & plat)162 GpuBufferGLES::GpuBufferGLES(Device& device, const GpuBufferDesc& desc, const GpuBufferPlatformData& plat)
163 : device_((DeviceGLES&)device), plat_(static_cast<const GpuBufferPlatformDataGL&>(plat)), desc_(desc),
164 isPersistantlyMapped_((desc.memoryPropertyFlags & CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT) &&
165 (desc.memoryPropertyFlags & CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT)),
166 // At some point see if other memory property flags should be used.
167 isMappable_(IS_BIT(desc.memoryPropertyFlags, CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT))
168 {
169 PLUGIN_ASSERT(device_.IsActive());
170 glGenBuffers(1, &plat_.buffer);
171 const auto oldBind = device_.BoundBuffer(INIT_TARGET);
172 device_.BindBuffer(INIT_TARGET, plat_.buffer);
173 if (plat_.eglClientBuffer && glBufferStorageExternalEXT) {
174 uint32_t flags = MakeFlags(desc.memoryPropertyFlags);
175 glBufferStorageExternalEXT(INIT_TARGET, 0, plat_.alignedByteSize,
176 reinterpret_cast<GLeglClientBufferEXT>(plat_.eglClientBuffer), flags);
177 }
178 device_.BindBuffer(INIT_TARGET, oldBind);
179 }
180
~GpuBufferGLES()181 GpuBufferGLES::~GpuBufferGLES()
182 {
183 if (plat_.buffer) {
184 PLUGIN_ASSERT(device_.IsActive());
185 if ((isPersistantlyMapped_) || (isMapped_)) {
186 isMapped_ = false;
187 // Unmap the buffer.
188 device_.BindBuffer(GL_COPY_WRITE_BUFFER, plat_.buffer);
189 glUnmapBuffer(GL_COPY_WRITE_BUFFER);
190 device_.BindBuffer(GL_COPY_WRITE_BUFFER, 0);
191 }
192 device_.DeleteBuffer(plat_.buffer);
193 }
194
195 #if (RENDER_PERF_ENABLED == 1)
196 RecordAllocation(-static_cast<int64_t>(plat_.alignedByteSize));
197 #endif
198 #if (RENDER_DEBUG_GPU_RESOURCE_IDS == 1)
199 PLUGIN_LOG_E("gpu buffer <: %u", plat_.buffer);
200 #endif
201 }
202
GetDesc() const203 const GpuBufferDesc& GpuBufferGLES::GetDesc() const
204 {
205 return desc_;
206 }
207
GetPlatformData() const208 const GpuBufferPlatformDataGL& GpuBufferGLES::GetPlatformData() const
209 {
210 return plat_;
211 }
212
Map()213 void* GpuBufferGLES::Map()
214 {
215 if (!isMappable_) {
216 PLUGIN_LOG_E("trying to map non-mappable gpu buffer");
217 return nullptr;
218 }
219 if (isMapped_) {
220 PLUGIN_LOG_E("gpu buffer already mapped");
221 Unmap();
222 }
223 isMapped_ = true;
224
225 if (isRingBuffer_) {
226 plat_.currentByteOffset += plat_.alignedBindByteSize;
227 if (plat_.currentByteOffset >= plat_.alignedByteSize) {
228 plat_.currentByteOffset = 0;
229 }
230 }
231
232 void* ret = nullptr;
233 if (isPersistantlyMapped_) {
234 if (data_) {
235 ret = data_ + plat_.currentByteOffset;
236 }
237 } else {
238 const auto keepActive = ActivateDevice(device_);
239
240 const auto oldBind = device_.BoundBuffer(GL_COPY_WRITE_BUFFER);
241 device_.BindBuffer(GL_COPY_WRITE_BUFFER, plat_.buffer);
242 if (!isRingBuffer_) {
243 ret = glMapBufferRange(GL_COPY_WRITE_BUFFER, 0, static_cast<GLsizeiptr>(plat_.alignedByteSize),
244 GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
245 } else {
246 ret = glMapBufferRange(GL_COPY_WRITE_BUFFER, static_cast<GLintptr>(plat_.currentByteOffset),
247 static_cast<GLsizeiptr>(plat_.bindMemoryByteSize), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT);
248 }
249 device_.BindBuffer(GL_COPY_WRITE_BUFFER, oldBind);
250 }
251 return ret;
252 }
253
Unmap() const254 void GpuBufferGLES::Unmap() const
255 {
256 if (!isMappable_) {
257 PLUGIN_LOG_E("trying to unmap non-mappable gpu buffer");
258 }
259 if (!isMapped_) {
260 PLUGIN_LOG_E("gpu buffer not mapped");
261 }
262 isMapped_ = false;
263
264 if (!isPersistantlyMapped_) {
265 const auto keepActive = ActivateDevice(device_);
266
267 const auto oldBind = device_.BoundBuffer(GL_COPY_WRITE_BUFFER);
268 device_.BindBuffer(GL_COPY_WRITE_BUFFER, plat_.buffer);
269 glUnmapBuffer(GL_COPY_WRITE_BUFFER);
270 device_.BindBuffer(GL_COPY_WRITE_BUFFER, oldBind);
271 }
272 }
273
MapMemory()274 void* GpuBufferGLES::MapMemory()
275 {
276 if (!isMappable_) {
277 PLUGIN_LOG_E("trying to map non-mappable gpu buffer");
278 return nullptr;
279 }
280 if (isMapped_) {
281 PLUGIN_LOG_E("gpu buffer already mapped");
282 Unmap();
283 }
284 isMapped_ = true;
285
286 void* ret = nullptr;
287 if (isPersistantlyMapped_) {
288 ret = data_;
289 } else {
290 const auto keepActive = ActivateDevice(device_);
291
292 const auto oldBind = device_.BoundBuffer(GL_COPY_WRITE_BUFFER);
293 device_.BindBuffer(GL_COPY_WRITE_BUFFER, plat_.buffer);
294 if (!isRingBuffer_) {
295 ret = glMapBufferRange(GL_COPY_WRITE_BUFFER, 0, static_cast<GLsizeiptr>(plat_.alignedByteSize),
296 GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
297 } else {
298 ret = glMapBufferRange(GL_COPY_WRITE_BUFFER, 0, static_cast<GLsizeiptr>(plat_.alignedByteSize),
299 GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT);
300 }
301 device_.BindBuffer(GL_COPY_WRITE_BUFFER, oldBind);
302 }
303 return ret;
304 }
305 RENDER_END_NAMESPACE()
306