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