• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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