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