1 /*
2 * Copyright (c) 2024 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 }
40 }
41 #endif
42
43 constexpr GLenum INIT_TARGET = GL_COPY_WRITE_BUFFER;
44
MakeFlags(uint32_t requiredFlags)45 constexpr uint32_t MakeFlags(uint32_t requiredFlags)
46 {
47 uint32_t flags = 0;
48 if ((requiredFlags & CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == 0) {
49 // allow non device local (non gpu) memory (since device_local not set)
50 flags |= GL_CLIENT_STORAGE_BIT_EXT;
51 }
52 if (requiredFlags & CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
53 // can be mapped (reads?)
54 flags |= GL_MAP_WRITE_BIT;
55 }
56 if (requiredFlags & CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
57 // no need to flush
58 flags |= GL_MAP_COHERENT_BIT_EXT;
59 }
60 if (flags & GL_MAP_COHERENT_BIT_EXT) {
61 // It is an error to specify MAP_COHERENT_BIT_EXT without also specifying MAP_PERSISTENT_BIT_EXT.
62 flags |= GL_MAP_PERSISTENT_BIT_EXT;
63 }
64 if (flags & GL_MAP_PERSISTENT_BIT_EXT) {
65 // If <flags> contains MAP_PERSISTENT_BIT_EXT, it must also contain at least one of
66 // MAP_READ_BIT or MAP_WRITE_BIT.
67 flags |= GL_MAP_WRITE_BIT;
68 }
69 return flags;
70 }
71 } // namespace
72
GpuBufferGLES(Device & device,const GpuBufferDesc & desc)73 GpuBufferGLES::GpuBufferGLES(Device& device, const GpuBufferDesc& desc)
74 : device_((DeviceGLES&)device), plat_({ {}, 0u, 0u, desc.byteSize, 0u, desc.byteSize }), desc_(desc),
75 isPersistantlyMapped_((desc.memoryPropertyFlags & CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT) &&
76 (desc.memoryPropertyFlags & CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT)),
77 // At some point see if other memory property flags should be used.
78 isMappable_(IS_BIT(desc.memoryPropertyFlags, CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT))
79 {
80 PLUGIN_ASSERT(device_.IsActive());
81 glGenBuffers(1, &plat_.buffer);
82
83 // we need to handle the alignment only for mappable uniform buffers due to binding offset
84 GLint minAlignment = sizeof(float) * 4u; // NOTE: un-educated guess here.
85 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &minAlignment);
86
87 minAlignment = minAlignment > 0 ? minAlignment : 1;
88 plat_.alignedBindByteSize = ((plat_.bindMemoryByteSize + (minAlignment - 1)) / minAlignment) * minAlignment;
89 plat_.alignedByteSize = plat_.alignedBindByteSize;
90
91 if (desc.engineCreationFlags & CORE_ENGINE_BUFFER_CREATION_DYNAMIC_RING_BUFFER) {
92 isRingBuffer_ = true;
93 plat_.alignedByteSize *= device_.GetCommandBufferingCount();
94 }
95
96 const auto oldBind = device_.BoundBuffer(INIT_TARGET);
97 device_.BindBuffer(INIT_TARGET, plat_.buffer);
98
99 // check for the extension
100 if (const bool hasBufferStorageEXT = device_.HasExtension("GL_EXT_buffer_storage"); hasBufferStorageEXT) {
101 uint32_t flags = MakeFlags(desc.memoryPropertyFlags);
102 glBufferStorageEXT(INIT_TARGET, static_cast<GLsizeiptr>(plat_.alignedByteSize), nullptr, flags);
103 if (isPersistantlyMapped_) {
104 // make the persistant mapping..
105 flags = flags & (~GL_CLIENT_STORAGE_BIT_EXT); // not valid for map buffer..
106 data_ = reinterpret_cast<uint8_t*>(
107 glMapBufferRange(INIT_TARGET, 0, static_cast<GLsizeiptr>(plat_.alignedByteSize), flags));
108 }
109 } else {
110 // glBufferStorageEXT not found, so persistant mapping is not possible.
111 isPersistantlyMapped_ = false;
112 // legacy path, no glbufferStorage extension.
113 if (desc_.engineCreationFlags & EngineBufferCreationFlagBits::CORE_ENGINE_BUFFER_CREATION_SINGLE_SHOT_STAGING) {
114 // single shot staging buffer so give the driver more hints. (cpu write once, gpu read few times)
115 glBufferData(INIT_TARGET, static_cast<GLsizeiptr>(plat_.alignedByteSize), nullptr, GL_STREAM_DRAW);
116 } else {
117 if (isMappable_) {
118 // modified repeatedly , used many times.
119 glBufferData(INIT_TARGET, static_cast<GLsizeiptr>(plat_.alignedByteSize), nullptr, GL_DYNAMIC_DRAW);
120 } else {
121 // modified once, used many times.
122 glBufferData(INIT_TARGET, static_cast<GLsizeiptr>(plat_.alignedByteSize), nullptr, GL_STATIC_DRAW);
123 }
124 }
125 }
126 device_.BindBuffer(INIT_TARGET, oldBind);
127
128 #if (RENDER_PERF_ENABLED == 1)
129 RecordAllocation(static_cast<int64_t>(plat_.alignedByteSize));
130 #endif
131
132 #if (RENDER_DEBUG_GPU_RESOURCE_IDS == 1)
133 PLUGIN_LOG_E("gpu buffer >: %u", plat_.buffer);
134 #endif
135 }
136
~GpuBufferGLES()137 GpuBufferGLES::~GpuBufferGLES()
138 {
139 if (plat_.buffer) {
140 PLUGIN_ASSERT(device_.IsActive());
141 if ((isPersistantlyMapped_) || (isMapped_)) {
142 isMapped_ = false;
143 // Unmap the buffer.
144 device_.BindBuffer(GL_COPY_WRITE_BUFFER, plat_.buffer);
145 glUnmapBuffer(GL_COPY_WRITE_BUFFER);
146 device_.BindBuffer(GL_COPY_WRITE_BUFFER, 0);
147 }
148 device_.DeleteBuffer(plat_.buffer);
149 }
150
151 #if (RENDER_PERF_ENABLED == 1)
152 RecordAllocation(-static_cast<int64_t>(plat_.alignedByteSize));
153 #endif
154 #if (RENDER_DEBUG_GPU_RESOURCE_IDS == 1)
155 PLUGIN_LOG_E("gpu buffer <: %u", plat_.buffer);
156 #endif
157 }
158
GetDesc() const159 const GpuBufferDesc& GpuBufferGLES::GetDesc() const
160 {
161 return desc_;
162 }
163
GetPlatformData() const164 const GpuBufferPlatformDataGL& GpuBufferGLES::GetPlatformData() const
165 {
166 return plat_;
167 }
168
Map()169 void* GpuBufferGLES::Map()
170 {
171 if (!isMappable_) {
172 PLUGIN_LOG_E("trying to map non-mappable gpu buffer");
173 return nullptr;
174 }
175 if (isMapped_) {
176 PLUGIN_LOG_E("gpu buffer already mapped");
177 Unmap();
178 }
179 isMapped_ = true;
180
181 if (isRingBuffer_) {
182 plat_.currentByteOffset += plat_.alignedBindByteSize;
183 if (plat_.currentByteOffset >= plat_.alignedByteSize) {
184 plat_.currentByteOffset = 0;
185 }
186 }
187
188 void* ret = nullptr;
189 if (isPersistantlyMapped_) {
190 if (data_) {
191 ret = data_ + plat_.currentByteOffset;
192 }
193 } else {
194 PLUGIN_ASSERT(device_.IsActive());
195 const auto oldBind = device_.BoundBuffer(GL_COPY_WRITE_BUFFER);
196 device_.BindBuffer(GL_COPY_WRITE_BUFFER, plat_.buffer);
197 if (!isRingBuffer_) {
198 ret = glMapBufferRange(GL_COPY_WRITE_BUFFER, 0, static_cast<GLsizeiptr>(plat_.alignedByteSize),
199 GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
200 } else {
201 ret = glMapBufferRange(GL_COPY_WRITE_BUFFER, static_cast<GLintptr>(plat_.currentByteOffset),
202 static_cast<GLsizeiptr>(plat_.bindMemoryByteSize), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT);
203 }
204 device_.BindBuffer(GL_COPY_WRITE_BUFFER, oldBind);
205 }
206 return ret;
207 }
208
Unmap() const209 void GpuBufferGLES::Unmap() const
210 {
211 if (!isMappable_) {
212 PLUGIN_LOG_E("trying to unmap non-mappable gpu buffer");
213 }
214 if (!isMapped_) {
215 PLUGIN_LOG_E("gpu buffer not mapped");
216 }
217 isMapped_ = false;
218
219 if (!isPersistantlyMapped_) {
220 PLUGIN_ASSERT(device_.IsActive());
221 const auto oldBind = device_.BoundBuffer(GL_COPY_WRITE_BUFFER);
222 device_.BindBuffer(GL_COPY_WRITE_BUFFER, plat_.buffer);
223 glUnmapBuffer(GL_COPY_WRITE_BUFFER);
224 device_.BindBuffer(GL_COPY_WRITE_BUFFER, oldBind);
225 }
226 }
227
MapMemory()228 void* GpuBufferGLES::MapMemory()
229 {
230 if (!isMappable_) {
231 PLUGIN_LOG_E("trying to map non-mappable gpu buffer");
232 return nullptr;
233 }
234 if (isMapped_) {
235 PLUGIN_LOG_E("gpu buffer already mapped");
236 Unmap();
237 }
238 isMapped_ = true;
239
240 void* ret = nullptr;
241 if (isPersistantlyMapped_) {
242 ret = data_;
243 } else {
244 PLUGIN_ASSERT(device_.IsActive());
245 const auto oldBind = device_.BoundBuffer(GL_COPY_WRITE_BUFFER);
246 device_.BindBuffer(GL_COPY_WRITE_BUFFER, plat_.buffer);
247 if (!isRingBuffer_) {
248 ret = glMapBufferRange(GL_COPY_WRITE_BUFFER, 0, static_cast<GLsizeiptr>(plat_.alignedByteSize),
249 GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
250 } else {
251 ret = glMapBufferRange(GL_COPY_WRITE_BUFFER, 0, static_cast<GLsizeiptr>(plat_.alignedByteSize),
252 GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT);
253 }
254 device_.BindBuffer(GL_COPY_WRITE_BUFFER, oldBind);
255 }
256 return ret;
257 }
258 RENDER_END_NAMESPACE()
259