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