• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "device_gles.h"
17 
18 #include <algorithm>
19 
20 #include <base/containers/string.h>
21 #include <base/math/vector.h>
22 #include <base/util/compile_time_hashes.h>
23 #include <render/namespace.h>
24 
25 #include "device/gpu_resource_manager.h"
26 #include "device/shader_manager.h"
27 #include "device/shader_module.h"
28 #include "gles/gl_functions.h"
29 #include "gles/gpu_buffer_gles.h"
30 #include "gles/gpu_image_gles.h"
31 #include "gles/gpu_program_gles.h"
32 #include "gles/gpu_sampler_gles.h"
33 #include "gles/gpu_semaphore_gles.h"
34 #include "gles/node_context_descriptor_set_manager_gles.h"
35 #include "gles/node_context_pool_manager_gles.h"
36 #include "gles/pipeline_state_object_gles.h"
37 #include "gles/render_backend_gles.h"
38 #include "gles/render_frame_sync_gles.h"
39 #include "gles/shader_module_gles.h"
40 #include "gles/swapchain_gles.h"
41 #include "util/log.h"
42 
43 using namespace BASE_NS;
44 
45 RENDER_BEGIN_NAMESPACE()
46 namespace {
47 // Make all temporary binds to unit GL_TEXTURE15. (should use the last available unit, so as to least affect actual
48 // usage) "The number of texture units is implementation-dependent, but must be at least 32. texture must be one of
49 // GL_TEXTUREi, where i ranges from zero to the value of GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS minus one." Currently our
50 // there is an implementation limit in our resource caching which limits it to 16... (this is why we use 16 instead of
51 // 32)
52 constexpr const uint32_t TEMP_BIND_UNIT = 15;
53 constexpr const string_view EXT_BUFFER_STORAGE = "GL_EXT_buffer_storage";
54 constexpr const uint32_t CACHE_VERSION = 1U;
55 #if RENDER_GL_DEBUG
56 #define DUMP(a)                       \
57     {                                 \
58         GLint val;                    \
59         glGetIntegerv(a, &val);       \
60         PLUGIN_LOG_V(#a ": %d", val); \
61     }
62 
63 bool (*filterErrorFunc)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
64     const string_view message, const void* userParam) noexcept = nullptr;
65 
SourceName(GLenum source)66 auto SourceName(GLenum source)
67 {
68     switch (source) {
69         case GL_DEBUG_SOURCE_API:
70             return "GL_DEBUG_SOURCE_API";
71         case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
72             return "GL_DEBUG_SOURCE_WINDOW_SYSTEM";
73         case GL_DEBUG_SOURCE_SHADER_COMPILER:
74             return "GL_DEBUG_SOURCE_SHADER_COMPILER";
75         case GL_DEBUG_SOURCE_THIRD_PARTY:
76             return "GL_DEBUG_SOURCE_THIRD_PARTY";
77         case GL_DEBUG_SOURCE_APPLICATION:
78             return "GL_DEBUG_SOURCE_APPLICATION";
79         case GL_DEBUG_SOURCE_OTHER:
80             return "GL_DEBUG_SOURCE_OTHER";
81 
82         default:
83             break;
84     }
85     return "UNKNOWN";
86 }
87 
TypeName(GLenum type)88 auto TypeName(GLenum type)
89 {
90     switch (type) {
91         case GL_DEBUG_TYPE_ERROR:
92             return "GL_DEBUG_TYPE_ERROR";
93         case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
94             return "GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR";
95         case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
96             return "GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR";
97         case GL_DEBUG_TYPE_PORTABILITY:
98             return "GL_DEBUG_TYPE_PORTABILITY";
99         case GL_DEBUG_TYPE_PERFORMANCE:
100             return "GL_DEBUG_TYPE_PERFORMANCE";
101         case GL_DEBUG_TYPE_MARKER:
102             return "GL_DEBUG_TYPE_MARKER";
103         case GL_DEBUG_TYPE_PUSH_GROUP:
104             return "GL_DEBUG_TYPE_PUSH_GROUP";
105         case GL_DEBUG_TYPE_POP_GROUP:
106             return "GL_DEBUG_TYPE_POP_GROUP";
107         case GL_DEBUG_TYPE_OTHER:
108             return "GL_DEBUG_TYPE_OTHER";
109 
110         default:
111             break;
112     }
113     return "UNKNOWN";
114 }
115 
SeverityName(GLenum severity)116 auto SeverityName(GLenum severity)
117 {
118     switch (severity) {
119         case GL_DEBUG_SEVERITY_LOW:
120             return "GL_DEBUG_SEVERITY_LOW";
121         case GL_DEBUG_SEVERITY_MEDIUM:
122             return "GL_DEBUG_SEVERITY_MEDIUM";
123         case GL_DEBUG_SEVERITY_HIGH:
124             return "GL_DEBUG_SEVERITY_HIGH";
125         case GL_DEBUG_SEVERITY_NOTIFICATION:
126             return "GL_DEBUG_SEVERITY_NOTIFICATION";
127 
128         default:
129             break;
130     }
131     return "UNKNOWN";
132 }
133 
134 #ifndef APIENTRY
135 #define APIENTRY
136 #endif
OnGlError(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar * message,const void * userParam)137 void APIENTRY OnGlError(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message,
138     const void* userParam) noexcept
139 {
140     if (type == GL_DEBUG_TYPE_PUSH_GROUP) {
141         return;
142     } else if (type == GL_DEBUG_TYPE_POP_GROUP) {
143         return;
144     } else if ((filterErrorFunc) && (filterErrorFunc(source, type, id, severity, length, message, userParam))) {
145         return;
146     } else if (type == GL_DEBUG_TYPE_ERROR) {
147         PLUGIN_LOG_E("---------------------opengl-callback-start------------\n"
148                      "source: %s\n"
149                      "type: %s\n"
150                      "id: %u\n"
151                      "severity: %s\n"
152                      "message: %s\n"
153                      "---------------------opengl-callback-end--------------\n",
154             SourceName(source), TypeName(type), id, SeverityName(severity), message);
155     } else {
156         PLUGIN_LOG_D("---------------------opengl-callback-start------------\n"
157                      "source: %s\n"
158                      "type: %s\n"
159                      "id: %u\n"
160                      "severity: %s\n"
161                      "message: %s\n"
162                      "---------------------opengl-callback-end--------------\n",
163             SourceName(source), TypeName(type), id, SeverityName(severity), message);
164     }
165 }
166 #else
167 #define DUMP(a)
168 #endif
169 
DumpLimits()170 void DumpLimits()
171 {
172 #if RENDER_GL_DEBUG
173     DUMP(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS);
174     DUMP(GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS);
175     DUMP(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS);
176     DUMP(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS);
177     DUMP(GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS);
178     DUMP(GL_MAX_SHADER_STORAGE_BLOCK_SIZE);
179 #endif
180 }
181 
182 template<typename State>
RegisterDebugCallback(const State & eglState)183 void RegisterDebugCallback(const State& eglState)
184 {
185 #if RENDER_GL_DEBUG
186     filterErrorFunc = (decltype(filterErrorFunc))eglState.ErrorFilter();
187     glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
188     glDebugMessageCallback(OnGlError, nullptr);
189     GLuint unusedIds = 0;
190     glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, &unusedIds, true);
191 #endif
192 }
193 
194 struct FormatFeatures {
195     GLenum internalFormat;
196     FormatFeatureFlags flags;
197 };
198 
199 // image store and atomic operations seem to go hand in hand
200 constexpr const FormatFeatureFlags ATOMIC_STORE =
201     CORE_FORMAT_FEATURE_STORAGE_IMAGE_BIT | CORE_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT;
202 // no writable texture buffers in gl?
203 constexpr const FormatFeatureFlags TEXEL_BUF = CORE_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT;
204 // color renderable
205 constexpr const FormatFeatureFlags CR = CORE_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
206 // texture filterable
207 constexpr const FormatFeatureFlags TF = CORE_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
208 //  required texture formats. assume can be sampled, and transfered to/from
209 constexpr const FormatFeatureFlags TEX =
210     CORE_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | CORE_FORMAT_FEATURE_TRANSFER_DST_BIT | CORE_FORMAT_FEATURE_TRANSFER_SRC_BIT;
211 // required depth format
212 constexpr const FormatFeatureFlags DS = CORE_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT | TEX | TF;
213 
214 constexpr const FormatFeatureFlags TF_TEX = TF | TEX;
215 #if RENDER_HAS_GL_BACKEND
216 static constexpr const FormatFeatureFlags CR_TEX = CR | TEX; // color renderable, texture format
217 #endif
218 constexpr const FormatFeatureFlags CR_REND_TEX = CR | TEX; // color renderable, renderbuffer, texture format
219 #if RENDER_HAS_GLES_BACKEND
220 constexpr const FormatFeatureFlags CR_TF_REND_TEX = CR | TF | TEX;
221 #endif
222 
223 constexpr const FormatFeatures IMAGE_FORMAT_FEATURES[] = {
224 #if RENDER_HAS_GL_BACKEND
225     { GL_R8, CR_TEX | ATOMIC_STORE | TEXEL_BUF },
226     { GL_R8_SNORM, CR_TEX | ATOMIC_STORE },
227     { GL_R16, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
228     { GL_R16_SNORM, CR_TEX | ATOMIC_STORE },
229     { GL_RG8, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
230     { GL_RG8_SNORM, CR_TEX | ATOMIC_STORE },
231     { GL_RG16, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
232     { GL_RG16_SNORM, CR_TEX | ATOMIC_STORE },
233     // R3_G3_B2 not in base format
234     { GL_RGB4, CR_TEX },
235     // RGB5 not in base format
236     { GL_RGB565, CR_REND_TEX },
237     { GL_RGB8, CR_TEX },
238     { GL_RGB8_SNORM, CR_TEX },
239     { GL_RGB10, CR_TEX },
240     { GL_RGB12, CR_TEX },
241     { GL_RGB16, CR_TEX },
242     { GL_RGB16_SNORM, CR_TEX },
243     // RGBA2 not in base format
244     { GL_RGBA4, CR_REND_TEX },
245     { GL_RGB5_A1, CR_REND_TEX },
246     { GL_RGBA8, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
247     { GL_RGBA8_SNORM, CR_TEX | ATOMIC_STORE },
248     { GL_RGB10_A2, CR_REND_TEX | ATOMIC_STORE },
249     { GL_RGB10_A2UI, CR_REND_TEX | ATOMIC_STORE },
250     { GL_RGBA12, CR_TEX },
251     { GL_RGBA16, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
252     { GL_RGBA16_SNORM, CR_TEX | ATOMIC_STORE },
253     { GL_SRGB8, CR_TEX },
254     { GL_SRGB8_ALPHA8, CR_REND_TEX },
255     { GL_R16F, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
256     { GL_RG16F, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
257     { GL_RGB16F, CR_TEX },
258     { GL_RGBA16F, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
259     { GL_R32F, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
260     { GL_RG32F, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
261     { GL_RGB32F, CR_TEX | TEXEL_BUF | TEXEL_BUF },
262     { GL_RGBA32F, CR_REND_TEX | ATOMIC_STORE },
263     { GL_R11F_G11F_B10F, CR_REND_TEX | ATOMIC_STORE },
264     { GL_RGB9_E5, TEX },
265     { GL_R8I, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
266     { GL_R8UI, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
267     { GL_R16I, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
268     { GL_R16UI, CR_REND_TEX | TEXEL_BUF },
269     { GL_R32I, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
270     { GL_R32UI, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
271     { GL_RG8I, CR_REND_TEX | TEXEL_BUF },
272     { GL_RG8UI, CR_REND_TEX | TEXEL_BUF },
273     { GL_RG16I, CR_REND_TEX | TEXEL_BUF },
274     { GL_RG16UI, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
275     { GL_RG32I, CR_REND_TEX | TEXEL_BUF },
276     { GL_RG32UI, CR_REND_TEX | TEXEL_BUF },
277     { GL_RGB8I, CR_TEX },
278     { GL_RGB8UI, CR_TEX },
279     { GL_RGB16I, CR_TEX },
280     { GL_RGB16UI, CR_TEX },
281     { GL_RGB32I, CR_TEX | TEXEL_BUF },
282     { GL_RGB32UI, CR_TEX | ATOMIC_STORE | TEXEL_BUF },
283     { GL_RGBA8I, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
284     { GL_RGBA8UI, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
285     { GL_RGBA16I, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
286     { GL_RGBA16UI, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
287     { GL_RGBA32I, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
288     { GL_RGBA32UI, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
289 #elif RENDER_HAS_GLES_BACKEND
290     { GL_R8, CR_TF_REND_TEX | TEXEL_BUF },
291     { GL_R8_SNORM, TF_TEX },
292     { GL_RG8, CR_TF_REND_TEX | TEXEL_BUF },
293     { GL_RG8_SNORM, TF_TEX },
294     { GL_RGB8, CR_TF_REND_TEX },
295     { GL_RGB8_SNORM, TF_TEX },
296     { GL_RGB565, CR_TF_REND_TEX },
297     { GL_RGBA4, CR_TF_REND_TEX },
298     { GL_RGB5_A1, CR_TF_REND_TEX },
299     { GL_RGBA8, CR_TF_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
300     { GL_RGBA8_SNORM, TF_TEX | ATOMIC_STORE },
301     { GL_RGB10_A2, CR_TF_REND_TEX },
302     { GL_RGB10_A2UI, CR_REND_TEX },
303     { GL_SRGB8, TF_TEX },
304     { GL_SRGB8_ALPHA8, CR_TF_REND_TEX },
305     { GL_R16F, CR_TF_REND_TEX | TEXEL_BUF },
306     { GL_RG16F, CR_TF_REND_TEX | TEXEL_BUF },
307     { GL_RGB16F, TF_TEX },
308     { GL_RGBA16F, CR_TF_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
309     { GL_R32F, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
310     { GL_RG32F, CR_REND_TEX | TEXEL_BUF },
311     { GL_RGB32F, TEX | TEXEL_BUF },
312     { GL_RGBA32F, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
313     { GL_R11F_G11F_B10F, CR_TF_REND_TEX },
314     { GL_RGB9_E5, TF_TEX },
315     { GL_R8I, CR_REND_TEX | TEXEL_BUF },
316     { GL_R8UI, CR_REND_TEX | TEXEL_BUF },
317     { GL_R16I, CR_REND_TEX | TEXEL_BUF },
318     { GL_R16UI, CR_REND_TEX | TEXEL_BUF },
319     { GL_R32I, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
320     { GL_R32UI, CR_REND_TEX | TEXEL_BUF },
321     { GL_RG8I, CR_REND_TEX | TEXEL_BUF },
322     { GL_RG8UI, CR_REND_TEX | TEXEL_BUF },
323     { GL_RG16I, CR_REND_TEX | TEXEL_BUF },
324     { GL_RG16UI, CR_REND_TEX | TEXEL_BUF },
325     { GL_RG32I, CR_REND_TEX | TEXEL_BUF },
326     { GL_RG32UI, CR_REND_TEX | TEXEL_BUF },
327     { GL_RGB8I, TEX },
328     { GL_RGB8UI, TEX },
329     { GL_RGB16I, TEX },
330     { GL_RGB16UI, TEX },
331     { GL_RGB32I, TEX | TEXEL_BUF },
332     { GL_RGB32UI, TEX | TEXEL_BUF },
333     { GL_RGBA8I, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
334     { GL_RGBA8UI, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
335     { GL_RGBA16I, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
336     { GL_RGBA16UI, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
337     { GL_RGBA32I, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
338     { GL_RGBA32UI, CR_REND_TEX | ATOMIC_STORE | TEXEL_BUF },
339 #endif
340     { GL_DEPTH_COMPONENT16, DS },
341     { GL_DEPTH_COMPONENT24, DS },
342     { GL_DEPTH_COMPONENT32F, DS },
343     { GL_DEPTH24_STENCIL8, DS },
344     { GL_DEPTH32F_STENCIL8, DS },
345     { GL_STENCIL_INDEX8, DS },
346 
347 #if (defined(GL_EXT_texture_sRGB_R8) && (GL_EXT_texture_sRGB_R8))
348     { GL_SR8_EXT, TF_TEX },
349 #endif
350 
351 #if (defined(GL_EXT_texture_sRGB_RG8) && (GL_EXT_texture_sRGB_RG8))
352     { GL_SRG8_EXT, TF_TEX },
353 #endif
354 
355 #if defined(GL_EXT_texture_format_BGRA8888) && (GL_EXT_texture_format_BGRA8888)
356     { GL_BGRA_EXT, CR_REND_TEX },
357 #endif
358 
359 #if defined(GL_EXT_texture_norm16) && (GL_EXT_texture_norm16)
360     { GL_R16_EXT, CR_TF_REND_TEX },
361     { GL_RG16_EXT, CR_TF_REND_TEX },
362     { GL_RGB16_EXT, TF_TEX },
363     { GL_RGBA16_EXT, CR_TF_REND_TEX },
364     { GL_R16_SNORM_EXT, TF_TEX },
365     { GL_RG16_SNORM_EXT, TF_TEX },
366     { GL_RGB16_SNORM_EXT, TF_TEX },
367     { GL_RGBA16_SNORM_EXT, TF_TEX },
368 #endif
369 
370     { GL_COMPRESSED_R11_EAC, TF_TEX },
371     { GL_COMPRESSED_SIGNED_R11_EAC, TF_TEX },
372     { GL_COMPRESSED_RG11_EAC, TF_TEX },
373     { GL_COMPRESSED_SIGNED_RG11_EAC, TF_TEX },
374     { GL_COMPRESSED_RGB8_ETC2, TF_TEX },
375     { GL_COMPRESSED_SRGB8_ETC2, TF_TEX },
376     { GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, TF_TEX },
377     { GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, TF_TEX },
378     { GL_COMPRESSED_RGBA8_ETC2_EAC, TF_TEX },
379     { GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, TF_TEX },
380 #if RENDER_HAS_GLES_BACKEND
381     { GL_COMPRESSED_RGBA_ASTC_4x4, TF_TEX },
382     { GL_COMPRESSED_RGBA_ASTC_5x4, TF_TEX },
383     { GL_COMPRESSED_RGBA_ASTC_5x5, TF_TEX },
384     { GL_COMPRESSED_RGBA_ASTC_6x5, TF_TEX },
385     { GL_COMPRESSED_RGBA_ASTC_6x6, TF_TEX },
386     { GL_COMPRESSED_RGBA_ASTC_8x5, TF_TEX },
387     { GL_COMPRESSED_RGBA_ASTC_8x6, TF_TEX },
388     { GL_COMPRESSED_RGBA_ASTC_8x8, TF_TEX },
389     { GL_COMPRESSED_RGBA_ASTC_10x5, TF_TEX },
390     { GL_COMPRESSED_RGBA_ASTC_10x6, TF_TEX },
391     { GL_COMPRESSED_RGBA_ASTC_10x8, TF_TEX },
392     { GL_COMPRESSED_RGBA_ASTC_10x10, TF_TEX },
393     { GL_COMPRESSED_RGBA_ASTC_12x10, TF_TEX },
394     { GL_COMPRESSED_RGBA_ASTC_12x12, TF_TEX },
395     { GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4, TF_TEX },
396     { GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4, TF_TEX },
397     { GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5, TF_TEX },
398     { GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5, TF_TEX },
399     { GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6, TF_TEX },
400     { GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5, TF_TEX },
401     { GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6, TF_TEX },
402     { GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8, TF_TEX },
403     { GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5, TF_TEX },
404     { GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6, TF_TEX },
405     { GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8, TF_TEX },
406     { GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10, TF_TEX },
407     { GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10, TF_TEX },
408     { GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12, TF_TEX },
409 #endif
410 #if defined(GL_EXT_texture_compression_s3tc) && (GL_EXT_texture_compression_s3tc)
411     { GL_COMPRESSED_RGB_S3TC_DXT1_EXT, TF_TEX },
412     { GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, TF_TEX },
413     { GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, TF_TEX },
414     { GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, TF_TEX },
415 #endif
416 #if defined(GL_ARB_texture_compression_bptc) && (GL_ARB_texture_compression_bptc)
417     { GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, TF_TEX },
418     { GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB, TF_TEX },
419     { GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, TF_TEX },
420     { GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB, TF_TEX },
421 #endif
422 #if defined(GL_EXT_texture_compression_rgtc) && (GL_EXT_texture_compression_rgtc)
423     { GL_COMPRESSED_RED_RGTC1_EXT, TF_TEX },
424     { GL_COMPRESSED_SIGNED_RED_RGTC1_EXT, TF_TEX },
425     { GL_COMPRESSED_RED_GREEN_RGTC2_EXT, TF_TEX },
426     { GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT, TF_TEX },
427 #endif
428 };
429 
430 // Dont allow SRGB_R8 and SRGB_R8G8 internal formats, instead use the GL_SRGB8 with swizzle as workaround.
431 #define USE_EXTENSION_FORMATS
432 
433 #define BLOCK_BITS_8 1
434 #define BLOCK_BITS_16 2
435 #define BLOCK_BITS_32 4
436 #define BLOCK_BITS_64 8
437 #define BLOCK_BITS_128 16
438 
439 // GL_EXT_texture_sRGB_R8 extension
440 #if (defined(GL_EXT_texture_sRGB_R8) && (GL_EXT_texture_sRGB_R8))
441 constexpr DeviceGLES::ImageFormat IMAGE_FORMATS_EXT_SRGB_R8[] = {
442     { BASE_FORMAT_R8_SRGB, GL_RED, GL_SR8_EXT, GL_UNSIGNED_BYTE, 1, { false, 0, 0, 0 },
443         { GL_RED, GL_ZERO, GL_ZERO, GL_ONE } },
444 };
445 #endif
446 
447 // GL_EXT_texture_sRGB_RG8 extension
448 #if (defined(GL_EXT_texture_sRGB_RG8) && (GL_EXT_texture_sRGB_RG8))
449 constexpr DeviceGLES::ImageFormat IMAGE_FORMATS_EXT_SRGB_RG8[] = {
450     { BASE_FORMAT_R8G8_SRGB, GL_RG, GL_SRG8_EXT, GL_UNSIGNED_BYTE, 1, { false, 0, 0, 0 },
451         { GL_RED, GL_GREEN, GL_ZERO, GL_ONE } },
452 };
453 #endif
454 
455 // GL_EXT_texture_sRGB extension
456 #if defined(GL_EXT_texture_sRGB) && (GL_EXT_texture_sRGB)
457 constexpr DeviceGLES::ImageFormat IMAGE_FORMATS_EXT_SRGB[] = {
458     { BASE_FORMAT_BC1_RGB_SRGB_BLOCK, GL_RGB, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, 0,
459         { true, 4, 4, BLOCK_BITS_64 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
460     { BASE_FORMAT_BC1_RGBA_SRGB_BLOCK, GL_RGBA, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, 0,
461         { true, 4, 4, BLOCK_BITS_64 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
462     { BASE_FORMAT_BC2_SRGB_BLOCK, GL_RGB, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_UNSIGNED_BYTE, 0,
463         { true, 4, 4, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
464     { BASE_FORMAT_BC3_SRGB_BLOCK, GL_RGB, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_UNSIGNED_BYTE, 0,
465         { true, 4, 4, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
466 };
467 #endif
468 
469 // GL_EXT_texture_format_BGRA8888 extension
470 #if defined(GL_EXT_texture_format_BGRA8888) && (GL_EXT_texture_format_BGRA8888)
471 constexpr DeviceGLES::ImageFormat IMAGE_FORMATS_EXT_BGRA[] = {
472     { BASE_FORMAT_B8G8R8A8_UNORM, GL_BGRA_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE, 4, { false, 0, 0, 0 },
473         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
474 };
475 #endif
476 
477 #if defined(GL_EXT_texture_norm16) && (GL_EXT_texture_norm16)
478 constexpr DeviceGLES::ImageFormat IMAGE_FORMATS_EXT_NORM16[] = {
479     { BASE_FORMAT_R16_UNORM, GL_RED, GL_R16_EXT, GL_UNSIGNED_SHORT, 2, { false, 0, 0, 0 },
480         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
481     { BASE_FORMAT_R16G16_UNORM, GL_RG, GL_RG16_EXT, GL_UNSIGNED_SHORT, 4, { false, 0, 0, 0 },
482         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
483     { BASE_FORMAT_R16G16B16_UNORM, GL_RGB, GL_RGB16_EXT, GL_UNSIGNED_SHORT, 6, { false, 0, 0, 0 },
484         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
485     { BASE_FORMAT_R16G16B16A16_UNORM, GL_RGBA, GL_RGBA16_EXT, GL_UNSIGNED_SHORT, 8, { false, 0, 0, 0 },
486         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
487     { BASE_FORMAT_R16_SNORM, GL_RED, GL_R16_SNORM_EXT, GL_SHORT, 2, { false, 0, 0, 0 },
488         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
489     { BASE_FORMAT_R16G16_SNORM, GL_RG, GL_RG16_SNORM_EXT, GL_SHORT, 4, { false, 0, 0, 0 },
490         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
491     { BASE_FORMAT_R16G16B16_SNORM, GL_RGB, GL_RGB16_SNORM_EXT, GL_SHORT, 6, { false, 0, 0, 0 },
492         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
493     { BASE_FORMAT_R16G16B16A16_SNORM, GL_RGBA, GL_RGBA16_SNORM_EXT, GL_SHORT, 8, { false, 0, 0, 0 },
494         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
495 };
496 #endif
497 
498 // GL_EXT_texture_compression_s3tc extension
499 #if defined(GL_EXT_texture_compression_s3tc) && (GL_EXT_texture_compression_s3tc)
500 constexpr DeviceGLES::ImageFormat IMAGE_FORMATS_EXT_S3TC[] = {
501     { BASE_FORMAT_BC1_RGB_UNORM_BLOCK, GL_RGB, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, 0,
502         { true, 4, 4, BLOCK_BITS_64 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
503     { BASE_FORMAT_BC1_RGBA_UNORM_BLOCK, GL_RGBA, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, 0,
504         { true, 4, 4, BLOCK_BITS_64 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
505     { BASE_FORMAT_BC2_UNORM_BLOCK, GL_RGBA, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_UNSIGNED_BYTE, 0,
506         { true, 4, 4, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
507     { BASE_FORMAT_BC3_UNORM_BLOCK, GL_RGBA, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_UNSIGNED_BYTE, 0,
508         { true, 4, 4, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
509 };
510 #endif
511 
512 // GL_ARB_texture_compression_bptc extension
513 #if defined(GL_ARB_texture_compression_bptc) && (GL_ARB_texture_compression_bptc)
514 static constexpr DeviceGLES::ImageFormat IMAGE_FORMATS_EXT_BPTC[] = {
515     { BASE_FORMAT_BC7_UNORM_BLOCK, GL_RGBA, GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, GL_UNSIGNED_BYTE, 0,
516         { true, 4, 4, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
517     { BASE_FORMAT_BC7_SRGB_BLOCK, GL_RGBA, GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB, GL_UNSIGNED_BYTE, 0,
518         { true, 4, 4, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
519     { BASE_FORMAT_BC6H_SFLOAT_BLOCK, GL_RGB, GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, GL_FLOAT, 0,
520         { true, 4, 4, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
521     { BASE_FORMAT_BC6H_UFLOAT_BLOCK, GL_RGB, GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB, GL_FLOAT, 0,
522         { true, 4, 4, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
523 };
524 #endif
525 
526 // GL_EXT_texture_norm16 extension
527 #if defined(GL_EXT_texture_compression_rgtc) && (GL_EXT_texture_compression_rgtc)
528 constexpr DeviceGLES::ImageFormat IMAGE_FORMATS_EXT_RGTC[] = {
529     { BASE_FORMAT_BC4_UNORM_BLOCK, GL_RED, GL_COMPRESSED_RED_RGTC1_EXT, GL_UNSIGNED_BYTE, 0,
530         { true, 4, 4, BLOCK_BITS_64 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
531     { BASE_FORMAT_BC4_SNORM_BLOCK, GL_RED, GL_COMPRESSED_SIGNED_RED_RGTC1_EXT, GL_UNSIGNED_BYTE, 0,
532         { true, 4, 4, BLOCK_BITS_64 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
533     { BASE_FORMAT_BC5_UNORM_BLOCK, GL_RG, GL_COMPRESSED_RED_GREEN_RGTC2_EXT, GL_UNSIGNED_BYTE, 0,
534         { true, 4, 4, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
535     { BASE_FORMAT_BC5_SNORM_BLOCK, GL_RG, GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT, GL_UNSIGNED_BYTE, 0,
536         { true, 4, 4, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
537 };
538 #endif
539 
540 constexpr DeviceGLES::ImageFormat IMAGE_FORMATS_FALLBACK[] = {
541     { BASE_FORMAT_R4G4_UNORM_PACK8, GL_RG, GL_RGBA4, GL_UNSIGNED_BYTE, 1, { false, 0, 0, 0 },
542         { GL_RED, GL_GREEN, GL_ZERO, GL_ONE } },
543     { BASE_FORMAT_B4G4R4A4_UNORM_PACK16, GL_RGBA, GL_RGBA4, GL_UNSIGNED_SHORT_4_4_4_4, 2, { false, 0, 0, 0 },
544         { GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA } },
545     { BASE_FORMAT_B5G6R5_UNORM_PACK16, GL_RGB, GL_RGB565, GL_UNSIGNED_SHORT_5_6_5, 2, { false, 0, 0, 0 },
546         { GL_BLUE, GL_GREEN, GL_RED, GL_ONE } },
547     { BASE_FORMAT_B5G5R5A1_UNORM_PACK16, GL_RGBA, GL_RGB5_A1, GL_UNSIGNED_SHORT_5_5_5_1, 2, { false, 0, 0, 0 },
548         { GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA } },
549     { BASE_FORMAT_A1R5G5B5_UNORM_PACK16, GL_RGBA, GL_RGB5_A1, GL_UNSIGNED_SHORT_5_5_5_1, 2, { false, 0, 0, 0 },
550         { GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA } },
551 
552     // not available in desktop, available as an extension in opengles. "GL_EXT_texture_sRGB_RG8"
553     { BASE_FORMAT_R8_SRGB, GL_RED, GL_SRGB8, GL_UNSIGNED_BYTE, 1, { false, 0, 0, 0 },
554         { GL_RED, GL_ZERO, GL_ZERO, GL_ONE } },
555     { BASE_FORMAT_R8G8_SRGB, GL_RG, GL_SRGB8, GL_UNSIGNED_BYTE, 1, { false, 0, 0, 0 },
556         { GL_RED, GL_GREEN, GL_ZERO, GL_ONE } },
557 
558     { BASE_FORMAT_A2R10G10B10_UNORM_PACK32, GL_RGBA, GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV, 4, { false, 0, 0, 0 },
559         { GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA } },
560     { BASE_FORMAT_A2R10G10B10_UINT_PACK32, GL_RGBA, GL_RGB10_A2UI, GL_UNSIGNED_INT_2_10_10_10_REV, 4,
561         { false, 0, 0, 0 }, { GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA } },
562 
563     // available as an extension in opengles. "GL_EXT_texture_norm16" -> fallback to half float
564     { BASE_FORMAT_R16_UNORM, GL_RED, GL_R16F, GL_HALF_FLOAT, 2, { false, 0, 0, 0 },
565         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
566     { BASE_FORMAT_R16G16_UNORM, GL_RG, GL_RG16F, GL_HALF_FLOAT, 4, { false, 0, 0, 0 },
567         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
568     { BASE_FORMAT_R16G16B16_UNORM, GL_RGB, GL_RGB16F, GL_HALF_FLOAT, 6, { false, 0, 0, 0 },
569         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
570     { BASE_FORMAT_R16G16B16A16_UNORM, GL_RGBA, GL_RGBA16F, GL_HALF_FLOAT, 8, { false, 0, 0, 0 },
571         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
572 };
573 
574 // NOTE: verify this table. add missing formats.
575 constexpr DeviceGLES::ImageFormat IMAGE_FORMATS[] = {
576     { BASE_FORMAT_UNDEFINED, GL_NONE, GL_NONE, GL_NONE, 0, { false, 0, 0, 0 },
577         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
578     // These are required in GL and GLES
579     { BASE_FORMAT_R8_UNORM, GL_RED, GL_R8, GL_UNSIGNED_BYTE, 1, { false, 0, 0, 0 },
580         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
581     { BASE_FORMAT_R8_SNORM, GL_RED, GL_R8_SNORM, GL_BYTE, 1, { false, 0, 0, 0 },
582         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
583     { BASE_FORMAT_R8G8_UNORM, GL_RG, GL_RG8, GL_UNSIGNED_BYTE, 2, { false, 0, 0, 0 },
584         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
585     { BASE_FORMAT_R8G8_SNORM, GL_RG, GL_RG8, GL_BYTE, 2, { false, 0, 0, 0 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
586     { BASE_FORMAT_R5G6B5_UNORM_PACK16, GL_RGB, GL_RGB565, GL_UNSIGNED_SHORT_5_6_5, 2, { false, 0, 0, 0 },
587         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
588     { BASE_FORMAT_R8G8B8_UNORM, GL_RGB, GL_RGB8, GL_UNSIGNED_BYTE, 3, { false, 0, 0, 0 },
589         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
590     { BASE_FORMAT_R8G8B8_SNORM, GL_RGB, GL_RGB8, GL_BYTE, 3, { false, 0, 0, 0 },
591         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
592     { BASE_FORMAT_R4G4B4A4_UNORM_PACK16, GL_RGBA, GL_RGBA4, GL_UNSIGNED_SHORT_4_4_4_4, 2, { false, 0, 0, 0 },
593         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
594     { BASE_FORMAT_R5G5B5A1_UNORM_PACK16, GL_RGBA, GL_RGB5_A1, GL_UNSIGNED_SHORT_5_5_5_1, 2, { false, 0, 0, 0 },
595         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
596     { BASE_FORMAT_R8G8B8A8_UNORM, GL_RGBA, GL_RGBA8, GL_UNSIGNED_BYTE, 4, { false, 0, 0, 0 },
597         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
598     { BASE_FORMAT_R8G8B8A8_SNORM, GL_RGBA, GL_RGBA8, GL_BYTE, 4, { false, 0, 0, 0 },
599         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
600     { BASE_FORMAT_A2B10G10R10_UNORM_PACK32, GL_RGBA, GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV, 4, { false, 0, 0, 0 },
601         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
602     { BASE_FORMAT_A2B10G10R10_UINT_PACK32, GL_RGBA, GL_RGB10_A2UI, GL_UNSIGNED_INT_2_10_10_10_REV, 4,
603         { false, 0, 0, 0 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
604     { BASE_FORMAT_R8G8B8_SRGB, GL_RGB, GL_SRGB8, GL_UNSIGNED_BYTE, 3, { false, 0, 0, 0 },
605         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
606     { BASE_FORMAT_R8G8B8A8_SRGB, GL_RGBA, GL_SRGB8_ALPHA8, GL_UNSIGNED_BYTE, 4, { false, 0, 0, 0 },
607         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
608     { BASE_FORMAT_R16_SFLOAT, GL_RED, GL_R16F, GL_HALF_FLOAT, 2, { false, 0, 0, 0 },
609         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
610     { BASE_FORMAT_R16G16_SFLOAT, GL_RG, GL_RG16F, GL_HALF_FLOAT, 4, { false, 0, 0, 0 },
611         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
612     { BASE_FORMAT_R16G16B16_SFLOAT, GL_RGB, GL_RGB16F, GL_HALF_FLOAT, 6, { false, 0, 0, 0 },
613         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
614     { BASE_FORMAT_R16G16B16A16_SFLOAT, GL_RGBA, GL_RGBA16F, GL_HALF_FLOAT, 8, { false, 0, 0, 0 },
615         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
616     { BASE_FORMAT_R32_SFLOAT, GL_RED, GL_R32F, GL_FLOAT, 4, { false, 0, 0, 0 },
617         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
618     { BASE_FORMAT_R32G32_SFLOAT, GL_RG, GL_RG32F, GL_FLOAT, 8, { false, 0, 0, 0 },
619         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
620     { BASE_FORMAT_R32G32B32_SFLOAT, GL_RGB, GL_RGB32F, GL_FLOAT, 12, { false, 0, 0, 0 },
621         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
622     { BASE_FORMAT_R32G32B32A32_SFLOAT, GL_RGBA, GL_RGBA32F, GL_FLOAT, 16, { false, 0, 0, 0 },
623         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
624     // Special R11 G11 B10 float format. This format does not work with compute on GLES, but works as a texture. (this
625     // is handled elsewhere)
626     { BASE_FORMAT_B10G11R11_UFLOAT_PACK32, GL_RGB, GL_R11F_G11F_B10F, GL_UNSIGNED_INT_10F_11F_11F_REV, 4,
627         { false, 0, 0, 0 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
628     { BASE_FORMAT_E5B9G9R9_UFLOAT_PACK32, GL_RGB, GL_RGB9_E5, GL_UNSIGNED_INT_5_9_9_9_REV, 4, { false, 0, 0, 0 },
629         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
630     { BASE_FORMAT_R8_SINT, GL_RED_INTEGER, GL_R8I, GL_BYTE, 1, { false, 0, 0, 0 },
631         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
632     { BASE_FORMAT_R8_UINT, GL_RED_INTEGER, GL_R8UI, GL_UNSIGNED_BYTE, 1, { false, 0, 0, 0 },
633         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
634     { BASE_FORMAT_R16_SINT, GL_RED_INTEGER, GL_R16I, GL_SHORT, 2, { false, 0, 0, 0 },
635         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
636     { BASE_FORMAT_R16_UINT, GL_RED_INTEGER, GL_R16UI, GL_UNSIGNED_SHORT, 2, { false, 0, 0, 0 },
637         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
638     { BASE_FORMAT_R32_SINT, GL_RED_INTEGER, GL_R32I, GL_INT, 4, { false, 0, 0, 0 },
639         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
640     { BASE_FORMAT_R32_UINT, GL_RED_INTEGER, GL_R32UI, GL_UNSIGNED_INT, 4, { false, 0, 0, 0 },
641         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
642     { BASE_FORMAT_R8G8_SINT, GL_RG_INTEGER, GL_RG8I, GL_BYTE, 2, { false, 0, 0, 0 },
643         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
644     { BASE_FORMAT_R8G8_UINT, GL_RG_INTEGER, GL_R8UI, GL_UNSIGNED_BYTE, 2, { false, 0, 0, 0 },
645         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
646     { BASE_FORMAT_R16G16_SINT, GL_RG_INTEGER, GL_RG16I, GL_SHORT, 4, { false, 0, 0, 0 },
647         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
648     { BASE_FORMAT_R16G16_UINT, GL_RG_INTEGER, GL_RG16UI, GL_UNSIGNED_SHORT, 4, { false, 0, 0, 0 },
649         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
650     { BASE_FORMAT_R32G32_SINT, GL_RG_INTEGER, GL_RG32I, GL_INT, 8, { false, 0, 0, 0 },
651         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
652     { BASE_FORMAT_R32G32_UINT, GL_RG_INTEGER, GL_RG32UI, GL_UNSIGNED_INT, 8, { false, 0, 0, 0 },
653         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
654     { BASE_FORMAT_R8G8B8_SINT, GL_RGB_INTEGER, GL_RGB8I, GL_BYTE, 3, { false, 0, 0, 0 },
655         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
656     { BASE_FORMAT_R8G8B8_UINT, GL_RGB_INTEGER, GL_RGB8UI, GL_UNSIGNED_BYTE, 3, { false, 0, 0, 0 },
657         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
658     { BASE_FORMAT_R16G16B16_SINT, GL_RGB_INTEGER, GL_RGB16I, GL_SHORT, 6, { false, 0, 0, 0 },
659         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
660     { BASE_FORMAT_R16G16B16_UINT, GL_RGB_INTEGER, GL_RGB16UI, GL_UNSIGNED_SHORT, 6, { false, 0, 0, 0 },
661         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
662     { BASE_FORMAT_R32G32B32_SINT, GL_RGB_INTEGER, GL_RGB32I, GL_INT, 12, { false, 0, 0, 0 },
663         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
664     { BASE_FORMAT_R32G32B32_UINT, GL_RGB_INTEGER, GL_RGB32UI, GL_UNSIGNED_INT, 12, { false, 0, 0, 0 },
665         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
666     { BASE_FORMAT_R8G8B8A8_SINT, GL_RGBA_INTEGER, GL_RGBA8I, GL_BYTE, 4, { false, 0, 0, 0 },
667         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
668     { BASE_FORMAT_R8G8B8A8_UINT, GL_RGBA_INTEGER, GL_RGBA8UI, GL_UNSIGNED_BYTE, 4, { false, 0, 0, 0 },
669         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
670     { BASE_FORMAT_R16G16B16A16_SINT, GL_RGBA_INTEGER, GL_RGBA16I, GL_SHORT, 8, { false, 0, 0, 0 },
671         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
672     { BASE_FORMAT_R16G16B16A16_UINT, GL_RGBA_INTEGER, GL_RGBA16UI, GL_UNSIGNED_SHORT, 8, { false, 0, 0, 0 },
673         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
674     { BASE_FORMAT_R32G32B32A32_SINT, GL_RGBA_INTEGER, GL_RGBA32I, GL_INT, 16, { false, 0, 0, 0 },
675         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
676     { BASE_FORMAT_R32G32B32A32_UINT, GL_RGBA_INTEGER, GL_RGBA32UI, GL_UNSIGNED_INT, 16, { false, 0, 0, 0 },
677         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
678     { BASE_FORMAT_D16_UNORM, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT16, GL_UNSIGNED_SHORT, 2, { false, 0, 0, 0 },
679         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
680     { BASE_FORMAT_X8_D24_UNORM_PACK32, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT24, GL_UNSIGNED_INT, 4, { false, 0, 0, 0 },
681         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
682     { BASE_FORMAT_D32_SFLOAT, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT32F, GL_FLOAT, 4, { false, 0, 0, 0 },
683         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
684     { BASE_FORMAT_S8_UINT, GL_STENCIL_INDEX, GL_STENCIL_INDEX8, GL_UNSIGNED_BYTE, 1, { false, 0, 0, 0 },
685         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
686     { BASE_FORMAT_D24_UNORM_S8_UINT, GL_DEPTH_STENCIL, GL_DEPTH24_STENCIL8, GL_UNSIGNED_INT_24_8, 4, { false, 0, 0, 0 },
687         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
688     { BASE_FORMAT_D32_SFLOAT_S8_UINT, GL_DEPTH_STENCIL, GL_DEPTH32F_STENCIL8, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, 8,
689         { false, 0, 0, 0 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
690     // EAC
691     { BASE_FORMAT_EAC_R11_UNORM_BLOCK, GL_RED, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE, 0,
692         { true, 4, 4, BLOCK_BITS_64 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
693     { BASE_FORMAT_EAC_R11_SNORM_BLOCK, GL_RED, GL_COMPRESSED_SIGNED_R11_EAC, GL_BYTE, 0, { true, 4, 4, BLOCK_BITS_64 },
694         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
695     { BASE_FORMAT_EAC_R11G11_UNORM_BLOCK, GL_RG, GL_COMPRESSED_RG11_EAC, GL_UNSIGNED_BYTE, 0,
696         { true, 4, 4, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
697     { BASE_FORMAT_EAC_R11G11_SNORM_BLOCK, GL_RG, GL_COMPRESSED_SIGNED_RG11_EAC, GL_BYTE, 0,
698         { true, 4, 4, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
699     // ETC
700     { BASE_FORMAT_ETC2_R8G8B8_UNORM_BLOCK, GL_RGB, GL_COMPRESSED_RGB8_ETC2, GL_UNSIGNED_BYTE, 0,
701         { true, 4, 4, BLOCK_BITS_64 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
702     { BASE_FORMAT_ETC2_R8G8B8_SRGB_BLOCK, GL_RGB, GL_COMPRESSED_SRGB8_ETC2, GL_UNSIGNED_BYTE, 0,
703         { true, 4, 4, BLOCK_BITS_64 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
704     { BASE_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK, GL_RGBA, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, 0,
705         { true, 4, 4, BLOCK_BITS_64 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
706     { BASE_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK, GL_RGBA, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, 0,
707         { true, 4, 4, BLOCK_BITS_64 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
708     { BASE_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK, GL_RGBA, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_UNSIGNED_BYTE, 0,
709         { true, 4, 4, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
710     { BASE_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK, GL_RGBA, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_UNSIGNED_BYTE, 0,
711         { true, 4, 4, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
712 #if RENDER_HAS_GL_BACKEND
713     // required by GL
714     { BASE_FORMAT_R16_UNORM, GL_RED, GL_R16, GL_UNSIGNED_SHORT, 2, { false, 0, 0, 0 },
715         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
716     { BASE_FORMAT_R16_SNORM, GL_RED, GL_R16, GL_SHORT, 2, { false, 0, 0, 0 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
717     { BASE_FORMAT_R16G16_UNORM, GL_RG, GL_RG16, GL_UNSIGNED_SHORT, 4, { false, 0, 0, 0 },
718         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
719     { BASE_FORMAT_R16G16_SNORM, GL_RG, GL_RG16, GL_SHORT, 4, { false, 0, 0, 0 },
720         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
721     // GL_R3_G3_B2, RGB4, RGB5, RGB10, RGB12 not in base formats
722     { BASE_FORMAT_R16G16B16_UNORM, GL_RGB, GL_RGB16, GL_UNSIGNED_SHORT, 6, { false, 0, 0, 0 },
723         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
724     { BASE_FORMAT_R16G16B16_SNORM, GL_RGB, GL_RGB16, GL_SHORT, 6, { false, 0, 0, 0 },
725         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
726     // RGBA2, RGBA12 not in base formats
727     { BASE_FORMAT_R16G16B16A16_UNORM, GL_RGBA, GL_RGBA16, GL_UNSIGNED_SHORT, 8, { false, 0, 0, 0 },
728         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
729     { BASE_FORMAT_R16G16B16A16_SNORM, GL_RGBA, GL_RGBA16, GL_SHORT, 8, { false, 0, 0, 0 },
730         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
731     // STENCIL_INDEX1, STENCIL_INDEX4, STENCIL_INDEX16 not in base formats
732     { BASE_FORMAT_B4G4R4A4_UNORM_PACK16, GL_BGRA, GL_RGBA4, GL_UNSIGNED_SHORT_4_4_4_4_REV, 2, { false, 0, 0, 0 },
733         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
734     { BASE_FORMAT_A1R5G5B5_UNORM_PACK16, GL_BGRA, GL_RGB5_A1, GL_UNSIGNED_SHORT_1_5_5_5_REV, 2, { false, 0, 0, 0 },
735         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
736     { BASE_FORMAT_B5G6R5_UNORM_PACK16, GL_BGR, GL_RGB565, GL_UNSIGNED_SHORT_5_6_5_REV, 2, { false, 0, 0, 0 },
737         { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
738 #elif RENDER_HAS_GLES_BACKEND
739     // required by GLES
740     { BASE_FORMAT_ASTC_4x4_UNORM_BLOCK, GL_RGBA, GL_COMPRESSED_RGBA_ASTC_4x4_KHR, GL_UNSIGNED_BYTE, 0,
741         { true, 4, 4, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
742     { BASE_FORMAT_ASTC_5x4_UNORM_BLOCK, GL_RGBA, GL_COMPRESSED_RGBA_ASTC_5x4_KHR, GL_UNSIGNED_BYTE, 0,
743         { true, 5, 4, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
744     { BASE_FORMAT_ASTC_5x5_UNORM_BLOCK, GL_RGBA, GL_COMPRESSED_RGBA_ASTC_5x5_KHR, GL_UNSIGNED_BYTE, 0,
745         { true, 5, 5, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
746     { BASE_FORMAT_ASTC_6x5_UNORM_BLOCK, GL_RGBA, GL_COMPRESSED_RGBA_ASTC_6x5_KHR, GL_UNSIGNED_BYTE, 0,
747         { true, 6, 5, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
748     { BASE_FORMAT_ASTC_6x6_UNORM_BLOCK, GL_RGBA, GL_COMPRESSED_RGBA_ASTC_6x6_KHR, GL_UNSIGNED_BYTE, 0,
749         { true, 6, 6, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
750     { BASE_FORMAT_ASTC_8x5_UNORM_BLOCK, GL_RGBA, GL_COMPRESSED_RGBA_ASTC_8x5_KHR, GL_UNSIGNED_BYTE, 0,
751         { true, 8, 5, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
752     { BASE_FORMAT_ASTC_8x6_UNORM_BLOCK, GL_RGBA, GL_COMPRESSED_RGBA_ASTC_8x6_KHR, GL_UNSIGNED_BYTE, 0,
753         { true, 8, 6, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
754     { BASE_FORMAT_ASTC_8x8_UNORM_BLOCK, GL_RGBA, GL_COMPRESSED_RGBA_ASTC_8x8_KHR, GL_UNSIGNED_BYTE, 0,
755         { true, 8, 8, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
756     { BASE_FORMAT_ASTC_10x5_UNORM_BLOCK, GL_RGBA, GL_COMPRESSED_RGBA_ASTC_10x5_KHR, GL_UNSIGNED_BYTE, 0,
757         { true, 10, 5, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
758     { BASE_FORMAT_ASTC_10x6_UNORM_BLOCK, GL_RGBA, GL_COMPRESSED_RGBA_ASTC_10x6_KHR, GL_UNSIGNED_BYTE, 0,
759         { true, 10, 6, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
760     { BASE_FORMAT_ASTC_10x8_UNORM_BLOCK, GL_RGBA, GL_COMPRESSED_RGBA_ASTC_10x8_KHR, GL_UNSIGNED_BYTE, 0,
761         { true, 10, 8, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
762     { BASE_FORMAT_ASTC_10x10_UNORM_BLOCK, GL_RGBA, GL_COMPRESSED_RGBA_ASTC_10x10_KHR, GL_UNSIGNED_BYTE, 0,
763         { true, 10, 10, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
764     { BASE_FORMAT_ASTC_12x10_UNORM_BLOCK, GL_RGBA, GL_COMPRESSED_RGBA_ASTC_12x10_KHR, GL_UNSIGNED_BYTE, 0,
765         { true, 12, 10, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
766     { BASE_FORMAT_ASTC_12x12_UNORM_BLOCK, GL_RGBA, GL_COMPRESSED_RGBA_ASTC_12x12_KHR, GL_UNSIGNED_BYTE, 0,
767         { true, 12, 12, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
768     { BASE_FORMAT_ASTC_4x4_SRGB_BLOCK, GL_RGBA, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, GL_UNSIGNED_BYTE, 0,
769         { true, 4, 4, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
770     { BASE_FORMAT_ASTC_5x4_SRGB_BLOCK, GL_RGBA, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, GL_UNSIGNED_BYTE, 0,
771         { true, 5, 4, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
772     { BASE_FORMAT_ASTC_5x5_SRGB_BLOCK, GL_RGBA, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, GL_UNSIGNED_BYTE, 0,
773         { true, 5, 5, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
774     { BASE_FORMAT_ASTC_6x5_SRGB_BLOCK, GL_RGBA, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, GL_UNSIGNED_BYTE, 0,
775         { true, 6, 5, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
776     { BASE_FORMAT_ASTC_6x6_SRGB_BLOCK, GL_RGBA, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, GL_UNSIGNED_BYTE, 0,
777         { true, 6, 6, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
778     { BASE_FORMAT_ASTC_8x5_SRGB_BLOCK, GL_RGBA, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, GL_UNSIGNED_BYTE, 0,
779         { true, 8, 5, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
780     { BASE_FORMAT_ASTC_8x6_SRGB_BLOCK, GL_RGBA, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, GL_UNSIGNED_BYTE, 0,
781         { true, 8, 6, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
782     { BASE_FORMAT_ASTC_8x8_SRGB_BLOCK, GL_RGBA, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, GL_UNSIGNED_BYTE, 0,
783         { true, 8, 8, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
784     { BASE_FORMAT_ASTC_10x5_SRGB_BLOCK, GL_RGBA, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, GL_UNSIGNED_BYTE, 0,
785         { true, 10, 5, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
786     { BASE_FORMAT_ASTC_10x6_SRGB_BLOCK, GL_RGBA, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, GL_UNSIGNED_BYTE, 0,
787         { true, 10, 6, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
788     { BASE_FORMAT_ASTC_10x8_SRGB_BLOCK, GL_RGBA, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, GL_UNSIGNED_BYTE, 0,
789         { true, 10, 8, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
790     { BASE_FORMAT_ASTC_10x10_SRGB_BLOCK, GL_RGBA, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, GL_UNSIGNED_BYTE, 0,
791         { true, 10, 10, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
792     { BASE_FORMAT_ASTC_12x10_SRGB_BLOCK, GL_RGBA, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, GL_UNSIGNED_BYTE, 0,
793         { true, 12, 10, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
794     { BASE_FORMAT_ASTC_12x12_SRGB_BLOCK, GL_RGBA, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, GL_UNSIGNED_BYTE, 0,
795         { true, 12, 12, BLOCK_BITS_128 }, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
796 #endif
797 };
798 
FillExtensionFormats(const DeviceGLES & device,BASE_NS::vector<DeviceGLES::ImageFormat> & sf)799 void FillExtensionFormats(const DeviceGLES& device, BASE_NS::vector<DeviceGLES::ImageFormat>& sf)
800 {
801 #if (defined(GL_EXT_texture_sRGB_R8) && (GL_EXT_texture_sRGB_R8))
802     if (device.HasExtension("GL_EXT_texture_sRGB_R8")) {
803         sf.append(std::begin(IMAGE_FORMATS_EXT_SRGB_R8), std::end(IMAGE_FORMATS_EXT_SRGB_R8));
804     }
805 #endif
806 
807 #if (defined(GL_EXT_texture_sRGB_RG8) && (GL_EXT_texture_sRGB_RG8))
808     if (device.HasExtension("GL_EXT_texture_sRGB_RG8")) {
809         sf.append(std::begin(IMAGE_FORMATS_EXT_SRGB_RG8), std::end(IMAGE_FORMATS_EXT_SRGB_RG8));
810     }
811 #endif
812 
813 #if defined(GL_EXT_texture_sRGB) && (GL_EXT_texture_sRGB)
814     if (device.HasExtension("GL_EXT_texture_sRGB")) {
815         sf.append(std::begin(IMAGE_FORMATS_EXT_SRGB), std::end(IMAGE_FORMATS_EXT_SRGB));
816     }
817 #endif
818 
819 #if defined(GL_EXT_texture_format_BGRA8888) && (GL_EXT_texture_format_BGRA8888)
820     if (device.HasExtension("GL_EXT_texture_format_BGRA8888")) {
821         sf.append(std::begin(IMAGE_FORMATS_EXT_BGRA), std::end(IMAGE_FORMATS_EXT_BGRA));
822     }
823 #endif
824 
825 #if defined(GL_EXT_texture_norm16) && (GL_EXT_texture_norm16)
826     if (device.HasExtension("GL_EXT_texture_norm16")) {
827         sf.append(std::begin(IMAGE_FORMATS_EXT_NORM16), std::end(IMAGE_FORMATS_EXT_NORM16));
828     }
829 #endif
830 
831 #if defined(GL_EXT_texture_compression_s3tc) && (GL_EXT_texture_compression_s3tc)
832     if (device.HasExtension("GL_EXT_texture_compression_s3tc")) {
833         sf.append(std::begin(IMAGE_FORMATS_EXT_S3TC), std::end(IMAGE_FORMATS_EXT_S3TC));
834     }
835 #endif
836 
837 #if defined(GL_ARB_texture_compression_bptc) && (GL_ARB_texture_compression_bptc)
838     if (device.HasExtension("GL_ARB_texture_compression_bptc")) {
839         sf.append(std::begin(IMAGE_FORMATS_EXT_BPTC), std::end(IMAGE_FORMATS_EXT_BPTC));
840     }
841 #endif
842 
843 #if defined(GL_EXT_texture_compression_rgtc) && (GL_EXT_texture_compression_rgtc)
844     if (device.HasExtension("GL_EXT_texture_compression_rgtc")) {
845         sf.append(std::begin(IMAGE_FORMATS_EXT_RGTC), std::end(IMAGE_FORMATS_EXT_RGTC));
846     }
847 #endif
848 }
849 
FillSupportedFormats(const DeviceGLES & device,BASE_NS::vector<DeviceGLES::ImageFormat> & sf)850 void FillSupportedFormats(const DeviceGLES& device, BASE_NS::vector<DeviceGLES::ImageFormat>& sf)
851 {
852     // First dump required formats and then add based on supported extensions
853     sf.append(std::begin(IMAGE_FORMATS), std::end(IMAGE_FORMATS));
854 
855     FillExtensionFormats(device, sf);
856 
857     // Keep the list sorted for faster lookup
858     std::sort(sf.begin(), sf.end(), [](const DeviceGLES::ImageFormat& lhs, const DeviceGLES::ImageFormat& rhs) {
859         return lhs.coreFormat < rhs.coreFormat;
860     });
861 }
862 
FillExtensions(BASE_NS::vector<BASE_NS::string_view> & extensions)863 void FillExtensions(BASE_NS::vector<BASE_NS::string_view>& extensions)
864 {
865     GLint n = 0;
866     glGetIntegerv(GL_NUM_EXTENSIONS, &n);
867     extensions.reserve(n + 1U);
868     for (GLuint i = 0U; i < static_cast<GLuint>(n); ++i) {
869         const auto ext = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i));
870         extensions.emplace_back(ext);
871     }
872     std::sort(
873         extensions.begin(), extensions.end(), [](const string_view& lhs, const string_view& rhs) { return lhs < rhs; });
874 #ifndef NDEBUG
875     PLUGIN_LOG_V("GL_EXTENSIONs:");
876     for (const auto& ext : extensions) {
877         PLUGIN_LOG_V("\t%s", ext.data());
878     }
879 #endif // !NDEBUG
880 }
881 } // namespace
882 
883 // Some OpenGL/ES features are supported and using them will lead to an assertion unless
884 // the following define is added locally or as part of the build command: #define HANDLE_UNSUPPORTED_ENUMS
TargetToBinding(uint32_t target)885 inline uint32_t DeviceGLES::TargetToBinding(uint32_t target)
886 {
887     if (target == GL_UNIFORM_BUFFER) {
888         return GL_UNIFORM_BUFFER_BINDING;
889     } else if (target == GL_SHADER_STORAGE_BUFFER) {
890         return GL_SHADER_STORAGE_BUFFER_BINDING;
891     } else if (target == GL_PIXEL_UNPACK_BUFFER) {
892         return GL_PIXEL_UNPACK_BUFFER_BINDING;
893     } else if (target == GL_COPY_READ_BUFFER) {
894         return GL_COPY_READ_BUFFER_BINDING;
895     } else if (target == GL_COPY_WRITE_BUFFER) {
896         return GL_COPY_WRITE_BUFFER_BINDING;
897 #ifdef HANDLE_UNSUPPORTED_ENUMS
898     } else if (target == GL_ATOMIC_COUNTER_BUFFER) {
899         return GL_ATOMIC_COUNTER_BUFFER_BINDING;
900     } else if (target == GL_TRANSFORM_FEEDBACK_BUFFER) {
901         return GL_TRANSFORM_FEEDBACK_BUFFER_BINDING;
902     } else if (target == GL_PIXEL_PACK_BUFFER) {
903         return GL_PIXEL_PACK_BUFFER_BINDING;
904     } else if (target == GL_QUERY_BUFFER) {
905         return GL_QUERY_BUFFER_BINDING;
906     } else if (target == GL_ARRAY_BUFFER) {
907         return GL_ARRAY_BUFFER_BINDING;
908     } else if (target == GL_DISPATCH_INDIRECT_BUFFER) {
909         return GL_DISPATCH_INDIRECT_BUFFER_BINDING;
910     } else if (target == GL_DRAW_INDIRECT_BUFFER) {
911         return GL_DRAW_INDIRECT_BUFFER_BINDING;
912     } else if (target == GL_ELEMENT_ARRAY_BUFFER) { // stored in VAO state...
913         return GL_ELEMENT_ARRAY_BUFFER_BINDING;
914     } else if (target == GL_TEXTURE_BUFFER) {
915         return GL_TEXTURE_BUFFER_BINDING;
916 #endif
917     }
918     PLUGIN_ASSERT_MSG(false, "UNHANDLED BUFFER BIND TARGET UNIT");
919     return GL_NONE;
920 }
921 
IndexedTargetToTargetId(uint32_t target)922 inline DeviceGLES::BufferBindId DeviceGLES::IndexedTargetToTargetId(uint32_t target)
923 {
924     if (target == GL_UNIFORM_BUFFER) {
925         return BufferBindId::UNIFORM_BUFFER_BIND;
926     } else if (target == GL_SHADER_STORAGE_BUFFER) {
927         return BufferBindId::SHADER_STORAGE_BUFFER_BIND;
928 #ifdef HANDLE_UNSUPPORTED_ENUMS
929     } else if (target == GL_ATOMIC_COUNTER_BUFFER) {
930         return BufferBindId::ATOMIC_COUNTER_BUFFER;
931     } else if (target == GL_TRANSFORM_FEEDBACK_BUFFER) {
932         return BufferBindId::TRANSFORM_FEEDBACK_BUFFER;
933 #endif
934     }
935     PLUGIN_ASSERT_MSG(false, "UNHANDLED BUFFER BIND TARGET UNIT");
936     return BufferBindId::MAX_BUFFER_BIND_ID;
937 }
938 
IndexedTargetIdToTarget(DeviceGLES::BufferBindId target)939 inline uint32_t DeviceGLES::IndexedTargetIdToTarget(DeviceGLES::BufferBindId target)
940 {
941     if (target == BufferBindId::UNIFORM_BUFFER_BIND) {
942         return GL_UNIFORM_BUFFER;
943     } else if (target == BufferBindId::SHADER_STORAGE_BUFFER_BIND) {
944         return GL_SHADER_STORAGE_BUFFER;
945 #ifdef HANDLE_UNSUPPORTED_ENUMS
946     } else if (target == BufferBindId::ATOMIC_COUNTER_BUFFER_BIND) {
947         return GL_ATOMIC_COUNTER_BUFFER;
948     } else if (target == BufferBindId::TRANSFORM_FEEDBACK_BUFFER_BIND) {
949         return GL_TRANSFORM_FEEDBACK_BUFFER;
950 #endif
951     }
952     PLUGIN_ASSERT_MSG(false, "UNHANDLED BUFFER BIND TARGET UNIT");
953     return 0;
954 }
955 
GenericTargetToTargetId(uint32_t target)956 inline DeviceGLES::BufferTargetId DeviceGLES::GenericTargetToTargetId(uint32_t target)
957 {
958     if (target == GL_PIXEL_UNPACK_BUFFER) {
959         return BufferTargetId::PIXEL_UNPACK_BUFFER;
960     } else if (target == GL_PIXEL_PACK_BUFFER) {
961         return BufferTargetId::PIXEL_PACK_BUFFER;
962     } else if (target == GL_COPY_READ_BUFFER) {
963         return BufferTargetId::COPY_READ_BUFFER;
964     } else if (target == GL_COPY_WRITE_BUFFER) {
965         return BufferTargetId::COPY_WRITE_BUFFER;
966     } else if (target == GL_UNIFORM_BUFFER) {
967         return BufferTargetId::UNIFORM_BUFFER;
968     } else if (target == GL_SHADER_STORAGE_BUFFER) {
969         return BufferTargetId::SHADER_STORAGE_BUFFER;
970     } else if (target == GL_DISPATCH_INDIRECT_BUFFER) {
971         return BufferTargetId::DISPATCH_INDIRECT_BUFFER;
972     } else if (target == GL_DRAW_INDIRECT_BUFFER) {
973         return BufferTargetId::DRAW_INDIRECT_BUFFER;
974 #ifdef HANDLE_UNSUPPORTED_ENUMS
975     } else if (target == GL_ATOMIC_COUNTER_BUFFER) {
976         return BufferTargetId::ATOMIC_COUNTER_BUFFER;
977     } else if (target == GL_QUERY_BUFFER) {
978         return BufferTargetId::QUERY_BUFFER;
979     } else if (target == GL_TRANSFORM_FEEDBACK_BUFFER) {
980         return BufferTargetId::TRANSFORM_FEEDBACK_BUFFER;
981     } else if (target == GL_ARRAY_BUFFER) {
982         return BufferTargetId::ARRAY_BUFFER;
983     } else if (target == GL_ELEMENT_ARRAY_BUFFER) { // stored in VAO state...
984         return BufferTargetId::ELEMENT_ARRAY_BUFFER;
985     } else if (target == GL_TEXTURE_BUFFER) {
986         return BufferTargetId::TEXTURE_BUFFER;
987 #endif
988     }
989     PLUGIN_ASSERT_MSG(false, "UNHANDLED BUFFER BIND TARGET");
990     return BufferTargetId::MAX_BUFFER_TARGET_ID;
991 }
992 
GenericTargetIdToTarget(BufferTargetId target)993 inline uint32_t DeviceGLES::GenericTargetIdToTarget(BufferTargetId target)
994 {
995     if (target == BufferTargetId::PIXEL_UNPACK_BUFFER) {
996         return GL_PIXEL_UNPACK_BUFFER;
997     } else if (target == BufferTargetId::PIXEL_PACK_BUFFER) {
998         return GL_PIXEL_PACK_BUFFER;
999     } else if (target == BufferTargetId::COPY_READ_BUFFER) {
1000         return GL_COPY_READ_BUFFER;
1001     } else if (target == BufferTargetId::COPY_WRITE_BUFFER) {
1002         return GL_COPY_WRITE_BUFFER;
1003     } else if (target == BufferTargetId::UNIFORM_BUFFER) {
1004         return GL_UNIFORM_BUFFER;
1005     } else if (target == BufferTargetId::SHADER_STORAGE_BUFFER) {
1006         return GL_SHADER_STORAGE_BUFFER;
1007     } else if (target == BufferTargetId::DISPATCH_INDIRECT_BUFFER) {
1008         return GL_DISPATCH_INDIRECT_BUFFER;
1009     } else if (target == BufferTargetId::DRAW_INDIRECT_BUFFER) {
1010         return GL_DRAW_INDIRECT_BUFFER;
1011 #ifdef HANDLE_UNSUPPORTED_ENUMS
1012     } else if (target == BufferTargetId::ATOMIC_COUNTER_BUFFER) {
1013         return GL_ATOMIC_COUNTER_BUFFER;
1014     } else if (target == BufferTargetId::QUERY_BUFFER) {
1015         return GL_QUERY_BUFFER;
1016     } else if (target == BufferTargetId::TRANSFORM_FEEDBACK_BUFFER) {
1017         return GL_TRANSFORM_FEEDBACK_BUFFER;
1018     } else if (target == BufferTargetId::ARRAY_BUFFER) {
1019         return GL_ARRAY_BUFFER;
1020     } else if (target == BufferTargetId::ELEMENT_ARRAY_BUFFER) { // stored in VAO state...
1021         return GL_ELEMENT_ARRAY_BUFFER;
1022     } else if (target == BufferTargetId::TEXTURE_BUFFER) {
1023         return GL_TEXTURE_BUFFER;
1024 #endif
1025     }
1026     PLUGIN_ASSERT_MSG(false, "UNHANDLED BUFFER BIND TARGET");
1027     return 0;
1028 }
1029 
TextureTargetToTargetId(uint32_t target)1030 inline DeviceGLES::TextureTargetId DeviceGLES::TextureTargetToTargetId(uint32_t target)
1031 {
1032     if (target == GL_TEXTURE_2D) {
1033         return TextureTargetId::TEXTURE_2D;
1034     } else if ((target == GL_TEXTURE_CUBE_MAP_POSITIVE_X) || (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_X) ||
1035                (target == GL_TEXTURE_CUBE_MAP_POSITIVE_Y) || (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y) ||
1036                (target == GL_TEXTURE_CUBE_MAP_POSITIVE_Z) || (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) ||
1037                (target == GL_TEXTURE_CUBE_MAP)) {
1038         return TextureTargetId::TEXTURE_CUBE_MAP;
1039 #if RENDER_HAS_GLES_BACKEND
1040     } else if (target == GL_TEXTURE_EXTERNAL_OES) {
1041         return TextureTargetId::TEXTURE_EXTERNAL_OES;
1042 #endif
1043     } else if (target == GL_TEXTURE_2D_MULTISAMPLE) {
1044         return TextureTargetId::TEXTURE_2D_MULTISAMPLE;
1045     } else if (target == GL_TEXTURE_2D_ARRAY) {
1046         return TextureTargetId::TEXTURE_2D_ARRAY;
1047     } else if (target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) {
1048         return TextureTargetId::TEXTURE_2D_MULTISAMPLE_ARRAY;
1049     } else if (target == GL_TEXTURE_3D) {
1050         return TextureTargetId::TEXTURE_3D;
1051     }
1052     PLUGIN_ASSERT_MSG(false, "UNHANDLED TEXTURE TARGET UNIT");
1053     return TextureTargetId::MAX_TEXTURE_TARGET_ID;
1054 }
1055 
TextureTargetIdToTarget(DeviceGLES::TextureTargetId target)1056 inline uint32_t DeviceGLES::TextureTargetIdToTarget(DeviceGLES::TextureTargetId target)
1057 {
1058     if (target == TextureTargetId::TEXTURE_2D) {
1059         return GL_TEXTURE_2D;
1060     } else if (target == TextureTargetId::TEXTURE_CUBE_MAP) {
1061         return GL_TEXTURE_CUBE_MAP;
1062 #if RENDER_HAS_GLES_BACKEND
1063     } else if (target == TextureTargetId::TEXTURE_EXTERNAL_OES) {
1064         return GL_TEXTURE_EXTERNAL_OES;
1065 #endif
1066     } else if (target == TextureTargetId::TEXTURE_2D_MULTISAMPLE) {
1067         return GL_TEXTURE_2D_MULTISAMPLE;
1068     } else if (target == TextureTargetId::TEXTURE_2D_MULTISAMPLE_ARRAY) {
1069         return GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
1070     } else if (target == TextureTargetId::TEXTURE_2D_ARRAY) {
1071         return GL_TEXTURE_2D_ARRAY;
1072     } else if (target == TextureTargetId::TEXTURE_3D) {
1073         return GL_TEXTURE_3D;
1074     }
1075     PLUGIN_ASSERT_MSG(false, "UNHANDLED TEXTURE TARGET UNIT");
1076     return 0;
1077 }
1078 
1079 thread_local bool DeviceGLES::isActiveInThread_ = false;
Activate(RenderHandle swapchain)1080 void DeviceGLES::Activate(RenderHandle swapchain)
1081 {
1082     if (HasSwapchain()) {
1083         eglState_.SetContext(static_cast<const SwapchainGLES*>(GetSwapchain(swapchain)));
1084     } else {
1085         // bind the dummy surface as there is no swapchain.
1086         eglState_.SetContext(nullptr);
1087     }
1088 }
1089 
SwapBuffers(const SwapchainGLES & swapchain)1090 void DeviceGLES::SwapBuffers(const SwapchainGLES& swapchain)
1091 {
1092     eglState_.SwapBuffers(swapchain);
1093 }
1094 
1095 #if RENDER_HAS_GL_BACKEND
GetEglState() const1096 const WGLHelpers::WGLState& DeviceGLES::GetEglState()
1097 #endif
1098 #if RENDER_HAS_GLES_BACKEND
1099     const EGLHelpers::EGLState& DeviceGLES::GetEglState()
1100 #endif
1101 {
1102     return eglState_;
1103 }
1104 
1105 #if RENDER_HAS_GLES_BACKEND
IsDepthResolveSupported() const1106 bool DeviceGLES::IsDepthResolveSupported() const
1107 {
1108     return backendConfig_.allowDepthResolve;
1109 }
1110 #endif
1111 
DeviceGLES(RenderContext & renderContext,DeviceCreateInfo const & createInfo)1112 DeviceGLES::DeviceGLES(RenderContext& renderContext, DeviceCreateInfo const& createInfo)
1113     : Device(renderContext, createInfo)
1114 {
1115     eglState_.CreateContext(createInfo);
1116     if (!eglState_.IsValid()) {
1117         PLUGIN_LOG_F("Failed to create a context");
1118         return;
1119     }
1120     eglState_.GlInitialize();
1121 
1122     RegisterDebugCallback(eglState_);
1123 
1124     PLUGIN_LOG_I("GL_VENDOR: %s", glGetString(GL_VENDOR));
1125     PLUGIN_LOG_I("GL_RENDERER: %s", glGetString(GL_RENDERER));
1126     PLUGIN_LOG_I("GL_VERSION: %s", glGetString(GL_VERSION));
1127     PLUGIN_LOG_I("GL_SHADING_LANGUAGE_VERSION: %s", glGetString(GL_SHADING_LANGUAGE_VERSION));
1128     GLint value = 0;
1129     glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &value);
1130     PLUGIN_LOG_I("GL_NUM_SHADER_BINARY_FORMATS: %d", value);
1131     if (value > 0) {
1132         supportsBinaryShaders_ = true;
1133 #if defined(RENDER_GL_DEBUG) && (RENDER_GL_DEBUG)
1134         vector<GLint> values(static_cast<size_t>(value), 0);
1135         glGetIntegerv(GL_SHADER_BINARY_FORMATS, values.data());
1136         for (const auto& format : values) {
1137             PLUGIN_LOG_I("     SHADER_BINARY_FORMATS: %x", format);
1138         }
1139 #endif
1140     }
1141     glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &value);
1142     PLUGIN_LOG_I("GL_NUM_PROGRAM_BINARY_FORMATS: %d", value);
1143     if (value > 0) {
1144         supportsBinaryPrograms_ = true;
1145 #if defined(RENDER_GL_DEBUG) && (RENDER_GL_DEBUG)
1146         vector<GLint> values(static_cast<size_t>(value), 0);
1147         glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, values.data());
1148         for (const auto& format : values) {
1149             PLUGIN_LOG_I("     PROGRAM_BINARY_FORMATS: %x", format);
1150         }
1151 #endif
1152     }
1153     FillExtensions(extensions_);
1154 
1155 #if RENDER_HAS_GL_BACKEND
1156     // Extension in OpenGL ES, but part of core in OpenGL.
1157     if (const auto pos = std::lower_bound(extensions_.cbegin(), extensions_.cend(), EXT_BUFFER_STORAGE,
1158             [](const string_view& element, const string_view& value) { return element < value; });
1159         (pos == extensions_.cend()) || (*pos != EXT_BUFFER_STORAGE)) {
1160         extensions_.insert(pos, EXT_BUFFER_STORAGE);
1161     }
1162     // Seamless cubemaps are always on in vulkan and gles 3.0..
1163     // (3.0 made it required, not supported prior to 3.0 es)
1164     // on desktop gl, it's optional.
1165     // (but must be supported since 3.2)
1166     // So just enable it always, so that desktop GL works as vulkan and GLES.
1167     glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
1168 #endif
1169 
1170     // Dump interesting constants.
1171     DumpLimits();
1172 
1173     boundReadFbo_ = boundWriteFbo_ = 0;
1174     eglState_.RestoreContext();
1175 #ifdef RENDER_OPTIMIZE_FOR_INTEGRATED_GPU
1176     // NOTE: we expect e.g. mobile devices to have integrated memory, where we can bypass staging and write directly to
1177     // linear gpu buffers without additional copies and performance decrease
1178     deviceSharedMemoryPropertyFlags_ = CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
1179 #endif
1180     SetDeviceStatus(true);
1181 
1182     FillSupportedFormats(*this, supportedFormats_);
1183 
1184     const GpuResourceManager::CreateInfo grmCreateInfo {
1185         GpuResourceManager::GPU_RESOURCE_MANAGER_OPTIMIZE_STAGING_MEMORY,
1186     };
1187     gpuResourceMgr_ = make_unique<GpuResourceManager>(*this, grmCreateInfo);
1188     shaderMgr_ = make_unique<ShaderManager>(*this);
1189     globalDescriptorSetMgr_ = make_unique<DescriptorSetManagerGles>(*this);
1190 
1191     lowLevelDevice_ = make_unique<LowLevelDeviceGLES>(*this);
1192 }
1193 
~DeviceGLES()1194 DeviceGLES::~DeviceGLES()
1195 {
1196     if (eglState_.IsValid()) {
1197         Activate(); // make sure we are active during teardown..
1198         WaitForIdle();
1199 
1200         globalDescriptorSetMgr_.reset();
1201         // must release handles before taking down gpu resource manager.
1202         swapchains_.clear();
1203 
1204         gpuResourceMgr_.reset();
1205         shaderMgr_.reset();
1206         Deactivate(); // make sure the previous context is still active..
1207         {
1208             // destroying the context should be the last thing we do
1209             auto lock = std::lock_guard(activeMutex_);
1210             eglState_.DestroyContext();
1211         }
1212     }
1213 }
1214 
HasExtension(const string_view extension) const1215 bool DeviceGLES::HasExtension(const string_view extension) const
1216 {
1217     return std::binary_search(extensions_.begin(), extensions_.end(), extension,
1218         [](const string_view& element, const string_view value) { return element < value; });
1219 }
1220 
GetBackendType() const1221 DeviceBackendType DeviceGLES::GetBackendType() const
1222 {
1223     return backendType_;
1224 }
1225 
GetPlatformData() const1226 const DevicePlatformData& DeviceGLES::GetPlatformData() const
1227 {
1228     return eglState_.GetPlatformData();
1229 }
1230 
GetLowLevelDevice() const1231 ILowLevelDevice& DeviceGLES::GetLowLevelDevice() const
1232 {
1233     return *lowLevelDevice_;
1234 }
1235 
GetFormatProperties(const Format format) const1236 FormatProperties DeviceGLES::GetFormatProperties(const Format format) const
1237 {
1238     FormatProperties properties;
1239     auto& glFormat = GetGlImageFormat(format);
1240     if (glFormat.internalFormat != GL_NONE) {
1241         if (auto pos = std::find_if(std::begin(IMAGE_FORMAT_FEATURES), std::end(IMAGE_FORMAT_FEATURES),
1242                 [internalFormat = glFormat.internalFormat](
1243                     const FormatFeatures& features) { return features.internalFormat == internalFormat; });
1244             pos != std::end(IMAGE_FORMAT_FEATURES)) {
1245             // split texel buffer support to bufferFeatures
1246             properties.linearTilingFeatures = properties.optimalTilingFeatures =
1247                 pos->flags & ~CORE_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT;
1248             // assume if the format can be sampled it can be used as a vertex buffer.
1249             properties.bufferFeatures =
1250                 ((pos->flags & CORE_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) ? CORE_FORMAT_FEATURE_VERTEX_BUFFER_BIT : 0U) |
1251                 (pos->flags & CORE_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT);
1252 #if RENDER_HAS_GL_BACKEND
1253             // desktop GL can filter anything
1254             properties.linearTilingFeatures |= TF;
1255             properties.optimalTilingFeatures |= TF;
1256 #endif
1257             // can probably blit if not compressed
1258             if (!glFormat.compression.compressed) {
1259                 properties.linearTilingFeatures |= CORE_FORMAT_FEATURE_BLIT_DST_BIT | CORE_FORMAT_FEATURE_BLIT_SRC_BIT;
1260                 properties.optimalTilingFeatures |= CORE_FORMAT_FEATURE_BLIT_DST_BIT | CORE_FORMAT_FEATURE_BLIT_SRC_BIT;
1261             }
1262             properties.bytesPerPixel = glFormat.bytesperpixel;
1263         }
1264     }
1265     return properties;
1266 }
1267 
GetAccelerationStructureBuildSizes(const AccelerationStructureBuildGeometryInfo & geometry,BASE_NS::array_view<const AccelerationStructureGeometryTrianglesInfo> triangles,BASE_NS::array_view<const AccelerationStructureGeometryAabbsInfo> aabbs,BASE_NS::array_view<const AccelerationStructureGeometryInstancesInfo> instances) const1268 AccelerationStructureBuildSizes DeviceGLES::GetAccelerationStructureBuildSizes(
1269     const AccelerationStructureBuildGeometryInfo& geometry,
1270     BASE_NS::array_view<const AccelerationStructureGeometryTrianglesInfo> triangles,
1271     BASE_NS::array_view<const AccelerationStructureGeometryAabbsInfo> aabbs,
1272     BASE_NS::array_view<const AccelerationStructureGeometryInstancesInfo> instances) const
1273 {
1274     return {};
1275 }
1276 
GetPlatformGpuMemoryAllocator()1277 PlatformGpuMemoryAllocator* DeviceGLES::GetPlatformGpuMemoryAllocator()
1278 {
1279     PLUGIN_ASSERT_MSG(false, "DeviceGLES::GetPlatformGpuMemoryAllocator called!");
1280     return nullptr;
1281 }
1282 
1283 // (re-)create swapchain
CreateDeviceSwapchain(const SwapchainCreateInfo & swapchainCreateInfo)1284 unique_ptr<Swapchain> DeviceGLES::CreateDeviceSwapchain(const SwapchainCreateInfo& swapchainCreateInfo)
1285 {
1286     PLUGIN_ASSERT(IsActive());
1287     auto swapchain = make_unique<SwapchainGLES>(*this, swapchainCreateInfo);
1288     // Switch to the new swapchain.
1289     eglState_.SetContext(swapchain.get());
1290     return swapchain;
1291 }
1292 
DestroyDeviceSwapchain()1293 void DeviceGLES::DestroyDeviceSwapchain()
1294 {
1295     PLUGIN_ASSERT(IsActive());
1296     // Drop to dummycontext (ie. 1x1 surface etc...)
1297     eglState_.SetContext(nullptr);
1298 }
1299 
IsActive() const1300 bool DeviceGLES::IsActive() const
1301 {
1302     return isActiveInThread_;
1303 }
1304 
Activate()1305 void DeviceGLES::Activate()
1306 {
1307     activeMutex_.lock();
1308     if (isActive_ == 0) {
1309         eglState_.SaveContext();
1310 
1311         constexpr RenderHandle defaultSwapchain {};
1312         Activate(defaultSwapchain);
1313         isActiveInThread_ = true;
1314     }
1315     isActive_++;
1316 }
1317 
Deactivate()1318 void DeviceGLES::Deactivate()
1319 {
1320     PLUGIN_ASSERT_MSG(isActiveInThread_, "Deactivate called while already inactive");
1321     if (isActive_ == 1) {
1322         eglState_.RestoreContext();
1323         isActiveInThread_ = false;
1324     }
1325     if (isActive_ > 0) {
1326         isActive_--;
1327     }
1328     activeMutex_.unlock();
1329 }
1330 
GetValidGpuQueue(const GpuQueue & gpuQueue) const1331 GpuQueue DeviceGLES::GetValidGpuQueue(const GpuQueue& gpuQueue) const
1332 {
1333     return { GpuQueue::QueueType::GRAPHICS, 0 }; // no queues -> graphics
1334 }
1335 
GetGpuQueueCount() const1336 uint32_t DeviceGLES::GetGpuQueueCount() const
1337 {
1338     return 1;
1339 }
1340 
1341 struct CacheHeader {
1342     uint32_t version;
1343     uint32_t programs;
1344     uint64_t revisionHash;
1345     struct Program {
1346         uint64_t vertHash;
1347         uint64_t fragHash;
1348         uint64_t compHash;
1349         GLuint offset;
1350         GLenum binaryFormat;
1351     };
1352 };
InitializePipelineCache(array_view<const uint8_t> initialData)1353 void DeviceGLES::InitializePipelineCache(array_view<const uint8_t> initialData)
1354 {
1355     if (initialData.size() <= sizeof(CacheHeader)) {
1356         return;
1357     }
1358     auto* header = reinterpret_cast<const CacheHeader*>(initialData.data());
1359     if ((header->version != CACHE_VERSION) ||
1360         (header->revisionHash != Hash(string_view(reinterpret_cast<const char*>(glGetString(GL_VENDOR))),
1361                                       string_view(reinterpret_cast<const char*>(glGetString(GL_RENDERER))),
1362                                       string_view(reinterpret_cast<const char*>(glGetString(GL_VERSION)))))) {
1363         return;
1364     }
1365     if ((sizeof(CacheHeader) + header->programs * sizeof(CacheHeader::Program)) > initialData.size()) {
1366         return;
1367     }
1368     auto programs = array_view(
1369         reinterpret_cast<const CacheHeader::Program*>(initialData.data() + sizeof(CacheHeader)), header->programs);
1370     auto binaryData = array_view(initialData.data() + (sizeof(CacheHeader) + programs.size_bytes()),
1371         initialData.size() - (sizeof(CacheHeader) + programs.size_bytes()));
1372     for (auto i = 0U; i < programs.size(); ++i) {
1373         auto& program = programs[i];
1374         GLsizei length;
1375         if ((i + 1) < programs.size()) {
1376             length = static_cast<GLsizei>(programs[i + 1].offset) - static_cast<GLsizei>(program.offset);
1377         } else {
1378             length = static_cast<GLsizei>(binaryData.size()) - static_cast<GLsizei>(program.offset);
1379         }
1380         if ((length < 0) || (program.offset + length) > binaryData.size()) {
1381             continue;
1382         }
1383 
1384         const GLuint programObj = glCreateProgram();
1385         glProgramBinary(programObj, program.binaryFormat, binaryData.data() + program.offset, length);
1386         GLint result = GL_FALSE;
1387         glGetProgramiv(programObj, GL_LINK_STATUS, &result);
1388         if (result != GL_FALSE) {
1389             auto& entry = programs_.emplace_back();
1390             entry.program = programObj;
1391             entry.hashVert = program.vertHash;
1392             entry.hashFrag = program.fragHash;
1393             entry.hashComp = program.compHash;
1394         } else {
1395 #if (RENDER_VALIDATION_ENABLED == 1)
1396             GLint logLength = 0;
1397             glGetProgramiv(programObj, GL_INFO_LOG_LENGTH, &logLength);
1398             string messages;
1399             messages.resize(static_cast<size_t>(logLength));
1400             glGetProgramInfoLog(programObj, logLength, 0, messages.data());
1401             PLUGIN_LOG_ONCE_E("gl_shader_linking_error_" + to_string(programObj),
1402                 "RENDER_VALIDATION: Shader linking error: %s", messages.c_str());
1403 #endif
1404             glDeleteProgram(programObj);
1405         }
1406     }
1407 }
1408 
GetPipelineCache() const1409 vector<uint8_t> DeviceGLES::GetPipelineCache() const
1410 {
1411     vector<uint8_t> cacheData;
1412     if (!supportsBinaryPrograms_) {
1413         return cacheData;
1414     }
1415 
1416     CacheHeader header;
1417     header.version = CACHE_VERSION;
1418     header.revisionHash = Hash(string_view(reinterpret_cast<const char*>(glGetString(GL_VENDOR))),
1419         string_view(reinterpret_cast<const char*>(glGetString(GL_RENDERER))),
1420         string_view(reinterpret_cast<const char*>(glGetString(GL_VERSION))));
1421 
1422     vector<CacheHeader::Program> programs;
1423     for (const auto& info : programs_) {
1424         GLint programLength = 0;
1425         glGetProgramiv(info.program, GL_PROGRAM_BINARY_LENGTH, &programLength);
1426         if (!programLength) {
1427             continue;
1428         }
1429         const auto offset = cacheData.size();
1430         cacheData.resize(offset + programLength);
1431         GLsizei length;
1432         GLenum binaryFormat;
1433         glGetProgramBinary(info.program, programLength, &length, &binaryFormat, cacheData.data() + offset);
1434         programs.push_back({ info.hashVert, info.hashFrag, info.hashComp, static_cast<GLuint>(offset), binaryFormat });
1435     }
1436     header.programs = static_cast<uint32_t>(programs.size());
1437     cacheData.insert(cacheData.cbegin(), sizeof(CacheHeader) + programs.size_in_bytes(), uint8_t(0U));
1438     CloneData(cacheData.data(), cacheData.size(), &header, sizeof(CacheHeader));
1439     CloneData(cacheData.data() + sizeof(CacheHeader), cacheData.size() - sizeof(CacheHeader), programs.data(),
1440         programs.size_in_bytes());
1441     return cacheData;
1442 }
1443 
WaitForIdle()1444 void DeviceGLES::WaitForIdle()
1445 {
1446     const bool activeState = IsActive();
1447     if (!activeState) {
1448         Activate();
1449     }
1450     if (!isRenderbackendRunning_) {
1451         PLUGIN_LOG_D("Device - WaitForIdle");
1452         glFinish();
1453     } else {
1454         PLUGIN_LOG_E("Device WaitForIdle can only called when render backend is not running");
1455     }
1456     if (!activeState) {
1457         Deactivate();
1458     }
1459 }
1460 
1461 #if (RENDER_HAS_GL_BACKEND)
CreateDeviceGL(RenderContext & renderContext,DeviceCreateInfo const & createInfo)1462 unique_ptr<Device> CreateDeviceGL(RenderContext& renderContext, DeviceCreateInfo const& createInfo)
1463 {
1464     if (auto device = make_unique<DeviceGLES>(renderContext, createInfo); device) {
1465         const auto& plat = static_cast<const DevicePlatformDataGL&>(device->GetPlatformData());
1466         if (plat.context != nullptr) {
1467             return device;
1468         }
1469     }
1470     return nullptr;
1471 }
1472 #endif
1473 #if (RENDER_HAS_GLES_BACKEND)
CreateDeviceGLES(RenderContext & renderContext,DeviceCreateInfo const & createInfo)1474 unique_ptr<Device> CreateDeviceGLES(RenderContext& renderContext, DeviceCreateInfo const& createInfo)
1475 {
1476     if (auto device = make_unique<DeviceGLES>(renderContext, createInfo); device) {
1477         const auto& plat = static_cast<const DevicePlatformDataGLES&>(device->GetPlatformData());
1478         if (plat.context != EGL_NO_CONTEXT) {
1479             return device;
1480         }
1481     }
1482     return nullptr;
1483 }
1484 #endif
1485 
ReleaseShader(uint32_t type,uint32_t shader)1486 void DeviceGLES::ReleaseShader(uint32_t type, uint32_t shader)
1487 {
1488     vector<ShaderCache::Entry>* cache = nullptr;
1489     if (type == GL_FRAGMENT_SHADER) {
1490         cache = &shaders_[DeviceGLES::FRAGMENT_CACHE].cache;
1491     } else if (type == GL_VERTEX_SHADER) {
1492         cache = &shaders_[DeviceGLES::VERTEX_CACHE].cache;
1493     } else if (type == GL_COMPUTE_SHADER) {
1494         cache = &shaders_[DeviceGLES::COMPUTE_CACHE].cache;
1495     } else {
1496         return;
1497     }
1498 
1499     const auto pos = std::find_if(
1500         cache->begin(), cache->end(), [shader](const ShaderCache::Entry& entry) { return entry.shader == shader; });
1501     if (pos != cache->end()) {
1502         ShaderCache::Entry& entry = *pos;
1503         entry.refCount--;
1504         if (entry.refCount == 0) {
1505             glDeleteShader(entry.shader);
1506             cache->erase(pos);
1507         }
1508         return;
1509     }
1510 
1511     PLUGIN_ASSERT_MSG(false, "Tried to release a non-existant shader?");
1512 }
1513 
ReleaseProgram(uint32_t program)1514 void DeviceGLES::ReleaseProgram(uint32_t program)
1515 {
1516     PLUGIN_ASSERT_MSG(isActive_, "Device not active when releasing shaders");
1517     for (auto it = programs_.begin(); it != programs_.end(); it++) {
1518         auto& t = *it;
1519         if (t.program != program) {
1520             continue;
1521         }
1522         t.refCount--;
1523         if (t.refCount == 0) {
1524             if (t.fragShader) {
1525                 ReleaseShader(GL_FRAGMENT_SHADER, t.fragShader);
1526             }
1527             if (t.vertShader) {
1528                 ReleaseShader(GL_VERTEX_SHADER, t.vertShader);
1529             }
1530             if (t.compShader) {
1531                 ReleaseShader(GL_COMPUTE_SHADER, t.compShader);
1532             }
1533             glDeleteProgram(t.program);
1534             programs_.erase(it);
1535         }
1536         return;
1537     }
1538     PLUGIN_ASSERT_MSG(false, "Tried to release a non-existant program?");
1539 }
1540 
CacheShader(int type,const string_view source)1541 const DeviceGLES::ShaderCache::Entry& DeviceGLES::CacheShader(int type, const string_view source)
1542 {
1543     PLUGIN_ASSERT(type < MAX_CACHES);
1544     if (source.empty()) {
1545         static constexpr DeviceGLES::ShaderCache::Entry invalid {};
1546         return invalid;
1547     }
1548     static constexpr GLenum types[] = { GL_VERTEX_SHADER, GL_FRAGMENT_SHADER, GL_COMPUTE_SHADER };
1549     // NOTE: check other hash functions, also i guess verify (strcmp) on collision would be prudent.
1550     const uint64_t hash = FNV1aHash(source.data(), source.size());
1551     PLUGIN_ASSERT(hash != 0);
1552     for (auto& t : shaders_[type].cache) {
1553         if (t.hash == hash) {
1554             shaders_[type].hit++;
1555             t.refCount++;
1556             return t;
1557         }
1558     }
1559     shaders_[type].miss++;
1560     DeviceGLES::ShaderCache::Entry entry;
1561     entry.hash = hash;
1562     entry.shader = glCreateShader(types[type]);
1563     entry.refCount = 1;
1564     const GLint len = static_cast<GLint>(source.length());
1565     const auto data = source.data();
1566     glShaderSource(entry.shader, 1, &data, &len);
1567     glCompileShader(entry.shader);
1568     GLint result = GL_FALSE;
1569     glGetShaderiv(entry.shader, GL_COMPILE_STATUS, &result);
1570     if (result == GL_FALSE) {
1571         GLint logLength = 0;
1572         glGetShaderiv(entry.shader, GL_INFO_LOG_LENGTH, &logLength);
1573         string messages;
1574         messages.resize(static_cast<size_t>(logLength));
1575         glGetShaderInfoLog(entry.shader, logLength, 0, messages.data());
1576         PLUGIN_LOG_F("Shader compilation error: %s", messages.c_str());
1577         glDeleteShader(entry.shader);
1578         entry.shader = 0U;
1579     }
1580     shaders_[type].cache.push_back(entry);
1581     return shaders_[type].cache.back();
1582 }
1583 
CacheProgram(const string_view vertSource,const string_view fragSource,const string_view compSource)1584 uint32_t DeviceGLES::CacheProgram(
1585     const string_view vertSource, const string_view fragSource, const string_view compSource)
1586 {
1587     PLUGIN_ASSERT_MSG(isActive_, "Device not active when building shaders");
1588     const uint64_t vertHash = vertSource.empty() ? 0U : FNV1aHash(vertSource.data(), vertSource.size());
1589     const uint64_t fragHash = fragSource.empty() ? 0U : FNV1aHash(fragSource.data(), fragSource.size());
1590     const uint64_t compHash = compSource.empty() ? 0U : FNV1aHash(compSource.data(), compSource.size());
1591     // Then check if we have the program already cached (ie. matching shaders linked)
1592     for (ProgramCache& t : programs_) {
1593         if ((t.hashVert != vertHash) || (t.hashFrag != fragHash) || (t.hashComp != compHash)) {
1594             continue;
1595         }
1596         pCacheHit_++;
1597         t.refCount++;
1598         return t.program;
1599     }
1600 
1601     // Hash and cache shader sources.
1602     const auto& vEntry = CacheShader(DeviceGLES::VERTEX_CACHE, vertSource);
1603     const auto& fEntry = CacheShader(DeviceGLES::FRAGMENT_CACHE, fragSource);
1604     const auto& cEntry = CacheShader(DeviceGLES::COMPUTE_CACHE, compSource);
1605     // Then check if we have the program already cached (ie. matching shaders linked)
1606     for (ProgramCache& t : programs_) {
1607         if ((t.hashVert != vEntry.hash) || (t.hashFrag != fEntry.hash) || (t.hashComp != cEntry.hash)) {
1608             continue;
1609         }
1610         pCacheHit_++;
1611         t.refCount++;
1612         return t.program;
1613     }
1614     // Create new program
1615     pCacheMiss_++;
1616     const GLuint program = glCreateProgram();
1617     if (supportsBinaryPrograms_) {
1618         glProgramParameteri(program, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
1619     }
1620 #if defined(CORE_USE_SEPARATE_SHADER_OBJECTS) && (CORE_USE_SEPARATE_SHADER_OBJECTS == 1)
1621     // enable separable programs.
1622     glProgramParameteri(program, GL_PROGRAM_SEPARABLE, GL_TRUE);
1623 #endif
1624     // Attach and link
1625     if (vEntry.shader) {
1626         glAttachShader(program, vEntry.shader);
1627     }
1628     if (fEntry.shader) {
1629         glAttachShader(program, fEntry.shader);
1630     }
1631     if (cEntry.shader) {
1632         glAttachShader(program, cEntry.shader);
1633     }
1634     glLinkProgram(program);
1635     if (vEntry.shader) {
1636         glDetachShader(program, vEntry.shader);
1637     }
1638     if (fEntry.shader) {
1639         glDetachShader(program, fEntry.shader);
1640     }
1641     if (cEntry.shader) {
1642         glDetachShader(program, cEntry.shader);
1643     }
1644     GLint result = GL_FALSE;
1645     glGetProgramiv(program, GL_LINK_STATUS, &result);
1646     if (result == GL_FALSE) {
1647 #if (RENDER_VALIDATION_ENABLED == 1)
1648         GLint logLength = 0;
1649         glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);
1650         string messages;
1651         messages.resize(static_cast<size_t>(logLength));
1652         glGetProgramInfoLog(program, logLength, 0, messages.data());
1653         PLUGIN_LOG_ONCE_E("gl_shader_linking_error_" + to_string(program),
1654             "RENDER_VALIDATION: Shader linking error: %s", messages.c_str());
1655 #endif
1656         glDeleteProgram(program);
1657         return 0U;
1658     }
1659     // Add the program to cache
1660     programs_.push_back(
1661         { program, vEntry.shader, fEntry.shader, cEntry.shader, vEntry.hash, fEntry.hash, cEntry.hash, 1 });
1662     return program;
1663 }
1664 
UseProgram(uint32_t program)1665 void DeviceGLES::UseProgram(uint32_t program)
1666 {
1667     if (boundProgram_ != program) {
1668         boundProgram_ = program;
1669         glUseProgram(static_cast<GLuint>(program));
1670     }
1671 }
1672 
BindBuffer(uint32_t target,uint32_t buffer)1673 void DeviceGLES::BindBuffer(uint32_t target, uint32_t buffer)
1674 {
1675     const uint32_t targetId = GenericTargetToTargetId(target);
1676     if (targetId >= MAX_BUFFER_TARGET_ID) {
1677         return;
1678     }
1679     auto& state = bufferBound_[targetId];
1680     if ((!state.bound) || (state.buffer != buffer)) {
1681         state.bound = true;
1682         state.buffer = buffer;
1683         glBindBuffer(target, static_cast<GLuint>(buffer));
1684     }
1685 }
1686 
BindBufferRange(uint32_t target,uint32_t binding,uint32_t buffer,uint64_t offset,uint64_t size)1687 void DeviceGLES::BindBufferRange(uint32_t target, uint32_t binding, uint32_t buffer, uint64_t offset, uint64_t size)
1688 {
1689     const uint32_t targetId = IndexedTargetToTargetId(target);
1690     if (targetId >= MAX_BUFFER_BIND_ID || binding >= MAX_BINDING_VALUE) {
1691         return;
1692     }
1693     auto& slot = boundBuffers_[targetId][binding];
1694 
1695     if ((slot.cached == false) || (slot.buffer != buffer) || (slot.offset != offset) || (slot.size != size)) {
1696         slot.cached = true;
1697         slot.buffer = buffer;
1698         slot.offset = offset;
1699         slot.size = size;
1700         glBindBufferRange(target, binding, buffer, static_cast<GLintptr>(offset), static_cast<GLsizeiptr>(size));
1701         // BindBufferRange sets the "generic" binding too. so make sure cache state is correct.
1702         const uint32_t targetId2 = GenericTargetToTargetId(target);
1703         auto& state = bufferBound_[targetId2];
1704         state.bound = true;
1705         state.buffer = buffer;
1706     }
1707     // NOTE: we are not forcing the generic bind point here. use BindBuffer to set the generic one if needed!
1708 }
1709 
BindSampler(uint32_t textureUnit,uint32_t sampler)1710 void DeviceGLES::BindSampler(uint32_t textureUnit, uint32_t sampler)
1711 {
1712     if ((sampler + 1) != boundSampler_[textureUnit]) {
1713         boundSampler_[textureUnit] = sampler + 1;
1714         glBindSampler(textureUnit, sampler);
1715     }
1716 }
1717 
BoundReadFrameBuffer() const1718 uint32_t DeviceGLES::BoundReadFrameBuffer() const
1719 {
1720     return boundReadFbo_;
1721 }
1722 
BoundWriteFrameBuffer() const1723 uint32_t DeviceGLES::BoundWriteFrameBuffer() const
1724 {
1725     return boundWriteFbo_;
1726 }
1727 
BoundProgram() const1728 uint32_t DeviceGLES::BoundProgram() const
1729 {
1730     return boundProgram_;
1731 }
1732 
BoundBuffer(uint32_t target) const1733 uint32_t DeviceGLES::BoundBuffer(uint32_t target) const
1734 {
1735     const uint32_t targetId = GenericTargetToTargetId(target);
1736     if (targetId >= MAX_BUFFER_BIND_ID) {
1737         return 0;
1738     }
1739     const auto& slot = bufferBound_[targetId];
1740     if (!slot.bound) {
1741         return 0;
1742     }
1743     return slot.buffer;
1744 }
1745 
BoundBuffer(uint32_t target,uint32_t binding) const1746 uint32_t DeviceGLES::BoundBuffer(uint32_t target, uint32_t binding) const
1747 {
1748     const uint32_t targetId = IndexedTargetToTargetId(target);
1749     if (targetId >= MAX_BUFFER_BIND_ID || binding >= MAX_BINDING_VALUE) {
1750         return 0;
1751     }
1752     const auto& slot = boundBuffers_[targetId][binding];
1753     if (!slot.cached) {
1754         return 0;
1755     }
1756     return slot.buffer;
1757 }
1758 
BoundSampler(uint32_t textureUnit) const1759 uint32_t DeviceGLES::BoundSampler(uint32_t textureUnit) const
1760 {
1761     if (textureUnit >= MAX_SAMPLERS) {
1762         return 0;
1763     }
1764     const uint32_t bound = boundSampler_[textureUnit];
1765     return bound ? (bound - 1) : bound;
1766 }
1767 
BoundTexture(uint32_t textureUnit,uint32_t target) const1768 uint32_t DeviceGLES::BoundTexture(uint32_t textureUnit, uint32_t target) const
1769 {
1770     const uint32_t targetId = TextureTargetToTargetId(target);
1771     if (textureUnit >= MAX_TEXTURE_UNITS || targetId >= MAX_TEXTURE_TARGET_ID) {
1772         return 0;
1773     }
1774     const uint32_t bound = boundTexture_[textureUnit][targetId];
1775     if (bound == 0) {
1776         return 0; // bound 0 == nothing has been bound via cache yet.
1777     }
1778     return bound - 1;
1779 }
1780 
BindImageTexture(uint32_t unit,uint32_t texture,uint32_t level,bool layered,uint32_t layer,uint32_t access,uint32_t format)1781 void DeviceGLES::BindImageTexture(
1782     uint32_t unit, uint32_t texture, uint32_t level, bool layered, uint32_t layer, uint32_t access, uint32_t format)
1783 {
1784     auto& image = boundImage_[unit];
1785     if ((!image.bound) || (image.texture != texture) || (image.level != level) || (image.layered != layered) ||
1786         (image.access != access) || (image.format != format)) {
1787         image.bound = true;
1788         image.texture = texture;
1789         image.level = level;
1790         image.layered = layered;
1791         image.access = access;
1792         image.format = format;
1793         glBindImageTexture(static_cast<GLuint>(unit), static_cast<GLuint>(texture), static_cast<GLint>(level),
1794             static_cast<GLboolean>(layered), static_cast<GLint>(layer), static_cast<GLenum>(access),
1795             static_cast<GLenum>(format));
1796     }
1797 }
1798 
SetActiveTextureUnit(uint32_t textureUnit)1799 void DeviceGLES::SetActiveTextureUnit(uint32_t textureUnit)
1800 {
1801     if ((textureUnit + 1) != activeTextureUnit_) {
1802         activeTextureUnit_ = textureUnit + 1;
1803         glActiveTexture(GL_TEXTURE0 + textureUnit);
1804     }
1805 }
1806 
BindTexture(uint32_t textureUnit,uint32_t target,uint32_t texture)1807 void DeviceGLES::BindTexture(uint32_t textureUnit, uint32_t target, uint32_t texture)
1808 {
1809     const uint32_t targetId = TextureTargetToTargetId(target);
1810     if (textureUnit >= MAX_TEXTURE_UNITS || targetId >= MAX_TEXTURE_TARGET_ID) {
1811         return;
1812     }
1813 #if RENDER_HAS_GLES_BACKEND
1814     if (target == GL_TEXTURE_EXTERNAL_OES) {
1815         // Work around for oes textures needing a bind to zero to update.
1816         SetActiveTextureUnit(textureUnit);
1817         glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
1818         boundTexture_[textureUnit][targetId] = 0;
1819         // Force the default sampler for OES textures.
1820         BindSampler(textureUnit, 0);
1821     }
1822 #endif
1823     if ((texture + 1) != boundTexture_[textureUnit][targetId]) {
1824         SetActiveTextureUnit(textureUnit);
1825         boundTexture_[textureUnit][targetId] = texture + 1;
1826         // remap the cubemap layer ids...
1827         switch (target) {
1828             case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1829             case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1830             case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1831             case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1832             case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1833             case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1834                 glBindTexture(GL_TEXTURE_CUBE_MAP, texture);
1835                 break;
1836             default:
1837                 glBindTexture(target, texture);
1838                 break;
1839         }
1840     }
1841 }
1842 
TexSwizzle(uint32_t image,uint32_t target,const Math::UVec4 & swizzle)1843 void DeviceGLES::TexSwizzle(uint32_t image, uint32_t target, const Math::UVec4& swizzle)
1844 {
1845     // set only if not default..
1846     if ((swizzle.x != GL_RED) || (swizzle.y != GL_GREEN) || (swizzle.z != GL_BLUE) || (swizzle.w != GL_ALPHA)) {
1847         SetActiveTextureUnit(TEMP_BIND_UNIT);
1848         BindTexture(TEMP_BIND_UNIT, target, image);
1849         glTexParameteri(static_cast<GLenum>(target), GL_TEXTURE_SWIZZLE_R, static_cast<GLint>(swizzle.x));
1850         glTexParameteri(static_cast<GLenum>(target), GL_TEXTURE_SWIZZLE_G, static_cast<GLint>(swizzle.y));
1851         glTexParameteri(static_cast<GLenum>(target), GL_TEXTURE_SWIZZLE_B, static_cast<GLint>(swizzle.z));
1852         glTexParameteri(static_cast<GLenum>(target), GL_TEXTURE_SWIZZLE_A, static_cast<GLint>(swizzle.w));
1853     }
1854 }
1855 
TexStorage2D(uint32_t image,uint32_t target,uint32_t levels,uint32_t internalformat,const Math::UVec2 & extent)1856 void DeviceGLES::TexStorage2D(
1857     uint32_t image, uint32_t target, uint32_t levels, uint32_t internalformat, const Math::UVec2& extent)
1858 {
1859     SetActiveTextureUnit(TEMP_BIND_UNIT);
1860     BindTexture(TEMP_BIND_UNIT, target, image);
1861     glTexStorage2D(static_cast<GLenum>(target), static_cast<GLsizei>(levels), static_cast<GLenum>(internalformat),
1862         static_cast<GLsizei>(extent.x), static_cast<GLsizei>(extent.y));
1863 }
1864 
TexStorage2DMultisample(uint32_t image,uint32_t target,uint32_t samples,uint32_t internalformat,const Math::UVec2 & extent,bool fixedsamplelocations)1865 void DeviceGLES::TexStorage2DMultisample(uint32_t image, uint32_t target, uint32_t samples, uint32_t internalformat,
1866     const Math::UVec2& extent, bool fixedsamplelocations)
1867 {
1868     SetActiveTextureUnit(TEMP_BIND_UNIT);
1869     BindTexture(TEMP_BIND_UNIT, target, image);
1870     glTexStorage2DMultisample(static_cast<GLenum>(target), static_cast<GLsizei>(samples),
1871         static_cast<GLenum>(internalformat), static_cast<GLsizei>(extent.x), static_cast<GLsizei>(extent.y),
1872         fixedsamplelocations);
1873 }
1874 
TexStorage3D(uint32_t image,uint32_t target,uint32_t levels,uint32_t internalformat,const Math::UVec3 & extent)1875 void DeviceGLES::TexStorage3D(
1876     uint32_t image, uint32_t target, uint32_t levels, uint32_t internalformat, const Math::UVec3& extent)
1877 {
1878     SetActiveTextureUnit(TEMP_BIND_UNIT);
1879     BindTexture(TEMP_BIND_UNIT, target, image);
1880     glTexStorage3D((GLenum)target, (GLsizei)levels, (GLenum)internalformat, (GLsizei)extent.x, (GLsizei)extent.y,
1881         (GLsizei)extent.z);
1882 }
1883 
TexStorage3DMultisample(uint32_t image,uint32_t target,uint32_t samples,uint32_t internalformat,const BASE_NS::Math::UVec3 & extent,bool fixedsamplelocations)1884 void DeviceGLES::TexStorage3DMultisample(uint32_t image, uint32_t target, uint32_t samples, uint32_t internalformat,
1885     const BASE_NS::Math::UVec3& extent, bool fixedsamplelocations)
1886 {
1887     SetActiveTextureUnit(TEMP_BIND_UNIT);
1888     BindTexture(TEMP_BIND_UNIT, target, image);
1889     glTexStorage3DMultisample(static_cast<GLenum>(target), static_cast<GLsizei>(samples),
1890         static_cast<GLenum>(internalformat), static_cast<GLsizei>(extent.x), static_cast<GLsizei>(extent.y),
1891         static_cast<GLsizei>(extent.z), fixedsamplelocations);
1892 }
1893 
TexSubImage2D(uint32_t image,uint32_t target,uint32_t level,const Math::UVec2 & offset,const Math::UVec2 & extent,uint32_t format,uint32_t type,const void * pixels)1894 void DeviceGLES::TexSubImage2D(uint32_t image, uint32_t target, uint32_t level, const Math::UVec2& offset,
1895     const Math::UVec2& extent, uint32_t format, uint32_t type, const void* pixels)
1896 {
1897     SetActiveTextureUnit(TEMP_BIND_UNIT);
1898     BindTexture(TEMP_BIND_UNIT, target, image);
1899     glTexSubImage2D((GLenum)target, (GLint)level, (GLint)offset.x, (GLint)offset.y, (GLsizei)extent.x,
1900         (GLsizei)extent.y, (GLenum)format, (GLenum)type, pixels);
1901 }
1902 
TexSubImage3D(uint32_t image,uint32_t target,uint32_t level,const Math::UVec3 & offset,const Math::UVec3 & extent,uint32_t format,uint32_t type,const void * pixels)1903 void DeviceGLES::TexSubImage3D(uint32_t image, uint32_t target, uint32_t level, const Math::UVec3& offset,
1904     const Math::UVec3& extent, uint32_t format, uint32_t type, const void* pixels)
1905 {
1906     SetActiveTextureUnit(TEMP_BIND_UNIT);
1907     BindTexture(TEMP_BIND_UNIT, target, image);
1908     glTexSubImage3D((GLenum)target, (GLint)level, (GLint)offset.x, (GLint)offset.y, (GLint)offset.z, (GLsizei)extent.x,
1909         (GLsizei)extent.y, (GLsizei)extent.z, (GLenum)format, (GLenum)type, pixels);
1910 }
1911 
CompressedTexSubImage2D(uint32_t image,uint32_t target,uint32_t level,const Math::UVec2 & offset,const Math::UVec2 & extent,uint32_t format,uint32_t imageSize,const void * data)1912 void DeviceGLES::CompressedTexSubImage2D(uint32_t image, uint32_t target, uint32_t level, const Math::UVec2& offset,
1913     const Math::UVec2& extent, uint32_t format, uint32_t imageSize, const void* data)
1914 {
1915     SetActiveTextureUnit(TEMP_BIND_UNIT);
1916     BindTexture(TEMP_BIND_UNIT, target, image);
1917     glCompressedTexSubImage2D((GLenum)target, (GLint)level, (GLint)offset.x, (GLint)offset.y, (GLsizei)extent.x,
1918         (GLsizei)extent.y, (GLenum)format, (GLint)imageSize, data);
1919 }
1920 
CompressedTexSubImage3D(uint32_t image,uint32_t target,uint32_t level,const Math::UVec3 & offset,const Math::UVec3 & extent,uint32_t format,uint32_t imageSize,const void * data)1921 void DeviceGLES::CompressedTexSubImage3D(uint32_t image, uint32_t target, uint32_t level, const Math::UVec3& offset,
1922     const Math::UVec3& extent, uint32_t format, uint32_t imageSize, const void* data)
1923 {
1924     SetActiveTextureUnit(TEMP_BIND_UNIT);
1925     BindTexture(TEMP_BIND_UNIT, target, image);
1926     glCompressedTexSubImage3D((GLenum)target, (GLint)level, (GLint)offset.x, (GLint)offset.y, (GLint)offset.z,
1927         (GLsizei)extent.x, (GLsizei)extent.y, (GLsizei)extent.z, (GLenum)format, (GLint)imageSize, data);
1928 }
1929 
GetGlImageFormat(const Format format) const1930 const DeviceGLES::ImageFormat& DeviceGLES::GetGlImageFormat(const Format format) const
1931 {
1932     if (const auto pos = std::lower_bound(supportedFormats_.begin(), supportedFormats_.end(), format,
1933         [](const ImageFormat& element, const Format value) { return element.coreFormat < value; });
1934         (pos != supportedFormats_.end()) && (pos->coreFormat == format)) {
1935         return *pos;
1936     }
1937     if (const auto pos = std::lower_bound(std::begin(IMAGE_FORMATS_FALLBACK), std::end(IMAGE_FORMATS_FALLBACK), format,
1938         [](const ImageFormat& element, const Format value) { return element.coreFormat < value; });
1939         (pos != std::end(IMAGE_FORMATS_FALLBACK)) && (pos->coreFormat == format)) {
1940         PLUGIN_LOG_I("using fallback for format %u", format);
1941         return *pos;
1942     }
1943     PLUGIN_LOG_I("asking for unsupported format %u", format);
1944     return supportedFormats_[0];
1945 }
1946 
DeleteTexture(uint32_t texture)1947 void DeviceGLES::DeleteTexture(uint32_t texture)
1948 {
1949     UnBindTexture(texture);
1950     glDeleteTextures(1, &texture);
1951 }
1952 
DeleteBuffer(uint32_t buffer)1953 void DeviceGLES::DeleteBuffer(uint32_t buffer)
1954 {
1955     UnBindBuffer(buffer);
1956     glDeleteBuffers(1, &buffer);
1957 }
1958 
DeleteSampler(uint32_t sampler)1959 void DeviceGLES::DeleteSampler(uint32_t sampler)
1960 {
1961     UnBindSampler(sampler);
1962     glDeleteSamplers(1, &sampler);
1963 }
1964 
CreateVertexArray()1965 uint32_t DeviceGLES::CreateVertexArray()
1966 {
1967     GLuint vao;
1968     glGenVertexArrays(1, &vao);
1969     if (vaoStatesInUse_ == vaoStates_.size()) {
1970         for (auto it = vaoStates_.begin(); it != vaoStates_.end(); it++) {
1971             if (it->vao == 0) {
1972                 // re-use old "object"
1973                 it->vao = vao;
1974                 vaoStatesInUse_++;
1975                 return static_cast<uint32_t>(1 + (it - vaoStates_.begin()));
1976             }
1977         }
1978     }
1979     VAOState v;
1980     v.vao = vao;
1981     vaoStates_.push_back(v);
1982     vaoStatesInUse_++;
1983     return static_cast<uint32_t>(vaoStates_.size());
1984 }
1985 
DeleteVertexArray(uint32_t vao)1986 void DeviceGLES::DeleteVertexArray(uint32_t vao)
1987 {
1988     PLUGIN_ASSERT(!vaoStates_.empty());
1989     if (vao > 0 && vao < vaoStates_.size()) {
1990         UnBindVertexArray(vao);
1991         auto& state = vaoStates_[vao - 1];
1992         glDeleteVertexArrays(1, &state.vao);
1993         state = {}; // clear the object.
1994         vaoStatesInUse_--;
1995     }
1996 }
1997 
DeleteFrameBuffer(uint32_t fbo)1998 void DeviceGLES::DeleteFrameBuffer(uint32_t fbo)
1999 {
2000     PLUGIN_ASSERT(IsActive());
2001     UnBindFrameBuffer(fbo);
2002     glDeleteFramebuffers(1, &fbo);
2003 #if (RENDER_DEBUG_GPU_RESOURCE_IDS == 1)
2004     PLUGIN_LOG_D("fbo id <: %u", fbo);
2005 #endif
2006 }
2007 
UnBindTexture(uint32_t texture)2008 void DeviceGLES::UnBindTexture(uint32_t texture)
2009 {
2010     uint32_t unit = 0;
2011     for (auto& textureUnit : boundTexture_) {
2012         uint32_t targetId = 0;
2013         for (uint32_t& typeBinding : textureUnit) {
2014             if (typeBinding == texture + 1) {
2015                 SetActiveTextureUnit(unit);
2016                 const uint32_t target = TextureTargetIdToTarget(TextureTargetId { targetId });
2017                 glBindTexture(target, 0);
2018                 typeBinding = 0;
2019             }
2020             targetId++;
2021         }
2022         unit++;
2023     }
2024 
2025     unit = 0;
2026     for (auto& image : boundImage_) {
2027         if ((image.bound) && (image.texture == texture)) {
2028             glBindImageTexture(static_cast<GLuint>(unit), 0, 0, false, 0, GL_READ_ONLY, GL_R32UI);
2029             // set default state...
2030             image.bound = false;
2031             image.texture = 0;
2032             image.level = 0;
2033             image.layered = false;
2034             image.access = GL_READ_ONLY;
2035             image.format = GL_R32UI;
2036         }
2037         unit++;
2038     }
2039 }
2040 
UnBindBuffer(uint32_t buffer)2041 void DeviceGLES::UnBindBuffer(uint32_t buffer)
2042 {
2043     uint32_t tid = 0;
2044     for (auto& buffers : boundBuffers_) {
2045         const uint32_t targetId = IndexedTargetIdToTarget(BufferBindId { tid });
2046         uint32_t bid = 0;
2047         for (auto& slot : buffers) {
2048             if (slot.buffer == buffer) {
2049                 glBindBufferRange(targetId, bid, 0, 0, 0);
2050                 // nothing bound
2051                 slot.cached = false;
2052                 slot.buffer = 0;
2053                 slot.offset = 0;
2054                 slot.size = 0;
2055             }
2056             bid++;
2057         }
2058         tid++;
2059     }
2060 
2061     tid = 0;
2062     for (auto& slot : bufferBound_) {
2063         if (slot.buffer == buffer) {
2064             const uint32_t targetId = GenericTargetIdToTarget(BufferTargetId { tid });
2065             glBindBuffer(targetId, 0);
2066             // nothing bound
2067             slot.bound = false;
2068             slot.buffer = 0;
2069         }
2070         tid++;
2071     }
2072 
2073     // scan VAOs also..
2074     UnBindBufferFromVertexArray(buffer);
2075 }
2076 
UnBindBufferFromVertexArray(uint32_t buffer)2077 void DeviceGLES::UnBindBufferFromVertexArray(uint32_t buffer)
2078 {
2079     uint32_t vao = 1;
2080     uint32_t wasbound = BoundVertexArray();
2081     for (auto& state : vaoStates_) {
2082         if (state.vao > 0) {
2083             auto& elementBuffer = state.elementBuffer;
2084             auto& vertexBufferBinds = state.vertexBufferBinds;
2085             int slot = 0;
2086             for (auto& t : vertexBufferBinds) {
2087                 if ((t.bound) && (t.buffer == buffer)) {
2088                     // detach the buffer from vao.
2089                     BindVertexArray(vao);
2090                     glBindVertexBuffer((GLuint)slot, 0, 0, 0);
2091                     t.bound = false;
2092                     t.buffer = 0;
2093                     t.offset = 0;
2094                     t.stride = 0;
2095                 }
2096                 slot++;
2097             }
2098             if ((elementBuffer.bound) && (elementBuffer.buffer == buffer)) {
2099                 // detach the buffer from vao.
2100                 BindVertexArray(vao);
2101                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
2102                 elementBuffer.bound = false;
2103                 elementBuffer.buffer = 0;
2104             }
2105         }
2106         vao++;
2107     }
2108     BindVertexArray(wasbound);
2109 }
2110 
UnBindSampler(uint32_t sampler)2111 void DeviceGLES::UnBindSampler(uint32_t sampler)
2112 {
2113     for (uint32_t& boundSampler : boundSampler_) {
2114         if ((sampler + 1) == boundSampler) {
2115             glBindSampler((sampler + 1), 0);
2116             boundSampler = 0;
2117         }
2118     }
2119 }
2120 
UnBindVertexArray(uint32_t vao)2121 void DeviceGLES::UnBindVertexArray(uint32_t vao)
2122 {
2123     if (boundVao_ == vao) {
2124         glBindVertexArray(0);
2125         boundVao_ = 0;
2126     }
2127 }
2128 
UnBindFrameBuffer(uint32_t fbo)2129 void DeviceGLES::UnBindFrameBuffer(uint32_t fbo)
2130 {
2131     if ((fbo == boundReadFbo_) && (fbo == boundWriteFbo_)) {
2132         boundReadFbo_ = 0;
2133         boundWriteFbo_ = 0;
2134         glBindFramebuffer(GL_FRAMEBUFFER, 0);
2135     } else if (boundWriteFbo_ == fbo) {
2136         boundWriteFbo_ = 0;
2137         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
2138     } else if (boundReadFbo_ == fbo) {
2139         boundReadFbo_ = 0;
2140         glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
2141     }
2142 }
2143 
BoundVertexArray() const2144 uint32_t DeviceGLES::BoundVertexArray() const
2145 {
2146     return boundVao_;
2147 }
2148 
BindFrameBuffer(uint32_t fbo)2149 void DeviceGLES::BindFrameBuffer(uint32_t fbo)
2150 {
2151     if ((boundReadFbo_ != fbo) && (boundWriteFbo_ != fbo)) {
2152         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
2153         boundReadFbo_ = boundWriteFbo_ = fbo;
2154     } else if (boundWriteFbo_ != fbo) {
2155         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
2156         boundWriteFbo_ = fbo;
2157     } else if (boundReadFbo_ != fbo) {
2158         glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
2159         boundReadFbo_ = fbo;
2160     }
2161 }
2162 
BindReadFrameBuffer(uint32_t fbo)2163 void DeviceGLES::BindReadFrameBuffer(uint32_t fbo)
2164 {
2165     if (boundReadFbo_ != fbo) {
2166         glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
2167         boundReadFbo_ = fbo;
2168     }
2169 }
2170 
BindWriteFrameBuffer(uint32_t fbo)2171 void DeviceGLES::BindWriteFrameBuffer(uint32_t fbo)
2172 {
2173     if (boundWriteFbo_ != fbo) {
2174         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
2175         boundWriteFbo_ = fbo;
2176     }
2177 }
2178 
BindVertexArray(uint32_t vao)2179 void DeviceGLES::BindVertexArray(uint32_t vao)
2180 {
2181     if (boundVao_ != vao) {
2182         PLUGIN_ASSERT(vao <= vaoStates_.size());
2183         if (vao > 0) {
2184             glBindVertexArray(vaoStates_[vao - 1].vao);
2185         } else {
2186             glBindVertexArray(0);
2187         }
2188         boundVao_ = vao;
2189     }
2190 }
2191 
BindVertexBuffer(uint32_t slot,uint32_t buffer,intptr_t offset,intptr_t stride)2192 void DeviceGLES::BindVertexBuffer(uint32_t slot, uint32_t buffer, intptr_t offset, intptr_t stride)
2193 {
2194     PLUGIN_ASSERT(boundVao_ > 0);
2195     PLUGIN_ASSERT(boundVao_ <= vaoStates_.size());
2196     auto& vertexBufferBinds = vaoStates_[boundVao_ - 1].vertexBufferBinds;
2197     bool bind = true;
2198     if (vertexBufferBinds[slot].bound) {
2199         bind = (vertexBufferBinds[slot].buffer != buffer) || (vertexBufferBinds[slot].offset != offset) ||
2200                (vertexBufferBinds[slot].stride != stride);
2201     }
2202     if (bind) {
2203         vertexBufferBinds[slot].bound = true;
2204         vertexBufferBinds[slot].buffer = buffer;
2205         vertexBufferBinds[slot].offset = offset;
2206         vertexBufferBinds[slot].stride = stride;
2207         glBindVertexBuffer((GLuint)slot, (GLuint)buffer, (GLintptr)offset, (GLsizei)stride);
2208     }
2209 }
2210 
VertexBindingDivisor(uint32_t slot,uint32_t divisor)2211 void DeviceGLES::VertexBindingDivisor(uint32_t slot, uint32_t divisor)
2212 {
2213     PLUGIN_ASSERT(boundVao_ > 0);
2214     PLUGIN_ASSERT(boundVao_ <= vaoStates_.size());
2215     auto& vertexBufferBinds = vaoStates_[boundVao_ - 1].vertexBufferBinds;
2216     if (vertexBufferBinds[slot].divisor != divisor) {
2217         vertexBufferBinds[slot].divisor = divisor;
2218         glVertexBindingDivisor(slot, divisor);
2219     }
2220 }
2221 
BindElementBuffer(uint32_t buffer)2222 void DeviceGLES::BindElementBuffer(uint32_t buffer)
2223 {
2224     PLUGIN_ASSERT(boundVao_ > 0);
2225     PLUGIN_ASSERT(boundVao_ <= vaoStates_.size());
2226     auto& elementBuffer = vaoStates_[boundVao_ - 1].elementBuffer;
2227     bool bind = true;
2228     if (elementBuffer.bound) {
2229         bind = (buffer != elementBuffer.buffer);
2230     }
2231     if (bind) {
2232         elementBuffer.bound = true;
2233         elementBuffer.buffer = buffer;
2234         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
2235     }
2236 }
2237 
AllowThreadedProcessing() const2238 bool DeviceGLES::AllowThreadedProcessing() const
2239 {
2240     return HasExtension(EXT_BUFFER_STORAGE);
2241 }
2242 
CreateGpuBuffer(const GpuBufferDesc & desc)2243 unique_ptr<GpuBuffer> DeviceGLES::CreateGpuBuffer(const GpuBufferDesc& desc)
2244 {
2245     return make_unique<GpuBufferGLES>(*this, desc);
2246 }
2247 
CreateGpuBuffer(const GpuAccelerationStructureDesc & desc)2248 unique_ptr<GpuBuffer> DeviceGLES::CreateGpuBuffer(const GpuAccelerationStructureDesc& desc)
2249 {
2250     return make_unique<GpuBufferGLES>(*this, desc.bufferDesc);
2251 }
2252 
CreateGpuImage(const GpuImageDesc & desc)2253 unique_ptr<GpuImage> DeviceGLES::CreateGpuImage(const GpuImageDesc& desc)
2254 {
2255     return make_unique<GpuImageGLES>(*this, desc);
2256 }
2257 
CreateGpuImageView(const GpuImageDesc & desc,const GpuImagePlatformData & platformData)2258 unique_ptr<GpuImage> DeviceGLES::CreateGpuImageView(const GpuImageDesc& desc, const GpuImagePlatformData& platformData)
2259 {
2260     PLUGIN_ASSERT(IsActive());
2261     return make_unique<GpuImageGLES>(*this, desc, platformData);
2262 }
2263 
CreateGpuImageViews(const Swapchain & platformSwapchain)2264 vector<unique_ptr<GpuImage>> DeviceGLES::CreateGpuImageViews(const Swapchain& platformSwapchain)
2265 {
2266     vector<unique_ptr<GpuImage>> gpuImages;
2267     const SwapchainGLES& swapchain = static_cast<const SwapchainGLES&>(platformSwapchain);
2268     const GpuImageDesc& desc = swapchain.GetDesc();
2269     const auto& swapchainPlat = swapchain.GetPlatformData();
2270 
2271     gpuImages.resize(swapchainPlat.swapchainImages.images.size());
2272 
2273     PLUGIN_ASSERT(IsActive());
2274     for (size_t idx = 0; idx < gpuImages.size(); ++idx) {
2275         GpuImagePlatformDataGL gpuImagePlat {};
2276         gpuImagePlat.image = swapchainPlat.swapchainImages.images[idx];
2277         gpuImagePlat.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA };
2278         gpuImages[idx] = CreateGpuImageView(desc, gpuImagePlat);
2279     }
2280     return gpuImages;
2281 }
2282 
CreateGpuSampler(const GpuSamplerDesc & desc)2283 unique_ptr<GpuSampler> DeviceGLES::CreateGpuSampler(const GpuSamplerDesc& desc)
2284 {
2285     return make_unique<GpuSamplerGLES>(*this, desc);
2286 }
2287 
CreateRenderFrameSync()2288 unique_ptr<RenderFrameSync> DeviceGLES::CreateRenderFrameSync()
2289 {
2290     return make_unique<RenderFrameSyncGLES>(*this);
2291 }
2292 
CreateRenderBackend(GpuResourceManager & gpuResourceMgr,CORE_NS::ITaskQueue * const)2293 unique_ptr<RenderBackend> DeviceGLES::CreateRenderBackend(
2294     GpuResourceManager& gpuResourceMgr, CORE_NS::ITaskQueue* const)
2295 {
2296     return make_unique<RenderBackendGLES>(*this, gpuResourceMgr);
2297 }
2298 
CreateShaderModule(const ShaderModuleCreateInfo & data)2299 unique_ptr<ShaderModule> DeviceGLES::CreateShaderModule(const ShaderModuleCreateInfo& data)
2300 {
2301     return make_unique<ShaderModuleGLES>(*this, data);
2302 }
2303 
CreateComputeShaderModule(const ShaderModuleCreateInfo & data)2304 unique_ptr<ShaderModule> DeviceGLES::CreateComputeShaderModule(const ShaderModuleCreateInfo& data)
2305 {
2306     return make_unique<ShaderModuleGLES>(*this, data);
2307 }
2308 
CreateGpuShaderProgram(const GpuShaderProgramCreateData & data)2309 unique_ptr<GpuShaderProgram> DeviceGLES::CreateGpuShaderProgram(const GpuShaderProgramCreateData& data)
2310 {
2311     return make_unique<GpuShaderProgramGLES>(*this, data);
2312 }
2313 
CreateGpuComputeProgram(const GpuComputeProgramCreateData & data)2314 unique_ptr<GpuComputeProgram> DeviceGLES::CreateGpuComputeProgram(const GpuComputeProgramCreateData& data)
2315 {
2316     return make_unique<GpuComputeProgramGLES>(*this, data);
2317 }
2318 
CreateNodeContextDescriptorSetManager()2319 unique_ptr<NodeContextDescriptorSetManager> DeviceGLES::CreateNodeContextDescriptorSetManager()
2320 {
2321     return make_unique<NodeContextDescriptorSetManagerGles>(*this);
2322 }
2323 
CreateNodeContextPoolManager(GpuResourceManager & gpuResourceMgr,const GpuQueue & gpuQueue)2324 unique_ptr<NodeContextPoolManager> DeviceGLES::CreateNodeContextPoolManager(
2325     GpuResourceManager& gpuResourceMgr, const GpuQueue& gpuQueue)
2326 {
2327     return make_unique<NodeContextPoolManagerGLES>(*this, gpuResourceMgr);
2328 }
2329 
CreateGraphicsPipelineStateObject(const GpuShaderProgram & gpuProgram,const GraphicsState & graphicsState,const PipelineLayout & pipelineLayout,const VertexInputDeclarationView & vertexInputDeclaration,const ShaderSpecializationConstantDataView & specializationConstants,const array_view<const DynamicStateEnum> dynamicStates,const RenderPassDesc & renderPassDesc,const array_view<const RenderPassSubpassDesc> & renderPassSubpassDescs,const uint32_t subpassIndex,const LowLevelRenderPassData * renderPassData,const LowLevelPipelineLayoutData * pipelineLayoutData)2330 unique_ptr<GraphicsPipelineStateObject> DeviceGLES::CreateGraphicsPipelineStateObject(
2331     const GpuShaderProgram& gpuProgram, const GraphicsState& graphicsState, const PipelineLayout& pipelineLayout,
2332     const VertexInputDeclarationView& vertexInputDeclaration,
2333     const ShaderSpecializationConstantDataView& specializationConstants,
2334     const array_view<const DynamicStateEnum> dynamicStates, const RenderPassDesc& renderPassDesc,
2335     const array_view<const RenderPassSubpassDesc>& renderPassSubpassDescs, const uint32_t subpassIndex,
2336     const LowLevelRenderPassData* renderPassData, const LowLevelPipelineLayoutData* pipelineLayoutData)
2337 {
2338     PLUGIN_ASSERT(!renderPassData);
2339     PLUGIN_ASSERT(!pipelineLayoutData);
2340     auto pipeline = make_unique<GraphicsPipelineStateObjectGLES>(*this, gpuProgram, graphicsState, pipelineLayout,
2341         vertexInputDeclaration, specializationConstants, dynamicStates, renderPassDesc, renderPassSubpassDescs);
2342     return unique_ptr<GraphicsPipelineStateObject> { pipeline->GetPlatformData().graphicsShader ? pipeline.release()
2343                                                                                                 : nullptr };
2344 }
2345 
CreateComputePipelineStateObject(const GpuComputeProgram & gpuProgram,const PipelineLayout & pipelineLayout,const ShaderSpecializationConstantDataView & specializationConstants,const LowLevelPipelineLayoutData * pipelineLayoutData)2346 unique_ptr<ComputePipelineStateObject> DeviceGLES::CreateComputePipelineStateObject(const GpuComputeProgram& gpuProgram,
2347     const PipelineLayout& pipelineLayout, const ShaderSpecializationConstantDataView& specializationConstants,
2348     const LowLevelPipelineLayoutData* pipelineLayoutData)
2349 {
2350     PLUGIN_ASSERT(!pipelineLayoutData);
2351     auto pipeline =
2352         make_unique<ComputePipelineStateObjectGLES>(*this, gpuProgram, pipelineLayout, specializationConstants);
2353     return unique_ptr<ComputePipelineStateObject> { pipeline->GetPlatformData().computeShader ? pipeline.release()
2354                                                                                               : nullptr };
2355 }
2356 
CreateGpuSemaphore()2357 unique_ptr<GpuSemaphore> DeviceGLES::CreateGpuSemaphore()
2358 {
2359     return make_unique<GpuSemaphoreGles>(*this);
2360 }
2361 
CreateGpuSemaphoreView(const uint64_t handle)2362 unique_ptr<GpuSemaphore> DeviceGLES::CreateGpuSemaphoreView(const uint64_t handle)
2363 {
2364     return make_unique<GpuSemaphoreGles>(*this, handle);
2365 }
2366 
SetBackendConfig(const BackendConfig & config)2367 void DeviceGLES::SetBackendConfig(const BackendConfig& config)
2368 {
2369 #if RENDER_HAS_GLES_BACKEND
2370     backendConfig_.allowDepthResolve = static_cast<const BackendConfigGLES&>(config).allowDepthResolve &&
2371                                        HasExtension("GL_EXT_multisampled_render_to_texture2");
2372 #endif
2373 }
2374 
LowLevelDeviceGLES(DeviceGLES & deviceGLES)2375 LowLevelDeviceGLES::LowLevelDeviceGLES(DeviceGLES& deviceGLES)
2376     : deviceGLES_(deviceGLES), gpuResourceMgr_(static_cast<GpuResourceManager&>(deviceGLES.GetGpuResourceManager()))
2377 {}
2378 
GetBackendType() const2379 DeviceBackendType LowLevelDeviceGLES::GetBackendType() const
2380 {
2381     return deviceGLES_.GetBackendType();
2382 }
2383 
2384 #if RENDER_HAS_EXPERIMENTAL
Activate()2385 void LowLevelDeviceGLES::Activate()
2386 {
2387     deviceGLES_.Activate();
2388 }
2389 
Deactivate()2390 void LowLevelDeviceGLES::Deactivate()
2391 {
2392     deviceGLES_.Deactivate();
2393 }
2394 
SwapBuffers()2395 void LowLevelDeviceGLES::SwapBuffers()
2396 {
2397     if (deviceGLES_.IsActive() && deviceGLES_.HasSwapchain()) {
2398         RenderHandle defaultSwapChain {};
2399         auto sc = static_cast<const SwapchainGLES*>(deviceGLES_.GetSwapchain(defaultSwapChain));
2400         deviceGLES_.SwapBuffers(*sc);
2401     }
2402 }
2403 #endif
2404 
2405 RENDER_END_NAMESPACE()
2406