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_image_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
23 #include <base/math/vector.h>
24 #include <render/namespace.h>
25
26 #include "gles/device_gles.h"
27 #include "gles/gl_functions.h"
28 #include "util/log.h"
29
30 using namespace BASE_NS;
31
32 RENDER_BEGIN_NAMESPACE()
33 namespace {
34 #if (RENDER_PERF_ENABLED == 1)
RecordAllocation(const int64_t alignedByteSize)35 void RecordAllocation(const int64_t alignedByteSize)
36 {
37 if (auto* inst = CORE_NS::GetInstance<CORE_NS::IPerformanceDataManagerFactory>(CORE_NS::UID_PERFORMANCE_FACTORY);
38 inst) {
39 CORE_NS::IPerformanceDataManager* pdm = inst->Get("Memory");
40 pdm->UpdateData("AllGpuImages", "GPU_IMAGE", alignedByteSize);
41 }
42 }
43 #endif
44
ConvertFormat(const DeviceGLES::ImageFormat & fmt)45 GpuImagePlatformDataGL ConvertFormat(const DeviceGLES::ImageFormat& fmt)
46 {
47 GpuImagePlatformDataGL result {};
48 if (fmt.coreFormat == BASE_FORMAT_UNDEFINED) {
49 PLUGIN_ASSERT_MSG(false, "Unsupported texture format in GpuImageGLES::convertFormat!");
50 }
51 result.bytesperpixel = fmt.bytesperpixel;
52 result.dataType = fmt.dataType;
53 result.format = fmt.format;
54 result.internalFormat = fmt.internalFormat;
55 result.compression = { fmt.compression.compressed, fmt.compression.blockW, fmt.compression.blockH,
56 fmt.compression.bytesperblock };
57 result.swizzle = fmt.swizzle;
58 return result;
59 }
60
ConvertSampleCountFlags(SampleCountFlags flags)61 constexpr uint32_t ConvertSampleCountFlags(SampleCountFlags flags)
62 {
63 uint32_t sampleCount = 1;
64 if ((uint32_t)flags != 1) {
65 // MSAA
66 sampleCount = (uint32_t)flags;
67 }
68 return sampleCount;
69 }
70
MapSwizzle(ComponentSwizzle swizzle,uint32_t input)71 GLenum MapSwizzle(ComponentSwizzle swizzle, uint32_t input)
72 {
73 switch (swizzle) {
74 case CORE_COMPONENT_SWIZZLE_IDENTITY:
75 return input;
76 case CORE_COMPONENT_SWIZZLE_ZERO:
77 return GL_ZERO;
78 case CORE_COMPONENT_SWIZZLE_ONE:
79 return GL_ONE;
80 case CORE_COMPONENT_SWIZZLE_R:
81 return GL_RED;
82 case CORE_COMPONENT_SWIZZLE_G:
83 return GL_GREEN;
84 case CORE_COMPONENT_SWIZZLE_B:
85 return GL_BLUE;
86 case CORE_COMPONENT_SWIZZLE_A:
87 return GL_ALPHA;
88 default:
89 break;
90 }
91 return input;
92 }
93
DoSwizzle(const GpuImageDesc & desc,GpuImagePlatformDataGL & plat)94 void DoSwizzle(const GpuImageDesc& desc, GpuImagePlatformDataGL& plat)
95 {
96 plat.swizzle.x = MapSwizzle(desc.componentMapping.r, plat.swizzle.x);
97 plat.swizzle.y = MapSwizzle(desc.componentMapping.g, plat.swizzle.y);
98 plat.swizzle.z = MapSwizzle(desc.componentMapping.b, plat.swizzle.z);
99 plat.swizzle.w = MapSwizzle(desc.componentMapping.a, plat.swizzle.w);
100 }
101
GenerateImageStorage(DeviceGLES & device,const GpuImageDesc & desc,GpuImagePlatformDataGL & plat)102 void GenerateImageStorage(DeviceGLES& device, const GpuImageDesc& desc, GpuImagePlatformDataGL& plat)
103 {
104 const uint32_t sampleCount = ConvertSampleCountFlags(desc.sampleCountFlags);
105 glGenTextures(1, &plat.image);
106 #if (RENDER_DEBUG_GPU_RESOURCE_IDS == 1)
107 if (plat.image) {
108 PLUGIN_LOG_D("gpu image id >: %u", plat.image);
109 }
110 #endif
111
112 const Math::UVec2 size2D { desc.width, desc.height };
113 switch (desc.imageViewType) {
114 case CORE_IMAGE_VIEW_TYPE_2D: {
115 PLUGIN_ASSERT_MSG(desc.layerCount == 1, "layerCount != 1 for normal texture!");
116 if (sampleCount > 1) {
117 plat.type = GL_TEXTURE_2D_MULTISAMPLE;
118 // must use fixed sample locations so that renderbuffer/texture fbos work.
119 device.TexStorage2DMultisample(plat.image, plat.type, sampleCount, plat.internalFormat, size2D, true);
120 } else {
121 plat.type = GL_TEXTURE_2D;
122 device.TexStorage2D(plat.image, plat.type, desc.mipCount, plat.internalFormat, size2D);
123 }
124 break;
125 }
126 case CORE_IMAGE_VIEW_TYPE_CUBE: {
127 PLUGIN_ASSERT_MSG(desc.layerCount == 6, "layerCount != 6 for cubemap!");
128 plat.type = GL_TEXTURE_CUBE_MAP;
129 device.TexStorage2D(plat.image, plat.type, desc.mipCount, plat.internalFormat, size2D);
130 break;
131 }
132 case CORE_IMAGE_VIEW_TYPE_2D_ARRAY: {
133 PLUGIN_ASSERT_MSG(desc.layerCount <= 256, "layerCount > 256 for 2D Array!");
134 if (sampleCount > 1 && device.HasExtension("GL_EXT_multiview_texture_multisample")) {
135 plat.type = GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
136 // must use fixed sample locations so that renderbuffer/texture fbos work.
137 device.TexStorage3DMultisample(plat.image, plat.type, sampleCount, plat.internalFormat,
138 { desc.width, desc.height, desc.layerCount }, true);
139 } else {
140 plat.type = GL_TEXTURE_2D_ARRAY;
141 device.TexStorage3D(plat.image, plat.type, desc.mipCount, plat.internalFormat,
142 { desc.width, desc.height, desc.layerCount });
143 }
144 break;
145 }
146 case CORE_IMAGE_VIEW_TYPE_3D: {
147 plat.type = GL_TEXTURE_3D;
148 device.TexStorage3D(
149 plat.image, plat.type, desc.mipCount, plat.internalFormat, { desc.width, desc.height, desc.depth });
150 break;
151 }
152 case CORE_IMAGE_VIEW_TYPE_1D:
153 case CORE_IMAGE_VIEW_TYPE_1D_ARRAY:
154 case CORE_IMAGE_VIEW_TYPE_CUBE_ARRAY:
155 default:
156 PLUGIN_ASSERT_MSG(false, "UNSUPPORTED IMAGEVIEW TYPE");
157 plat.type = GL_NONE;
158 break;
159 }
160 // set swizzle.
161 DoSwizzle(desc, plat);
162 device.TexSwizzle(plat.image, plat.type, plat.swizzle);
163 }
164 } // namespace
165
GetPlatformData(const DeviceGLES & device,Format format)166 GpuImagePlatformDataGL GpuImageGLES::GetPlatformData(const DeviceGLES& device, Format format)
167 {
168 const auto& fmt = device.GetGlImageFormat(format);
169 return ConvertFormat(fmt);
170 }
171
GpuImageGLES(Device & device,const GpuImageDesc & desc)172 GpuImageGLES::GpuImageGLES(Device& device, const GpuImageDesc& desc)
173 : GpuImage(), device_((DeviceGLES&)device), desc_(desc)
174 {
175 PLUGIN_ASSERT(device_.IsActive());
176 PLUGIN_ASSERT_MSG(desc_.memoryPropertyFlags & MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
177 "Device local memory is only memory property supported for GLES GpuImage (flags: %u)",
178 desc_.memoryPropertyFlags);
179 plat_ = GetPlatformData(device_, desc_.format);
180 // Check for formats that require special attention.
181 if ((desc.usageFlags & CORE_IMAGE_USAGE_STORAGE_BIT)) {
182 // Force the format to "other" (there might be others that require "special handling".
183 if (desc_.format == BASE_FORMAT_B10G11R11_UFLOAT_PACK32) {
184 plat_ = GetPlatformData(device_, BASE_FORMAT_R16G16B16A16_SFLOAT);
185 }
186 }
187 const bool isArray =
188 (desc_.imageViewType == CORE_IMAGE_VIEW_TYPE_1D_ARRAY || desc_.imageViewType == CORE_IMAGE_VIEW_TYPE_2D_ARRAY ||
189 desc_.imageViewType == CORE_IMAGE_VIEW_TYPE_CUBE_ARRAY);
190 const bool isSrc = (desc_.usageFlags & CORE_IMAGE_USAGE_TRANSFER_SRC_BIT);
191 const bool isDst = (desc_.usageFlags & CORE_IMAGE_USAGE_TRANSFER_DST_BIT);
192 const bool isSample = (desc_.usageFlags & CORE_IMAGE_USAGE_SAMPLED_BIT);
193 const bool isStorage = (desc_.usageFlags & CORE_IMAGE_USAGE_STORAGE_BIT);
194 // could check for bool isColor = (desc_.usageFlags & CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
195 // could check for bool isDepth = (desc_.usageFlags & CORE_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
196 // could check for bool isTrans = (desc_.usageFlags & CORE_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT);
197 const bool isInput = (desc_.usageFlags & CORE_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
198 if ((!isArray) && (!isSrc) && (!isDst) && (!isSample) && (!isStorage) && (!isInput)) {
199 // Use render buffers for "non-input,non-compute,non-texture,no src/dst transfer" images
200 // ie. temporary render targets
201 glGenRenderbuffers(1, &plat_.renderBuffer);
202 #if (RENDER_DEBUG_GPU_RESOURCE_IDS == 1)
203 if (plat_.renderBuffer) {
204 PLUGIN_LOG_D("gpu renderbuffer id >: %u", plat_.renderBuffer);
205 }
206 #endif
207 glBindRenderbuffer(GL_RENDERBUFFER, plat_.renderBuffer);
208 const uint32_t sampleCount = ConvertSampleCountFlags(desc_.sampleCountFlags);
209 if (sampleCount > 1) {
210 #if RENDER_HAS_GLES_BACKEND
211 // Sadly Mali driver doesn't understand a multisampled render buffer created with the core function attached
212 // to the same FBO with FramebufferTexture2DMultisampleEXT attachments, so in order to use that on Mali
213 // render buffer must also use the EXT function.
214 if (device_.HasExtension("GL_EXT_multisampled_render_to_texture2")) {
215 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, (GLsizei)sampleCount, plat_.internalFormat,
216 (GLsizei)desc_.width, (GLsizei)desc_.height);
217 } else {
218 glRenderbufferStorageMultisample(GL_RENDERBUFFER, (GLsizei)sampleCount, plat_.internalFormat,
219 (GLsizei)desc_.width, (GLsizei)desc_.height);
220 }
221 #else
222 glRenderbufferStorageMultisample(GL_RENDERBUFFER, (GLsizei)sampleCount, plat_.internalFormat,
223 (GLsizei)desc_.width, (GLsizei)desc_.height);
224 #endif
225 } else {
226 glRenderbufferStorage(GL_RENDERBUFFER, plat_.internalFormat, (GLsizei)desc_.width, (GLsizei)desc_.height);
227 }
228 } else {
229 GenerateImageStorage(device_, desc_, plat_);
230 }
231 #if (RENDER_PERF_ENABLED == 1)
232 RecordAllocation(static_cast<int64_t>(plat_.bytesperpixel * desc_.width * desc_.height * desc_.depth));
233 #endif
234 }
235
GpuImageGLES(Device & device,const GpuImageDesc & desc,const GpuImagePlatformData & platformData)236 GpuImageGLES::GpuImageGLES(Device& device, const GpuImageDesc& desc, const GpuImagePlatformData& platformData)
237 : GpuImage(), device_((DeviceGLES&)device), plat_((const GpuImagePlatformDataGL&)platformData), desc_(desc),
238 ownsResources_(false)
239 {
240 PLUGIN_ASSERT(device_.IsActive());
241 #if (RENDER_HAS_GLES_BACKEND == 1)
242 if (reinterpret_cast<GLeglImageOES>(plat_.eglImage) != 0) {
243 glGenTextures(1, &plat_.image);
244 #if (RENDER_DEBUG_GPU_RESOURCE_IDS == 1)
245 PLUGIN_LOG_D("gpu image id >: %u", plat_.image);
246 #endif
247
248 constexpr const uint32_t TEMP_BIND_UNIT = 15u;
249 // store the previous tex id for restoring.
250 const auto oldTex = device_.BoundTexture(TEMP_BIND_UNIT, GL_TEXTURE_EXTERNAL_OES);
251 device_.BindTexture(TEMP_BIND_UNIT, GL_TEXTURE_EXTERNAL_OES, plat_.image);
252
253 // need to make sure the correct texUnit is active when calling GL directly.
254 device_.SetActiveTextureUnit(TEMP_BIND_UNIT);
255 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
256 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
257 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
258 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
259 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, reinterpret_cast<GLeglImageOES>(plat_.eglImage));
260
261 // set swizzle.
262 DoSwizzle(desc, plat_);
263 device_.TexSwizzle(plat_.image, GL_TEXTURE_EXTERNAL_OES, plat_.swizzle);
264
265 // restore previous tex id.
266 device_.BindTexture(TEMP_BIND_UNIT, GL_TEXTURE_EXTERNAL_OES, oldTex);
267 }
268 #endif // RENDER_HAS_GLES_BACKEND
269 }
270
~GpuImageGLES()271 GpuImageGLES::~GpuImageGLES()
272 {
273 PLUGIN_ASSERT(device_.IsActive());
274 if (ownsResources_) {
275 if (plat_.image) {
276 device_.DeleteTexture(plat_.image);
277 #if (RENDER_DEBUG_GPU_RESOURCE_IDS == 1)
278 PLUGIN_LOG_D("gpu image id <: %u", plat_.image);
279 #endif
280 }
281 if (plat_.renderBuffer) {
282 glDeleteRenderbuffers(1, &plat_.renderBuffer);
283 #if (RENDER_DEBUG_GPU_RESOURCE_IDS == 1)
284 PLUGIN_LOG_D("gpu render buffer id <: %u", plat_.renderBuffer);
285 #endif
286 }
287
288 #if (RENDER_PERF_ENABLED == 1)
289 RecordAllocation(-static_cast<int64_t>(plat_.bytesperpixel * desc_.width * desc_.height * desc_.depth));
290 #endif
291 }
292 #if (RENDER_HAS_GLES_BACKEND == 1)
293 if (reinterpret_cast<GLeglImageOES>(plat_.eglImage) != 0) {
294 if (plat_.image) {
295 device_.DeleteTexture(plat_.image);
296 #if (RENDER_DEBUG_GPU_RESOURCE_IDS == 1)
297 PLUGIN_LOG_D("gpu image id <: %u", plat_.image);
298 #endif
299 }
300 }
301 #endif
302 }
303
GetDesc() const304 const GpuImageDesc& GpuImageGLES::GetDesc() const
305 {
306 return desc_;
307 }
308
GetPlatformData() const309 const GpuImagePlatformDataGL& GpuImageGLES::GetPlatformData() const
310 {
311 return plat_;
312 }
313
GetBasePlatformData() const314 const GpuImagePlatformData& GpuImageGLES::GetBasePlatformData() const
315 {
316 return plat_;
317 }
318
GetAdditionalFlags() const319 GpuImage::AdditionalFlags GpuImageGLES::GetAdditionalFlags() const
320 {
321 // expecting all egl images to need special platform conversion (e.g. OES binding)
322 return (plat_.eglImage) ? ADDITIONAL_PLATFORM_CONVERSION_BIT : 0u;
323 }
324 RENDER_END_NAMESPACE()
325