• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 #include "render_backend_gles.h"
16 
17 #include <algorithm>
18 
19 #include <base/containers/fixed_string.h>
20 #include <core/perf/intf_performance_data_manager.h>
21 #include <render/datastore/render_data_store_render_pods.h> // NodeGraphBackbufferConfiguration...
22 #include <render/namespace.h>
23 
24 #if (RENDER_PERF_ENABLED == 1)
25 #include "perf/gpu_query.h"
26 #include "perf/gpu_query_manager.h"
27 #endif
28 #include "device/gpu_resource_manager.h"
29 #include "gles/device_gles.h"
30 #include "gles/gl_functions.h"
31 #include "gles/gpu_buffer_gles.h"
32 #include "gles/gpu_image_gles.h"
33 #include "gles/gpu_program_gles.h"
34 #include "gles/gpu_query_gles.h"
35 #include "gles/gpu_sampler_gles.h"
36 #include "gles/node_context_descriptor_set_manager_gles.h"
37 #include "gles/node_context_pool_manager_gles.h"
38 #include "gles/pipeline_state_object_gles.h"
39 #include "gles/render_frame_sync_gles.h"
40 #include "gles/swapchain_gles.h"
41 #include "nodecontext/render_command_list.h"
42 #include "nodecontext/render_node_graph_node_store.h" // RenderCommandFrameData
43 #include "util/log.h"
44 
45 #define IS_BIT(value, bit) (((value & bit) == bit) ? true : false)
46 #define IS_BIT_GL(value, bit) (((value & bit) == bit) ? (GLboolean)GL_TRUE : (GLboolean)GL_FALSE)
47 
48 using namespace BASE_NS;
49 
50 // NOTE: implement missing commands, add state caching and cleanup a bit more.
51 RENDER_BEGIN_NAMESPACE()
52 namespace Gles {
53 // Indices to colorBlendConstants
54 static constexpr uint32_t RED_INDEX = 0;
55 static constexpr uint32_t GREEN_INDEX = 1;
56 static constexpr uint32_t BLUE_INDEX = 2;
57 static constexpr uint32_t ALPHA_INDEX = 3;
58 static constexpr uint32_t CUBEMAP_LAYERS = 6;
59 struct Bind {
60     DescriptorType descriptorType { CORE_DESCRIPTOR_TYPE_MAX_ENUM };
61     struct bufferType {
62         uint32_t bufferId;
63         uint32_t offset;
64         uint32_t size;
65     };
66     struct imageType {
67         GpuImageGLES* image;
68         uint32_t mode;
69         uint32_t mipLevel;
70     };
71     struct samplerType {
72         uint32_t samplerId;
73     };
74     struct Resource {
75         union {
76             Bind::bufferType buffer { 0, 0, 0 };
77             Bind::imageType image;
78         };
79         samplerType sampler { 0 };
80     };
81     vector<Resource> resources;
82 };
83 } // namespace Gles
84 namespace {
85 // Enable if needed.
86 #if RENDER_DEBUG_COMMAND_MARKERS_ENABLED
87 static constexpr const string_view COMMAND_NAMES[] = { "Undefined", "Draw", "DrawIndirect", "Dispatch",
88     "DispatchIndirect", "BindPipeline", "BeginRenderPass", "NextSubpass", "EndRenderPass", "BindVertexBuffers",
89     "BindIndexBuffer", "CopyBuffer", "CopyBufferImage", "CopyImage", "BlitImage", "BarrierPoint",
90     "UpdateDescriptorSets", "BindDescriptorSets", "PushConstant", "DynamicStateViewport", "DynamicStateScissor",
91     "DynamicStateLineWidth", "DynamicStateDepthBias", "DynamicStateBlendConstants", "DynamicStateDepthBounds",
92     "DynamicStateStencil", "ExecuteBackendFramePosition", "WriteTimestamp", "GpuQueueTransferRelease",
93     "GpuGueueTransferAcquire" };
94 #endif
95 
GetRenderHandleType(const DescriptorType descriptorType)96 constexpr RenderHandleType GetRenderHandleType(const DescriptorType descriptorType)
97 {
98     if (descriptorType == CORE_DESCRIPTOR_TYPE_SAMPLER) {
99         return RenderHandleType::GPU_SAMPLER;
100     } else if (((descriptorType >= CORE_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) &&
101                    (descriptorType <= CORE_DESCRIPTOR_TYPE_STORAGE_IMAGE)) ||
102                (descriptorType == CORE_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)) {
103         return RenderHandleType::GPU_IMAGE;
104     } else if ((descriptorType >= CORE_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) &&
105                (descriptorType <= CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) {
106         return RenderHandleType::GPU_BUFFER;
107     }
108     return RenderHandleType::UNDEFINED;
109 }
110 
getCubeMapTarget(GLenum type,uint32_t layer)111 GLenum getCubeMapTarget(GLenum type, uint32_t layer)
112 {
113     if (type == GL_TEXTURE_CUBE_MAP) {
114         constexpr GLenum layerId[] = { GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
115             GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
116             GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0 };
117         PLUGIN_ASSERT_MSG(layer < Gles::CUBEMAP_LAYERS, "Invalid cubemap index %u", layer);
118         return layerId[layer];
119     }
120     PLUGIN_ASSERT_MSG(false, "Unhandled type in getTarget! %x", type);
121     return GL_NONE;
122 }
123 
getTarget(GLenum type,uint32_t layer,uint32_t sampleCount)124 GLenum getTarget(GLenum type, uint32_t layer, uint32_t sampleCount)
125 {
126     if (type == GL_TEXTURE_2D) {
127         if (sampleCount > 1) {
128             return GL_TEXTURE_2D_MULTISAMPLE;
129         }
130         return GL_TEXTURE_2D;
131     }
132     if (type == GL_TEXTURE_CUBE_MAP) {
133         PLUGIN_ASSERT_MSG(sampleCount == 1, "Cubemap texture can't have MSAA");
134         return getCubeMapTarget(type, layer);
135     }
136     PLUGIN_ASSERT_MSG(false, "Unhandled type in getTarget! %x", type);
137     return GL_NONE;
138 }
139 struct BlitArgs {
140     uint32_t mipLevel {};
141     Size3D rect0 {};
142     Size3D rect1 {};
143     uint32_t height {};
144 };
145 
DoBlit(const Filter filter,const BlitArgs & src,const BlitArgs & dst)146 void DoBlit(const Filter filter, const BlitArgs& src, const BlitArgs& dst)
147 {
148     // Handle top-left / bottom-left origin conversion
149     GLint sy = static_cast<GLint>(src.rect0.height);
150     const GLint sh = static_cast<const GLint>(src.rect1.height);
151     const GLint sfh = static_cast<GLint>(src.height >> src.mipLevel);
152     sy = sfh - (sy + sh);
153     GLint dy = static_cast<GLint>(dst.rect0.height);
154     const GLint dh = static_cast<const GLint>(dst.rect1.height);
155     const GLint dfh = static_cast<GLint>(dst.height >> dst.mipLevel);
156     dy = dfh - (dy + dh);
157     GLenum glfilter = GL_NEAREST;
158     if (filter == CORE_FILTER_NEAREST) {
159         glfilter = GL_NEAREST;
160     } else if (filter == CORE_FILTER_LINEAR) {
161         glfilter = GL_LINEAR;
162     } else {
163         PLUGIN_ASSERT_MSG(false, "RenderCommandBlitImage Invalid filter mode");
164     }
165     glBlitFramebuffer(static_cast<GLint>(src.rect0.width), sy, static_cast<GLint>(src.rect1.width), sfh,
166         static_cast<GLint>(dst.rect0.width), dy, static_cast<GLint>(dst.rect1.width), dfh, GL_COLOR_BUFFER_BIT,
167         glfilter);
168 }
169 
GetPrimFromTopology(PrimitiveTopology op)170 GLenum GetPrimFromTopology(PrimitiveTopology op)
171 {
172     switch (op) {
173         case CORE_PRIMITIVE_TOPOLOGY_POINT_LIST:
174             return GL_POINTS;
175         case CORE_PRIMITIVE_TOPOLOGY_LINE_LIST:
176             return GL_LINES;
177         case CORE_PRIMITIVE_TOPOLOGY_LINE_STRIP:
178             return GL_LINE_STRIP;
179         case CORE_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
180             return GL_TRIANGLES;
181         case CORE_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
182             return GL_TRIANGLE_STRIP;
183         case CORE_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
184             return GL_TRIANGLE_FAN;
185 #if defined(GL_ES_VERSION_3_2) || defined(GL_VERSION_3_2)
186             // The following are valid after gles 3.2
187         case CORE_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
188             return GL_LINES_ADJACENCY;
189         case CORE_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
190             return GL_LINE_STRIP_ADJACENCY;
191         case CORE_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
192             return GL_TRIANGLES_ADJACENCY;
193         case CORE_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
194             return GL_TRIANGLE_STRIP_ADJACENCY;
195         case CORE_PRIMITIVE_TOPOLOGY_PATCH_LIST:
196             return GL_PATCHES;
197 #endif
198         case CORE_PRIMITIVE_TOPOLOGY_MAX_ENUM:
199         default:
200             PLUGIN_ASSERT_MSG(false, "Unsupported primitive topology");
201             break;
202     }
203     return GL_POINTS;
204 }
205 
GetBlendOp(BlendOp func)206 GLenum GetBlendOp(BlendOp func)
207 {
208     switch (func) {
209         case CORE_BLEND_OP_ADD:
210             return GL_FUNC_ADD;
211         case CORE_BLEND_OP_SUBTRACT:
212             return GL_FUNC_SUBTRACT;
213         case CORE_BLEND_OP_REVERSE_SUBTRACT:
214             return GL_FUNC_REVERSE_SUBTRACT;
215         case CORE_BLEND_OP_MIN:
216             return GL_MIN;
217         case CORE_BLEND_OP_MAX:
218             return GL_MAX;
219         case CORE_BLEND_OP_MAX_ENUM:
220         default:
221             break;
222     }
223     return GL_FUNC_ADD;
224 }
225 
GetBlendFactor(BlendFactor factor)226 GLenum GetBlendFactor(BlendFactor factor)
227 {
228     switch (factor) {
229         case CORE_BLEND_FACTOR_ZERO:
230             return GL_ZERO;
231         case CORE_BLEND_FACTOR_ONE:
232             return GL_ONE;
233         case CORE_BLEND_FACTOR_SRC_COLOR:
234             return GL_SRC_COLOR;
235         case CORE_BLEND_FACTOR_ONE_MINUS_SRC_COLOR:
236             return GL_ONE_MINUS_SRC_COLOR;
237         case CORE_BLEND_FACTOR_DST_COLOR:
238             return GL_DST_COLOR;
239         case CORE_BLEND_FACTOR_ONE_MINUS_DST_COLOR:
240             return GL_ONE_MINUS_DST_COLOR;
241         case CORE_BLEND_FACTOR_SRC_ALPHA:
242             return GL_SRC_ALPHA;
243         case CORE_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA:
244             return GL_ONE_MINUS_SRC_ALPHA;
245         case CORE_BLEND_FACTOR_DST_ALPHA:
246             return GL_DST_ALPHA;
247         case CORE_BLEND_FACTOR_ONE_MINUS_DST_ALPHA:
248             return GL_ONE_MINUS_DST_ALPHA;
249         case CORE_BLEND_FACTOR_CONSTANT_COLOR:
250             return GL_CONSTANT_COLOR;
251         case CORE_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR:
252             return GL_ONE_MINUS_CONSTANT_COLOR;
253         case CORE_BLEND_FACTOR_CONSTANT_ALPHA:
254             return GL_CONSTANT_ALPHA;
255         case CORE_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA:
256             return GL_ONE_MINUS_CONSTANT_ALPHA;
257         case CORE_BLEND_FACTOR_SRC_ALPHA_SATURATE:
258             return GL_SRC_ALPHA_SATURATE;
259             // NOTE: check the GLES3.2...
260             /* following requires EXT_blend_func_extended (dual source blending) */
261         case CORE_BLEND_FACTOR_SRC1_COLOR:
262         case CORE_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR:
263         case CORE_BLEND_FACTOR_SRC1_ALPHA:
264         case CORE_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA:
265         case CORE_BLEND_FACTOR_MAX_ENUM:
266         default:
267             break;
268     }
269     return GL_ONE;
270 }
271 
GetCompareOp(CompareOp aOp)272 GLenum GetCompareOp(CompareOp aOp)
273 {
274     switch (aOp) {
275         case CORE_COMPARE_OP_NEVER:
276             return GL_NEVER;
277         case CORE_COMPARE_OP_LESS:
278             return GL_LESS;
279         case CORE_COMPARE_OP_EQUAL:
280             return GL_EQUAL;
281         case CORE_COMPARE_OP_LESS_OR_EQUAL:
282             return GL_LEQUAL;
283         case CORE_COMPARE_OP_GREATER:
284             return GL_GREATER;
285         case CORE_COMPARE_OP_NOT_EQUAL:
286             return GL_NOTEQUAL;
287         case CORE_COMPARE_OP_GREATER_OR_EQUAL:
288             return GL_GEQUAL;
289         case CORE_COMPARE_OP_ALWAYS:
290             return GL_ALWAYS;
291         case CORE_COMPARE_OP_MAX_ENUM:
292         default:
293             break;
294     }
295     return GL_ALWAYS;
296 }
297 
GetStencilOp(StencilOp aOp)298 GLenum GetStencilOp(StencilOp aOp)
299 {
300     switch (aOp) {
301         case CORE_STENCIL_OP_KEEP:
302             return GL_KEEP;
303         case CORE_STENCIL_OP_ZERO:
304             return GL_ZERO;
305         case CORE_STENCIL_OP_REPLACE:
306             return GL_REPLACE;
307         case CORE_STENCIL_OP_INCREMENT_AND_CLAMP:
308             return GL_INCR;
309         case CORE_STENCIL_OP_DECREMENT_AND_CLAMP:
310             return GL_DECR;
311         case CORE_STENCIL_OP_INVERT:
312             return GL_INVERT;
313         case CORE_STENCIL_OP_INCREMENT_AND_WRAP:
314             return GL_INCR_WRAP;
315         case CORE_STENCIL_OP_DECREMENT_AND_WRAP:
316             return GL_DECR_WRAP;
317         case CORE_STENCIL_OP_MAX_ENUM:
318         default:
319             break;
320     }
321     return GL_KEEP;
322 }
323 
SetState(GLenum type,bool enabled)324 void SetState(GLenum type, bool enabled)
325 {
326     if (enabled) {
327         glEnable(type);
328     } else {
329         glDisable(type);
330     }
331 }
332 
SetCullMode(const GraphicsState::RasterizationState & rs)333 void SetCullMode(const GraphicsState::RasterizationState& rs)
334 {
335     SetState(GL_CULL_FACE, (rs.cullModeFlags != CORE_CULL_MODE_NONE));
336 
337     switch (rs.cullModeFlags) {
338         case CORE_CULL_MODE_FRONT_BIT:
339             glCullFace(GL_FRONT);
340             break;
341         case CORE_CULL_MODE_BACK_BIT:
342             glCullFace(GL_BACK);
343             break;
344         case CORE_CULL_MODE_FRONT_AND_BACK:
345             glCullFace(GL_FRONT_AND_BACK);
346             break;
347         case CORE_CULL_MODE_NONE:
348         case CORE_CULL_MODE_FLAG_BITS_MAX_ENUM:
349         default:
350             break;
351     }
352 }
353 
SetFrontFace(const GraphicsState::RasterizationState & rs)354 void SetFrontFace(const GraphicsState::RasterizationState& rs)
355 {
356     switch (rs.frontFace) {
357         case CORE_FRONT_FACE_COUNTER_CLOCKWISE:
358             glFrontFace(GL_CCW);
359             break;
360         case CORE_FRONT_FACE_CLOCKWISE:
361             glFrontFace(GL_CW);
362             break;
363         case CORE_FRONT_FACE_MAX_ENUM:
364         default:
365             break;
366     }
367 }
368 
369 #if RENDER_HAS_GL_BACKEND
SetPolygonMode(const GraphicsState::RasterizationState & rs)370 void SetPolygonMode(const GraphicsState::RasterizationState& rs)
371 {
372     GLenum mode;
373     switch (rs.polygonMode) {
374         default:
375         case CORE_POLYGON_MODE_FILL:
376             mode = GL_FILL;
377             break;
378         case CORE_POLYGON_MODE_LINE:
379             mode = GL_LINE;
380             break;
381         case CORE_POLYGON_MODE_POINT:
382             mode = GL_POINT;
383             break;
384     }
385     glPolygonMode(GL_FRONT_AND_BACK, mode);
386 }
387 #endif
388 
Invalidate(GLenum framebuffer,int32_t count,const GLenum invalidate[],const RenderPassDesc & rpd,const LowlevelFramebufferGL & frameBuffer)389 void Invalidate(GLenum framebuffer, int32_t count, const GLenum invalidate[], const RenderPassDesc& rpd,
390     const LowlevelFramebufferGL& frameBuffer)
391 {
392     if (count > 0) {
393         if ((frameBuffer.width == rpd.renderArea.extentWidth) && (frameBuffer.height == rpd.renderArea.extentHeight)) {
394             // Invalidate the whole buffer.  (attachment sizes match render area)
395             glInvalidateFramebuffer(framebuffer, static_cast<GLsizei>(count), invalidate);
396         } else {
397             // invalidate only a part of the render target..
398             // NOTE: verify that this works, we might need to flip the Y axis the same way as scissors etc.
399             const GLint X = static_cast<const GLint>(rpd.renderArea.offsetX);
400             const GLint Y = static_cast<const GLint>(rpd.renderArea.offsetY);
401             const GLsizei W = static_cast<const GLsizei>(rpd.renderArea.extentWidth);
402             const GLsizei H = static_cast<const GLsizei>(rpd.renderArea.extentHeight);
403             glInvalidateSubFramebuffer(framebuffer, static_cast<GLsizei>(count), invalidate, X, Y, W, H);
404         }
405     }
406 }
407 
408 struct BlitData {
409     const GpuImagePlatformDataGL& iPlat;
410     const GpuImageDesc& imageDesc;
411     const BufferImageCopy& bufferImageCopy;
412     uintptr_t data { 0 };
413     uint64_t size { 0 };
414     uint64_t sizeOfData { 0 };
415     bool compressed { false };
416 };
417 
BlitArray(DeviceGLES & device_,const BlitData & bd)418 void BlitArray(DeviceGLES& device_, const BlitData& bd)
419 {
420     const auto& iPlat = bd.iPlat;
421     const auto& bufferImageCopy = bd.bufferImageCopy;
422     const auto& imageSubresource = bufferImageCopy.imageSubresource;
423     const auto& imageDesc = bd.imageDesc;
424     const uint32_t mip = imageSubresource.mipLevel;
425     const Math::UVec3 imageSize { imageDesc.width >> mip, imageDesc.height >> mip, imageDesc.depth };
426     // NOTE: image offset depth is ignored
427     const Math::UVec2 offset { bufferImageCopy.imageOffset.width, bufferImageCopy.imageOffset.height };
428     const Math::UVec3 extent3D { Math::min(imageSize.x - offset.x, bufferImageCopy.imageExtent.width),
429         Math::min(imageSize.y - offset.y, bufferImageCopy.imageExtent.height),
430         Math::min(imageSize.z, bufferImageCopy.imageExtent.depth) };
431     const bool valid = (offset.x < imageSize.x) && (offset.y < imageSize.y);
432     if (valid) {
433         uintptr_t data = bd.data;
434         const uint32_t layerCount = imageSubresource.baseArrayLayer + imageSubresource.layerCount;
435         for (uint32_t layer = imageSubresource.baseArrayLayer; layer < layerCount; layer++) {
436             const Math::UVec3 offset3D { offset.x, offset.y, layer };
437             if (bd.compressed) {
438                 device_.CompressedTexSubImage3D(iPlat.image, iPlat.type, imageSubresource.mipLevel, offset3D, extent3D,
439                     iPlat.internalFormat, static_cast<uint32_t>(bd.sizeOfData), reinterpret_cast<const void*>(data));
440             } else {
441                 device_.TexSubImage3D(iPlat.image, iPlat.type, imageSubresource.mipLevel, offset3D, extent3D,
442                     iPlat.format, iPlat.dataType, reinterpret_cast<const void*>(data));
443             }
444             data += static_cast<ptrdiff_t>(bd.sizeOfData);
445         }
446     }
447 }
448 
Blit2D(DeviceGLES & device_,const BlitData & bd)449 void Blit2D(DeviceGLES& device_, const BlitData& bd)
450 {
451     const auto& iPlat = bd.iPlat;
452     const auto& bufferImageCopy = bd.bufferImageCopy;
453     const auto& imageSubresource = bufferImageCopy.imageSubresource;
454     const auto& imageDesc = bd.imageDesc;
455     const uint32_t mip = imageSubresource.mipLevel;
456     const Math::UVec2 imageSize { imageDesc.width >> mip, imageDesc.height >> mip };
457     const Math::UVec2 offset { bufferImageCopy.imageOffset.width, bufferImageCopy.imageOffset.height };
458     const Math::UVec2 extent { Math::min(imageSize.x - offset.x, bufferImageCopy.imageExtent.width),
459         Math::min(imageSize.y - offset.y, bufferImageCopy.imageExtent.height) };
460     PLUGIN_ASSERT_MSG(imageSubresource.baseArrayLayer == 0 && imageSubresource.layerCount == 1,
461         "RenderCommandCopyBufferImage Texture2D with baseArrayLayer!=0 && layerCount!= 1");
462     const bool valid = (offset.x < imageSize.x) && (offset.y < imageSize.y);
463     const uintptr_t data = bd.data;
464     if (valid && bd.compressed) {
465         device_.CompressedTexSubImage2D(iPlat.image, iPlat.type, imageSubresource.mipLevel, offset, extent,
466             iPlat.internalFormat, static_cast<uint32_t>(bd.sizeOfData), reinterpret_cast<const void*>(data));
467     } else if (valid) {
468         device_.TexSubImage2D(iPlat.image, iPlat.type, imageSubresource.mipLevel, offset, extent, iPlat.format,
469             iPlat.dataType, reinterpret_cast<const void*>(data));
470     }
471 }
472 
BlitCube(DeviceGLES & device_,const BlitData & bd)473 void BlitCube(DeviceGLES& device_, const BlitData& bd)
474 {
475     const auto& iPlat = bd.iPlat;
476     const auto& bufferImageCopy = bd.bufferImageCopy;
477     const auto& imageSubresource = bufferImageCopy.imageSubresource;
478     const Math::UVec2 offset { bufferImageCopy.imageOffset.width, bufferImageCopy.imageOffset.height };
479     const Math::UVec2 extent { bufferImageCopy.imageExtent.width, bufferImageCopy.imageExtent.height };
480     constexpr GLenum faceId[] = { GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
481         GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
482         GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0 };
483     PLUGIN_UNUSED(Gles::CUBEMAP_LAYERS);
484     PLUGIN_ASSERT_MSG(imageSubresource.baseArrayLayer == 0 && imageSubresource.layerCount == Gles::CUBEMAP_LAYERS,
485         "RenderCommandCopyBufferImage Cubemap with baseArrayLayer!=0 && layerCount!= 6");
486     uintptr_t data = bd.data;
487     const uint32_t lastLayer = imageSubresource.baseArrayLayer + imageSubresource.layerCount;
488     for (uint32_t i = imageSubresource.baseArrayLayer; i < lastLayer; i++) {
489         const GLenum face = faceId[i]; // convert layer index to cube map face id.
490         if (face == 0) {
491             // reached the end of cubemap faces (see faceId)
492             // so must stop copying.
493             break;
494         }
495         if (bd.compressed) {
496             device_.CompressedTexSubImage2D(iPlat.image, face, imageSubresource.mipLevel, offset, extent,
497                 iPlat.internalFormat, static_cast<uint32_t>(bd.sizeOfData), reinterpret_cast<const void*>(data));
498         } else {
499             device_.TexSubImage2D(iPlat.image, face, imageSubresource.mipLevel, offset, extent, iPlat.format,
500                 iPlat.dataType, reinterpret_cast<const void*>(data));
501         }
502         data += static_cast<ptrdiff_t>(bd.sizeOfData);
503     }
504 }
505 template<bool usePixelUnpackBuffer>
506 
SetupBlit(DeviceGLES & device_,const BufferImageCopy & bufferImageCopy,GpuBufferGLES & srcGpuBuffer,const GpuImageGLES & dstGpuImage)507 BlitData SetupBlit(DeviceGLES& device_, const BufferImageCopy& bufferImageCopy, GpuBufferGLES& srcGpuBuffer,
508     const GpuImageGLES& dstGpuImage)
509 {
510     const auto& iPlat = dstGpuImage.GetPlatformData();
511     const auto& imageOffset = bufferImageCopy.imageOffset;
512     PLUGIN_UNUSED(imageOffset);
513     const auto& imageExtent = bufferImageCopy.imageExtent;
514     PLUGIN_ASSERT_MSG(imageExtent.depth == 1, "RenderCommandCopyBufferImage with imageExtent.depth != 1");
515     PLUGIN_ASSERT_MSG(imageOffset.depth == 0, "RenderCommandCopyBufferImage with imageOffset.depth != 0");
516     const uint64_t size = static_cast<uint64_t>(iPlat.bytesperpixel) *
517                           static_cast<uint64_t>(bufferImageCopy.bufferImageHeight) *
518                           static_cast<uint64_t>(bufferImageCopy.bufferRowLength);
519     uintptr_t data = bufferImageCopy.bufferOffset;
520     if constexpr (usePixelUnpackBuffer) {
521         const auto& plat = srcGpuBuffer.GetPlatformData();
522         device_.BindBuffer(GL_PIXEL_UNPACK_BUFFER, plat.buffer);
523     } else {
524         // Use the mapped pointer for glTexSubImage2D, this is a workaround on GL_INVALID_OPERATION on PVR GLES
525         // simulator and crash with ETC2 textures on NVIDIA..
526         data += reinterpret_cast<uintptr_t>(srcGpuBuffer.Map());
527     }
528     uint64_t sizeOfData = size;
529     const auto& compinfo = iPlat.compression;
530     if (compinfo.compressed) {
531         // how many blocks in width
532         const int64_t blockW = (imageExtent.width + (compinfo.blockW - 1)) / compinfo.blockW;
533         // how many blocks in height
534         const int64_t blockH = (imageExtent.height + (compinfo.blockH - 1)) / compinfo.blockH;
535         // size in bytes..
536         sizeOfData = static_cast<uint64_t>(((blockW * blockH) * compinfo.bytesperblock));
537 
538         // Warn for partial copies. we do not handle those at the moment.
539         if (bufferImageCopy.bufferRowLength != 0) {
540             if (bufferImageCopy.bufferRowLength != blockW * compinfo.blockW) {
541                 PLUGIN_LOG_W("Partial copies of compressed texture data is not currently supported. "
542                              "Stride must match image width (with block align). "
543                              "bufferImageCopy.bufferRowLength(%d) "
544                              "imageExtent.width(%d) ",
545                     bufferImageCopy.bufferRowLength, imageExtent.width);
546             }
547         }
548         glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
549     } else {
550         glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(bufferImageCopy.bufferRowLength));
551     }
552     glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // Make sure the align is tight.
553     return { iPlat, dstGpuImage.GetDesc(), bufferImageCopy, data, size, sizeOfData, compinfo.compressed };
554 }
555 template<bool usePixelUnpackBuffer>
556 
FinishBlit(DeviceGLES & device_,const GpuBufferGLES & srcGpuBuffer)557 void FinishBlit(DeviceGLES& device_, const GpuBufferGLES& srcGpuBuffer)
558 {
559     if constexpr (usePixelUnpackBuffer) {
560         device_.BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
561     } else {
562         srcGpuBuffer.Unmap();
563     }
564 }
565 
566 template<typename T, size_t N>
Compare(const T (& a)[N],const T (& b)[N])567 constexpr size_t Compare(const T (&a)[N], const T (&b)[N])
568 {
569     for (size_t i = 0; i < N; i++) {
570         if (a[i] != b[i])
571             return false;
572     }
573     return true;
574 }
575 
576 template<typename T, size_t N>
577 
Set(T (& a)[N],const T (& b)[N])578 constexpr size_t Set(T (&a)[N], const T (&b)[N])
579 {
580     for (size_t i = 0; i < N; i++) {
581         a[i] = b[i];
582     }
583     return true;
584 }
585 
CompareBlendFactors(const GraphicsState::ColorBlendState::Attachment & a,const GraphicsState::ColorBlendState::Attachment & b)586 bool CompareBlendFactors(
587     const GraphicsState::ColorBlendState::Attachment& a, const GraphicsState::ColorBlendState::Attachment& b)
588 {
589     return (a.srcColorBlendFactor == b.srcColorBlendFactor) && (a.srcAlphaBlendFactor == b.srcAlphaBlendFactor) &&
590            (a.dstColorBlendFactor == b.dstColorBlendFactor) && (a.dstAlphaBlendFactor == b.dstAlphaBlendFactor);
591 }
592 
SetBlendFactors(GraphicsState::ColorBlendState::Attachment & a,const GraphicsState::ColorBlendState::Attachment & b)593 void SetBlendFactors(GraphicsState::ColorBlendState::Attachment& a, const GraphicsState::ColorBlendState::Attachment& b)
594 {
595     a.srcColorBlendFactor = b.srcColorBlendFactor;
596     a.srcAlphaBlendFactor = b.srcAlphaBlendFactor;
597     a.dstColorBlendFactor = b.dstColorBlendFactor;
598     a.dstAlphaBlendFactor = b.dstAlphaBlendFactor;
599 }
600 
CompareBlendOps(const GraphicsState::ColorBlendState::Attachment & a,const GraphicsState::ColorBlendState::Attachment & b)601 bool CompareBlendOps(
602     const GraphicsState::ColorBlendState::Attachment& a, const GraphicsState::ColorBlendState::Attachment& b)
603 {
604     return (a.colorBlendOp == b.colorBlendOp) && (a.alphaBlendOp == b.alphaBlendOp);
605 };
606 
SetBlendOps(GraphicsState::ColorBlendState::Attachment & a,const GraphicsState::ColorBlendState::Attachment & b)607 void SetBlendOps(GraphicsState::ColorBlendState::Attachment& a, const GraphicsState::ColorBlendState::Attachment& b)
608 {
609     a.colorBlendOp = b.colorBlendOp;
610     a.alphaBlendOp = b.alphaBlendOp;
611 }
612 
CompareStencilOp(const GraphicsState::StencilOpState & a,const GraphicsState::StencilOpState & b)613 bool CompareStencilOp(const GraphicsState::StencilOpState& a, const GraphicsState::StencilOpState& b)
614 {
615     return (a.failOp == b.failOp) && (a.depthFailOp == b.depthFailOp) && (a.passOp == b.passOp);
616 }
617 
SetStencilOp(GraphicsState::StencilOpState & a,const GraphicsState::StencilOpState & b)618 void SetStencilOp(GraphicsState::StencilOpState& a, const GraphicsState::StencilOpState& b)
619 {
620     a.failOp = b.failOp;
621     a.depthFailOp = b.depthFailOp;
622     a.passOp = b.passOp;
623 }
624 
setStencilCompareOp(GraphicsState::StencilOpState & a,const GraphicsState::StencilOpState & b)625 void setStencilCompareOp(GraphicsState::StencilOpState& a, const GraphicsState::StencilOpState& b)
626 {
627     a.compareOp = b.compareOp;
628     a.compareMask = b.compareMask;
629     a.reference = b.reference;
630 }
631 } // namespace
632 
RenderBackendGLES(Device & device,GpuResourceManager & gpuResourceManager)633 RenderBackendGLES::RenderBackendGLES(Device& device, GpuResourceManager& gpuResourceManager)
634     : RenderBackend(), device_(static_cast<DeviceGLES&>(device)), gpuResourceMgr_(gpuResourceManager)
635 {
636 #if (RENDER_PERF_ENABLED == 1)
637     validGpuQueries_ = false;
638 #if (RENDER_GPU_TIMESTAMP_QUERIES_ENABLED == 1)
639     gpuQueryMgr_ = make_unique<GpuQueryManager>();
640 #if RENDER_HAS_GL_BACKEND
641     if (device_.GetBackendType() == DeviceBackendType::OPENGL) {
642         validGpuQueries_ = true;
643     }
644 #endif
645 #if RENDER_HAS_GLES_BACKEND
646     if (device_.GetBackendType() == DeviceBackendType::OPENGLES) {
647         // Check if GL_EXT_disjoint_timer_query is available.
648         validGpuQueries_ = device_.HasExtension("GL_EXT_disjoint_timer_query");
649     }
650 #endif
651 #endif // RENDER_GPU_TIMESTAMP_QUERIES_ENABLED
652 #endif // RENDER_PERF_ENABLED
653 #if RENDER_HAS_GLES_BACKEND
654     if (device_.GetBackendType() == DeviceBackendType::OPENGLES) {
655         multisampledRenderToTexture_ = device_.HasExtension("GL_EXT_multisampled_render_to_texture2");
656     }
657 #endif
658     PLUGIN_ASSERT(device_.IsActive());
659     PrimeCache(GraphicsState {}); // Initializes cache.
660     glGenFramebuffers(1, &blitImageSourceFbo_);
661     glGenFramebuffers(1, &blitImageDestinationFbo_);
662 #if (RENDER_DEBUG_GPU_RESOURCE_IDS == 1)
663     PLUGIN_LOG_D("fbo id >: %u", blitImageSourceFbo_);
664     PLUGIN_LOG_D("fbo id >: %u", blitImageDestinationFbo_);
665 #endif
666 #if !RENDER_HAS_GLES_BACKEND
667     glEnable(GL_PROGRAM_POINT_SIZE);
668 #endif
669 }
670 
~RenderBackendGLES()671 RenderBackendGLES::~RenderBackendGLES()
672 {
673     PLUGIN_ASSERT(device_.IsActive());
674     device_.DeleteFrameBuffer(blitImageSourceFbo_);
675     device_.DeleteFrameBuffer(blitImageDestinationFbo_);
676 }
677 
Present(const RenderBackendBackBufferConfiguration & backBufferConfig)678 void RenderBackendGLES::Present(const RenderBackendBackBufferConfiguration& backBufferConfig)
679 {
680 #if (RENDER_DEV_ENABLED == 1)
681     if (backBufferConfig.config.gpuSemaphoreHandle != 0) {
682         // NOTE: not implemented
683         PLUGIN_LOG_E("NodeGraphBackBufferConfiguration semaphore not signaled");
684     }
685 #endif
686     const bool isSwapchain =
687         (backBufferConfig.config.backBufferType == NodeGraphBackBufferConfiguration::BackBufferType::SWAPCHAIN);
688     if (isSwapchain && backBufferConfig.config.present && device_.HasSwapchain()) {
689         const SwapchainGLES* swp = device_.GetSwapchain();
690         if (swp == nullptr) {
691             return;
692         }
693 #if (RENDER_PERF_ENABLED == 1)
694         {
695             commonCpuTimers_.present.Begin();
696         }
697 #endif
698 #if RENDER_GL_FLIP_Y_SWAPCHAIN
699         // Blit and flip our swapchain frame to backbuffer..
700         const auto& sdesc = swp->GetDesc();
701         if (scissorEnabled_) {
702             glDisable(GL_SCISSOR_TEST);
703             scissorEnabled_ = false;
704         }
705         const auto& platSwapchain = static_cast<const SwapchainPlatformDataGL&>(swp->GetPlatformData());
706         device_.BindReadFrameBuffer(platSwapchain.fbos[presentationInfo_.swapchainImageIndex]);
707         device_.BindWriteFrameBuffer(0); // FBO 0  is the surface bound to current context..
708         glBlitFramebuffer(0, 0, (GLint)sdesc.width, (GLint)sdesc.height, 0, (GLint)sdesc.height, (GLint)sdesc.width, 0,
709             GL_COLOR_BUFFER_BIT, GL_NEAREST);
710         device_.BindReadFrameBuffer(0);
711 #endif
712 #if RENDER_HAS_GLES_BACKEND
713         /*
714         "
715         If surface is a back-buffered window surface, eglSwapBuffers then the color buffer is copied (posted) native
716         window associated with that surface. If surface is a single-buffered window, pixmap, or pixel buffer
717         surface, eglSwapBuffers has no effect. " -
718         https://www.khronos.org/registry/EGL/sdk/docs/man/html/eglSwapBuffers.xhtml
719         */
720         if (device_.GetBackendType() == DeviceBackendType::OPENGLES) {
721             const auto& data = static_cast<const DevicePlatformDataGLES&>(device_.GetPlatformData());
722             const auto& platSwapchain = static_cast<const SwapchainPlatformDataGL&>(swp->GetPlatformData());
723             eglSwapBuffers(data.display, (EGLSurface)platSwapchain.surface);
724         }
725 #endif
726 #if RENDER_HAS_GL_BACKEND
727         if (device_.GetBackendType() == DeviceBackendType::OPENGL) {
728             const auto& data = static_cast<const DevicePlatformDataGL&>(device_.GetPlatformData());
729             SwapBuffers(data.display);
730         }
731 #endif
732 #if (RENDER_PERF_ENABLED == 1)
733         {
734             commonCpuTimers_.present.End();
735         }
736 #endif
737     }
738 }
739 
ResetState()740 void RenderBackendGLES::ResetState()
741 {
742     boundProgram_ = {};
743     boundIndexBuffer_ = {};
744     vertexAttribBinds_ = 0;
745     renderingToDefaultFbo_ = false;
746     boundComputePipeline_ = nullptr;
747     boundGraphicsPipeline_ = nullptr;
748     currentPsoHandle_ = {};
749     renderArea_ = {};
750     activeRenderPass_ = {};
751     currentSubPass_ = 0;
752     currentFrameBuffer_ = nullptr;
753     scissorBoxUpdated_ = viewportDepthRangeUpdated_ = viewportUpdated_ = true;
754     inRenderpass_ = 0;
755 }
756 
ResetBindings()757 void RenderBackendGLES::ResetBindings()
758 {
759     for (auto& b : boundObjects_) {
760         b.dirty = true;
761     }
762 }
763 
Render(RenderCommandFrameData & renderCommandFrameData,const RenderBackendBackBufferConfiguration & backBufferConfig)764 void RenderBackendGLES::Render(
765     RenderCommandFrameData& renderCommandFrameData, const RenderBackendBackBufferConfiguration& backBufferConfig)
766 {
767     // NOTE: all command lists are validated before entering here
768     PLUGIN_ASSERT(device_.IsActive());
769 #if (RENDER_PERF_ENABLED == 1)
770     commonCpuTimers_.full.Begin();
771     commonCpuTimers_.acquire.Begin();
772 #endif
773     presentationInfo_ = {};
774     const bool isSwapchain =
775         (backBufferConfig.config.backBufferType == NodeGraphBackBufferConfiguration::BackBufferType::SWAPCHAIN);
776     if (isSwapchain) {
777         if (device_.HasSwapchain()) {
778             SwapchainGLES* swp = device_.GetSwapchain();
779             presentationInfo_.swapchainImageIndex = swp->GetNextImage();
780             // remap image to backbuffer
781             const RenderHandle backBufferHandle =
782                 gpuResourceMgr_.GetImageRawHandle(backBufferConfig.config.backBufferName);
783             const RenderHandle currentSwapchainHandle = gpuResourceMgr_.GetImageRawHandle(
784                 "CORE_DEFAULT_SWAPCHAIN_" + to_string(presentationInfo_.swapchainImageIndex));
785             // special swapchain remapping
786             gpuResourceMgr_.RenderBackendImmediateRemapGpuImageHandle(backBufferHandle, currentSwapchainHandle);
787         } else {
788             PLUGIN_ASSERT_MSG(
789                 false, "backBufferConfig.backBufferType == SWAPCHAIN but device_.HasSwapchain() == false.");
790         }
791     }
792 #if (RENDER_PERF_ENABLED == 1)
793     commonCpuTimers_.acquire.End();
794 
795     StartFrameTimers(renderCommandFrameData);
796     commonCpuTimers_.execute.Begin();
797 #endif
798     // Reset bindings.
799     ResetState();
800     for (const auto& ref : renderCommandFrameData.renderCommandContexts) {
801         // Reset bindings between command lists..
802         ResetBindings();
803         RenderSingleCommandList(ref);
804     }
805 #if (RENDER_PERF_ENABLED == 1)
806     commonCpuTimers_.execute.End();
807 #endif
808     if (auto* frameSync = static_cast<RenderFrameSyncGLES*>(renderCommandFrameData.renderFrameSync); frameSync) {
809         frameSync->GetFrameFence();
810     }
811 #if (RENDER_PERF_ENABLED == 1)
812     commonCpuTimers_.full.End();
813     EndFrameTimers();
814 #endif
815 }
816 
RenderCommandUndefined(const RenderCommandWithType & renderCommand)817 void RenderBackendGLES::RenderCommandUndefined(const RenderCommandWithType& renderCommand)
818 {
819     PLUGIN_ASSERT_MSG(false, "non-valid render command");
820 }
821 
RenderSingleCommandList(const RenderCommandContext & renderCommandCtx)822 void RenderBackendGLES::RenderSingleCommandList(const RenderCommandContext& renderCommandCtx)
823 {
824     // these are validated in render graph
825     managers_ = { renderCommandCtx.nodeContextPsoMgr, renderCommandCtx.contextPoolMgr,
826         renderCommandCtx.nodeContextDescriptorSetMgr, renderCommandCtx.renderBarrierList };
827 #if (RENDER_PERF_ENABLED == 1) || (RENDER_DEBUG_MARKERS_ENABLED == 1)
828     const auto& debugName = renderCommandCtx.debugName;
829 #endif
830 #if (RENDER_PERF_ENABLED == 1)
831     perfCounters_ = {};
832     PLUGIN_ASSERT(timers_.count(debugName) == 1);
833     PerfDataSet& perfDataSet = timers_[debugName];
834     perfDataSet.cpuTimer.Begin();
835 #if (RENDER_GPU_TIMESTAMP_QUERIES_ENABLED == 1)
836     if (validGpuQueries_) {
837 #ifdef GL_GPU_DISJOINT_EXT
838         /* Clear disjoint error */
839         GLint disjointOccurred = 0;
840         glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjointOccurred);
841 #endif
842         GpuQuery* gpuQuery = gpuQueryMgr_->Get(perfDataSet.gpuHandle);
843         PLUGIN_ASSERT(gpuQuery);
844 
845         const auto& platData = static_cast<const GpuQueryPlatformDataGLES&>(gpuQuery->GetPlatformData());
846         PLUGIN_ASSERT(platData.queryObject);
847         glBeginQuery(GL_TIME_ELAPSED_EXT, platData.queryObject);
848     }
849 #endif // RENDER_GPU_TIMESTAMP_QUERIES_ENABLED
850 #endif // RENDER_PERF_ENABLED
851 #if (RENDER_DEBUG_MARKERS_ENABLED == 1)
852     glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, (const GLchar*)debugName.data());
853 #endif
854     for (const auto& ref : renderCommandCtx.renderCommandList->GetRenderCommands()) {
855         PLUGIN_ASSERT(ref.rc);
856 #if RENDER_DEBUG_COMMAND_MARKERS_ENABLED
857         glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, (const GLchar*)COMMAND_NAMES[(uint32_t)ref.type].data());
858 #endif
859         (this->*(COMMAND_HANDLERS[static_cast<uint32_t>(ref.type)]))(ref);
860 #if RENDER_DEBUG_COMMAND_MARKERS_ENABLED
861         glPopDebugGroup();
862 #endif
863     }
864 #if (RENDER_DEBUG_MARKERS_ENABLED == 1)
865     glPopDebugGroup();
866 #endif
867 #if (RENDER_PERF_ENABLED == 1)
868 #if (RENDER_GPU_TIMESTAMP_QUERIES_ENABLED == 1)
869     if (validGpuQueries_) {
870         glEndQuery(GL_TIME_ELAPSED_EXT);
871     }
872 #endif // RENDER_GPU_TIMESTAMP_QUERIES_ENABLED
873     perfDataSet.cpuTimer.End();
874     CopyPerfTimeStamp(debugName, perfDataSet);
875 #endif // RENDER_PERF_ENABLED
876 }
877 
RenderCommandBindPipeline(const RenderCommandWithType & ref)878 void RenderBackendGLES::RenderCommandBindPipeline(const RenderCommandWithType& ref)
879 {
880     PLUGIN_ASSERT(ref.type == RenderCommandType::BIND_PIPELINE);
881     const auto& renderCmd = *static_cast<const struct RenderCommandBindPipeline*>(ref.rc);
882     boundProgram_ = {};
883     if (renderCmd.pipelineBindPoint == PipelineBindPoint::CORE_PIPELINE_BIND_POINT_COMPUTE) {
884         PLUGIN_ASSERT(currentFrameBuffer_ == nullptr);
885         BindComputePipeline(renderCmd);
886     } else if (renderCmd.pipelineBindPoint == PipelineBindPoint::CORE_PIPELINE_BIND_POINT_GRAPHICS) {
887         BindGraphicsPipeline(renderCmd);
888     }
889     currentPsoHandle_ = renderCmd.psoHandle;
890 }
891 
BindComputePipeline(const struct RenderCommandBindPipeline & renderCmd)892 void RenderBackendGLES::BindComputePipeline(const struct RenderCommandBindPipeline& renderCmd)
893 {
894     const auto* pso = static_cast<const ComputePipelineStateObjectGLES*>(
895         managers_.psoMgr->GetComputePso(renderCmd.psoHandle, nullptr));
896     PLUGIN_ASSERT_MSG(pso, "getComputePso returned nullptr");
897     if (pso) {
898         const auto& data = static_cast<const PipelineStateObjectPlatformDataGL&>(pso->GetPlatformData());
899         // Setup descriptorset bind cache..
900         SetupCache(data.pipelineLayout);
901     }
902     boundComputePipeline_ = pso;
903     boundGraphicsPipeline_ = nullptr;
904 }
905 
SetupCache(const PipelineLayout & pipelineLayout)906 void RenderBackendGLES::SetupCache(const PipelineLayout& pipelineLayout)
907 {
908     // based on pipeline layout. (note that compatible sets should "save state")
909     for (uint32_t set = 0; set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT; ++set) {
910         // mark unmatching sets dirty (all for now)
911         // resize the cache stuffs.
912         const auto& s = pipelineLayout.descriptorSetLayouts[set];
913         if (s.set == PipelineLayoutConstants::INVALID_INDEX) {
914             boundObjects_[set].resources.clear();
915             boundObjects_[set].dirty = true;
916             continue;
917         }
918         PLUGIN_ASSERT(s.set == set);
919 
920         size_t maxB = 0;
921         // NOTE: compatibility optimizations?
922         // NOTE: we expect bindings to be sorted.
923         if (s.bindings.back().binding == s.bindings.size() - 1) {
924             // since the last binding matches the size, expect it to be continuous.
925             maxB = s.bindings.size();
926         } else {
927             // Sparse binding.
928             // NOTE: note sparse sets will waste memory here. (see notes in
929             // https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkDescriptorSetLayoutBinding.html)
930             for (uint32_t bind = 0; bind < s.bindings.size(); bind++) {
931                 if (s.bindings[bind].binding > maxB)
932                     maxB = s.bindings[bind].binding;
933             }
934             maxB += 1; // zero based bindings..
935         }
936         if (boundObjects_[set].resources.size() != maxB) {
937             // resource count change.. (so it's dirty then)
938             boundObjects_[set].resources.clear(); // clear because we don't care what it had before.
939             boundObjects_[set].resources.resize(maxB);
940             boundObjects_[set].dirty = true;
941         }
942 
943         for (uint32_t bind = 0; bind < s.bindings.size(); bind++) {
944             const auto& b = s.bindings[bind];
945             auto& o = boundObjects_[set].resources[b.binding];
946             // ignore b.shaderStageFlags for now.
947             if ((o.resources.size() != b.descriptorCount) || (o.descriptorType != b.descriptorType)) {
948                 // mark set dirty, since "not matching"
949                 o.resources.clear();
950                 o.resources.resize(b.descriptorCount);
951                 o.descriptorType = b.descriptorType;
952                 boundObjects_[set].dirty = true;
953             }
954         }
955     }
956 }
957 
BindGraphicsPipeline(const struct RenderCommandBindPipeline & renderCmd)958 void RenderBackendGLES::BindGraphicsPipeline(const struct RenderCommandBindPipeline& renderCmd)
959 {
960     const auto* pso =
961         static_cast<const GraphicsPipelineStateObjectGLES*>(managers_.psoMgr->GetGraphicsPso(renderCmd.psoHandle,
962             activeRenderPass_.renderPassDesc, activeRenderPass_.subpasses, currentSubPass_, 0, nullptr, nullptr));
963     PLUGIN_ASSERT_MSG(pso, "getGraphicsPso returned nullptr");
964     if (pso) {
965         const auto& data = static_cast<const PipelineStateObjectPlatformDataGL&>(pso->GetPlatformData());
966         dynamicStateFlags_ = data.dynamicStateFlags | data.graphicsState.dynamicStateFlags;
967         DoGraphicsState(data.graphicsState);
968         // NOTE: Johannes Pystynen 03.02.2020, deprecate (default viewport/scissor should be set from default
969         // targets at some point)
970         if (!IS_BIT(dynamicStateFlags_, CORE_DYNAMIC_STATE_VIEWPORT)) {
971             SetViewport(renderArea_, ViewportDesc { 0.0f, 0.0f, static_cast<float>(renderArea_.extentWidth),
972                                          static_cast<float>(renderArea_.extentHeight), 0.0f, 1.0f });
973         }
974         if (!IS_BIT(dynamicStateFlags_, CORE_DYNAMIC_STATE_SCISSOR)) {
975             SetScissor(renderArea_, ScissorDesc { 0, 0, renderArea_.extentWidth, renderArea_.extentHeight });
976         }
977         // Setup descriptorset bind cache..
978         SetupCache(data.pipelineLayout);
979     }
980     boundComputePipeline_ = nullptr;
981     boundGraphicsPipeline_ = pso;
982 }
983 
RenderCommandDraw(const RenderCommandWithType & ref)984 void RenderBackendGLES::RenderCommandDraw(const RenderCommandWithType& ref)
985 {
986     PLUGIN_ASSERT(ref.type == RenderCommandType::DRAW);
987     const auto& renderCmd = *static_cast<struct RenderCommandDraw*>(ref.rc);
988     PLUGIN_ASSERT(boundGraphicsPipeline_);
989     PLUGIN_ASSERT(boundComputePipeline_ == nullptr);
990     BindResources();
991     const auto type = GetPrimFromTopology(topology_);
992     const GLsizei firstVertex = static_cast<const GLsizei>(renderCmd.firstVertex);
993     const GLsizei instanceCount = static_cast<GLsizei>(renderCmd.instanceCount);
994     // firstInstance is not supported yet, need to set the SPIRV_Cross generated uniform
995     // "SPIRV_Cross_BaseInstance" to renderCmd.firstInstance;
996     if (renderCmd.indexCount) {
997         uintptr_t offsetp = boundIndexBuffer_.offset;
998         GLenum indexType = GL_UNSIGNED_SHORT;
999         switch (boundIndexBuffer_.type) {
1000             case CORE_INDEX_TYPE_UINT16:
1001                 offsetp += renderCmd.firstIndex * sizeof(uint16_t);
1002                 indexType = GL_UNSIGNED_SHORT;
1003                 break;
1004             case CORE_INDEX_TYPE_UINT32:
1005                 offsetp += renderCmd.firstIndex * sizeof(uint32_t);
1006                 indexType = GL_UNSIGNED_INT;
1007                 break;
1008             case CORE_INDEX_TYPE_MAX_ENUM:
1009             default:
1010                 PLUGIN_ASSERT_MSG(false, "Invalid indexbuffer type");
1011                 break;
1012         }
1013         const GLsizei indexCount = static_cast<const GLsizei>(renderCmd.indexCount);
1014         const void* offset = reinterpret_cast<const void*>(offsetp);
1015         if (renderCmd.instanceCount > 1) {
1016             if (renderCmd.firstVertex) {
1017                 glDrawElementsInstancedBaseVertex(type, indexCount, indexType, offset, instanceCount, firstVertex);
1018             } else {
1019                 glDrawElementsInstanced(type, indexCount, indexType, offset, instanceCount);
1020             }
1021         } else {
1022             if (renderCmd.vertexOffset) {
1023                 glDrawElementsBaseVertex(
1024                     type, indexCount, indexType, offset, static_cast<GLint>(renderCmd.vertexOffset));
1025             } else {
1026                 glDrawElements(type, indexCount, indexType, offset);
1027             }
1028         }
1029 #if (RENDER_PERF_ENABLED == 1)
1030         ++perfCounters_.drawCount;
1031         perfCounters_.instanceCount += renderCmd.instanceCount;
1032         perfCounters_.triangleCount += renderCmd.indexCount * renderCmd.instanceCount;
1033 #endif
1034     } else {
1035         const GLsizei vertexCount = static_cast<const GLsizei>(renderCmd.vertexCount);
1036         if (renderCmd.instanceCount > 1) {
1037             glDrawArraysInstanced(type, firstVertex, vertexCount, instanceCount);
1038         } else {
1039             glDrawArrays(type, firstVertex, vertexCount);
1040         }
1041 #if (RENDER_PERF_ENABLED == 1)
1042         ++perfCounters_.drawCount;
1043         perfCounters_.instanceCount += renderCmd.instanceCount;
1044         perfCounters_.triangleCount += (renderCmd.vertexCount * 3) * renderCmd.instanceCount; // 3: vertex dimension
1045 #endif
1046     }
1047 }
1048 
RenderCommandDrawIndirect(const RenderCommandWithType & ref)1049 void RenderBackendGLES::RenderCommandDrawIndirect(const RenderCommandWithType& ref)
1050 {
1051     PLUGIN_ASSERT(ref.type == RenderCommandType::DRAW_INDIRECT);
1052     const auto& renderCmd = *static_cast<const struct RenderCommandDrawIndirect*>(ref.rc);
1053     PLUGIN_ASSERT(boundGraphicsPipeline_);
1054     PLUGIN_ASSERT(boundComputePipeline_ == nullptr);
1055     BindResources();
1056     const GpuBufferGLES* gpuBuffer = gpuResourceMgr_.GetBuffer<GpuBufferGLES>(renderCmd.argsHandle);
1057     PLUGIN_ASSERT(gpuBuffer);
1058     if (gpuBuffer) {
1059         const auto& plat = gpuBuffer->GetPlatformData();
1060         device_.BindBuffer(GL_DRAW_INDIRECT_BUFFER, plat.buffer);
1061         const auto type = GetPrimFromTopology(topology_);
1062         auto offset = static_cast<GLintptr>(renderCmd.offset);
1063         if (renderCmd.drawType == DrawType::DRAW_INDEXED_INDIRECT) {
1064             GLenum indexType = GL_UNSIGNED_SHORT;
1065             switch (boundIndexBuffer_.type) {
1066                 case CORE_INDEX_TYPE_UINT16:
1067                     indexType = GL_UNSIGNED_SHORT;
1068                     break;
1069                 case CORE_INDEX_TYPE_UINT32:
1070                     indexType = GL_UNSIGNED_INT;
1071                     break;
1072                 case CORE_INDEX_TYPE_MAX_ENUM:
1073                 default:
1074                     PLUGIN_ASSERT_MSG(false, "Invalid indexbuffer type");
1075                     break;
1076             }
1077             for (uint32_t i = 0; i < renderCmd.drawCount; ++i) {
1078                 glDrawElementsIndirect(type, indexType, reinterpret_cast<const void*>(offset));
1079                 offset += renderCmd.stride;
1080             }
1081         } else {
1082             for (uint32_t i = 0; i < renderCmd.drawCount; ++i) {
1083                 glDrawArraysIndirect(type, reinterpret_cast<const void*>(offset));
1084                 offset += renderCmd.stride;
1085             }
1086         }
1087 #if (RENDER_PERF_ENABLED == 1)
1088         perfCounters_.drawIndirectCount += renderCmd.drawCount;
1089 #endif
1090     }
1091 }
1092 
RenderCommandDispatch(const RenderCommandWithType & ref)1093 void RenderBackendGLES::RenderCommandDispatch(const RenderCommandWithType& ref)
1094 {
1095     PLUGIN_ASSERT(ref.type == RenderCommandType::DISPATCH);
1096     const auto& renderCmd = *static_cast<const struct RenderCommandDispatch*>(ref.rc);
1097     PLUGIN_ASSERT(boundGraphicsPipeline_ == nullptr);
1098     PLUGIN_ASSERT(boundComputePipeline_);
1099     BindResources();
1100     glDispatchCompute(renderCmd.groupCountX, renderCmd.groupCountY, renderCmd.groupCountZ);
1101 #if (RENDER_PERF_ENABLED == 1)
1102     ++perfCounters_.dispatchCount;
1103 #endif
1104 }
1105 
RenderCommandDispatchIndirect(const RenderCommandWithType & ref)1106 void RenderBackendGLES::RenderCommandDispatchIndirect(const RenderCommandWithType& ref)
1107 {
1108     PLUGIN_ASSERT(ref.type == RenderCommandType::DISPATCH_INDIRECT);
1109     const auto& renderCmd = *static_cast<const struct RenderCommandDispatchIndirect*>(ref.rc);
1110     PLUGIN_ASSERT(boundGraphicsPipeline_ == nullptr);
1111     PLUGIN_ASSERT(boundComputePipeline_);
1112     BindResources();
1113     const GpuBufferGLES* gpuBuffer = gpuResourceMgr_.GetBuffer<GpuBufferGLES>(renderCmd.argsHandle);
1114     PLUGIN_ASSERT(gpuBuffer);
1115     if (gpuBuffer) {
1116         const auto& plat = gpuBuffer->GetPlatformData();
1117         device_.BindBuffer(GL_DISPATCH_INDIRECT_BUFFER, plat.buffer);
1118         glDispatchComputeIndirect(static_cast<GLintptr>(renderCmd.offset));
1119 #if (RENDER_PERF_ENABLED == 1)
1120         ++perfCounters_.dispatchIndirectCount;
1121 #endif
1122     }
1123 }
1124 
ClearScissorInit(const RenderPassDesc::RenderArea & aArea)1125 void RenderBackendGLES::ClearScissorInit(const RenderPassDesc::RenderArea& aArea)
1126 {
1127     resetScissor_ = false;           // need to reset scissor state after clear?
1128     clearScissorSet_ = true;         // need to setup clear scissors before clear?
1129     clearScissor_ = aArea;           // area to be cleared
1130     if (scissorPrimed_) {            // have scissors been set yet?
1131         if ((!scissorBoxUpdated_) && // if there is a pending scissor change, ignore the scissorbox.
1132             (clearScissor_.offsetX == scissorBox_.offsetX) && (clearScissor_.offsetY == scissorBox_.offsetY) &&
1133             (clearScissor_.extentWidth == scissorBox_.extentWidth) &&
1134             (clearScissor_.extentHeight == scissorBox_.extentHeight)) {
1135             // Current scissors match clearscissor area, so no need to set it again.
1136             clearScissorSet_ = false;
1137         }
1138     }
1139 }
1140 
ClearScissorSet()1141 void RenderBackendGLES::ClearScissorSet()
1142 {
1143     if (clearScissorSet_) {       // do we need to set clear scissors.
1144         clearScissorSet_ = false; // clear scissors have been set now.
1145         resetScissor_ = true;     // we are modifying scissors, so remember to reset them afterwards.
1146         glScissor(static_cast<GLint>(clearScissor_.offsetX), static_cast<GLint>(clearScissor_.offsetY),
1147             static_cast<GLsizei>(clearScissor_.extentWidth), static_cast<GLsizei>(clearScissor_.extentHeight));
1148     }
1149 }
1150 
ClearScissorReset()1151 void RenderBackendGLES::ClearScissorReset()
1152 {
1153     if (resetScissor_) { // need to reset correct scissors?
1154         if (!scissorPrimed_) {
1155             // scissors have not been set yet, so use clearbox as current cache state (and don't change scissor
1156             // setting)
1157             scissorPrimed_ = true;
1158             scissorBox_.offsetX = clearScissor_.offsetX;
1159             scissorBox_.offsetY = clearScissor_.offsetY;
1160             scissorBox_.extentHeight = clearScissor_.extentHeight;
1161             scissorBox_.extentWidth = clearScissor_.extentWidth;
1162         } else {
1163             // Restore scissor box to cached state. (update scissors when needed, since clearBox != scissorBox)
1164             scissorBoxUpdated_ = true; // ie. request to update scissor state.
1165         }
1166     }
1167 }
1168 
HandleColorAttachments(const array_view<const RenderPassDesc::AttachmentDesc * > colorAttachments)1169 void RenderBackendGLES::HandleColorAttachments(const array_view<const RenderPassDesc::AttachmentDesc*> colorAttachments)
1170 {
1171     constexpr ColorComponentFlags clearAll = CORE_COLOR_COMPONENT_R_BIT | CORE_COLOR_COMPONENT_G_BIT |
1172                                              CORE_COLOR_COMPONENT_B_BIT | CORE_COLOR_COMPONENT_A_BIT;
1173     const auto& cBlend = cacheState_.colorBlendState;
1174     for (uint32_t idx = 0; idx < colorAttachments.size(); ++idx) {
1175         if (colorAttachments[idx] == nullptr) {
1176             continue;
1177         }
1178         const auto& ref = *(colorAttachments[idx]);
1179         if (ref.loadOp == AttachmentLoadOp::CORE_ATTACHMENT_LOAD_OP_CLEAR) {
1180             const auto& cBlendState = cBlend.colorAttachments[idx];
1181             if (clearAll != cBlendState.colorWriteMask) {
1182                 glColorMaski(idx, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1183             }
1184             ClearScissorSet();
1185             // glClearBufferfv only for float formats?
1186             // glClearBufferiv & glClearbufferuv only for integer formats?
1187             glClearBufferfv(GL_COLOR, static_cast<GLint>(idx), ref.clearValue.color.float32);
1188             if (clearAll != cBlendState.colorWriteMask) {
1189                 // NOTE: We might not need to restore here.. (we need to peek in to the command list to find out...)
1190                 glColorMaski(idx, IS_BIT_GL(cBlendState.colorWriteMask, CORE_COLOR_COMPONENT_R_BIT),
1191                     IS_BIT_GL(cBlendState.colorWriteMask, CORE_COLOR_COMPONENT_G_BIT),
1192                     IS_BIT_GL(cBlendState.colorWriteMask, CORE_COLOR_COMPONENT_B_BIT),
1193                     IS_BIT_GL(cBlendState.colorWriteMask, CORE_COLOR_COMPONENT_A_BIT));
1194             }
1195         }
1196     }
1197 }
1198 
HandleDepthAttachment(const RenderPassDesc::AttachmentDesc & depthAttachment)1199 void RenderBackendGLES::HandleDepthAttachment(const RenderPassDesc::AttachmentDesc& depthAttachment)
1200 {
1201     const GLuint allBits = 0xFFFFFFFFu;
1202     const auto& ref = depthAttachment;
1203     const bool clearDepth = (ref.loadOp == AttachmentLoadOp::CORE_ATTACHMENT_LOAD_OP_CLEAR);
1204     const bool clearStencil = (ref.stencilLoadOp == AttachmentLoadOp::CORE_ATTACHMENT_LOAD_OP_CLEAR);
1205     // Change state if needed.
1206     if ((clearDepth) && (!cacheState_.depthStencilState.enableDepthWrite)) {
1207         glDepthMask(GL_TRUE);
1208     }
1209     if (clearStencil) {
1210         if (cacheState_.depthStencilState.frontStencilOpState.writeMask != allBits) {
1211             glStencilMaskSeparate(GL_FRONT, allBits);
1212         }
1213         if (cacheState_.depthStencilState.backStencilOpState.writeMask != allBits) {
1214             glStencilMaskSeparate(GL_BACK, allBits);
1215         }
1216     }
1217     if (clearDepth || clearStencil) {
1218         // Set the scissors for clear..
1219         ClearScissorSet();
1220     }
1221     // Do clears.
1222     if (clearDepth && clearStencil) {
1223         glClearBufferfi(GL_DEPTH_STENCIL, 0, ref.clearValue.depthStencil.depth,
1224             static_cast<GLint>(ref.clearValue.depthStencil.stencil));
1225     } else if (clearDepth) {
1226         glClearBufferfv(GL_DEPTH, 0, &ref.clearValue.depthStencil.depth);
1227     } else if (clearStencil) {
1228         glClearBufferiv(GL_STENCIL, 0, reinterpret_cast<const GLint*>(&ref.clearValue.depthStencil.stencil));
1229     }
1230 
1231     // Restore cached state, if we touched the state.
1232     if ((clearDepth) && (!cacheState_.depthStencilState.enableDepthWrite)) {
1233         // NOTE: We might not need to restore here.. (we need to peek in to the command list to find out...)
1234         glDepthMask(GL_FALSE);
1235     }
1236     if (clearStencil) {
1237         // NOTE: We might not need to restore here.. (we need to peek in to the command list to find out...)
1238         if (cacheState_.depthStencilState.frontStencilOpState.writeMask != allBits) {
1239             glStencilMaskSeparate(GL_FRONT, cacheState_.depthStencilState.frontStencilOpState.writeMask);
1240         }
1241         if (cacheState_.depthStencilState.backStencilOpState.writeMask != allBits) {
1242             glStencilMaskSeparate(GL_BACK, cacheState_.depthStencilState.backStencilOpState.writeMask);
1243         }
1244     }
1245 }
1246 
DoSubPass(uint32_t subPass)1247 void RenderBackendGLES::DoSubPass(uint32_t subPass)
1248 {
1249     PLUGIN_ASSERT(currentFrameBuffer_);
1250     if (currentFrameBuffer_ == nullptr) {
1251         // Completely invalid state in backend.
1252         return;
1253     }
1254     device_.BindFrameBuffer(currentFrameBuffer_->fbos[currentSubPass_].fbo);
1255     ClearScissorInit(renderArea_);
1256     if (cacheState_.rasterizationState.enableRasterizerDiscard) { // Rasterizer discard affects glClearBuffer*
1257         SetState(GL_RASTERIZER_DISCARD, GL_FALSE);
1258     }
1259     const auto& rpd = activeRenderPass_.renderPassDesc;
1260     {
1261         // NOTE: clear is not yet optimal. depth, stencil and color should be cleared using ONE glClear call if
1262         // possible. (ie. all buffers at once)
1263         const auto& sb = activeRenderPass_.subpasses[subPass];
1264         renderingToDefaultFbo_ = false;
1265         if (sb.colorAttachmentCount > 0) {
1266             // collect color attachment infos..
1267             const RenderPassDesc::AttachmentDesc*
1268                 colorAttachments[PipelineStateConstants::MAX_RENDER_PASS_ATTACHMENT_COUNT];
1269             for (uint32_t ci = 0; ci < sb.colorAttachmentCount; ci++) {
1270                 uint32_t index = sb.colorAttachmentIndices[ci];
1271                 if (resolveToBackbuffer_[index]) // NOTE: this could fail with multiple color attachments....
1272                     renderingToDefaultFbo_ = true;
1273                 if (!attachmentCleared_[index]) {
1274                     attachmentCleared_[index] = true;
1275                     colorAttachments[ci] = &rpd.attachments[index];
1276                 } else {
1277                     colorAttachments[ci] = nullptr;
1278                 }
1279             }
1280             HandleColorAttachments(array_view(colorAttachments, sb.colorAttachmentCount));
1281         }
1282         if (sb.depthAttachmentCount) {
1283             if (!attachmentCleared_[sb.depthAttachmentIndex]) {
1284                 attachmentCleared_[sb.depthAttachmentIndex] = true;
1285                 HandleDepthAttachment(rpd.attachments[sb.depthAttachmentIndex]);
1286             }
1287         }
1288     }
1289     if (cacheState_.rasterizationState.enableRasterizerDiscard) { // Rasterizer discard affects glClearBuffer*
1290         // NOTE: We might not need to restore here.. (we need to peek in to the command list to find out...)
1291         SetState(GL_RASTERIZER_DISCARD, GL_TRUE);
1292     }
1293     ClearScissorReset();
1294 }
1295 
ScanPasses(const RenderPassDesc & rpd)1296 void RenderBackendGLES::ScanPasses(const RenderPassDesc& rpd)
1297 {
1298     for (uint32_t sub = 0; sub < rpd.subpassCount; sub++) {
1299         const auto& currentSubPass = activeRenderPass_.subpasses[sub];
1300         for (uint32_t ci = 0; ci < currentSubPass.resolveAttachmentCount; ci++) {
1301             uint32_t resolveTo = currentSubPass.resolveAttachmentIndices[ci];
1302             if (attachmentFirstUse_[resolveTo] == 0xFFFFFFFF) {
1303                 attachmentFirstUse_[resolveTo] = sub;
1304             }
1305             attachmentLastUse_[resolveTo] = sub;
1306             const auto& p = static_cast<const GpuImagePlatformDataGL&>(attachmentImage_[resolveTo]->GetPlatformData());
1307             if ((p.image == 0) && (p.renderBuffer == 0)) {
1308                 // mark the "resolveFrom" (ie. the colorattachment) as "backbuffer-like", since we resolve to
1309                 // backbuffer...
1310                 uint32_t resolveFrom = currentSubPass.colorAttachmentIndices[ci];
1311                 resolveToBackbuffer_[resolveFrom] = true;
1312             }
1313         }
1314         for (uint32_t ci = 0; ci < currentSubPass.inputAttachmentCount; ci++) {
1315             uint32_t index = currentSubPass.inputAttachmentIndices[ci];
1316             if (attachmentFirstUse_[index] == 0xFFFFFFFF) {
1317                 attachmentFirstUse_[index] = sub;
1318             }
1319             attachmentLastUse_[index] = sub;
1320         }
1321         for (uint32_t ci = 0; ci < currentSubPass.colorAttachmentCount; ci++) {
1322             uint32_t index = currentSubPass.colorAttachmentIndices[ci];
1323             if (attachmentFirstUse_[index] == 0xFFFFFFFF) {
1324                 attachmentFirstUse_[index] = sub;
1325             }
1326             attachmentLastUse_[index] = sub;
1327             const auto& p = static_cast<const GpuImagePlatformDataGL&>(attachmentImage_[index]->GetPlatformData());
1328             if ((p.image == 0) && (p.renderBuffer == 0)) {
1329                 resolveToBackbuffer_[index] = true;
1330             }
1331         }
1332         if (currentSubPass.depthAttachmentCount > 0) {
1333             uint32_t index = currentSubPass.depthAttachmentIndex;
1334             if (attachmentFirstUse_[index] == 0xFFFFFFFF) {
1335                 attachmentFirstUse_[index] = sub;
1336             }
1337             attachmentLastUse_[index] = sub;
1338         }
1339     }
1340 }
1341 
RenderCommandBeginRenderPass(const RenderCommandWithType & ref)1342 void RenderBackendGLES::RenderCommandBeginRenderPass(const RenderCommandWithType& ref)
1343 {
1344     PLUGIN_ASSERT(ref.type == RenderCommandType::BEGIN_RENDER_PASS);
1345     const auto& renderCmd = *static_cast<const struct RenderCommandBeginRenderPass*>(ref.rc);
1346     if (renderCmd.beginType == RenderPassBeginType::RENDER_PASS_SUBPASS_BEGIN) {
1347         currentSubPass_++;
1348         PLUGIN_ASSERT(currentSubPass_ < activeRenderPass_.renderPassDesc.subpassCount);
1349         DoSubPass(currentSubPass_);
1350         return;
1351     }
1352     inRenderpass_++;
1353     PLUGIN_ASSERT_MSG(inRenderpass_ == 1, "RenderBackendGLES beginrenderpass mInRenderpass %u", inRenderpass_);
1354     activeRenderPass_ = renderCmd; // Store this because we need it later (in NextRenderPass)
1355 
1356     const auto& rpd = activeRenderPass_.renderPassDesc;
1357     renderArea_ = rpd.renderArea; // can subpasses have different render areas?
1358     auto& aCpm = *(static_cast<NodeContextPoolManagerGLES*>(managers_.poolMgr));
1359     if (multisampledRenderToTexture_) {
1360         aCpm.FilterRenderPass(activeRenderPass_);
1361     }
1362     currentFrameBuffer_ = &(aCpm.GetFramebuffer(aCpm.GetFramebufferHandle(activeRenderPass_)));
1363     PLUGIN_ASSERT(currentFrameBuffer_);
1364     if (currentFrameBuffer_ == nullptr) {
1365         // Completely invalid state in backend.
1366         return;
1367     }
1368     PLUGIN_ASSERT_MSG(
1369         activeRenderPass_.subpassStartIndex == 0, "activeRenderPass_.subpassStartIndex != 0 not handled!");
1370     currentSubPass_ = 0;
1371     PLUGIN_ASSERT(rpd.subpassContents == SubpassContents::CORE_SUBPASS_CONTENTS_INLINE);
1372     // find first and last use, clear clearflags. (this could be cached in the lowlewel classes)
1373     for (uint32_t i = 0; i < rpd.attachmentCount; i++) {
1374         attachmentCleared_[i] = false;
1375         attachmentFirstUse_[i] = 0xFFFFFFFF;
1376         attachmentLastUse_[i] = 0;
1377         resolveToBackbuffer_[i] = false;
1378         attachmentImage_[i] = static_cast<const GpuImageGLES*>(gpuResourceMgr_.GetImage(rpd.attachmentHandles[i]));
1379     }
1380     ScanPasses(rpd);
1381     DoSubPass(0);
1382 #if (RENDER_PERF_ENABLED == 1)
1383     ++perfCounters_.renderPassCount;
1384 #endif
1385 }
1386 
RenderCommandNextSubpass(const RenderCommandWithType & ref)1387 void RenderBackendGLES::RenderCommandNextSubpass(const RenderCommandWithType& ref)
1388 {
1389     PLUGIN_ASSERT(ref.type == RenderCommandType::NEXT_SUBPASS);
1390     const auto& renderCmd = *static_cast<const struct RenderCommandNextSubpass*>(ref.rc);
1391     PLUGIN_UNUSED(renderCmd);
1392     PLUGIN_ASSERT(renderCmd.subpassContents == SubpassContents::CORE_SUBPASS_CONTENTS_INLINE);
1393     currentSubPass_++;
1394     PLUGIN_ASSERT(currentSubPass_ < activeRenderPass_.renderPassDesc.subpassCount);
1395     DoSubPass(currentSubPass_);
1396 }
1397 
InvalidateDepthStencil(array_view<uint32_t> invalidateAttachment,const RenderPassDesc & rpd,const RenderPassSubpassDesc & currentSubPass)1398 int32_t RenderBackendGLES::InvalidateDepthStencil(
1399     array_view<uint32_t> invalidateAttachment, const RenderPassDesc& rpd, const RenderPassSubpassDesc& currentSubPass)
1400 {
1401     int32_t depthCount = 0;
1402     if (currentSubPass.depthAttachmentCount > 0) {
1403         const uint32_t index = currentSubPass.depthAttachmentIndex;
1404         if (attachmentLastUse_[index] == currentSubPass_) { // is last use of the attachment
1405             const auto& image = attachmentImage_[index];
1406             const auto& dplat = static_cast<const GpuImagePlatformDataGL&>(image->GetPlatformData());
1407             if (dplat.image || dplat.renderBuffer) {
1408                 bool depth = false;
1409                 bool stencil = false;
1410                 if (rpd.attachments[index].storeOp == CORE_ATTACHMENT_STORE_OP_DONT_CARE) {
1411                     if ((dplat.format == GL_DEPTH_COMPONENT) || (dplat.format == GL_DEPTH_STENCIL)) {
1412                         depth = true;
1413                     }
1414                 }
1415                 if (rpd.attachments[index].stencilStoreOp == CORE_ATTACHMENT_STORE_OP_DONT_CARE) {
1416                     if ((dplat.format == GL_STENCIL) || (dplat.format == GL_DEPTH_STENCIL)) {
1417                         stencil = true;
1418                     }
1419                 }
1420                 if (depth && stencil) {
1421                     invalidateAttachment[0] = GL_DEPTH_STENCIL_ATTACHMENT;
1422                     depthCount++;
1423                 } else if (stencil) {
1424                     invalidateAttachment[0] = GL_STENCIL_ATTACHMENT;
1425                     depthCount++;
1426                 } else if (depth) {
1427                     invalidateAttachment[0] = GL_DEPTH_ATTACHMENT;
1428                     depthCount++;
1429                 }
1430             }
1431         }
1432     }
1433     return depthCount;
1434 }
1435 
InvalidateColor(array_view<uint32_t> invalidateAttachment,const RenderPassDesc & rpd,const RenderPassSubpassDesc & currentSubPass)1436 int32_t RenderBackendGLES::InvalidateColor(
1437     array_view<uint32_t> invalidateAttachment, const RenderPassDesc& rpd, const RenderPassSubpassDesc& currentSubPass)
1438 {
1439     int32_t colorCount = 0;
1440     // see which parts of the fbo can be invalidated...
1441     // collect color attachment infos..
1442     for (uint32_t ci = 0; ci < currentSubPass.colorAttachmentCount; ci++) {
1443         const uint32_t index = currentSubPass.colorAttachmentIndices[ci];
1444         if (attachmentLastUse_[index] == currentSubPass_) { // is last use of the attachment
1445             const auto& image = attachmentImage_[index];
1446             const auto& dplat = static_cast<const GpuImagePlatformDataGL&>(image->GetPlatformData());
1447             if (dplat.image || dplat.renderBuffer) {
1448                 if (rpd.attachments[index].storeOp == CORE_ATTACHMENT_STORE_OP_DONT_CARE) {
1449                     invalidateAttachment[static_cast<size_t>(colorCount)] = GL_COLOR_ATTACHMENT0 + ci;
1450                     colorCount++;
1451                 }
1452             }
1453         }
1454     }
1455     return colorCount;
1456 }
1457 
ResolveMSAA(const RenderPassDesc & rpd,const RenderPassSubpassDesc & currentSubPass)1458 uint32_t RenderBackendGLES::ResolveMSAA(const RenderPassDesc& rpd, const RenderPassSubpassDesc& currentSubPass)
1459 {
1460     const GLbitfield mask = ((currentSubPass.resolveAttachmentCount > 0u) ? GL_COLOR_BUFFER_BIT : 0u) |
1461                             ((currentSubPass.depthResolveAttachmentCount > 0u) ? GL_DEPTH_BUFFER_BIT : 0u);
1462     if (mask) {
1463         // Resolve MSAA buffers.
1464         // NOTE: ARM recommends NOT to use glBlitFramebuffer here
1465         device_.BindReadFrameBuffer(currentFrameBuffer_->fbos[currentSubPass_].fbo);
1466         device_.BindWriteFrameBuffer(currentFrameBuffer_->fbos[currentSubPass_].resolve);
1467         if (scissorEnabled_) {
1468             glDisable(GL_SCISSOR_TEST);
1469             scissorEnabled_ = false;
1470         }
1471         // FLIP_RESOLVE_DEFAULT_FBO not needed, since we render flipped if end result will be resolved to fbo..
1472         // hopefully it works now.
1473 #if defined(FLIP_RESOLVE_DEFAULT_FBO) && FLIP_RESOLVE_DEFAULT_FBO
1474         if (currentFrameBuffer_->resolveFbo[currentSubPass_] == 0) {
1475             // flip if resolving to default fbo. (NOTE: sample count of destination must be zero or equal to source)
1476             // and in mali devices src and dst rects MUST be equal. (which is not according to spec)
1477             // IE. can't flip and resolve at the same time on MALI based devices.
1478             // NEED A FIX HERE!
1479             glBlitFramebuffer(0, 0, static_cast<GLint>(currentFrameBuffer_->width),
1480                 static_cast<GLint>(currentFrameBuffer_->height), 0, static_cast<GLint>(currentFrameBuffer_->height),
1481                 static_cast<GLint>(currentFrameBuffer_->width), 0, mask, GL_NEAREST);
1482             return GL_READ_FRAMEBUFFER;
1483         }
1484 #endif
1485         glBlitFramebuffer(0, 0, static_cast<GLint>(currentFrameBuffer_->width),
1486             static_cast<GLint>(currentFrameBuffer_->height), 0, 0, static_cast<GLint>(currentFrameBuffer_->width),
1487             static_cast<GLint>(currentFrameBuffer_->height), mask,
1488             GL_NEAREST); // no flip
1489         return GL_READ_FRAMEBUFFER;
1490     }
1491     return GL_FRAMEBUFFER;
1492 }
1493 
RenderCommandEndRenderPass(const RenderCommandWithType & ref)1494 void RenderBackendGLES::RenderCommandEndRenderPass(const RenderCommandWithType& ref)
1495 {
1496     PLUGIN_ASSERT(ref.type == RenderCommandType::END_RENDER_PASS);
1497     const auto& renderCmd = *static_cast<const struct RenderCommandEndRenderPass*>(ref.rc);
1498     if (renderCmd.endType == RenderPassEndType::END_RENDER_PASS) {
1499         PLUGIN_ASSERT_MSG(inRenderpass_ == 1, "RenderBackendGLES endrenderpass mInRenderpass %u", inRenderpass_);
1500         inRenderpass_--;
1501     }
1502     PLUGIN_ASSERT(currentFrameBuffer_);
1503     if (currentFrameBuffer_ == nullptr) {
1504         // Completely invalid state in backend.
1505         return;
1506     }
1507     const auto& rpd = activeRenderPass_.renderPassDesc;
1508     const auto& currentSubPass = activeRenderPass_.subpasses[currentSubPass_];
1509 
1510     // Resolve MSAA
1511     const uint32_t fbType = ResolveMSAA(rpd, currentSubPass);
1512 
1513     // Finally invalidate color and depth..
1514     GLenum invalidate[PipelineStateConstants::MAX_COLOR_ATTACHMENT_COUNT + 1] = {};
1515     int32_t invalidateCount = InvalidateColor(invalidate, rpd, currentSubPass);
1516     invalidateCount += InvalidateDepthStencil(
1517         array_view(invalidate + invalidateCount, countof(invalidate) - invalidateCount), rpd, currentSubPass);
1518 
1519     // NOTE: all attachments should be the same size AND mCurrentFrameBuffer->width/height should match that!
1520     Invalidate(fbType, invalidateCount, invalidate, rpd, *currentFrameBuffer_);
1521 
1522     if (inRenderpass_ == 0) {
1523         currentFrameBuffer_ = nullptr;
1524     }
1525 }
1526 
RenderCommandBindVertexBuffers(const RenderCommandWithType & ref)1527 void RenderBackendGLES::RenderCommandBindVertexBuffers(const RenderCommandWithType& ref)
1528 {
1529     PLUGIN_ASSERT(ref.type == RenderCommandType::BIND_VERTEX_BUFFERS);
1530     const auto& renderCmd = *static_cast<const struct RenderCommandBindVertexBuffers*>(ref.rc);
1531     PLUGIN_ASSERT(renderCmd.vertexBufferCount > 0);
1532     PLUGIN_ASSERT(renderCmd.vertexBufferCount <= PipelineStateConstants::MAX_VERTEX_BUFFER_COUNT);
1533     PLUGIN_ASSERT(boundGraphicsPipeline_);
1534     if (!boundGraphicsPipeline_) {
1535         return;
1536     }
1537     vertexAttribBinds_ = renderCmd.vertexBufferCount;
1538     for (size_t i = 0; i < renderCmd.vertexBufferCount; i++) {
1539         const auto& currVb = renderCmd.vertexBuffers[i];
1540         const auto* gpuBuffer = gpuResourceMgr_.GetBuffer<GpuBufferGLES>(currVb.bufferHandle);
1541         PLUGIN_ASSERT(gpuBuffer);
1542         if (gpuBuffer) {
1543             const auto& plat = gpuBuffer->GetPlatformData();
1544             uintptr_t offset = currVb.bufferOffset;
1545             offset += plat.currentByteOffset;
1546             vertexAttribBindSlots_[i].id = plat.buffer;
1547             vertexAttribBindSlots_[i].offset = static_cast<intptr_t>(offset);
1548         } else {
1549             vertexAttribBindSlots_[i].id = 0;
1550             vertexAttribBindSlots_[i].offset = 0;
1551         }
1552     }
1553 }
1554 
RenderCommandBindIndexBuffer(const RenderCommandWithType & ref)1555 void RenderBackendGLES::RenderCommandBindIndexBuffer(const RenderCommandWithType& ref)
1556 {
1557     PLUGIN_ASSERT(ref.type == RenderCommandType::BIND_INDEX_BUFFER);
1558     const auto& renderCmd = *static_cast<const struct RenderCommandBindIndexBuffer*>(ref.rc);
1559     const GpuBufferGLES* gpuBuffer = gpuResourceMgr_.GetBuffer<GpuBufferGLES>(renderCmd.indexBuffer.bufferHandle);
1560     PLUGIN_ASSERT(gpuBuffer);
1561     if (gpuBuffer) {
1562         const auto& plat = gpuBuffer->GetPlatformData();
1563         boundIndexBuffer_.offset = renderCmd.indexBuffer.bufferOffset;
1564         boundIndexBuffer_.offset += plat.currentByteOffset;
1565         boundIndexBuffer_.type = renderCmd.indexBuffer.indexType;
1566         boundIndexBuffer_.id = plat.buffer;
1567     }
1568 }
1569 
RenderCommandBlitImage(const RenderCommandWithType & ref)1570 void RenderBackendGLES::RenderCommandBlitImage(const RenderCommandWithType& ref)
1571 {
1572     PLUGIN_ASSERT(ref.type == RenderCommandType::BLIT_IMAGE);
1573     const auto& renderCmd = *static_cast<const struct RenderCommandBlitImage*>(ref.rc);
1574     const auto* srcImage = gpuResourceMgr_.GetImage<GpuImageGLES>(renderCmd.srcHandle);
1575     const auto* dstImage = gpuResourceMgr_.GetImage<GpuImageGLES>(renderCmd.dstHandle);
1576     PLUGIN_ASSERT_MSG(srcImage, "RenderCommandBlitImage srcImage==nullptr");
1577     PLUGIN_ASSERT_MSG(dstImage, "RenderCommandBlitImage dstImage==nullptr");
1578     if ((srcImage == nullptr) || (dstImage == nullptr)) {
1579         return;
1580     }
1581     const auto& srcDesc = srcImage->GetDesc();
1582     const auto& srcPlat = srcImage->GetPlatformData();
1583     const auto& dstDesc = dstImage->GetDesc();
1584     const auto& dstPlat = dstImage->GetPlatformData();
1585     const auto& srcRect = renderCmd.imageBlit.srcOffsets;
1586     const auto& dstRect = renderCmd.imageBlit.dstOffsets;
1587     const auto& src = renderCmd.imageBlit.srcSubresource;
1588     const auto& dst = renderCmd.imageBlit.dstSubresource;
1589     const GLint srcMipLevel = static_cast<GLint>(src.mipLevel);
1590     const GLint dstMipLevel = static_cast<GLint>(dst.mipLevel);
1591     const uint32_t srcSampleCount = static_cast<uint32_t>(srcDesc.sampleCountFlags);
1592     const uint32_t dstSampleCount = static_cast<uint32_t>(dstDesc.sampleCountFlags);
1593     PLUGIN_ASSERT_MSG(src.layerCount == dst.layerCount, "Source and Destination layercounts do not match!");
1594     PLUGIN_ASSERT_MSG(inRenderpass_ == 0, "RenderCommandBlitImage while inRenderPass");
1595     glDisable(GL_SCISSOR_TEST);
1596     scissorEnabled_ = false;
1597     // NOTE: LAYERS! (texture arrays)
1598     device_.BindReadFrameBuffer(blitImageSourceFbo_);
1599     device_.BindWriteFrameBuffer(blitImageDestinationFbo_);
1600     for (uint32_t layer = 0; layer < src.layerCount; layer++) {
1601         const GLenum srcType = getTarget(srcPlat.type, layer, srcSampleCount);
1602         const GLenum dstType = getTarget(dstPlat.type, layer, dstSampleCount);
1603         // glFramebufferTextureLayer for array textures....
1604         glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, srcType, srcPlat.image, srcMipLevel);
1605         glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dstType, dstPlat.image, dstMipLevel);
1606         DoBlit(renderCmd.filter, { src.mipLevel, srcRect[0], srcRect[1], srcDesc.height },
1607             { dst.mipLevel, dstRect[0], dstRect[1], dstDesc.height });
1608         glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, srcType, 0, 0);
1609         glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dstType, 0, 0);
1610     }
1611 }
1612 
RenderCommandCopyBuffer(const RenderCommandWithType & ref)1613 void RenderBackendGLES::RenderCommandCopyBuffer(const RenderCommandWithType& ref)
1614 {
1615     PLUGIN_ASSERT(ref.type == RenderCommandType::COPY_BUFFER);
1616     const auto& renderCmd = *static_cast<const struct RenderCommandCopyBuffer*>(ref.rc);
1617     const auto* srcGpuBuffer = gpuResourceMgr_.GetBuffer<GpuBufferGLES>(renderCmd.srcHandle);
1618     const auto* dstGpuBuffer = gpuResourceMgr_.GetBuffer<GpuBufferGLES>(renderCmd.dstHandle);
1619     PLUGIN_ASSERT(srcGpuBuffer);
1620     PLUGIN_ASSERT(dstGpuBuffer);
1621     if (srcGpuBuffer && dstGpuBuffer) {
1622         const auto& srcData = srcGpuBuffer->GetPlatformData();
1623         const auto& dstData = dstGpuBuffer->GetPlatformData();
1624         const auto oldBindR = device_.BoundBuffer(GL_COPY_READ_BUFFER);
1625         const auto oldBindW = device_.BoundBuffer(GL_COPY_WRITE_BUFFER);
1626         device_.BindBuffer(GL_COPY_READ_BUFFER, srcData.buffer);
1627         device_.BindBuffer(GL_COPY_WRITE_BUFFER, dstData.buffer);
1628         glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER,
1629             static_cast<GLintptr>(renderCmd.bufferCopy.srcOffset),
1630             static_cast<GLintptr>(renderCmd.bufferCopy.dstOffset), static_cast<GLsizeiptr>(renderCmd.bufferCopy.size));
1631         device_.BindBuffer(GL_COPY_READ_BUFFER, oldBindR);
1632         device_.BindBuffer(GL_COPY_WRITE_BUFFER, oldBindW);
1633     }
1634 }
1635 
BufferToImageCopy(const struct RenderCommandCopyBufferImage & renderCmd)1636 void RenderBackendGLES::BufferToImageCopy(const struct RenderCommandCopyBufferImage& renderCmd)
1637 {
1638 #if (RENDER_HAS_GLES_BACKEND == 1) & defined(_WIN32)
1639     // use the workaround only for gles backend on windows. (pvr simulator bug)
1640     constexpr const bool usePixelUnpackBuffer = false;
1641 #else
1642     // expect this to work, and the nvidia bug to be fixed.
1643     constexpr const bool usePixelUnpackBuffer = true;
1644 #endif
1645     auto* srcGpuBuffer = gpuResourceMgr_.GetBuffer<GpuBufferGLES>(renderCmd.srcHandle);
1646     auto* dstGpuImage = gpuResourceMgr_.GetImage<GpuImageGLES>(renderCmd.dstHandle);
1647     PLUGIN_ASSERT(srcGpuBuffer);
1648     PLUGIN_ASSERT(dstGpuImage);
1649     if ((srcGpuBuffer == nullptr) || (dstGpuImage == nullptr)) {
1650         return;
1651     }
1652     const auto info = SetupBlit<usePixelUnpackBuffer>(device_, renderCmd.bufferImageCopy, *srcGpuBuffer, *dstGpuImage);
1653     if (info.iPlat.type == GL_TEXTURE_CUBE_MAP) {
1654         BlitCube(device_, info);
1655     } else if (info.iPlat.type == GL_TEXTURE_2D) {
1656         Blit2D(device_, info);
1657     } else if (info.iPlat.type == GL_TEXTURE_2D_ARRAY) {
1658         BlitArray(device_, info);
1659 #if RENDER_HAS_GLES_BACKEND
1660     } else if (info.iPlat.type == GL_TEXTURE_EXTERNAL_OES) {
1661         PLUGIN_LOG_E("Tried to copy to GL_TEXTURE_EXTERNAL_OES. Ignored!");
1662 #endif
1663     } else {
1664         PLUGIN_ASSERT_MSG(false, "RenderCommandCopyBufferImage unhandled type");
1665     }
1666     FinishBlit<usePixelUnpackBuffer>(device_, *srcGpuBuffer);
1667 }
1668 
ImageToBufferCopy(const struct RenderCommandCopyBufferImage & renderCmd)1669 void RenderBackendGLES::ImageToBufferCopy(const struct RenderCommandCopyBufferImage& renderCmd)
1670 {
1671     const auto& bc = renderCmd.bufferImageCopy;
1672     const auto* srcGpuImage = static_cast<GpuImageGLES*>(gpuResourceMgr_.GetImage(renderCmd.srcHandle));
1673     const auto* dstGpuBuffer = static_cast<GpuBufferGLES*>(gpuResourceMgr_.GetBuffer(renderCmd.dstHandle));
1674     PLUGIN_ASSERT(srcGpuImage);
1675     PLUGIN_ASSERT(dstGpuBuffer);
1676     if ((srcGpuImage == nullptr) || (dstGpuBuffer == nullptr)) {
1677         return;
1678     }
1679     const auto& iPlat = static_cast<const GpuImagePlatformDataGL&>(srcGpuImage->GetPlatformData());
1680     const auto& bPlat = static_cast<const GpuBufferPlatformDataGL&>(dstGpuBuffer->GetPlatformData());
1681     if ((iPlat.type != GL_TEXTURE_CUBE_MAP) && (iPlat.type != GL_TEXTURE_2D)) {
1682         PLUGIN_LOG_E("Unsupported texture type in ImageToBufferCopy %x", iPlat.type);
1683         return;
1684     }
1685     device_.BindReadFrameBuffer(blitImageSourceFbo_);
1686     PLUGIN_ASSERT(bc.imageSubresource.layerCount == 1);
1687     GLenum type = GL_TEXTURE_2D;
1688     if (iPlat.type == GL_TEXTURE_CUBE_MAP) {
1689         type = getCubeMapTarget(iPlat.type, bc.imageSubresource.baseArrayLayer);
1690     }
1691     // glFramebufferTextureLayer for array textures....
1692     glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, type, static_cast<GLuint>(iPlat.image),
1693         static_cast<GLint>(bc.imageSubresource.mipLevel));
1694     const Math::UVec2 sPos { bc.imageOffset.width, bc.imageOffset.height };
1695     const Math::UVec2 sExt { bc.imageExtent.width, bc.imageExtent.height };
1696     device_.BindBuffer(GL_PIXEL_PACK_BUFFER, bPlat.buffer);
1697     glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(bc.bufferRowLength));
1698     glPixelStorei(GL_PACK_ALIGNMENT, 1);
1699     uintptr_t dstOffset = bc.bufferOffset + bPlat.currentByteOffset;
1700     glReadnPixels(static_cast<GLint>(sPos.x), static_cast<GLint>(sPos.y), static_cast<GLsizei>(sExt.x),
1701         static_cast<GLsizei>(sExt.y), iPlat.format, static_cast<GLenum>(iPlat.dataType),
1702         static_cast<GLsizei>(bPlat.alignedByteSize), reinterpret_cast<void*>(dstOffset));
1703     device_.BindBuffer(GL_PIXEL_PACK_BUFFER, 0);
1704     glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, type, 0, 0);
1705 }
1706 
RenderCommandCopyBufferImage(const RenderCommandWithType & ref)1707 void RenderBackendGLES::RenderCommandCopyBufferImage(const RenderCommandWithType& ref)
1708 {
1709     PLUGIN_ASSERT(ref.type == RenderCommandType::COPY_BUFFER_IMAGE);
1710     const auto& renderCmd = *static_cast<const struct RenderCommandCopyBufferImage*>(ref.rc);
1711     PLUGIN_ASSERT(inRenderpass_ == 0); // this command should never run during renderpass..
1712     if (renderCmd.copyType == RenderCommandCopyBufferImage::CopyType::BUFFER_TO_IMAGE) {
1713         BufferToImageCopy(renderCmd);
1714     } else if (renderCmd.copyType == RenderCommandCopyBufferImage::CopyType::IMAGE_TO_BUFFER) {
1715         ImageToBufferCopy(renderCmd);
1716     } else {
1717         // IMPLEMENT IMAGE TO BUFFER mode.
1718         PLUGIN_LOG_E("RenderBackendGLES::RenderCommandCopyBufferImage: Not implemented RenderCommandCopyBufferImage");
1719     }
1720 }
1721 
RenderCommandCopyImage(const RenderCommandWithType & ref)1722 void RenderBackendGLES::RenderCommandCopyImage(const RenderCommandWithType& ref)
1723 {
1724     PLUGIN_ASSERT(ref.type == RenderCommandType::COPY_IMAGE);
1725     PLUGIN_ASSERT(inRenderpass_ == 0); // this command should never run during renderpass..
1726     {
1727         // IMPLEMENT IMAGE TO IMAGE mode.
1728         PLUGIN_LOG_E("RenderBackendGLES::RenderCommandCopyBufferImage: Not implemented RenderCommandCopyImage");
1729     }
1730 }
1731 
RenderCommandBarrierPoint(const RenderCommandWithType & ref)1732 void RenderBackendGLES::RenderCommandBarrierPoint(const RenderCommandWithType& ref)
1733 {
1734     PLUGIN_ASSERT(ref.type == RenderCommandType::BARRIER_POINT);
1735     const auto& renderCmd = *static_cast<const struct RenderCommandBarrierPoint*>(ref.rc);
1736     const auto& rbList = *managers_.rbList;
1737     // NOTE: proper flagging of barriers.
1738     if (const RenderBarrierList::BarrierPointBarriers* barrierPointBarriers =
1739             rbList.GetBarrierPointBarriers(renderCmd.barrierPointIndex);
1740         barrierPointBarriers) {
1741         const uint32_t barrierListCount = barrierPointBarriers->barrierListCount;
1742         const auto* nextBarrierList = barrierPointBarriers->firstBarrierList;
1743         GLbitfield barriers = 0;
1744         GLbitfield barriersByRegion = 0;
1745         for (uint32_t barrierListIndex = 0; barrierListIndex < barrierListCount; ++barrierListIndex) {
1746             if (nextBarrierList == nullptr) {
1747                 // cannot be null, just a safety
1748                 PLUGIN_ASSERT(false);
1749                 return;
1750             }
1751             const auto& barrierListRef = *nextBarrierList;
1752             nextBarrierList = barrierListRef.nextBarrierPointBarrierList; // advance to next
1753             const uint32_t barrierCount = barrierListRef.count;
1754             // helper which covers barriers supported by Barrier and BarrierByRegion
1755             auto commonBarrierBits = [](AccessFlags accessFlags, RenderHandleType resourceType) -> GLbitfield {
1756                 GLbitfield barriers = 0;
1757                 if (accessFlags & CORE_ACCESS_UNIFORM_READ_BIT) {
1758                     barriers |= GL_UNIFORM_BARRIER_BIT;
1759                 }
1760                 if (accessFlags & CORE_ACCESS_SHADER_READ_BIT) {
1761                     // shader read covers UBO, SSBO, storage image etc. use resource type to limit the options.
1762                     if (resourceType == RenderHandleType::GPU_IMAGE) {
1763                         barriers |= GL_TEXTURE_FETCH_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT;
1764                     } else if (resourceType == RenderHandleType::GPU_BUFFER) {
1765                         barriers |= GL_UNIFORM_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT;
1766                     } else {
1767                         barriers |= GL_UNIFORM_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT |
1768                                     GL_TEXTURE_FETCH_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT;
1769                     }
1770                 }
1771                 if (accessFlags & CORE_ACCESS_SHADER_WRITE_BIT) {
1772                     if (resourceType == RenderHandleType::GPU_IMAGE) {
1773                         barriers |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT;
1774                     } else if (resourceType == RenderHandleType::GPU_BUFFER) {
1775                         barriers |= GL_SHADER_STORAGE_BARRIER_BIT;
1776                     } else {
1777                         barriers |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT;
1778                     }
1779                 }
1780                 if (accessFlags & (CORE_ACCESS_INPUT_ATTACHMENT_READ_BIT | CORE_ACCESS_COLOR_ATTACHMENT_READ_BIT |
1781                                       CORE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT)) {
1782                     barriers |= GL_FRAMEBUFFER_BARRIER_BIT;
1783                 }
1784                 // GL_ATOMIC_COUNTER_BARRIER_BIT is not used at the moment
1785                 return barriers;
1786             };
1787             for (uint32_t barrierIdx = 0; barrierIdx < barrierCount; ++barrierIdx) {
1788                 const auto& barrier = barrierListRef.commandBarriers[barrierIdx];
1789 
1790                 // check if written by previous shader as an attachment or storage/ image buffer
1791                 if (barrier.src.accessFlags & (CORE_ACCESS_SHADER_WRITE_BIT | CORE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
1792                                                   CORE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT)) {
1793                     const auto resourceHandle = barrier.resourceHandle;
1794                     const auto handleType = RenderHandleUtil::GetHandleType(resourceHandle);
1795 
1796                     // barrier by region is between fragment shaders and supports a subset of barriers.
1797                     if ((barrier.src.pipelineStageFlags & CORE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT) &&
1798                         (barrier.dst.pipelineStageFlags & CORE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT)) {
1799                         barriersByRegion |= commonBarrierBits(barrier.dst.accessFlags, handleType);
1800                     } else {
1801                         // check the barriers shared with ByRegion
1802                         barriers |= commonBarrierBits(barrier.dst.accessFlags, handleType);
1803 
1804                         // the rest are invalid for ByRegion
1805                         if (barrier.dst.accessFlags & CORE_ACCESS_INDIRECT_COMMAND_READ_BIT) {
1806                             barriers |= GL_COMMAND_BARRIER_BIT;
1807                         }
1808                         if (barrier.dst.accessFlags & CORE_ACCESS_INDEX_READ_BIT) {
1809                             barriers |= GL_ELEMENT_ARRAY_BARRIER_BIT;
1810                         }
1811                         if (barrier.dst.accessFlags & CORE_ACCESS_VERTEX_ATTRIBUTE_READ_BIT) {
1812                             barriers |= GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT;
1813                         }
1814                         // which are the correct accessFlags?
1815                         // GL_PIXEL_BUFFER_BARRIER_BIT:
1816                         // - buffer objects via the GL_PIXEL_PACK_BUFFER and GL_PIXEL_UNPACK_BUFFER bindings (via
1817                         // glReadPixels, glTexSubImage1D, etc.)
1818                         // GL_TEXTURE_UPDATE_BARRIER_BIT:
1819                         // - texture via glTex(Sub)Image*, glCopyTex(Sub)Image*, glCompressedTex(Sub)Image*, and reads
1820                         // via glGetTexImage GL_BUFFER_UPDATE_BARRIER_BIT:
1821                         // - glBufferSubData, glCopyBufferSubData, or glGetBufferSubData, or to buffer object memory
1822                         // mapped
1823                         //  by glMapBuffer or glMapBufferRange
1824                         // These two are cover all memory access, CORE_ACCESS_MEMORY_READ_BIT,
1825                         // CORE_ACCESS_MEMORY_WRITE_BIT?
1826                         if (barrier.dst.accessFlags & (CORE_ACCESS_TRANSFER_READ_BIT | CORE_ACCESS_TRANSFER_WRITE_BIT |
1827                                                           CORE_ACCESS_HOST_READ_BIT | CORE_ACCESS_HOST_WRITE_BIT)) {
1828                             if (handleType == RenderHandleType::GPU_IMAGE) {
1829                                 barriers |= GL_TEXTURE_UPDATE_BARRIER_BIT;
1830                             } else if (handleType == RenderHandleType::GPU_BUFFER) {
1831                                 barriers |= GL_BUFFER_UPDATE_BARRIER_BIT | GL_PIXEL_BUFFER_BARRIER_BIT;
1832                             }
1833                         }
1834                         // GL_TRANSFORM_FEEDBACK_BARRIER_BIT is not used at the moment
1835                     }
1836                 }
1837             }
1838         }
1839         if (barriers) {
1840             glMemoryBarrier(barriers);
1841         }
1842         if (barriersByRegion) {
1843             // only for fragment-fragment
1844             glMemoryBarrierByRegion(barriersByRegion);
1845         }
1846     }
1847 }
1848 
RenderCommandUpdateDescriptorSets(const RenderCommandWithType & ref)1849 void RenderBackendGLES::RenderCommandUpdateDescriptorSets(const RenderCommandWithType& ref)
1850 {
1851     PLUGIN_ASSERT(ref.type == RenderCommandType::UPDATE_DESCRIPTOR_SETS);
1852 #if (RENDER_VALIDATION_ENABLED == 1)
1853     const auto& renderCmd = *static_cast<const struct RenderCommandUpdateDescriptorSets*>(ref.rc);
1854     auto& aNcdsm = *managers_.descriptorSetMgr;
1855     {
1856         for (uint32_t descIdx = 0; descIdx < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT; ++descIdx) {
1857             const auto descHandle = renderCmd.descriptorSetHandles[descIdx];
1858             if (RenderHandleUtil::GetHandleType(descHandle) != RenderHandleType::DESCRIPTOR_SET) {
1859                 continue;
1860             }
1861 
1862             // first update gpu descriptor indices
1863             aNcdsm.UpdateDescriptorSetGpuHandle(descHandle);
1864         }
1865     }
1866 #endif
1867 }
1868 
SetupBind(const DescriptorSetLayoutBinding & binding,vector<Gles::Bind> & resources)1869 Gles::Bind& RenderBackendGLES::SetupBind(const DescriptorSetLayoutBinding& binding, vector<Gles::Bind>& resources)
1870 {
1871     PLUGIN_ASSERT(binding.binding < resources.size());
1872     auto& obj = resources[binding.binding];
1873     PLUGIN_ASSERT(obj.resources.size() == binding.descriptorCount);
1874     PLUGIN_ASSERT(obj.descriptorType == binding.descriptorType);
1875     return obj;
1876 }
1877 
BindSampler(const BindableSampler & res,Gles::Bind & obj,uint32_t index)1878 void RenderBackendGLES::BindSampler(const BindableSampler& res, Gles::Bind& obj, uint32_t index)
1879 {
1880     const auto* gpuSampler = gpuResourceMgr_.GetSampler<GpuSamplerGLES>(res.handle);
1881     if (gpuSampler) {
1882         const auto& plat = gpuSampler->GetPlatformData();
1883         obj.resources[index].sampler.samplerId = plat.sampler;
1884     } else {
1885         obj.resources[index].sampler.samplerId = 0;
1886     }
1887 }
1888 
BindImage(const BindableImage & res,const GpuResourceState & resState,Gles::Bind & obj,uint32_t index)1889 void RenderBackendGLES::BindImage(
1890     const BindableImage& res, const GpuResourceState& resState, Gles::Bind& obj, uint32_t index)
1891 {
1892     const AccessFlags accessFlags = resState.accessFlags;
1893     auto* gpuImage = gpuResourceMgr_.GetImage<GpuImageGLES>(res.handle);
1894     auto& ref = obj.resources[index];
1895     ref.image.image = gpuImage;
1896     const bool read = IS_BIT(accessFlags, CORE_ACCESS_SHADER_READ_BIT);
1897     const bool write = IS_BIT(accessFlags, CORE_ACCESS_SHADER_WRITE_BIT);
1898     if (read && write) {
1899         ref.image.mode = GL_READ_WRITE;
1900     } else if (read) {
1901         ref.image.mode = GL_READ_ONLY;
1902     } else if (write) {
1903         ref.image.mode = GL_WRITE_ONLY;
1904     } else {
1905         // no read and no write?
1906         ref.image.mode = GL_READ_WRITE;
1907     }
1908     ref.image.mipLevel = res.mip;
1909 }
1910 
BindImageSampler(const BindableImage & res,const GpuResourceState & resState,Gles::Bind & obj,uint32_t index)1911 void RenderBackendGLES::BindImageSampler(
1912     const BindableImage& res, const GpuResourceState& resState, Gles::Bind& obj, uint32_t index)
1913 {
1914     BindImage(res, resState, obj, index);
1915     BindSampler(BindableSampler { res.samplerHandle }, obj, index);
1916 }
1917 
BindBuffer(const BindableBuffer & res,Gles::Bind & obj,uint32_t dynamicOffset,uint32_t index)1918 void RenderBackendGLES::BindBuffer(const BindableBuffer& res, Gles::Bind& obj, uint32_t dynamicOffset, uint32_t index)
1919 {
1920     const auto* gpuBuffer = gpuResourceMgr_.GetBuffer<GpuBufferGLES>(res.handle);
1921     if (gpuBuffer) {
1922         const auto& plat = gpuBuffer->GetPlatformData();
1923         const uint32_t baseOffset = res.byteOffset;
1924         obj.resources[index].buffer.offset = baseOffset + plat.currentByteOffset + dynamicOffset;
1925         obj.resources[index].buffer.size = std::min(plat.bindMemoryByteSize - baseOffset, res.byteSize);
1926         obj.resources[index].buffer.bufferId = plat.buffer;
1927     } else {
1928         obj.resources[index].buffer.offset = 0;
1929         obj.resources[index].buffer.size = 0;
1930         obj.resources[index].buffer.bufferId = 0;
1931     }
1932 }
1933 
ProcessBindings(const struct RenderCommandBindDescriptorSets & renderCmd,const DescriptorSetLayoutBindingResources & data,uint32_t set,uint32_t & curDynamic)1934 void RenderBackendGLES::ProcessBindings(const struct RenderCommandBindDescriptorSets& renderCmd,
1935     const DescriptorSetLayoutBindingResources& data, uint32_t set, uint32_t& curDynamic)
1936 {
1937     BindState& bind = boundObjects_[set];
1938     vector<Gles::Bind>& resources = bind.resources;
1939 #if RENDER_HAS_GLES_BACKEND
1940     bind.oesBinds.clear();
1941 #endif
1942     const auto& buffers = data.buffers;
1943     const auto& images = data.images;
1944     const auto& samplers = data.samplers;
1945     for (const auto& res : data.bindings) {
1946         auto& obj = SetupBind(res.binding, resources);
1947 #if RENDER_HAS_GLES_BACKEND
1948         bool hasOes = false;
1949 #endif
1950         auto GetArrayOffset = [](const auto& data, const auto& res) {
1951             const RenderHandleType type = GetRenderHandleType(res.binding.descriptorType);
1952             if (type == RenderHandleType::GPU_BUFFER) {
1953                 return data.buffers[res.resourceIndex].arrayOffset;
1954             } else if (type == RenderHandleType::GPU_IMAGE) {
1955                 return data.images[res.resourceIndex].arrayOffset;
1956             } else if (type == RenderHandleType::GPU_SAMPLER) {
1957                 return data.samplers[res.resourceIndex].arrayOffset;
1958             }
1959             return 0u;
1960         };
1961         const bool hasArrOffset = (res.binding.descriptorCount > 1);
1962         const uint32_t arrayOffset = hasArrOffset ? GetArrayOffset(data, res) : 0;
1963         for (uint8_t index = 0; index < res.binding.descriptorCount; index++) {
1964             const uint32_t resIdx = (index == 0) ? res.resourceIndex : (arrayOffset + index - 1);
1965             GpuImageGLES* image = nullptr;
1966             switch (res.binding.descriptorType) {
1967                 case CORE_DESCRIPTOR_TYPE_SAMPLER: {
1968                     const auto& bRes = samplers[resIdx];
1969                     BindSampler(bRes.resource, obj, index);
1970                     break;
1971                 }
1972                 case CORE_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
1973                 case CORE_DESCRIPTOR_TYPE_STORAGE_IMAGE:
1974                 case CORE_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
1975                     const auto& bRes = images[resIdx];
1976                     BindImage(bRes.resource, bRes.state, obj, index);
1977                     image = obj.resources[index].image.image;
1978                     break;
1979                 }
1980                 case CORE_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
1981                     const auto& bRes = images[resIdx];
1982                     BindImageSampler(bRes.resource, bRes.state, obj, index);
1983                     image = obj.resources[index].image.image;
1984                     break;
1985                 }
1986                 case CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
1987                 case CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
1988                     const auto& bRes = buffers[resIdx];
1989                     uint32_t dynamicOffset = 0;
1990                     if (curDynamic < renderCmd.dynamicOffsetCount) {
1991                         dynamicOffset = renderCmd.dynamicOffsets[curDynamic];
1992                         curDynamic++;
1993                     }
1994                     BindBuffer(bRes.resource, obj, dynamicOffset, index);
1995                     break;
1996                 }
1997                 case CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
1998                 case CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER: {
1999                     const auto& bRes = buffers[resIdx];
2000                     BindBuffer(bRes.resource, obj, 0, index);
2001                     break;
2002                 }
2003                 case CORE_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
2004                 case CORE_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
2005                 case CORE_DESCRIPTOR_TYPE_MAX_ENUM:
2006                 default:
2007                     PLUGIN_ASSERT_MSG(false, "Unhandled descriptor type");
2008                     break;
2009             }
2010 #if RENDER_HAS_GLES_BACKEND
2011             if ((image) && (image->GetPlatformData().type == GL_TEXTURE_EXTERNAL_OES)) {
2012                 hasOes = true;
2013             }
2014 #endif
2015         }
2016 #if RENDER_HAS_GLES_BACKEND
2017         if (hasOes) {
2018             bind.oesBinds.push_back(OES_Bind { (uint8_t)set, (uint8_t)res.binding.binding });
2019         }
2020 #endif
2021     }
2022 }
2023 
RenderCommandBindDescriptorSets(const RenderCommandWithType & ref)2024 void RenderBackendGLES::RenderCommandBindDescriptorSets(const RenderCommandWithType& ref)
2025 {
2026     PLUGIN_ASSERT(ref.type == RenderCommandType::BIND_DESCRIPTOR_SETS);
2027     PLUGIN_ASSERT_MSG((boundComputePipeline_ || boundGraphicsPipeline_), "No pipeline bound!");
2028     const auto& renderCmd = *static_cast<const struct RenderCommandBindDescriptorSets*>(ref.rc);
2029     PLUGIN_ASSERT_MSG(renderCmd.psoHandle == currentPsoHandle_, "psoHandle mismatch");
2030 
2031     const auto& aNcdsm = *managers_.descriptorSetMgr;
2032     uint32_t CurDynamic = 0;
2033     for (uint32_t idx = renderCmd.firstSet; idx < renderCmd.firstSet + renderCmd.setCount; ++idx) {
2034         PLUGIN_ASSERT_MSG(idx < Gles::ResourceLimits::MAX_SETS, "Invalid descriptorset index");
2035         const auto descriptorSetHandle = renderCmd.descriptorSetHandles[idx];
2036         PLUGIN_ASSERT(RenderHandleUtil::IsValid(descriptorSetHandle));
2037         const auto& data = aNcdsm.GetCpuDescriptorSetData(descriptorSetHandle);
2038         boundObjects_[idx].dirty = true; // mark the set as "changed"
2039         ProcessBindings(renderCmd, data, idx, CurDynamic);
2040         // (note, nothing actually gets bound yet.. just the bind cache is updated)
2041     }
2042 }
2043 
SetPushConstant(uint32_t program,const Gles::PushConstantReflection & pc,const void * data)2044 void RenderBackendGLES::SetPushConstant(uint32_t program, const Gles::PushConstantReflection& pc, const void* data)
2045 {
2046     const GLint location = static_cast<GLint>(pc.location);
2047     // the consts list has been filtered and cleared of unused uniforms.
2048     PLUGIN_ASSERT(location != Gles::INVALID_LOCATION);
2049     GLint count = Math::max(static_cast<GLint>(pc.arraySize), 1);
2050     switch (pc.type) {
2051         case GL_UNSIGNED_INT: {
2052             glProgramUniform1uiv(program, location, count, static_cast<const GLuint*>(data));
2053             break;
2054         }
2055         case GL_FLOAT: {
2056             glProgramUniform1fv(program, location, count, static_cast<const GLfloat*>(data));
2057             break;
2058         }
2059         case GL_FLOAT_VEC2: {
2060             glProgramUniform2fv(program, location, count, static_cast<const GLfloat*>(data));
2061             break;
2062         }
2063         case GL_FLOAT_VEC4: {
2064             glProgramUniform4fv(program, location, count, static_cast<const GLfloat*>(data));
2065             break;
2066         }
2067         case GL_FLOAT_MAT4: {
2068             glProgramUniformMatrix4fv(program, location, count, false, static_cast<const GLfloat*>(data));
2069             break;
2070         }
2071         case GL_UNSIGNED_INT_VEC4: {
2072             glProgramUniform4uiv(program, location, count, static_cast<const GLuint*>(data));
2073             break;
2074         }
2075         default:
2076             PLUGIN_ASSERT_MSG(false, "Unhandled pushconstant variable type");
2077     }
2078 }
2079 
SetPushConstants(uint32_t program,const array_view<Gles::PushConstantReflection> & consts)2080 void RenderBackendGLES::SetPushConstants(uint32_t program, const array_view<Gles::PushConstantReflection>& consts)
2081 {
2082     if (boundProgram_.setPushConstants) {
2083         boundProgram_.setPushConstants = false;
2084         const auto& renderCmd = boundProgram_.pushConstants;
2085         PLUGIN_ASSERT_MSG(renderCmd.psoHandle == currentPsoHandle_, "psoHandle mismatch");
2086         PLUGIN_ASSERT_MSG(renderCmd.pushConstant.byteSize > 0, "PushConstant byteSize is zero!");
2087         PLUGIN_ASSERT_MSG(renderCmd.data, "PushConstant data is nullptr!");
2088         if ((renderCmd.data == nullptr) || (renderCmd.pushConstant.byteSize == 0))
2089             return;
2090         // ASSERT: expecting data is valid
2091         // NOTE: handle rest of the types
2092         for (const auto& pc : consts) {
2093             const size_t offs = pc.offset;
2094             if ((offs + pc.size) > renderCmd.pushConstant.byteSize) {
2095                 PLUGIN_LOG_E(
2096                     "pushConstant data invalid (data for %s is missing [offset:%zu size:%zu] byteSize of data:%u)",
2097                     pc.name.c_str(), pc.offset, pc.size, renderCmd.pushConstant.byteSize);
2098                 continue;
2099             }
2100             /*
2101             NOTE: handle the strides....
2102             consts[i].array_stride;
2103             consts[i].matrix_stride; */
2104             SetPushConstant(program, pc, &renderCmd.data[offs]);
2105         }
2106     }
2107 }
2108 
RenderCommandPushConstant(const RenderCommandWithType & ref)2109 void RenderBackendGLES::RenderCommandPushConstant(const RenderCommandWithType& ref)
2110 {
2111     PLUGIN_ASSERT(ref.type == RenderCommandType::PUSH_CONSTANT);
2112     PLUGIN_ASSERT_MSG((boundComputePipeline_ || boundGraphicsPipeline_), "No pipeline bound!");
2113     const auto& renderCmd = *static_cast<const struct RenderCommandPushConstant*>(ref.rc);
2114     PLUGIN_ASSERT(renderCmd.pushConstant.byteSize > 0);
2115     PLUGIN_ASSERT(renderCmd.data);
2116     PLUGIN_ASSERT_MSG(renderCmd.psoHandle == currentPsoHandle_, "psoHandle mismatch");
2117     boundProgram_.setPushConstants = true;
2118     boundProgram_.pushConstants = renderCmd;
2119 }
2120 
2121 // dynamic states
RenderCommandDynamicStateViewport(const RenderCommandWithType & ref)2122 void RenderBackendGLES::RenderCommandDynamicStateViewport(const RenderCommandWithType& ref)
2123 {
2124     PLUGIN_ASSERT(ref.type == RenderCommandType::DYNAMIC_STATE_VIEWPORT);
2125     const auto& renderCmd = *static_cast<const struct RenderCommandDynamicStateViewport*>(ref.rc);
2126     const ViewportDesc& vd = renderCmd.viewportDesc;
2127     SetViewport(renderArea_, vd);
2128 }
2129 
RenderCommandDynamicStateScissor(const RenderCommandWithType & ref)2130 void RenderBackendGLES::RenderCommandDynamicStateScissor(const RenderCommandWithType& ref)
2131 {
2132     PLUGIN_ASSERT(ref.type == RenderCommandType::DYNAMIC_STATE_SCISSOR);
2133     const auto& renderCmd = *static_cast<const struct RenderCommandDynamicStateScissor*>(ref.rc);
2134     const ScissorDesc& sd = renderCmd.scissorDesc;
2135     SetScissor(renderArea_, sd);
2136 }
2137 
RenderCommandDynamicStateLineWidth(const RenderCommandWithType & ref)2138 void RenderBackendGLES::RenderCommandDynamicStateLineWidth(const RenderCommandWithType& ref)
2139 {
2140     PLUGIN_ASSERT(ref.type == RenderCommandType::DYNAMIC_STATE_LINE_WIDTH);
2141     const auto& renderCmd = *static_cast<const struct RenderCommandDynamicStateLineWidth*>(ref.rc);
2142     if (renderCmd.lineWidth != cacheState_.rasterizationState.lineWidth) {
2143         cacheState_.rasterizationState.lineWidth = renderCmd.lineWidth;
2144         glLineWidth(renderCmd.lineWidth);
2145     }
2146 }
2147 
RenderCommandDynamicStateDepthBias(const RenderCommandWithType & ref)2148 void RenderBackendGLES::RenderCommandDynamicStateDepthBias(const RenderCommandWithType& ref)
2149 {
2150     PLUGIN_ASSERT(ref.type == RenderCommandType::DYNAMIC_STATE_DEPTH_BIAS);
2151     PLUGIN_ASSERT_MSG(false, "RenderCommandDynamicStateDepthBias not implemented");
2152 }
2153 
RenderCommandDynamicStateBlendConstants(const RenderCommandWithType & ref)2154 void RenderBackendGLES::RenderCommandDynamicStateBlendConstants(const RenderCommandWithType& ref)
2155 {
2156     PLUGIN_ASSERT(ref.type == RenderCommandType::DYNAMIC_STATE_BLEND_CONSTANTS);
2157     PLUGIN_ASSERT_MSG(false, "RenderCommandDynamicStateBlendConstants not implemented");
2158 }
2159 
RenderCommandDynamicStateDepthBounds(const RenderCommandWithType & ref)2160 void RenderBackendGLES::RenderCommandDynamicStateDepthBounds(const RenderCommandWithType& ref)
2161 {
2162     PLUGIN_ASSERT(ref.type == RenderCommandType::DYNAMIC_STATE_DEPTH_BOUNDS);
2163     PLUGIN_ASSERT_MSG(false, "RenderCommandDynamicStateDepthBounds not implemented");
2164 }
2165 
SetStencilState(const uint32_t frontFlags,const GraphicsState::StencilOpState & front,const uint32_t backFlags,const GraphicsState::StencilOpState & back)2166 void RenderBackendGLES::SetStencilState(const uint32_t frontFlags, const GraphicsState::StencilOpState& front,
2167     const uint32_t backFlags, const GraphicsState::StencilOpState& back)
2168 {
2169     auto& cFront = cacheState_.depthStencilState.frontStencilOpState;
2170     auto& cBack = cacheState_.depthStencilState.backStencilOpState;
2171     const uint32_t FUNCMASK =
2172         (StencilSetFlags::SETCOMPAREOP | StencilSetFlags::SETCOMPAREMASK | StencilSetFlags::SETREFERENCE);
2173     if (frontFlags & StencilSetFlags::SETWRITEMASK) {
2174         cFront.writeMask = front.writeMask;
2175         glStencilMaskSeparate(GL_FRONT, cFront.writeMask);
2176     }
2177     if (frontFlags & FUNCMASK) {
2178         setStencilCompareOp(cFront, front);
2179         glStencilFuncSeparate(
2180             GL_FRONT, GetCompareOp(cFront.compareOp), static_cast<GLint>(cFront.reference), cFront.compareMask);
2181     }
2182     if (frontFlags & StencilSetFlags::SETOP) {
2183         SetStencilOp(cFront, front);
2184         glStencilOpSeparate(
2185             GL_FRONT, GetStencilOp(cFront.failOp), GetStencilOp(cFront.depthFailOp), GetStencilOp(cFront.passOp));
2186     }
2187     if (backFlags & StencilSetFlags::SETWRITEMASK) {
2188         cBack.writeMask = back.writeMask;
2189         glStencilMaskSeparate(GL_BACK, cBack.writeMask);
2190     }
2191     if (backFlags & FUNCMASK) {
2192         setStencilCompareOp(cBack, back);
2193         glStencilFuncSeparate(
2194             GL_BACK, GetCompareOp(cBack.compareOp), static_cast<GLint>(cBack.reference), cBack.compareMask);
2195     }
2196     if (backFlags & StencilSetFlags::SETOP) {
2197         SetStencilOp(cBack, back);
2198         glStencilOpSeparate(
2199             GL_FRONT, GetStencilOp(cBack.failOp), GetStencilOp(cBack.depthFailOp), GetStencilOp(cBack.passOp));
2200     }
2201 }
2202 
RenderCommandDynamicStateStencil(const RenderCommandWithType & ref)2203 void RenderBackendGLES::RenderCommandDynamicStateStencil(const RenderCommandWithType& ref)
2204 {
2205     PLUGIN_ASSERT(ref.type == RenderCommandType::DYNAMIC_STATE_STENCIL);
2206     const auto& renderCmd = *static_cast<const struct RenderCommandDynamicStateStencil*>(ref.rc);
2207     auto& cFront = cacheState_.depthStencilState.frontStencilOpState;
2208     auto& cBack = cacheState_.depthStencilState.backStencilOpState;
2209     uint32_t setFront = 0;
2210     uint32_t setBack = 0;
2211     if (renderCmd.faceMask & StencilFaceFlagBits::CORE_STENCIL_FACE_FRONT_BIT) {
2212         if (renderCmd.dynamicState == StencilDynamicState::COMPARE_MASK) {
2213             if (renderCmd.mask != cFront.compareMask) {
2214                 cFront.compareMask = renderCmd.mask;
2215                 setFront |= StencilSetFlags::SETCOMPAREMASK;
2216             }
2217         } else if (renderCmd.dynamicState == StencilDynamicState::WRITE_MASK) {
2218             if (renderCmd.mask != cFront.writeMask) {
2219                 cFront.writeMask = renderCmd.mask;
2220                 setFront |= StencilSetFlags::SETWRITEMASK;
2221             }
2222         } else if (renderCmd.dynamicState == StencilDynamicState::REFERENCE) {
2223             if (renderCmd.mask != cFront.reference) {
2224                 cFront.reference = renderCmd.mask;
2225                 setFront |= StencilSetFlags::SETREFERENCE;
2226             }
2227         }
2228     }
2229     if (renderCmd.faceMask & StencilFaceFlagBits::CORE_STENCIL_FACE_BACK_BIT) {
2230         if (renderCmd.dynamicState == StencilDynamicState::COMPARE_MASK) {
2231             if (renderCmd.mask != cBack.compareMask) {
2232                 cBack.compareMask = renderCmd.mask;
2233                 setBack |= StencilSetFlags::SETCOMPAREMASK;
2234             }
2235         } else if (renderCmd.dynamicState == StencilDynamicState::WRITE_MASK) {
2236             if (renderCmd.mask != cBack.writeMask) {
2237                 cBack.writeMask = renderCmd.mask;
2238                 setBack |= StencilSetFlags::SETWRITEMASK;
2239             }
2240         } else if (renderCmd.dynamicState == StencilDynamicState::REFERENCE) {
2241             if (renderCmd.mask != cBack.reference) {
2242                 cBack.reference = renderCmd.mask;
2243                 setBack |= StencilSetFlags::SETREFERENCE;
2244             }
2245         }
2246     }
2247     SetStencilState(setFront, cFront, setBack, cBack);
2248 }
2249 
RenderCommandExecuteBackendFramePosition(const RenderCommandWithType & renderCmd)2250 void RenderBackendGLES::RenderCommandExecuteBackendFramePosition(const RenderCommandWithType& renderCmd)
2251 {
2252     PLUGIN_ASSERT_MSG(false, "RenderCommandExecuteBackendFramePosition not implemented");
2253 }
2254 
RenderCommandWriteTimestamp(const RenderCommandWithType & renderCmd)2255 void RenderBackendGLES::RenderCommandWriteTimestamp(const RenderCommandWithType& renderCmd)
2256 {
2257     PLUGIN_ASSERT_MSG(false, "RenderCommandWriteTimestamp not implemented");
2258 }
2259 
BindVertexInputs(const VertexInputDeclarationData & decldata,const array_view<const int32_t> & vertexInputs)2260 void RenderBackendGLES::BindVertexInputs(
2261     const VertexInputDeclarationData& decldata, const array_view<const int32_t>& vertexInputs)
2262 {
2263     // update bindings for the VAO.
2264     for (uint32_t i = 0; i < vertexAttribBinds_; i++) {
2265         const auto& slot = vertexAttribBindSlots_[i];
2266         if ((slot.id) && (vertexInputs[i] != Gles::INVALID_LOCATION)) {
2267             const auto& bindingRef = decldata.bindingDescriptions[i];
2268             // buffer bound to slot, and it's used by the shader.
2269             PLUGIN_ASSERT(vertexInputs[i] == (int32_t)i);
2270             device_.BindVertexBuffer(i, slot.id, slot.offset, bindingRef.stride);
2271             /*
2272             core/vulkan
2273             bindingRef.vertexInputRate =  CORE_VERTEX_INPUT_RATE_VERTEX (0)  attribute index advances per vertex
2274             bindingRef.vertexInputRate =  CORE_VERTEX_INPUT_RATE_INSTANCE (1)  attribute index advances per instance
2275 
2276             gl/gles
2277             If divisor is  0, the attributes using the buffer bound to bindingindex advance once per vertex.
2278             If divisor is >0, the attributes advance once per divisor instances of the set(s) of vertices being
2279             rendered.
2280 
2281             so we can directly pass the inputRate as VertexBindingDivisor. (ie. advance once per instance)
2282             ie. enum happens to match and can simply cast.
2283             */
2284             static_assert(CORE_VERTEX_INPUT_RATE_VERTEX == 0 && CORE_VERTEX_INPUT_RATE_INSTANCE == 1);
2285             device_.VertexBindingDivisor(i, static_cast<uint32_t>(bindingRef.vertexInputRate));
2286         } else {
2287             // nothing bound to this slot, do this so we don't get stale data in the shader.
2288             device_.BindVertexBuffer(i, 0, 0, 0);
2289         }
2290     }
2291 }
2292 
BindResources()2293 void RenderBackendGLES::BindResources()
2294 {
2295 #if RENDER_HAS_GLES_BACKEND
2296     // scan all sets here to see if any of the sets has oes.
2297     // we don't actually need to rebuild this info every time.
2298     // should "emulate" the gpu descriptor sets better. (and store this information along with the other bind cache data
2299     // there)
2300     bool needClear = true;
2301     for (size_t set = 0; set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT; set++) {
2302         const auto& oes = boundObjects_[set].oesBinds;
2303         if (!oes.empty()) {
2304             if (needClear) {
2305                 needClear = false;
2306                 oesBinds_.clear();
2307             }
2308             oesBinds_.insert(oesBinds_.end(), oes.begin(), oes.end());
2309         }
2310     }
2311     if (needClear) {
2312         oesBinds_.clear();
2313     }
2314 #endif
2315     const array_view<Binder>* resourceList = nullptr;
2316     const array_view<Gles::PushConstantReflection>* pushConstants = nullptr;
2317     int32_t flipLocation = 0;
2318     uint32_t program = 0;
2319     // Push constants and "fliplocation" uniform (ie. uniform state) should be only updated if changed...
2320     if (currentFrameBuffer_) { // mCurrentFrameBuffer is only set if graphics pipeline is bound..
2321         PLUGIN_ASSERT(boundComputePipeline_ == nullptr);
2322         PLUGIN_ASSERT(boundGraphicsPipeline_);
2323         array_view<const int32_t> vertexInputs;
2324         const auto& pipelineData =
2325             static_cast<const PipelineStateObjectPlatformDataGL&>(boundGraphicsPipeline_->GetPlatformData());
2326         const GpuShaderProgramGLES* shader = pipelineData.graphicsShader;
2327 #if RENDER_HAS_GLES_BACKEND
2328         if (!oesBinds_.empty()) {
2329             // okay, oes vector contains the set/bind to which an OES texture is bounds
2330             // ask for a compatible program from the boundGraphicsPipeline_
2331             shader = boundGraphicsPipeline_->GetOESProgram(oesBinds_);
2332         }
2333 #endif
2334         const auto& sd = static_cast<const GpuShaderProgramPlatformDataGL&>(shader->GetPlatformData());
2335         program = sd.program;
2336         vertexInputs = { sd.inputs, countof(sd.inputs) };
2337         FlushViewportScissors();
2338         if (!scissorEnabled_) {
2339             scissorEnabled_ = true;
2340             glEnable(GL_SCISSOR_TEST); // Always enabled
2341         }
2342 #if (RENDER_PERF_ENABLED == 1)
2343         if (device_.BoundProgram() != program) {
2344             ++perfCounters_.bindProgram;
2345         }
2346 #endif
2347         device_.UseProgram(program);
2348         device_.BindVertexArray(pipelineData.vao);
2349         BindVertexInputs(pipelineData.vertexInputDeclaration, vertexInputs);
2350         device_.BindElementBuffer(boundIndexBuffer_.id);
2351         resourceList = &sd.resourceList;
2352         flipLocation = sd.flipLocation;
2353         pushConstants = &sd.pushConstants;
2354     } else {
2355         PLUGIN_ASSERT(boundGraphicsPipeline_ == nullptr);
2356         PLUGIN_ASSERT(boundComputePipeline_);
2357         const auto& pipelineData =
2358             static_cast<const PipelineStateObjectPlatformDataGL&>(boundComputePipeline_->GetPlatformData());
2359         const auto& sd =
2360             static_cast<const GpuComputeProgramPlatformDataGL&>(pipelineData.computeShader->GetPlatformData());
2361         program = sd.program;
2362 #if (RENDER_PERF_ENABLED == 1)
2363         if (device_.BoundProgram() != program) {
2364             ++perfCounters_.bindProgram;
2365         }
2366 #endif
2367         device_.UseProgram(program);
2368         resourceList = &sd.resourceList;
2369         flipLocation = sd.flipLocation;
2370         pushConstants = &sd.pushConstants;
2371     }
2372 
2373     SetPushConstants(program, *pushConstants);
2374     if (flipLocation != Gles::INVALID_LOCATION) {
2375         const float flip = (renderingToDefaultFbo_) ? (-1.f) : (1.f);
2376         glProgramUniform1fv(program, flipLocation, 1, &flip);
2377     }
2378 
2379     for (const auto& r : *resourceList) {
2380         /* if (!boundObjects_[r.set].dirty) {    //not yet working properly. needs more testing, "rebinds" mitigated by
2381         the lower-level gl state cache. continue;
2382         } */
2383         const auto& res = boundObjects_[r.set].resources[r.bind];
2384         PLUGIN_ASSERT(res.resources.size() == r.id.size());
2385         auto resType = res.descriptorType;
2386         if (resType == CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) {
2387             resType = CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
2388         }
2389         if (resType == CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
2390             resType = CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER;
2391         }
2392         PLUGIN_ASSERT(resType == r.type);
2393         for (uint32_t index = 0; index < res.resources.size(); index++) {
2394             const auto& obj = res.resources[index];
2395             for (const auto& id : r.id[index]) {
2396                 if ((resType == CORE_DESCRIPTOR_TYPE_SAMPLER) ||
2397                     (resType == CORE_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)) {
2398 #if (RENDER_PERF_ENABLED == 1)
2399                     if (device_.BoundSampler(id + index) != obj.sampler.samplerId) {
2400                         ++perfCounters_.bindSampler;
2401                     }
2402 #endif
2403                     device_.BindSampler(id + index, obj.sampler.samplerId);
2404                 }
2405                 if ((resType == CORE_DESCRIPTOR_TYPE_SAMPLED_IMAGE) ||
2406                     (resType == CORE_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) ||
2407                     (resType == CORE_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) ||
2408                     (resType == CORE_DESCRIPTOR_TYPE_STORAGE_IMAGE)) {
2409                     if (obj.image.image) {
2410                         auto& dplat = const_cast<GpuImagePlatformDataGL&>(obj.image.image->GetPlatformData());
2411                         if ((resType == CORE_DESCRIPTOR_TYPE_SAMPLED_IMAGE) ||
2412                             (resType == CORE_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)) {
2413 #if (RENDER_PERF_ENABLED == 1)
2414                             if (device_.BoundTexture(id + index, dplat.type) != dplat.image) {
2415                                 ++perfCounters_.bindTexture;
2416                             }
2417 #endif
2418                             device_.BindTexture(id + index, dplat.type, dplat.image);
2419                         }
2420                         if (resType == CORE_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) {
2421 #if (RENDER_PERF_ENABLED == 1)
2422                             if (device_.BoundTexture(id + index, dplat.type) != dplat.image) {
2423                                 ++perfCounters_.bindTexture;
2424                             }
2425                             if (device_.BoundSampler(id + index) != 0) {
2426                                 ++perfCounters_.bindSampler;
2427                             }
2428 #endif
2429                             device_.BindTexture(id + index, dplat.type, dplat.image);
2430                             device_.BindSampler(id + index, 0);
2431                         }
2432                         if (resType == CORE_DESCRIPTOR_TYPE_STORAGE_IMAGE) {
2433                             uint32_t level = 0;
2434                             if (obj.image.mipLevel != PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS) {
2435                                 level = obj.image.mipLevel;
2436                             }
2437                             device_.BindImageTexture(
2438                                 id + index, dplat.image, level, false, 0, obj.image.mode, dplat.internalFormat);
2439                         } else {
2440                             // Check and update (if needed) the forced miplevel.
2441                             // NOTE: we are actually modifiying the texture object bound above!
2442                             // NOTE: the last setting is active, can not have different miplevels bound from single
2443                             // resource.
2444                             if (dplat.mipLevel != obj.image.mipLevel) {
2445                                 dplat.mipLevel = obj.image.mipLevel;
2446                                 if (obj.image.mipLevel != PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS) {
2447                                     glTexParameteri(
2448                                         dplat.type, GL_TEXTURE_BASE_LEVEL, static_cast<GLint>(obj.image.mipLevel));
2449                                     glTexParameteri(
2450                                         dplat.type, GL_TEXTURE_MAX_LEVEL, static_cast<GLint>(obj.image.mipLevel));
2451                                 } else {
2452                                     // set defaults.
2453                                     glTexParameteri(dplat.type, GL_TEXTURE_BASE_LEVEL, 0);
2454                                     glTexParameteri(dplat.type, GL_TEXTURE_MAX_LEVEL, 1000); // 1000: default mip level
2455                                 }
2456                             }
2457                         }
2458                     }
2459                 }
2460                 if (resType == CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER) {
2461 #if (RENDER_PERF_ENABLED == 1)
2462                     if (device_.BoundBuffer(GL_UNIFORM_BUFFER) != obj.buffer.bufferId) {
2463                         ++perfCounters_.bindBuffer;
2464                     }
2465 #endif
2466                     device_.BindBufferRange(
2467                         GL_UNIFORM_BUFFER, id + index, obj.buffer.bufferId, obj.buffer.offset, obj.buffer.size);
2468                 }
2469                 if (resType == CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER) {
2470 #if (RENDER_PERF_ENABLED == 1)
2471                     if (device_.BoundBuffer(GL_SHADER_STORAGE_BUFFER) != obj.buffer.bufferId) {
2472                         ++perfCounters_.bindBuffer;
2473                     }
2474 #endif
2475                     device_.BindBufferRange(
2476                         GL_SHADER_STORAGE_BUFFER, id + index, obj.buffer.bufferId, obj.buffer.offset, obj.buffer.size);
2477                 }
2478             }
2479         }
2480     }
2481     // mark all bound.
2482     for (auto& b : boundObjects_) {
2483         b.dirty = false;
2484     }
2485 }
2486 
2487 #if (RENDER_PERF_ENABLED == 1)
StartFrameTimers(const RenderCommandFrameData & renderCommandFrameData)2488 void RenderBackendGLES::StartFrameTimers(const RenderCommandFrameData& renderCommandFrameData)
2489 {
2490     for (const auto& renderCommandContext : renderCommandFrameData.renderCommandContexts) {
2491         const string_view& debugName = renderCommandContext.debugName;
2492         if (timers_.count(debugName) == 0) { // new timers
2493 #if (RENDER_GPU_TIMESTAMP_QUERIES_ENABLED == 1)
2494             PerfDataSet& perfDataSet = timers_[debugName];
2495             constexpr GpuQueryDesc desc { QueryType::CORE_QUERY_TYPE_TIMESTAMP, 0 };
2496             perfDataSet.gpuHandle = gpuQueryMgr_->Create(debugName, CreateGpuQueryGLES(device_, desc));
2497 #else
2498             timers_.insert({ debugName, {} });
2499 #endif
2500         }
2501     }
2502 }
2503 
EndFrameTimers()2504 void RenderBackendGLES::EndFrameTimers()
2505 {
2506     if (CORE_NS::IPerformanceDataManagerFactory* globalPerfData =
2507             CORE_NS::GetInstance<CORE_NS ::IPerformanceDataManagerFactory>(CORE_NS::UID_PERFORMANCE_FACTORY);
2508         globalPerfData) {
2509         CORE_NS::IPerformanceDataManager* perfData = globalPerfData->Get("Renderer");
2510         perfData->UpdateData("RenderBackend", "Full_Cpu", commonCpuTimers_.full.GetMicroseconds());
2511         perfData->UpdateData("RenderBackend", "Acquire_Cpu", commonCpuTimers_.acquire.GetMicroseconds());
2512         perfData->UpdateData("RenderBackend", "Execute_Cpu", commonCpuTimers_.execute.GetMicroseconds());
2513         perfData->UpdateData("RenderBackend", "Submit_Cpu", commonCpuTimers_.submit.GetMicroseconds());
2514         perfData->UpdateData("RenderBackend", "Present_Cpu", commonCpuTimers_.present.GetMicroseconds());
2515     }
2516 }
2517 
CopyPerfTimeStamp(const string_view name,PerfDataSet & perfDataSet)2518 void RenderBackendGLES::CopyPerfTimeStamp(const string_view name, PerfDataSet& perfDataSet)
2519 {
2520 #if (RENDER_GPU_TIMESTAMP_QUERIES_ENABLED == 1)
2521     int64_t gpuMicroSeconds = 0;
2522     if (validGpuQueries_) {
2523         GpuQuery* gpuQuery = gpuQueryMgr_->Get(perfDataSet.gpuHandle);
2524         PLUGIN_ASSERT(gpuQuery);
2525 
2526         gpuQuery->NextQueryIndex();
2527 
2528         const auto& platData = static_cast<const GpuQueryPlatformDataGLES&>(gpuQuery->GetPlatformData());
2529         PLUGIN_ASSERT(platData.queryObject);
2530 
2531         GLint disjointOccurred = 0;
2532 #ifdef GL_GPU_DISJOINT_EXT
2533         // Clear disjoint error
2534         glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjointOccurred);
2535 #endif
2536         if (disjointOccurred == 0) {
2537             GLuint64 gpuNanoSeconds = 0U;
2538 #ifdef GL_GPU_DISJOINT_EXT
2539             glGetQueryObjectui64vEXT(platData.queryObject, GL_QUERY_RESULT, &gpuNanoSeconds);
2540 #else
2541             glGetQueryObjectui64v(platData.queryObject, GL_QUERY_RESULT, &gpuNanoSeconds);
2542 #endif
2543             static uint64_t NANOSECONDS_TO_MICROSECONDS = 1000;
2544             gpuMicroSeconds = static_cast<int64_t>(gpuNanoSeconds / NANOSECONDS_TO_MICROSECONDS);
2545             if (gpuMicroSeconds > UINT32_MAX) {
2546                 gpuMicroSeconds = 0;
2547             }
2548         } else {
2549             PLUGIN_LOG_V("GL_GPU_DISJOINT_EXT disjoint occurred.");
2550         }
2551     }
2552 #endif
2553     const int64_t cpuMicroSeconds = perfDataSet.cpuTimer.GetMicroseconds();
2554 
2555     if (CORE_NS::IPerformanceDataManagerFactory* globalPerfData =
2556             CORE_NS::GetInstance<CORE_NS::IPerformanceDataManagerFactory>(CORE_NS::UID_PERFORMANCE_FACTORY);
2557         globalPerfData) {
2558         CORE_NS::IPerformanceDataManager* perfData = globalPerfData->Get("RenderNode");
2559 
2560         perfData->UpdateData(name, "Backend_Cpu", cpuMicroSeconds);
2561 #if (RENDER_GPU_TIMESTAMP_QUERIES_ENABLED == 1)
2562         perfData->UpdateData(name, "Backend_Gpu", gpuMicroSeconds);
2563 #endif
2564         perfData->UpdateData(name, "Backend_Count_Triangle", perfCounters_.triangleCount);
2565         perfData->UpdateData(name, "Backend_Count_InstanceCount", perfCounters_.instanceCount);
2566         perfData->UpdateData(name, "Backend_Count_Draw", perfCounters_.drawCount);
2567         perfData->UpdateData(name, "Backend_Count_DrawIndirect", perfCounters_.drawIndirectCount);
2568         perfData->UpdateData(name, "Backend_Count_Dispatch", perfCounters_.dispatchCount);
2569         perfData->UpdateData(name, "Backend_Count_DispatchIndirect", perfCounters_.dispatchIndirectCount);
2570         perfData->UpdateData(name, "Backend_Count_RenderPass", perfCounters_.renderPassCount);
2571         perfData->UpdateData(name, "Backend_Count_BindProgram", perfCounters_.bindProgram);
2572         perfData->UpdateData(name, "Backend_Count_BindSample", perfCounters_.bindSampler);
2573         perfData->UpdateData(name, "Backend_Count_BindTexture", perfCounters_.bindTexture);
2574         perfData->UpdateData(name, "Backend_Count_BindBuffer", perfCounters_.bindBuffer);
2575     }
2576 }
2577 #endif
2578 
PrimeDepthStencilState(const GraphicsState & graphicsState)2579 void RenderBackendGLES::PrimeDepthStencilState(const GraphicsState& graphicsState)
2580 {
2581     auto& cDepth = cacheState_.depthStencilState;
2582     cDepth = graphicsState.depthStencilState;
2583     // CORE_DYNAMIC_STATE_DEPTH_BOUNDS NOT SUPPORTED ON GLES. (and not implemented on GL either)
2584     SetState(GL_DEPTH_TEST, cDepth.enableDepthTest);
2585     SetState(GL_STENCIL_TEST, cDepth.enableStencilTest);
2586     glDepthFunc(GetCompareOp(cDepth.depthCompareOp));
2587     glDepthMask((cDepth.enableDepthWrite ? static_cast<GLboolean>(GL_TRUE) : static_cast<GLboolean>(GL_FALSE)));
2588     const uint32_t updateAllFlags =
2589         (StencilSetFlags::SETOP | StencilSetFlags::SETCOMPAREMASK | StencilSetFlags::SETCOMPAREOP |
2590             StencilSetFlags::SETREFERENCE | StencilSetFlags::SETWRITEMASK);
2591     SetStencilState(updateAllFlags, cDepth.frontStencilOpState, updateAllFlags, cDepth.backStencilOpState);
2592 }
2593 
PrimeBlendState(const GraphicsState & graphicsState)2594 void RenderBackendGLES::PrimeBlendState(const GraphicsState& graphicsState)
2595 {
2596     auto& cBlend = cacheState_.colorBlendState;
2597     cBlend = graphicsState.colorBlendState;
2598     glBlendColor(cBlend.colorBlendConstants[Gles::RED_INDEX], cBlend.colorBlendConstants[Gles::GREEN_INDEX],
2599         cBlend.colorBlendConstants[Gles::BLUE_INDEX], cBlend.colorBlendConstants[Gles::ALPHA_INDEX]);
2600     GLuint maxColorAttachments;
2601     glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, (GLint*)&maxColorAttachments);
2602     maxColorAttachments = BASE_NS::Math::min(PipelineStateConstants::MAX_COLOR_ATTACHMENT_COUNT, maxColorAttachments);
2603     for (GLuint i = 0; i < maxColorAttachments; i++) {
2604         const auto& cBlendState = cBlend.colorAttachments[i];
2605         glColorMaski(i, IS_BIT_GL(cBlendState.colorWriteMask, CORE_COLOR_COMPONENT_R_BIT),
2606             IS_BIT_GL(cBlendState.colorWriteMask, CORE_COLOR_COMPONENT_G_BIT),
2607             IS_BIT_GL(cBlendState.colorWriteMask, CORE_COLOR_COMPONENT_B_BIT),
2608             IS_BIT_GL(cBlendState.colorWriteMask, CORE_COLOR_COMPONENT_A_BIT));
2609         if (cBlendState.enableBlend) {
2610             glEnablei(GL_BLEND, i);
2611         } else {
2612             glDisablei(GL_BLEND, i);
2613         }
2614         glBlendFuncSeparatei(i, GetBlendFactor(cBlendState.srcColorBlendFactor),
2615             GetBlendFactor(cBlendState.dstColorBlendFactor), GetBlendFactor(cBlendState.srcAlphaBlendFactor),
2616             GetBlendFactor(cBlendState.dstAlphaBlendFactor));
2617         glBlendEquationSeparatei(i, GetBlendOp(cBlendState.colorBlendOp), GetBlendOp(cBlendState.alphaBlendOp));
2618     }
2619     // logicops are unsupported on GLES
2620 }
2621 
PrimeCache(const GraphicsState & graphicsState)2622 void RenderBackendGLES::PrimeCache(const GraphicsState& graphicsState) // Forces the graphics state..
2623 {
2624     if (cachePrimed_) {
2625         return;
2626     }
2627     cachePrimed_ = true;
2628     /// GRAPHICSSTATE     inputAssembly
2629     const auto& ia = graphicsState.inputAssembly;
2630     auto& cia = cacheState_.inputAssembly;
2631     cia.enablePrimitiveRestart = ia.enablePrimitiveRestart;
2632     SetState(GL_PRIMITIVE_RESTART_FIXED_INDEX, ia.enablePrimitiveRestart);
2633     topology_ = ia.primitiveTopology;
2634     /// GRAPHICSSTATE     rasterizationState
2635     const auto& rs = graphicsState.rasterizationState;
2636     auto& crs = cacheState_.rasterizationState;
2637     // save, since we need to hack for non fill modes etc ! (possibly need shader help for lines...)
2638     polygonMode_ = rs.polygonMode;
2639     // GL_DEPTH_CLAMP,rs.enableDepthClamp NOT SUPPORTED    CHECK GLES 3.2
2640     crs.enableRasterizerDiscard = rs.enableRasterizerDiscard;
2641     SetState(GL_RASTERIZER_DISCARD, rs.enableRasterizerDiscard);
2642     crs.enableDepthBias = rs.enableDepthBias;
2643     SetState(GL_POLYGON_OFFSET_FILL, rs.enableDepthBias);
2644     crs.depthBiasConstantFactor = rs.depthBiasConstantFactor;
2645     crs.depthBiasSlopeFactor = rs.depthBiasSlopeFactor;
2646     glPolygonOffset(rs.depthBiasSlopeFactor, rs.depthBiasConstantFactor);
2647     // depthBiasClamp NOT SUPPORTED! CHECK GLES 3.2
2648     // If cull mode Flags change...
2649     crs.cullModeFlags = rs.cullModeFlags;
2650     SetCullMode(crs);
2651     crs.frontFace = rs.frontFace;
2652     SetFrontFace(crs);
2653     crs.lineWidth = rs.lineWidth;
2654     glLineWidth(rs.lineWidth);
2655     PrimeDepthStencilState(graphicsState);
2656     PrimeBlendState(graphicsState);
2657 }
2658 
UpdateDepthState(const GraphicsState & graphicsState)2659 void RenderBackendGLES::UpdateDepthState(const GraphicsState& graphicsState)
2660 {
2661     const auto& depth = graphicsState.depthStencilState;
2662     auto& cDepth = cacheState_.depthStencilState;
2663     if (depth.enableDepthTest != cDepth.enableDepthTest) {
2664         cDepth.enableDepthTest = depth.enableDepthTest;
2665         SetState(GL_DEPTH_TEST, depth.enableDepthTest);
2666     }
2667     if (depth.depthCompareOp != cDepth.depthCompareOp) {
2668         cDepth.depthCompareOp = depth.depthCompareOp;
2669         glDepthFunc(GetCompareOp(depth.depthCompareOp));
2670     }
2671     if (depth.enableDepthWrite != cDepth.enableDepthWrite) {
2672         cDepth.enableDepthWrite = depth.enableDepthWrite;
2673         glDepthMask((depth.enableDepthWrite == GL_TRUE));
2674     }
2675     if (!IS_BIT(dynamicStateFlags_, CORE_DYNAMIC_STATE_DEPTH_BOUNDS)) {
2676         // CORE_DYNAMIC_STATE_DEPTH_BOUNDS not supported on GLES.
2677     }
2678 }
2679 
UpdateStencilState(const GraphicsState & graphicsState)2680 void RenderBackendGLES::UpdateStencilState(const GraphicsState& graphicsState)
2681 {
2682     const auto& depth = graphicsState.depthStencilState;
2683     auto& cDepth = cacheState_.depthStencilState;
2684     if (depth.enableStencilTest != cDepth.enableStencilTest) {
2685         cDepth.enableStencilTest = depth.enableStencilTest;
2686         SetState(GL_STENCIL_TEST, depth.enableStencilTest);
2687     }
2688     uint32_t setFront = 0;
2689     uint32_t setBack = 0;
2690     if (!IS_BIT(dynamicStateFlags_, CORE_DYNAMIC_STATE_STENCIL_REFERENCE)) {
2691         if (cDepth.frontStencilOpState.reference != depth.frontStencilOpState.reference) {
2692             setFront |= StencilSetFlags::SETREFERENCE;
2693         }
2694         if (cDepth.backStencilOpState.reference != depth.backStencilOpState.reference) {
2695             setBack |= StencilSetFlags::SETREFERENCE;
2696         }
2697     }
2698     if (!IS_BIT(dynamicStateFlags_, CORE_DYNAMIC_STATE_STENCIL_COMPARE_MASK)) {
2699         if (cDepth.frontStencilOpState.compareMask != depth.frontStencilOpState.compareMask) {
2700             setFront |= StencilSetFlags::SETCOMPAREMASK;
2701         }
2702         if (cDepth.backStencilOpState.compareMask != depth.backStencilOpState.compareMask) {
2703             setBack |= StencilSetFlags::SETCOMPAREMASK;
2704         }
2705     }
2706     if (!IS_BIT(dynamicStateFlags_, CORE_DYNAMIC_STATE_STENCIL_WRITE_MASK)) {
2707         if (cDepth.frontStencilOpState.writeMask != depth.frontStencilOpState.writeMask) {
2708             setFront |= StencilSetFlags::SETWRITEMASK;
2709         }
2710         if (cDepth.backStencilOpState.writeMask != depth.backStencilOpState.writeMask) {
2711             setBack |= StencilSetFlags::SETWRITEMASK;
2712         }
2713     }
2714     if (cDepth.frontStencilOpState.compareOp != depth.frontStencilOpState.compareOp) {
2715         setFront |= StencilSetFlags::SETCOMPAREOP;
2716     }
2717     if (cDepth.backStencilOpState.compareOp != depth.backStencilOpState.compareOp) {
2718         setBack |= StencilSetFlags::SETCOMPAREOP;
2719     }
2720     if (!CompareStencilOp(cDepth.frontStencilOpState, depth.frontStencilOpState)) {
2721         setFront |= StencilSetFlags::SETOP;
2722     }
2723     if (!CompareStencilOp(cDepth.backStencilOpState, depth.backStencilOpState)) {
2724         setBack |= StencilSetFlags::SETOP;
2725     }
2726     SetStencilState(setFront, depth.frontStencilOpState, setBack, depth.backStencilOpState);
2727 }
2728 
UpdateDepthStencilState(const GraphicsState & graphicsState)2729 void RenderBackendGLES::UpdateDepthStencilState(const GraphicsState& graphicsState)
2730 {
2731     UpdateDepthState(graphicsState);
2732     UpdateStencilState(graphicsState);
2733 }
2734 
UpdateBlendState(const GraphicsState & graphicsState)2735 void RenderBackendGLES::UpdateBlendState(const GraphicsState& graphicsState)
2736 {
2737     const auto& blend = graphicsState.colorBlendState;
2738     auto& cBlend = cacheState_.colorBlendState;
2739     for (GLuint i = 0; i < blend.colorAttachmentCount; i++) {
2740         const auto& blendState = blend.colorAttachments[i];
2741         auto& cBlendState = cBlend.colorAttachments[i];
2742         if (blendState.colorWriteMask != cBlendState.colorWriteMask) {
2743             cBlendState.colorWriteMask = blendState.colorWriteMask;
2744             glColorMaski(i, IS_BIT_GL(cBlendState.colorWriteMask, CORE_COLOR_COMPONENT_R_BIT),
2745                 IS_BIT_GL(cBlendState.colorWriteMask, CORE_COLOR_COMPONENT_G_BIT),
2746                 IS_BIT_GL(cBlendState.colorWriteMask, CORE_COLOR_COMPONENT_B_BIT),
2747                 IS_BIT_GL(cBlendState.colorWriteMask, CORE_COLOR_COMPONENT_A_BIT));
2748         }
2749 
2750         // Check if blend state has changed
2751         bool factorsChanged = false;
2752         bool opsChanged = false;
2753 
2754         if (blendState.enableBlend) {
2755             factorsChanged = !CompareBlendFactors(cBlendState, blendState);
2756             opsChanged = !CompareBlendOps(cBlendState, blendState);
2757         }
2758 
2759         if (blendState.enableBlend != cBlendState.enableBlend || factorsChanged || opsChanged) {
2760             cBlendState.enableBlend = blendState.enableBlend;
2761             if (blendState.enableBlend) {
2762                 glEnablei(GL_BLEND, i);
2763                 if (factorsChanged) {
2764                     SetBlendFactors(cBlendState, blendState);
2765                     glBlendFuncSeparatei(i, GetBlendFactor(cBlendState.srcColorBlendFactor),
2766                         GetBlendFactor(cBlendState.dstColorBlendFactor),
2767                         GetBlendFactor(cBlendState.srcAlphaBlendFactor),
2768                         GetBlendFactor(cBlendState.dstAlphaBlendFactor));
2769                 }
2770                 if (opsChanged) {
2771                     SetBlendOps(cBlendState, blendState);
2772                     glBlendEquationSeparatei(
2773                         i, GetBlendOp(cBlendState.colorBlendOp), GetBlendOp(cBlendState.alphaBlendOp));
2774                 }
2775             } else {
2776                 glDisablei(GL_BLEND, i);
2777             }
2778         }
2779     }
2780     if (!IS_BIT(dynamicStateFlags_, CORE_DYNAMIC_STATE_BLEND_CONSTANTS)) {
2781         if (!Compare(cBlend.colorBlendConstants, blend.colorBlendConstants)) {
2782             Set(cBlend.colorBlendConstants, blend.colorBlendConstants);
2783             glBlendColor(blend.colorBlendConstants[Gles::RED_INDEX], blend.colorBlendConstants[Gles::GREEN_INDEX],
2784                 blend.colorBlendConstants[Gles::BLUE_INDEX], blend.colorBlendConstants[Gles::ALPHA_INDEX]);
2785         }
2786     }
2787     // logicOps in blend not supported on GLES
2788 }
2789 
UpdateRasterizationState(const GraphicsState & graphicsState)2790 void RenderBackendGLES::UpdateRasterizationState(const GraphicsState& graphicsState)
2791 {
2792     const auto& rs = graphicsState.rasterizationState;
2793     auto& crs = cacheState_.rasterizationState;
2794     // save, since we need to hack for non fill modes etc ! (possibly need shader help for lines...)
2795     polygonMode_ = rs.polygonMode;
2796 #if RENDER_HAS_GL_BACKEND
2797     if (rs.polygonMode != crs.polygonMode) {
2798         crs.polygonMode = rs.polygonMode;
2799         SetPolygonMode(rs);
2800     }
2801 #endif
2802     if (rs.enableDepthClamp != crs.enableDepthClamp) {
2803         crs.enableDepthClamp = rs.enableDepthClamp;
2804         // NOT SUPPORTED    (needs an extension)
2805     }
2806     if (rs.enableRasterizerDiscard != crs.enableRasterizerDiscard) {
2807         crs.enableRasterizerDiscard = rs.enableRasterizerDiscard;
2808         SetState(GL_RASTERIZER_DISCARD, rs.enableRasterizerDiscard);
2809     }
2810     if (rs.enableDepthBias != crs.enableDepthBias) {
2811         crs.enableDepthBias = rs.enableDepthBias;
2812         SetState(GL_POLYGON_OFFSET_FILL, rs.enableDepthBias);
2813     }
2814     if (!IS_BIT(dynamicStateFlags_, CORE_DYNAMIC_STATE_DEPTH_BIAS)) {
2815         if ((rs.depthBiasConstantFactor != crs.depthBiasConstantFactor) ||
2816             (rs.depthBiasSlopeFactor != crs.depthBiasSlopeFactor)) {
2817             crs.depthBiasConstantFactor = rs.depthBiasConstantFactor;
2818             crs.depthBiasSlopeFactor = rs.depthBiasSlopeFactor;
2819             glPolygonOffset(rs.depthBiasSlopeFactor, rs.depthBiasConstantFactor);
2820         }
2821         // depthBiasClamp NOT SUPPORTED    (needs an extension)
2822     }
2823     // If cull mode Flags change...
2824     if (rs.cullModeFlags != crs.cullModeFlags) {
2825         crs.cullModeFlags = rs.cullModeFlags;
2826         SetCullMode(crs);
2827     }
2828     auto frontFace = rs.frontFace;
2829     if (!renderingToDefaultFbo_) {
2830         // Flip winding for default fbo.
2831         if (frontFace == FrontFace::CORE_FRONT_FACE_COUNTER_CLOCKWISE) {
2832             frontFace = FrontFace::CORE_FRONT_FACE_CLOCKWISE;
2833         } else if (frontFace == FrontFace::CORE_FRONT_FACE_CLOCKWISE) {
2834             frontFace = FrontFace::CORE_FRONT_FACE_COUNTER_CLOCKWISE;
2835         }
2836     }
2837     if (frontFace != crs.frontFace) {
2838         crs.frontFace = frontFace;
2839         SetFrontFace(crs);
2840     }
2841     if (!IS_BIT(dynamicStateFlags_, CORE_DYNAMIC_STATE_LINE_WIDTH)) {
2842         if (rs.lineWidth != crs.lineWidth) {
2843             crs.lineWidth = rs.lineWidth;
2844             glLineWidth(rs.lineWidth);
2845         }
2846     }
2847 }
2848 
DoGraphicsState(const GraphicsState & graphicsState)2849 void RenderBackendGLES::DoGraphicsState(const GraphicsState& graphicsState)
2850 {
2851     /// GRAPHICSSTATE     inputAssembly
2852     const auto& ia = graphicsState.inputAssembly;
2853     if (ia.enablePrimitiveRestart != graphicsState.inputAssembly.enablePrimitiveRestart) {
2854         auto& cia = cacheState_.inputAssembly;
2855         cia.enablePrimitiveRestart = ia.enablePrimitiveRestart;
2856         SetState(GL_PRIMITIVE_RESTART_FIXED_INDEX, ia.enablePrimitiveRestart);
2857     }
2858     topology_ = ia.primitiveTopology;
2859     UpdateRasterizationState(graphicsState);
2860     UpdateDepthStencilState(graphicsState);
2861     UpdateBlendState(graphicsState);
2862 }
2863 
SetViewport(const RenderPassDesc::RenderArea & ra,const ViewportDesc & vd)2864 void RenderBackendGLES::SetViewport(const RenderPassDesc::RenderArea& ra, const ViewportDesc& vd)
2865 {
2866     // NOTE: viewportdesc is in floats?!?
2867     bool forceV = false;
2868     bool forceD = false;
2869     if (!viewportPrimed_) {
2870         viewportPrimed_ = true;
2871         forceV = true;
2872         forceD = true;
2873     }
2874     if ((vd.x != viewport_.x) || (vd.y != viewport_.y) || (vd.width != viewport_.width) ||
2875         (vd.height != viewport_.height)) {
2876         forceV = true;
2877     }
2878     if ((vd.minDepth != viewport_.minDepth) || (vd.maxDepth != viewport_.maxDepth)) {
2879         forceD = true;
2880     }
2881 
2882     if (forceV) {
2883         viewport_.x = vd.x;
2884         viewport_.y = vd.y;
2885         viewport_.width = vd.width;
2886         viewport_.height = vd.height;
2887         viewportUpdated_ = true;
2888     }
2889     if (forceD) {
2890         viewport_.minDepth = vd.minDepth;
2891         viewport_.maxDepth = vd.maxDepth;
2892         viewportDepthRangeUpdated_ = true;
2893     }
2894 }
2895 
SetScissor(const RenderPassDesc::RenderArea & ra,const ScissorDesc & sd)2896 void RenderBackendGLES::SetScissor(const RenderPassDesc::RenderArea& ra, const ScissorDesc& sd)
2897 {
2898     // NOTE: scissordesc is in floats?!?
2899     bool force = false;
2900     if (!scissorPrimed_) {
2901         scissorPrimed_ = true;
2902         force = true;
2903     }
2904     if ((sd.offsetX != scissorBox_.offsetX) || (sd.offsetY != scissorBox_.offsetY) ||
2905         (sd.extentWidth != scissorBox_.extentWidth) || (sd.extentHeight != scissorBox_.extentHeight)) {
2906         force = true;
2907     }
2908     if (force) {
2909         scissorBox_ = sd;
2910         scissorBoxUpdated_ = true;
2911     }
2912 }
2913 
FlushViewportScissors()2914 void RenderBackendGLES::FlushViewportScissors()
2915 {
2916     PLUGIN_ASSERT(currentFrameBuffer_);
2917     bool force = false;
2918     if (scissorViewportSetDefaultFbo_ != renderingToDefaultFbo_) {
2919         force = true;
2920         scissorViewportSetDefaultFbo_ = renderingToDefaultFbo_;
2921     }
2922     if ((viewportUpdated_) || (force)) {
2923         viewportUpdated_ = false;
2924         // Handle top-left / bottom-left origin conversion
2925         PLUGIN_ASSERT(currentFrameBuffer_);
2926         GLint y = static_cast<GLint>(viewport_.y);
2927         const GLsizei h = static_cast<GLsizei>(viewport_.height);
2928         if (renderingToDefaultFbo_) {
2929             const GLsizei fh = static_cast<GLint>(currentFrameBuffer_->height);
2930             y = fh - (y + h);
2931         }
2932         glViewport(static_cast<GLint>(viewport_.x), y, static_cast<GLsizei>(viewport_.width), h);
2933     }
2934     if ((scissorBoxUpdated_) || (force)) {
2935         scissorBoxUpdated_ = false;
2936         // Handle top-left / bottom-left origin conversion
2937         GLint y = static_cast<GLint>(scissorBox_.offsetY);
2938         const GLsizei h = static_cast<GLsizei>(scissorBox_.extentHeight);
2939         if (renderingToDefaultFbo_) {
2940             const GLsizei fh = static_cast<GLint>(currentFrameBuffer_->height);
2941             y = fh - (y + h);
2942         }
2943         glScissor(static_cast<GLint>(scissorBox_.offsetX), y, static_cast<GLsizei>(scissorBox_.extentWidth), h);
2944     }
2945     if (viewportDepthRangeUpdated_) {
2946         viewportDepthRangeUpdated_ = false;
2947         glDepthRangef(viewport_.minDepth, viewport_.maxDepth);
2948     }
2949 }
2950 RENDER_END_NAMESPACE()
2951