• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Razakhel / RaZ / 18059902851

27 Sep 2025 12:32PM UTC coverage: 74.093% (+0.04%) from 74.05%
18059902851

push

github

Razakhel
[Utils/Logger] Added formatted logging overloads

- Formatted calls to logging functions and made use of std::format() in several other places

100 of 170 new or added lines in 36 files covered. (58.82%)

4 existing lines in 2 files now uncovered.

8334 of 11248 relevant lines covered (74.09%)

1757.71 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

57.79
/src/RaZ/Render/Renderer.cpp
1
#include "RaZ/Render/Renderer.hpp"
2
#include "RaZ/Utils/Logger.hpp"
3

4
#include "GL/glew.h"
5

6
#include "tracy/Tracy.hpp"
7
#include "tracy/TracyOpenGL.hpp"
8

9
#include <algorithm>
10
#include <array>
11
#include <cassert>
12

13
namespace Raz {
14

15
namespace {
16

17
#if !defined(RAZ_PLATFORM_MAC) && !defined(USE_OPENGL_ES)
18
inline void GLAPIENTRY logCallback(GLenum source,
176✔
19
                                   GLenum type,
20
                                   unsigned int id,
21
                                   GLenum severity,
22
                                   int /* length */,
23
                                   const char* message,
24
                                   const void* /* userParam */) {
25
  if (severity == GL_DEBUG_SEVERITY_NOTIFICATION)
176✔
26
    return;
80✔
27

28
  if (id == 131218)
96✔
29
    return; // "Shader is being recompiled based on GL state". May be avoidable, but disabled for now
×
30

31
  std::string errorMsg = "[OpenGL]\n\t";
96✔
32

33
  switch (source) {
96✔
34
    case GL_DEBUG_SOURCE_API:             errorMsg += "Source: OpenGL\n\t"; break;
80✔
35
    case GL_DEBUG_SOURCE_WINDOW_SYSTEM:   errorMsg += "Source: Window system\n\t"; break;
×
36
    case GL_DEBUG_SOURCE_SHADER_COMPILER: errorMsg += "Source: Shader compiler\n\t"; break;
16✔
37
    case GL_DEBUG_SOURCE_THIRD_PARTY:     errorMsg += "Source: Third party\n\t"; break;
×
38
    case GL_DEBUG_SOURCE_APPLICATION:     errorMsg += "Source: Application\n\t"; break;
×
39
    case GL_DEBUG_SOURCE_OTHER:           errorMsg += "Source: Other\n\t"; break;
×
40
    default: break;
×
41
  }
42

43
  switch (type) {
96✔
44
    case GL_DEBUG_TYPE_ERROR:               errorMsg += "Type: Error\n\t"; break;
96✔
45
    case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: errorMsg += "Type: Deprecated behavior\n\t"; break;
×
46
    case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:  errorMsg += "Type: Undefined behavior\n\t"; break;
×
47
    case GL_DEBUG_TYPE_PORTABILITY:         errorMsg += "Type: Portability\n\t"; break;
×
48
    case GL_DEBUG_TYPE_PERFORMANCE:         errorMsg += "Type: Performance\n\t"; break;
×
49
    case GL_DEBUG_TYPE_OTHER:               errorMsg += "Type: Other\n\t"; break;
×
50
    default: break;
×
51
  }
52

53
  errorMsg += "ID: " + std::to_string(id) + "\n\t";
96✔
54

55
  switch (severity) {
96✔
56
    case GL_DEBUG_SEVERITY_HIGH:   errorMsg += "Severity: High\n\t"; break;
96✔
57
    case GL_DEBUG_SEVERITY_MEDIUM: errorMsg += "Severity: Medium\n\t"; break;
×
58
    case GL_DEBUG_SEVERITY_LOW:    errorMsg += "Severity: Low\n\t"; break;
×
59
    // Messages with a GL_DEBUG_SEVERITY_NOTIFICATION severity are ignored at the beginning of this function
60
    default: break;
×
61
  }
62

63
  errorMsg += "Message: " + std::string(message);
96✔
64

65
  Logger::error(errorMsg);
96✔
66
}
96✔
67
#endif
68

69
inline constexpr const char* recoverGlErrorStr(unsigned int errorCode) {
×
70
  switch (errorCode) {
×
71
    case GL_INVALID_ENUM:                  return "Unrecognized error code (Invalid enum)";
×
72
    case GL_INVALID_VALUE:                 return "Numeric argument out of range (Invalid value)";
×
73
    case GL_INVALID_OPERATION:             return "Operation illegal in current state (Invalid operation)";
×
74
    case GL_INVALID_FRAMEBUFFER_OPERATION: return "Framebuffer object is incomplete (Invalid framebuffer operation)";
×
75
    case GL_STACK_OVERFLOW:                return "Stack overflow";
×
76
    case GL_STACK_UNDERFLOW:               return "Stack underflow";
×
77
    case GL_OUT_OF_MEMORY:                 return "Not enough memory left (Out of memory)";
×
78
    case GL_CONTEXT_LOST:                  return "OpenGL context has been lost due to a graphics card reset (Context lost)";
×
79
    case GL_NO_ERROR:                      return "No error";
×
80
    default:                               return "Unknown error";
×
81
  }
82
}
83

84
} // namespace
85

86
void Renderer::initialize() {
35✔
87
  ZoneScopedN("Renderer::initialize");
88

89
  if (s_isInitialized)
35✔
90
    return;
33✔
91

92
  Logger::debug("[Renderer] Initializing...");
2✔
93

94
  glewExperimental = GL_TRUE;
2✔
95

96
  if (glewInit() != GLEW_OK) {
2✔
97
    Logger::error("[Renderer] Failed to initialize GLEW");
×
98
    return;
×
99
  }
100

101
  s_isInitialized = true;
2✔
102

103
  TracyGpuContext
104

105
  getParameter(StateParameter::MAJOR_VERSION, &s_majorVersion);
2✔
106
  getParameter(StateParameter::MINOR_VERSION, &s_minorVersion);
2✔
107

108
  // Recovering supported extensions
109
  {
110
    int extCount {};
2✔
111
    getParameter(StateParameter::EXTENSION_COUNT, &extCount);
2✔
112

113
    s_extensions.reserve(static_cast<std::size_t>(extCount));
2✔
114

115
    for (int extIndex = 0; extIndex < extCount; ++extIndex)
458✔
116
      s_extensions.emplace(getExtension(static_cast<unsigned int>(extIndex)));
456✔
117
  }
118

119
#if !defined(NDEBUG) || defined(RAZ_FORCE_DEBUG_LOG)
120
  {
121
    std::string extMsg = "[Renderer] Available extensions:";
2✔
122
    for (const std::string& extension : s_extensions)
458✔
123
      extMsg += "\n    - " + extension;
456✔
124
    Logger::debug(extMsg);
2✔
125
  }
2✔
126
#endif
127

128
  recoverDefaultFramebufferColorFormat();
2✔
129
  recoverDefaultFramebufferDepthFormat();
2✔
130

131
#if !defined(RAZ_PLATFORM_MAC) && !defined(USE_OPENGL_ES) // Setting the debug message callback provokes a crash on macOS & isn't available on OpenGL ES
132
  if (checkVersion(4, 3)) {
2✔
133
    enable(Capability::DEBUG_OUTPUT);
2✔
134
    enable(Capability::DEBUG_OUTPUT_SYNCHRONOUS);
2✔
135
    glDebugMessageCallback(&logCallback, nullptr);
2✔
136
  }
137
#endif
138

139
  Logger::debug("[Renderer] Initialized; using OpenGL "
2✔
140
#if defined(USE_OPENGL_ES)
141
    "ES "
142
#endif
143
    + std::to_string(s_majorVersion) + '.' + std::to_string(s_minorVersion));
4✔
144
}
145

146
void Renderer::enable(Capability capability) {
126✔
147
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
126✔
148

149
  glEnable(static_cast<unsigned int>(capability));
126✔
150

151
  printConditionalErrors();
126✔
152
}
126✔
153

154
void Renderer::disable(Capability capability) {
1✔
155
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
1✔
156

157
  glDisable(static_cast<unsigned int>(capability));
1✔
158

159
  printConditionalErrors();
1✔
160
}
1✔
161

162
bool Renderer::isEnabled(Capability capability) {
×
163
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
164

165
  const bool isEnabled = (glIsEnabled(static_cast<unsigned int>(capability)) == GL_TRUE);
×
166

167
  printConditionalErrors();
×
168

169
  return isEnabled;
×
170
}
171

172
std::string Renderer::getContextInfo(ContextInfo info) {
×
173
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
174

175
  std::string res = reinterpret_cast<const char*>(glGetString(static_cast<unsigned int>(info)));
×
176

177
  printConditionalErrors();
×
178

179
  return res;
×
180
}
181

182
std::string Renderer::getExtension(unsigned int extIndex) {
456✔
183
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
456✔
184
#if defined(RAZ_CONFIG_DEBUG)
185
  int extCount {};
456✔
186
  getParameter(StateParameter::EXTENSION_COUNT, &extCount);
456✔
187
  assert("Error: Extension index must be less than the total extension count." && static_cast<int>(extIndex) < extCount);
456✔
188
#endif
189

190
  std::string extension = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, extIndex));
456✔
191

192
  printConditionalErrors();
456✔
193

194
  return extension;
912✔
195
}
196

197
void Renderer::getParameter(StateParameter parameter, unsigned char* values) {
×
198
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
199

200
  glGetBooleanv(static_cast<unsigned int>(parameter), values);
×
201

202
  printConditionalErrors();
×
203
}
×
204

205
void Renderer::getParameter(StateParameter parameter, int* values) {
1,035✔
206
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
1,035✔
207

208
  glGetIntegerv(static_cast<unsigned int>(parameter), values);
1,035✔
209

210
  printConditionalErrors();
1,035✔
211
}
1,035✔
212

213
void Renderer::getParameter(StateParameter parameter, int64_t* values) {
×
214
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
215

216
  glGetInteger64v(static_cast<unsigned int>(parameter), values);
×
217

218
  printConditionalErrors();
×
219
}
×
220

221
void Renderer::getParameter(StateParameter parameter, float* values) {
×
222
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
223

224
  glGetFloatv(static_cast<unsigned int>(parameter), values);
×
225

226
  printConditionalErrors();
×
227
}
×
228

229
void Renderer::getParameter(StateParameter parameter, double* values) {
×
230
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
231

232
  glGetDoublev(static_cast<unsigned int>(parameter), values);
×
233

234
  printConditionalErrors();
×
235
}
×
236

237
void Renderer::getParameter(StateParameter parameter, unsigned int index, unsigned char* values) {
×
238
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
239

240
  glGetBooleani_v(static_cast<unsigned int>(parameter), index, values);
×
241

242
  printConditionalErrors();
×
243
}
×
244

245
void Renderer::getParameter(StateParameter parameter, unsigned int index, int* values) {
×
246
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
247

248
  glGetIntegeri_v(static_cast<unsigned int>(parameter), index, values);
×
249

250
  printConditionalErrors();
×
251
}
×
252

253
void Renderer::getParameter(StateParameter parameter, unsigned int index, int64_t* values) {
×
254
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
255

256
  glGetInteger64i_v(static_cast<unsigned int>(parameter), index, values);
×
257

258
  printConditionalErrors();
×
259
}
×
260

261
unsigned int Renderer::getActiveTexture() {
×
262
  int texture {};
×
263
  getParameter(StateParameter::ACTIVE_TEXTURE, &texture);
×
264

265
  return static_cast<unsigned int>(texture - GL_TEXTURE0);
×
266
}
267

268
unsigned int Renderer::getCurrentProgram() {
558✔
269
  int program {};
558✔
270
  getParameter(StateParameter::CURRENT_PROGRAM, &program);
558✔
271

272
  return static_cast<unsigned int>(program);
558✔
273
}
274

275
void Renderer::clearColor(float red, float green, float blue, float alpha) {
15✔
276
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
15✔
277

278
  glClearColor(red, green, blue, alpha);
15✔
279

280
  printConditionalErrors();
15✔
281
}
15✔
282

283
void Renderer::clear(MaskType mask) {
50✔
284
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
50✔
285

286
  TracyGpuZone("Renderer::clear")
287

288
  glClear(static_cast<unsigned int>(mask));
50✔
289

290
  printConditionalErrors();
50✔
291
}
50✔
292

293
void Renderer::setDepthFunction(DepthStencilFunction func) {
4✔
294
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
4✔
295

296
  TracyGpuZone("Renderer::setDepthFunction")
297

298
  glDepthFunc(static_cast<unsigned int>(func));
4✔
299

300
  printConditionalErrors();
4✔
301
}
4✔
302

303
void Renderer::setStencilFunction(DepthStencilFunction func, int ref, unsigned int mask, FaceOrientation orientation) {
×
304
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
305

306
  glStencilFuncSeparate(static_cast<unsigned int>(orientation), static_cast<unsigned int>(func), ref, mask);
×
307

308
  printConditionalErrors();
×
309
}
×
310

311
void Renderer::setStencilOperations(StencilOperation stencilFailOp, StencilOperation depthFailOp, StencilOperation successOp, FaceOrientation orientation) {
×
312
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
313

314
  glStencilOpSeparate(static_cast<unsigned int>(stencilFailOp),
×
315
                      static_cast<unsigned int>(depthFailOp),
316
                      static_cast<unsigned int>(successOp),
317
                      static_cast<unsigned int>(orientation));
318

319
  printConditionalErrors();
×
320
}
×
321

322
void Renderer::setStencilMask(unsigned int mask, FaceOrientation orientation) {
×
323
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
324

325
  glStencilMaskSeparate(static_cast<unsigned int>(orientation), mask);
×
326

327
  printConditionalErrors();
×
328
}
×
329

330
void Renderer::setBlendFunction(BlendFactor source, BlendFactor destination) {
×
331
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
332

333
  glBlendFunc(static_cast<unsigned int>(source), static_cast<unsigned int>(destination));
×
334

335
  printConditionalErrors();
×
336
}
×
337

338
void Renderer::setFaceCulling(FaceOrientation orientation) {
×
339
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
340

341
  glCullFace(static_cast<unsigned int>(orientation));
×
342

343
  printConditionalErrors();
×
344
}
×
345

346
#if !defined(USE_OPENGL_ES)
347
void Renderer::setPolygonMode(FaceOrientation orientation, PolygonMode mode) {
×
348
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
349

350
  glPolygonMode(static_cast<unsigned int>(orientation), static_cast<unsigned int>(mode));
×
351

352
  printConditionalErrors();
×
353
}
×
354

355
void Renderer::setClipControl(ClipOrigin origin, ClipDepth depth) {
24✔
356
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
24✔
357
  assert("Error: Setting clip control requires OpenGL 4.5+ or the 'GL_ARB_clip_control' extension."
24✔
358
      && (checkVersion(4, 5) || isExtensionSupported("GL_ARB_clip_control")));
359

360
  glClipControl(static_cast<unsigned int>(origin), static_cast<unsigned int>(depth));
24✔
361

362
  printConditionalErrors();
24✔
363
}
24✔
364

365
void Renderer::setPatchVertexCount(int value) {
×
366
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
367
  assert("Error: Setting patch vertices requires OpenGL 4.0+ or the 'GL_ARB_tessellation_shader' extension."
×
368
      && (checkVersion(4, 0) || isExtensionSupported("GL_ARB_tessellation_shader")));
369
  assert("Error: A patch needs at least one vertex." && value > 0);
×
370

371
  glPatchParameteri(GL_PATCH_VERTICES, value);
×
372

373
  printConditionalErrors();
×
374
}
×
375

376
void Renderer::setPatchParameter(PatchParameter param, const float* values) {
×
377
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
378
  assert("Error: Setting a patch parameter requires OpenGL 4.0+ or the 'GL_ARB_tessellation_shader' extension."
×
379
      && (checkVersion(4, 0) || isExtensionSupported("GL_ARB_tessellation_shader")));
380

381
  glPatchParameterfv(static_cast<unsigned int>(param), values);
×
382

383
  printConditionalErrors();
×
384
}
×
385
#endif
386

387
void Renderer::setPixelStorage(PixelStorage storage, unsigned int value) {
36✔
388
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
36✔
389

390
  glPixelStorei(static_cast<unsigned int>(storage), static_cast<int>(value));
36✔
391

392
#if !defined(NDEBUG) && !defined(SKIP_RENDERER_ERRORS)
393
  const ErrorCodes errorCodes = recoverErrors();
394

395
  if (errorCodes[ErrorCode::INVALID_VALUE])
396
    Logger::error("Renderer::setPixelStorage - {} is not a valid alignment value. Only 1, 2, 4 & 8 are accepted", value);
397
#endif
398
}
36✔
399

400
void Renderer::recoverFrame(unsigned int width, unsigned int height, TextureFormat format, PixelDataType dataType, void* data) {
11✔
401
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
11✔
402

403
  TracyGpuZone("Renderer::recoverFrame")
404

405
  glReadPixels(0, 0, static_cast<int>(width), static_cast<int>(height), static_cast<unsigned int>(format), static_cast<unsigned int>(dataType), data);
11✔
406

407
  printConditionalErrors();
11✔
408
}
11✔
409

410
void Renderer::generateVertexArrays(unsigned int count, unsigned int* indices) {
43✔
411
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
43✔
412

413
  glGenVertexArrays(static_cast<int>(count), indices);
43✔
414

415
  printConditionalErrors();
43✔
416
}
43✔
417

418
void Renderer::bindVertexArray(unsigned int index) {
135✔
419
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
135✔
420

421
  glBindVertexArray(index);
135✔
422

423
  printConditionalErrors();
135✔
424
}
135✔
425

426
void Renderer::enableVertexAttribArray(unsigned int index) {
110✔
427
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
110✔
428

429
  glEnableVertexAttribArray(index);
110✔
430

431
  printConditionalErrors();
110✔
432
}
110✔
433

434
void Renderer::setVertexAttrib(unsigned int index, AttribDataType dataType, uint8_t size, unsigned int stride, unsigned int offset, bool normalize) {
110✔
435
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
110✔
436

437
  glVertexAttribPointer(index, size, static_cast<unsigned int>(dataType), normalize, static_cast<int>(stride), reinterpret_cast<const void*>(offset));
110✔
438

439
  printConditionalErrors();
110✔
440
}
110✔
441

442
void Renderer::setVertexAttribDivisor(unsigned int index, unsigned int divisor) {
×
443
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
444

445
  glVertexAttribDivisor(index, divisor);
×
446

447
  printConditionalErrors();
×
448
}
×
449

450
void Renderer::deleteVertexArrays(unsigned int count, const unsigned int* indices) {
43✔
451
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
43✔
452

453
  glDeleteVertexArrays(static_cast<int>(count), indices);
43✔
454

455
  printConditionalErrors();
43✔
456
}
43✔
457

458
void Renderer::generateBuffers(unsigned int count, unsigned int* indices) {
183✔
459
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
183✔
460

461
  glGenBuffers(static_cast<int>(count), indices);
183✔
462

463
  printConditionalErrors();
183✔
464
}
183✔
465

466
void Renderer::bindBuffer(BufferType type, unsigned int index) {
398✔
467
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
398✔
468

469
  glBindBuffer(static_cast<unsigned int>(type), index);
398✔
470

471
  printConditionalErrors();
398✔
472
}
398✔
473

474
void Renderer::bindBufferBase(BufferType type, unsigned int bindingIndex, unsigned int bufferIndex) {
89✔
475
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
89✔
476

477
  glBindBufferBase(static_cast<unsigned int>(type), bindingIndex, bufferIndex);
89✔
478

479
  printConditionalErrors();
89✔
480
}
89✔
481

482
void Renderer::bindBufferRange(BufferType type, unsigned int bindingIndex, unsigned int bufferIndex, std::ptrdiff_t offset, std::ptrdiff_t size) {
1✔
483
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
1✔
484

485
  glBindBufferRange(static_cast<unsigned int>(type), bindingIndex, bufferIndex, offset, size);
1✔
486

487
  printConditionalErrors();
1✔
488
}
1✔
489

490
void Renderer::sendBufferData(BufferType type, std::ptrdiff_t size, const void* data, BufferDataUsage usage) {
154✔
491
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
154✔
492

493
  glBufferData(static_cast<unsigned int>(type), size, data, static_cast<unsigned int>(usage));
154✔
494

495
  printConditionalErrors();
154✔
496
}
154✔
497

498
void Renderer::sendBufferSubData(BufferType type, std::ptrdiff_t offset, std::ptrdiff_t dataSize, const void* data) {
303✔
499
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
303✔
500

501
  glBufferSubData(static_cast<unsigned int>(type), offset, dataSize, data);
303✔
502

503
  printConditionalErrors();
303✔
504
}
303✔
505

506
void Renderer::deleteBuffers(unsigned int count, const unsigned int* indices) {
183✔
507
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
183✔
508

509
  glDeleteBuffers(static_cast<int>(count), indices);
183✔
510

511
  printConditionalErrors();
183✔
512
}
183✔
513

514
void Renderer::generateTextures(unsigned int count, unsigned int* indices) {
393✔
515
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
393✔
516

517
  glGenTextures(static_cast<int>(count), indices);
393✔
518

519
  printConditionalErrors();
393✔
520
}
393✔
521

522
bool Renderer::isTexture(unsigned int index) {
1✔
523
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
1✔
524

525
  const bool isTexture = (glIsTexture(index) == GL_TRUE);
1✔
526

527
  printConditionalErrors();
1✔
528

529
  return isTexture;
1✔
530
}
531

532
void Renderer::bindTexture(TextureType type, unsigned int index) {
3,047✔
533
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
3,047✔
534

535
  glBindTexture(static_cast<unsigned int>(type), index);
3,047✔
536

537
  printConditionalErrors();
3,047✔
538
}
3,047✔
539

540
#if !defined(USE_WEBGL)
541
void Renderer::bindImageTexture(unsigned int imageUnitIndex, unsigned int textureIndex, int textureLevel,
3✔
542
                                bool isLayered, int layer,
543
                                ImageAccess imgAccess, ImageInternalFormat imgFormat) {
544
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
3✔
545
#if !defined(USE_OPENGL_ES)
546
  assert("Error: Binding an image texture requires OpenGL 4.2+." && checkVersion(4, 2));
3✔
547
#else
548
  assert("Error: Binding an image texture requires OpenGL ES 3.1+." && checkVersion(3, 1));
549
#endif
550

551
  glBindImageTexture(imageUnitIndex, textureIndex, textureLevel, isLayered, layer, static_cast<unsigned int>(imgAccess), static_cast<unsigned int>(imgFormat));
3✔
552

553
  printConditionalErrors();
3✔
554
}
3✔
555
#endif
556

557
void Renderer::setActiveTexture(unsigned int index) {
56✔
558
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
56✔
559

560
  glActiveTexture(GL_TEXTURE0 + index);
56✔
561

562
  printConditionalErrors();
56✔
563
}
56✔
564

565
void Renderer::setTextureParameter(TextureType type, TextureParameter param, int value) {
2,426✔
566
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
2,426✔
567

568
  glTexParameteri(static_cast<unsigned int>(type), static_cast<unsigned int>(param), value);
2,426✔
569

570
  printConditionalErrors();
2,426✔
571
}
2,426✔
572

573
void Renderer::setTextureParameter(TextureType type, TextureParameter param, float value) {
×
574
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
575

576
  glTexParameterf(static_cast<unsigned int>(type), static_cast<unsigned int>(param), value);
×
577

578
  printConditionalErrors();
×
579
}
×
580

581
void Renderer::setTextureParameter(TextureType type, TextureParameter param, const int* values) {
×
582
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
583

584
  glTexParameteriv(static_cast<unsigned int>(type), static_cast<unsigned int>(param), values);
×
585

586
  printConditionalErrors();
×
587
}
×
588

589
void Renderer::setTextureParameter(TextureType type, TextureParameter param, const float* values) {
×
590
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
591

592
  glTexParameterfv(static_cast<unsigned int>(type), static_cast<unsigned int>(param), values);
×
593

594
  printConditionalErrors();
×
595
}
×
596

597
#if !defined(USE_OPENGL_ES)
598
void Renderer::setTextureParameter(unsigned int textureIndex, TextureParameter param, int value) {
×
599
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
600
  assert("Error: OpenGL 4.5+ is needed to set a parameter with a texture index." && checkVersion(4, 5));
×
601

602
  glTextureParameteri(textureIndex, static_cast<unsigned int>(param), value);
×
603

604
  printConditionalErrors();
×
605
}
×
606

607
void Renderer::setTextureParameter(unsigned int textureIndex, TextureParameter param, float value) {
×
608
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
609
  assert("Error: OpenGL 4.5+ is needed to set a parameter with a texture index." && checkVersion(4, 5));
×
610

611
  glTextureParameterf(textureIndex, static_cast<unsigned int>(param), value);
×
612

613
  printConditionalErrors();
×
614
}
×
615

616
void Renderer::setTextureParameter(unsigned int textureIndex, TextureParameter param, const int* values) {
×
617
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
618
  assert("Error: OpenGL 4.5+ is needed to set a parameter with a texture index." && checkVersion(4, 5));
×
619

620
  glTextureParameteriv(textureIndex, static_cast<unsigned int>(param), values);
×
621

622
  printConditionalErrors();
×
623
}
×
624

625
void Renderer::setTextureParameter(unsigned int textureIndex, TextureParameter param, const float* values) {
×
626
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
627
  assert("Error: OpenGL 4.5+ is needed to set a parameter with a texture index." && checkVersion(4, 5));
×
628

629
  glTextureParameterfv(textureIndex, static_cast<unsigned int>(param), values);
×
630

631
  printConditionalErrors();
×
632
}
×
633

634
void Renderer::sendImageData1D(TextureType type,
21✔
635
                               unsigned int mipmapLevel,
636
                               TextureInternalFormat internalFormat,
637
                               unsigned int width,
638
                               TextureFormat format,
639
                               PixelDataType dataType, const void* data) {
640
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
21✔
641

642
  TracyGpuZone("Renderer::sendImageData1D")
643

644
  glTexImage1D(static_cast<unsigned int>(type),
21✔
645
               static_cast<int>(mipmapLevel),
646
               static_cast<int>(internalFormat),
647
               static_cast<int>(width),
648
               0,
649
               static_cast<unsigned int>(format),
650
               static_cast<unsigned int>(dataType),
651
               data);
652

653
  printConditionalErrors();
21✔
654
}
21✔
655

656
void Renderer::sendImageSubData1D(TextureType type,
×
657
                                  unsigned int mipmapLevel,
658
                                  unsigned int offsetX,
659
                                  unsigned int width,
660
                                  TextureFormat format,
661
                                  PixelDataType dataType, const void* data) {
662
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
663

664
  TracyGpuZone("Renderer::sendImageSubData1D")
665

666
  glTexSubImage1D(static_cast<unsigned int>(type),
×
667
                  static_cast<int>(mipmapLevel),
668
                  static_cast<int>(offsetX),
669
                  static_cast<int>(width),
670
                  static_cast<unsigned int>(format),
671
                  static_cast<unsigned int>(dataType),
672
                  data);
673

674
  printConditionalErrors();
×
675
}
×
676
#endif
677

678
void Renderer::sendImageData2D(TextureType type,
421✔
679
                               unsigned int mipmapLevel,
680
                               TextureInternalFormat internalFormat,
681
                               unsigned int width, unsigned int height,
682
                               TextureFormat format,
683
                               PixelDataType dataType, const void* data) {
684
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
421✔
685

686
  TracyGpuZone("Renderer::sendImageData2D")
687

688
  glTexImage2D(static_cast<unsigned int>(type),
421✔
689
               static_cast<int>(mipmapLevel),
690
               static_cast<int>(internalFormat),
691
               static_cast<int>(width),
692
               static_cast<int>(height),
693
               0,
694
               static_cast<unsigned int>(format),
695
               static_cast<unsigned int>(dataType),
696
               data);
697

698
  printConditionalErrors();
421✔
699
}
421✔
700

701
void Renderer::sendImageSubData2D(TextureType type,
×
702
                                  unsigned int mipmapLevel,
703
                                  unsigned int offsetX, unsigned int offsetY,
704
                                  unsigned int width, unsigned int height,
705
                                  TextureFormat format,
706
                                  PixelDataType dataType, const void* data) {
707
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
708

709
  TracyGpuZone("Renderer::sendImageSubData2D")
710

711
  glTexSubImage2D(static_cast<unsigned int>(type),
×
712
                  static_cast<int>(mipmapLevel),
713
                  static_cast<int>(offsetX),
714
                  static_cast<int>(offsetY),
715
                  static_cast<int>(width),
716
                  static_cast<int>(height),
717
                  static_cast<unsigned int>(format),
718
                  static_cast<unsigned int>(dataType),
719
                  data);
720

721
  printConditionalErrors();
×
722
}
×
723

724
void Renderer::sendImageData3D(TextureType type,
50✔
725
                               unsigned int mipmapLevel,
726
                               TextureInternalFormat internalFormat,
727
                               unsigned int width, unsigned int height, unsigned int depth,
728
                               TextureFormat format,
729
                               PixelDataType dataType, const void* data) {
730
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
50✔
731

732
  TracyGpuZone("Renderer::sendImageData3D")
733

734
  glTexImage3D(static_cast<unsigned int>(type),
50✔
735
               static_cast<int>(mipmapLevel),
736
               static_cast<int>(internalFormat),
737
               static_cast<int>(width),
738
               static_cast<int>(height),
739
               static_cast<int>(depth),
740
               0,
741
               static_cast<unsigned int>(format),
742
               static_cast<unsigned int>(dataType),
743
               data);
744

745
  printConditionalErrors();
50✔
746
}
50✔
747

748
void Renderer::sendImageSubData3D(TextureType type,
12✔
749
                                  unsigned int mipmapLevel,
750
                                  unsigned int offsetX, unsigned int offsetY, unsigned int offsetZ,
751
                                  unsigned int width, unsigned int height, unsigned int depth,
752
                                  TextureFormat format,
753
                                  PixelDataType dataType, const void* data) {
754
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
12✔
755

756
  TracyGpuZone("Renderer::sendImageSubData3D")
757

758
  glTexSubImage3D(static_cast<unsigned int>(type),
12✔
759
                  static_cast<int>(mipmapLevel),
760
                  static_cast<int>(offsetX),
761
                  static_cast<int>(offsetY),
762
                  static_cast<int>(offsetZ),
763
                  static_cast<int>(width),
764
                  static_cast<int>(height),
765
                  static_cast<int>(depth),
766
                  static_cast<unsigned int>(format),
767
                  static_cast<unsigned int>(dataType),
768
                  data);
769

770
  printConditionalErrors();
12✔
771
}
12✔
772

773
#if !defined(USE_OPENGL_ES)
774
void Renderer::recoverTextureAttribute(TextureType type, unsigned int mipmapLevel, TextureAttribute attribute, int* values) {
34✔
775
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
34✔
776

777
  glGetTexLevelParameteriv(static_cast<unsigned int>(type), static_cast<int>(mipmapLevel), static_cast<unsigned int>(attribute), values);
34✔
778

779
  printConditionalErrors();
34✔
780
}
34✔
781

782
void Renderer::recoverTextureAttribute(TextureType type, unsigned int mipmapLevel, TextureAttribute attribute, float* values) {
×
783
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
784

785
  glGetTexLevelParameterfv(static_cast<unsigned int>(type), static_cast<int>(mipmapLevel), static_cast<unsigned int>(attribute), values);
×
786

787
  printConditionalErrors();
×
788
}
×
789

790
int Renderer::recoverTextureWidth(TextureType type, unsigned int mipmapLevel) {
9✔
791
  int width {};
9✔
792
  recoverTextureAttribute(type, mipmapLevel, TextureAttribute::WIDTH, &width);
9✔
793

794
  return width;
9✔
795
}
796

797
int Renderer::recoverTextureHeight(TextureType type, unsigned int mipmapLevel) {
9✔
798
  int height {};
9✔
799
  recoverTextureAttribute(type, mipmapLevel, TextureAttribute::HEIGHT, &height);
9✔
800

801
  return height;
9✔
802
}
803

804
int Renderer::recoverTextureDepth(TextureType type, unsigned int mipmapLevel) {
3✔
805
  int depth {};
3✔
806
  recoverTextureAttribute(type, mipmapLevel, TextureAttribute::DEPTH, &depth);
3✔
807

808
  return depth;
3✔
809
}
810

811
TextureInternalFormat Renderer::recoverTextureInternalFormat(TextureType type, unsigned int mipmapLevel) {
13✔
812
  int format {};
13✔
813
  recoverTextureAttribute(type, mipmapLevel, TextureAttribute::INTERNAL_FORMAT, &format);
13✔
814

815
  return static_cast<TextureInternalFormat>(format);
13✔
816
}
817

818
void Renderer::recoverTextureData(TextureType type, unsigned int mipmapLevel, TextureFormat format, PixelDataType dataType, void* data) {
59✔
819
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
59✔
820

821
  TracyGpuZone("Renderer::recoverTextureData")
822

823
  glGetTexImage(static_cast<unsigned int>(type),
59✔
824
                static_cast<int>(mipmapLevel),
825
                static_cast<unsigned int>(format),
826
                static_cast<unsigned int>(dataType),
827
                data);
828

829
  printConditionalErrors();
59✔
830
}
59✔
831
#endif
832

833
void Renderer::generateMipmap(TextureType type) {
53✔
834
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
53✔
835

836
  TracyGpuZone("Renderer::generateMipmap")
837

838
  glGenerateMipmap(static_cast<unsigned int>(type));
53✔
839

840
  printConditionalErrors();
53✔
841
}
53✔
842

843
#if !defined(USE_OPENGL_ES)
844
void Renderer::generateMipmap(unsigned int textureIndex) {
×
845
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
846
  assert("Error: OpenGL 4.5+ is needed to generate mipmap with a texture index." && checkVersion(4, 5));
×
847

848
  TracyGpuZone("Renderer::generateMipmap")
849

850
  glGenerateTextureMipmap(textureIndex);
×
851

852
  printConditionalErrors();
×
853
}
×
854
#endif
855

856
void Renderer::deleteTextures(unsigned int count, const unsigned int* indices) {
393✔
857
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
393✔
858

859
  glDeleteTextures(static_cast<int>(count), indices);
393✔
860

861
  printConditionalErrors();
393✔
862
}
393✔
863

864
void Renderer::generateSamplers(unsigned int count, unsigned int* indices) {
×
865
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
866

867
  glGenSamplers(static_cast<int>(count), indices);
×
868

869
  printConditionalErrors();
×
870
}
×
871

872
bool Renderer::isSampler(unsigned int index) {
×
873
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
874

875
  const bool isSampler = (glIsSampler(index) == GL_TRUE);
×
876

877
  printConditionalErrors();
×
878

879
  return isSampler;
×
880
}
881

882
void Renderer::bindSampler(unsigned int textureUnit, unsigned int samplerIndex) {
×
883
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
884

885
  glBindSampler(textureUnit, samplerIndex);
×
886

887
  printConditionalErrors();
×
888
}
×
889

890
void Renderer::setSamplerParameter(unsigned int samplerIndex, SamplerParameter param, int value) {
×
891
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
892

893
  glSamplerParameteri(samplerIndex, static_cast<unsigned int>(param), value);
×
894

895
  printConditionalErrors();
×
896
}
×
897

898
void Renderer::setSamplerParameter(unsigned int samplerIndex, SamplerParameter param, float value) {
×
899
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
900

901
  glSamplerParameterf(samplerIndex, static_cast<unsigned int>(param), value);
×
902

903
  printConditionalErrors();
×
904
}
×
905

906
void Renderer::setSamplerParameter(unsigned int samplerIndex, SamplerParameter param, const int* values) {
×
907
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
908

909
  glSamplerParameteriv(samplerIndex, static_cast<unsigned int>(param), values);
×
910

911
  printConditionalErrors();
×
912
}
×
913

914
void Renderer::setSamplerParameter(unsigned int samplerIndex, SamplerParameter param, const float* values) {
×
915
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
916

917
  glSamplerParameterfv(samplerIndex, static_cast<unsigned int>(param), values);
×
918

919
  printConditionalErrors();
×
920
}
×
921

922
void Renderer::deleteSamplers(unsigned int count, const unsigned int* indices) {
×
923
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
924

925
  glDeleteSamplers(static_cast<int>(count), indices);
×
926

927
  printConditionalErrors();
×
928
}
×
929

930
void Renderer::resizeViewport(int xOrigin, int yOrigin, unsigned int width, unsigned int height) {
22✔
931
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
22✔
932

933
  glViewport(xOrigin, yOrigin, static_cast<int>(width), static_cast<int>(height));
22✔
934

935
  printConditionalErrors();
22✔
936
}
22✔
937

938
unsigned int Renderer::createProgram() {
183✔
939
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
183✔
940

941
  const unsigned int programIndex = glCreateProgram();
183✔
942

943
  printConditionalErrors();
183✔
944

945
  return programIndex;
183✔
946
}
947

948
void Renderer::getProgramParameter(unsigned int index, ProgramParameter parameter, int* parameters) {
701✔
949
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
701✔
950

951
  glGetProgramiv(index, static_cast<unsigned int>(parameter), parameters);
701✔
952

953
  printConditionalErrors();
701✔
954
}
701✔
955

956
bool Renderer::isProgramLinked(unsigned int index) {
423✔
957
  int linkStatus {};
423✔
958
  getProgramParameter(index, ProgramParameter::LINK_STATUS, &linkStatus);
423✔
959

960
  return (linkStatus == GL_TRUE);
423✔
961
}
962

963
unsigned int Renderer::recoverActiveUniformCount(unsigned int programIndex) {
2✔
964
  int uniformCount {};
2✔
965
  getProgramParameter(programIndex, ProgramParameter::ACTIVE_UNIFORMS, &uniformCount);
2✔
966

967
  return static_cast<unsigned int>(uniformCount);
2✔
968
}
969

970
std::vector<unsigned int> Renderer::recoverAttachedShaders(unsigned int programIndex) {
276✔
971
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
276✔
972

973
  int attachedShaderCount {};
276✔
974
  getProgramParameter(programIndex, ProgramParameter::ATTACHED_SHADERS, &attachedShaderCount);
276✔
975

976
  if (attachedShaderCount == 0)
276✔
977
    return {};
131✔
978

979
  std::vector<unsigned int> shaderIndices(static_cast<std::size_t>(attachedShaderCount));
145✔
980

981
  int recoveredShaderCount {};
145✔
982
  glGetAttachedShaders(programIndex, attachedShaderCount, &recoveredShaderCount, shaderIndices.data());
145✔
983

984
  printConditionalErrors();
145✔
985

986
  if (recoveredShaderCount == 0)
145✔
987
    return {};
×
988

989
  return shaderIndices;
145✔
990
}
145✔
991

992
void Renderer::linkProgram(unsigned int index) {
171✔
993
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
171✔
994

995
  TracyGpuZone("Renderer::linkProgram")
996

997
  glLinkProgram(index);
171✔
998

999
  if (!isProgramLinked(index)) {
171✔
1000
    char infoLog[512];
1001

1002
    glGetProgramInfoLog(index, static_cast<int>(std::size(infoLog)), nullptr, infoLog);
46✔
1003
    Logger::error("[Renderer] Shader program link failed (ID {}): {}", index, infoLog);
23✔
1004
  }
1005

1006
  printConditionalErrors();
171✔
1007
}
171✔
1008

1009
void Renderer::useProgram(unsigned int index) {
315✔
1010
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
315✔
1011

1012
  TracyGpuZone("Renderer::useProgram")
1013

1014
  glUseProgram(index);
315✔
1015

1016
#if !defined(NDEBUG) && !defined(SKIP_RENDERER_ERRORS)
1017
  const ErrorCodes errorCodes = recoverErrors();
1018

1019
  if (errorCodes[ErrorCode::INVALID_VALUE])
1020
    Logger::error("Renderer::useProgram - Invalid shader program index ({})", index);
1021

1022
  if (errorCodes[ErrorCode::INVALID_OPERATION]) {
1023
    std::string errorMsg = "Renderer::useProgram - ";
1024

1025
    if (!isProgramLinked(index))
1026
      errorMsg += "A shader program must be linked before being defined as used.";
1027
    else
1028
      errorMsg += "Unknown invalid operation.";
1029

1030
    Logger::error(errorMsg);
1031
  }
1032
#endif
1033
}
315✔
1034

1035
void Renderer::deleteProgram(unsigned int index) {
183✔
1036
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
183✔
1037

1038
  glDeleteProgram(index);
183✔
1039

1040
  printConditionalErrors();
183✔
1041
}
183✔
1042

1043
unsigned int Renderer::createShader(ShaderType type) {
703✔
1044
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
703✔
1045
#if !defined(USE_OPENGL_ES)
1046
  assert("Error: Creating a tessellation shader requires OpenGL 4.0+ or the 'GL_ARB_tessellation_shader' extension."
703✔
1047
      && ((type != ShaderType::TESSELLATION_CONTROL && type != ShaderType::TESSELLATION_EVALUATION)
1048
      || checkVersion(4, 0) || isExtensionSupported("GL_ARB_tessellation_shader")));
1049
  assert("Error: Creating a compute shader requires OpenGL 4.3+ or the 'GL_ARB_compute_shader' extension."
703✔
1050
      && (type != ShaderType::COMPUTE || checkVersion(4, 3) || isExtensionSupported("GL_ARB_compute_shader")));
1051
#else
1052
  assert("Error: Geometry shaders are unsupported with OpenGL ES." && type != ShaderType::GEOMETRY);
1053
  assert("Error: Tessellation shaders are unsupported with OpenGL ES."
1054
         && type != ShaderType::TESSELLATION_CONTROL && type != ShaderType::TESSELLATION_EVALUATION);
1055
  assert("Error: Creating a compute shader requires OpenGL ES 3.1+ or the 'GL_ARB_compute_shader' extension."
1056
      && (type != ShaderType::COMPUTE || checkVersion(3, 1) || isExtensionSupported("GL_ARB_compute_shader")));
1057
#endif
1058

1059
  const unsigned int shaderIndex = glCreateShader(static_cast<unsigned int>(type));
703✔
1060

1061
  printConditionalErrors();
703✔
1062

1063
  return shaderIndex;
703✔
1064
}
1065

1066
int Renderer::recoverShaderInfo(unsigned int index, ShaderInfo info) {
465✔
1067
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
465✔
1068

1069
  int res {};
465✔
1070
  glGetShaderiv(index, static_cast<unsigned int>(info), &res);
465✔
1071

1072
  printConditionalErrors();
465✔
1073

1074
  return res;
465✔
1075
}
1076

1077
void Renderer::sendShaderSource(unsigned int index, const char* source, int length) {
309✔
1078
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
309✔
1079

1080
  TracyGpuZone("Renderer::sendShaderSource")
1081

1082
  glShaderSource(index, 1, &source, &length);
309✔
1083

1084
  printConditionalErrors();
309✔
1085
}
309✔
1086

1087
std::string Renderer::recoverShaderSource(unsigned int index) {
52✔
1088
  TracyGpuZone("Renderer::recoverShaderSource")
1089

1090
  const int sourceLength = recoverShaderInfo(index, ShaderInfo::SOURCE_LENGTH);
52✔
1091

1092
  if (sourceLength == 0)
52✔
1093
    return {};
12✔
1094

1095
  std::string source;
40✔
1096
  source.resize(static_cast<std::size_t>(sourceLength - 1)); // The recovered length includes the null terminator, hence the -1
40✔
1097

1098
  glGetShaderSource(index, sourceLength, nullptr, source.data());
40✔
1099

1100
  printConditionalErrors();
40✔
1101

1102
  return source;
40✔
1103
}
40✔
1104

1105
void Renderer::compileShader(unsigned int index) {
370✔
1106
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
370✔
1107

1108
  TracyGpuZone("Renderer::compileShader")
1109

1110
  glCompileShader(index);
370✔
1111

1112
  if (!isShaderCompiled(index)) {
370✔
1113
    char infoLog[512];
1114

1115
    glGetShaderInfoLog(index, static_cast<int>(std::size(infoLog)), nullptr, infoLog);
112✔
1116
    Logger::error("[Renderer] Shader compilation failed (ID {}): {}", index, infoLog);
56✔
1117
  }
1118

1119
  printConditionalErrors();
370✔
1120
}
370✔
1121

1122
void Renderer::attachShader(unsigned int programIndex, unsigned int shaderIndex) {
287✔
1123
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
287✔
1124

1125
  glAttachShader(programIndex, shaderIndex);
287✔
1126

1127
  printConditionalErrors();
287✔
1128
}
287✔
1129

1130
void Renderer::detachShader(unsigned int programIndex, unsigned int shaderIndex) {
26✔
1131
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
26✔
1132

1133
  glDetachShader(programIndex, shaderIndex);
26✔
1134

1135
  printConditionalErrors();
26✔
1136
}
26✔
1137

1138
bool Renderer::isShaderAttached(unsigned int programIndex, unsigned int shaderIndex) {
276✔
1139
  const std::vector<unsigned int> shaderIndices = recoverAttachedShaders(programIndex);
276✔
1140
  return (std::ranges::find(shaderIndices, shaderIndex) != shaderIndices.cend());
552✔
1141
}
276✔
1142

1143
void Renderer::deleteShader(unsigned int index) {
703✔
1144
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
703✔
1145

1146
  glDeleteShader(index);
703✔
1147

1148
  printConditionalErrors();
703✔
1149
}
703✔
1150

1151
int Renderer::recoverUniformLocation(unsigned int programIndex, const char* uniformName) {
519✔
1152
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
519✔
1153

1154
  const int location = glGetUniformLocation(programIndex, uniformName);
519✔
1155

1156
#if !defined(NDEBUG) && !defined(SKIP_RENDERER_ERRORS)
1157
  printErrors();
1158

1159
  if (location == -1)
1160
    Logger::warn("Uniform '{}' unrecognized", uniformName);
1161
#endif
1162

1163
  return location;
519✔
1164
}
1165

1166
void Renderer::recoverUniformInfo(unsigned int programIndex, unsigned int uniformIndex, UniformType& type, std::string& name, int* size) {
13✔
1167
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
13✔
1168

1169
  int nameLength {};
13✔
1170
  int uniformSize {};
13✔
1171
  unsigned int uniformType {};
13✔
1172
  std::array<char, 256> uniformName {};
13✔
1173

1174
  glGetActiveUniform(programIndex, uniformIndex, static_cast<int>(uniformName.size()), &nameLength, &uniformSize, &uniformType, uniformName.data());
39✔
1175

1176
  type = static_cast<UniformType>(uniformType);
13✔
1177

1178
  name.resize(static_cast<std::size_t>(nameLength));
13✔
1179
  std::copy(uniformName.cbegin(), uniformName.cbegin() + nameLength, name.begin());
13✔
1180

1181
  if (size)
13✔
1182
    *size = uniformSize;
13✔
1183

1184
#if !defined(NDEBUG) && !defined(SKIP_RENDERER_ERRORS)
1185
  const ErrorCodes errorCodes = recoverErrors();
1186

1187
  if (errorCodes.isEmpty())
1188
    return;
1189

1190
  if (errorCodes[ErrorCode::INVALID_OPERATION])
1191
    Logger::error("Renderer::recoverUniformInfo - Tried to fetch program information from a non-program object");
1192

1193
  if (errorCodes[ErrorCode::INVALID_VALUE]) {
1194
    std::string errorMsg = "Renderer::recoverUniformInfo - ";
1195

1196
    const unsigned int uniCount = recoverActiveUniformCount(programIndex);
1197

1198
    if (uniformIndex >= uniCount)
1199
      errorMsg += std::format("The given uniform index ({}) is greater than or equal to the program's active uniform count ({})", uniformIndex, uniCount);
1200
    else
1201
      errorMsg += "The given program index has not been created by OpenGL";
1202

1203
    Logger::error(errorMsg);
1204
  }
1205
#endif
1206
}
13✔
1207

1208
UniformType Renderer::recoverUniformType(unsigned int programIndex, unsigned int uniformIndex) {
×
1209
  UniformType type {};
×
1210
  std::string name;
×
1211
  recoverUniformInfo(programIndex, uniformIndex, type, name);
×
1212

1213
  return type;
×
1214
}
×
1215

1216
std::string Renderer::recoverUniformName(unsigned int programIndex, unsigned int uniformIndex) {
×
1217
  UniformType type {};
×
1218
  std::string name;
×
1219
  recoverUniformInfo(programIndex, uniformIndex, type, name);
×
1220

1221
  return name;
×
1222
}
×
1223

1224
void Renderer::recoverUniformData(unsigned int programIndex, int uniformIndex, int* data) {
×
1225
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1226

1227
  glGetUniformiv(programIndex, uniformIndex, data);
×
1228

1229
  printConditionalErrors();
×
1230
}
×
1231

1232
void Renderer::recoverUniformData(unsigned int programIndex, int uniformIndex, unsigned int* data) {
×
1233
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1234

1235
  glGetUniformuiv(programIndex, uniformIndex, data);
×
1236

1237
  printConditionalErrors();
×
1238
}
×
1239

1240
void Renderer::recoverUniformData(unsigned int programIndex, int uniformIndex, float* data) {
×
1241
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1242

1243
  glGetUniformfv(programIndex, uniformIndex, data);
×
1244

1245
  printConditionalErrors();
×
1246
}
×
1247

1248
#if !defined(USE_OPENGL_ES)
1249
void Renderer::recoverUniformData(unsigned int programIndex, int uniformIndex, double* data) {
×
1250
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1251
  assert("Error: Recovering uniform data of type double requires OpenGL 4.0+." && checkVersion(4, 0));
×
1252

1253
  glGetUniformdv(programIndex, uniformIndex, data);
×
1254

1255
  printConditionalErrors();
×
1256
}
×
1257
#endif
1258

1259
void Renderer::bindUniformBlock(unsigned int programIndex, unsigned int uniformBlockIndex, unsigned int bindingIndex) {
14✔
1260
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
14✔
1261

1262
  glUniformBlockBinding(programIndex, uniformBlockIndex, bindingIndex);
14✔
1263

1264
  printConditionalErrors();
14✔
1265
}
14✔
1266

1267
unsigned int Renderer::recoverUniformBlockIndex(unsigned int programIndex, const char* uniformBlockName) {
54✔
1268
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
54✔
1269

1270
  const unsigned int index = glGetUniformBlockIndex(programIndex, uniformBlockName);
54✔
1271

1272
  printConditionalErrors();
54✔
1273

1274
  return index;
54✔
1275
}
1276

1277
void Renderer::sendUniform(int uniformIndex, int value) {
249✔
1278
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
249✔
1279

1280
  glUniform1i(uniformIndex, value);
249✔
1281

1282
  printConditionalErrors();
249✔
1283
}
249✔
1284

1285
void Renderer::sendUniform(int uniformIndex, unsigned int value) {
×
1286
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1287

1288
  glUniform1ui(uniformIndex, value);
×
1289

1290
  printConditionalErrors();
×
1291
}
×
1292

1293
void Renderer::sendUniform(int uniformIndex, float value) {
126✔
1294
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
126✔
1295

1296
  glUniform1f(uniformIndex, value);
126✔
1297

1298
  printConditionalErrors();
126✔
1299
}
126✔
1300

1301
void Renderer::sendUniformVector1i(int uniformIndex, const int* values, int count) {
×
1302
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1303

1304
  glUniform1iv(uniformIndex, count, values);
×
1305

1306
  printConditionalErrors();
×
1307
}
×
1308

1309
void Renderer::sendUniformVector2i(int uniformIndex, const int* values, int count) {
×
1310
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1311

1312
  glUniform2iv(uniformIndex, count, values);
×
1313

1314
  printConditionalErrors();
×
1315
}
×
1316

1317
void Renderer::sendUniformVector3i(int uniformIndex, const int* values, int count) {
×
1318
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1319

1320
  glUniform3iv(uniformIndex, count, values);
×
1321

1322
  printConditionalErrors();
×
1323
}
×
1324

1325
void Renderer::sendUniformVector4i(int uniformIndex, const int* values, int count) {
×
1326
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1327

1328
  glUniform4iv(uniformIndex, count, values);
×
1329

1330
  printConditionalErrors();
×
1331
}
×
1332

1333
void Renderer::sendUniformVector1ui(int uniformIndex, const unsigned int* values, int count) {
×
1334
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1335

1336
  glUniform1uiv(uniformIndex, count, values);
×
1337

1338
  printConditionalErrors();
×
1339
}
×
1340

1341
void Renderer::sendUniformVector2ui(int uniformIndex, const unsigned int* values, int count) {
×
1342
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1343

1344
  glUniform2uiv(uniformIndex, count, values);
×
1345

1346
  printConditionalErrors();
×
1347
}
×
1348

1349
void Renderer::sendUniformVector3ui(int uniformIndex, const unsigned int* values, int count) {
×
1350
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1351

1352
  glUniform3uiv(uniformIndex, count, values);
×
1353

1354
  printConditionalErrors();
×
1355
}
×
1356

1357
void Renderer::sendUniformVector4ui(int uniformIndex, const unsigned int* values, int count) {
×
1358
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1359

1360
  glUniform4uiv(uniformIndex, count, values);
×
1361

1362
  printConditionalErrors();
×
1363
}
×
1364

1365
void Renderer::sendUniformVector1(int uniformIndex, const float* values, int count) {
16✔
1366
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
16✔
1367

1368
  glUniform1fv(uniformIndex, count, values);
16✔
1369

1370
  printConditionalErrors();
16✔
1371
}
16✔
1372

1373
void Renderer::sendUniformVector2(int uniformIndex, const float* values, int count) {
107✔
1374
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
107✔
1375

1376
  glUniform2fv(uniformIndex, count, values);
107✔
1377

1378
  printConditionalErrors();
107✔
1379
}
107✔
1380

1381
void Renderer::sendUniformVector3(int uniformIndex, const float* values, int count) {
46✔
1382
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
46✔
1383

1384
  glUniform3fv(uniformIndex, count, values);
46✔
1385

1386
  printConditionalErrors();
46✔
1387
}
46✔
1388

1389
void Renderer::sendUniformVector4(int uniformIndex, const float* values, int count) {
×
1390
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1391

1392
  glUniform4fv(uniformIndex, count, values);
×
1393

1394
  printConditionalErrors();
×
1395
}
×
1396

1397
void Renderer::sendUniformMatrix2x2(int uniformIndex, const float* values, int count, bool transpose) {
×
1398
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1399

1400
  glUniformMatrix2fv(uniformIndex, count, transpose, values);
×
1401

1402
  printConditionalErrors();
×
1403
}
×
1404

1405
void Renderer::sendUniformMatrix3x3(int uniformIndex, const float* values, int count, bool transpose) {
×
1406
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1407

1408
  glUniformMatrix3fv(uniformIndex, count, transpose, values);
×
1409

1410
  printConditionalErrors();
×
1411
}
×
1412

1413
void Renderer::sendUniformMatrix4x4(int uniformIndex, const float* values, int count, bool transpose) {
×
1414
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1415

1416
  glUniformMatrix4fv(uniformIndex, count, transpose, values);
×
1417

1418
  printConditionalErrors();
×
1419
}
×
1420

1421
void Renderer::generateFramebuffers(int count, unsigned int* indices) {
129✔
1422
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
129✔
1423

1424
  glGenFramebuffers(count, indices);
129✔
1425

1426
  printConditionalErrors();
129✔
1427
}
129✔
1428

1429
void Renderer::bindFramebuffer(unsigned int index, FramebufferType type) {
204✔
1430
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
204✔
1431

1432
  glBindFramebuffer(static_cast<unsigned int>(type), index);
204✔
1433

1434
#if !defined(NDEBUG) && !defined(SKIP_RENDERER_ERRORS)
1435
  const ErrorCodes errorCodes = recoverErrors();
1436

1437
  if (errorCodes[ErrorCode::INVALID_OPERATION])
1438
    Logger::error("Renderer::bindFramebuffer - Bound object is not a valid framebuffer");
1439
#endif
1440
}
204✔
1441

1442
FramebufferStatus Renderer::getFramebufferStatus(FramebufferType type) {
×
1443
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1444

1445
  const unsigned int status = glCheckFramebufferStatus(static_cast<unsigned int>(type));
×
1446

1447
  printConditionalErrors();
×
1448

1449
  return static_cast<FramebufferStatus>(status);
×
1450
}
1451

1452
#if !defined(USE_OPENGL_ES)
1453
void Renderer::setFramebufferTexture(FramebufferAttachment attachment,
×
1454
                                     unsigned int textureIndex, unsigned int mipmapLevel,
1455
                                     FramebufferType type) {
1456
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1457

1458
  TracyGpuZone("Renderer::setFramebufferTexture")
1459

1460
  glFramebufferTexture(static_cast<unsigned int>(type),
×
1461
                       static_cast<unsigned int>(attachment),
1462
                       textureIndex,
1463
                       static_cast<int>(mipmapLevel));
1464

1465
  printConditionalErrors();
×
1466
}
×
1467

1468
void Renderer::setFramebufferTexture1D(FramebufferAttachment attachment,
×
1469
                                       unsigned int textureIndex, unsigned int mipmapLevel,
1470
                                       FramebufferType type) {
1471
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1472

1473
  TracyGpuZone("Renderer::setFramebufferTexture1D")
1474

1475
  glFramebufferTexture1D(static_cast<unsigned int>(type),
×
1476
                         static_cast<unsigned int>(attachment),
1477
                         static_cast<unsigned int>(TextureType::TEXTURE_1D),
1478
                         textureIndex,
1479
                         static_cast<int>(mipmapLevel));
1480

1481
  printConditionalErrors();
×
1482
}
×
1483
#endif
1484

1485
void Renderer::setFramebufferTexture2D(FramebufferAttachment attachment,
85✔
1486
                                       unsigned int textureIndex, unsigned int mipmapLevel,
1487
                                       TextureType textureType,
1488
                                       FramebufferType type) {
1489
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
85✔
1490

1491
  TracyGpuZone("Renderer::setFramebufferTexture2D")
1492

1493
  glFramebufferTexture2D(static_cast<unsigned int>(type),
85✔
1494
                         static_cast<unsigned int>(attachment),
1495
                         static_cast<unsigned int>(textureType),
1496
                         textureIndex,
1497
                         static_cast<int>(mipmapLevel));
1498

1499
  printConditionalErrors();
85✔
1500
}
85✔
1501

1502
#if !defined(USE_OPENGL_ES)
1503
void Renderer::setFramebufferTexture3D(FramebufferAttachment attachment,
×
1504
                                       unsigned int textureIndex, unsigned int mipmapLevel, unsigned int layer,
1505
                                       FramebufferType type) {
1506
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1507

1508
  TracyGpuZone("Renderer::setFramebufferTexture3D")
1509

1510
  glFramebufferTexture3D(static_cast<unsigned int>(type),
×
1511
                         static_cast<unsigned int>(attachment),
1512
                         static_cast<unsigned int>(TextureType::TEXTURE_3D),
1513
                         textureIndex,
1514
                         static_cast<int>(mipmapLevel),
1515
                         static_cast<int>(layer));
1516

1517
  printConditionalErrors();
×
1518
}
×
1519
#endif
1520

1521
void Renderer::recoverFramebufferAttachmentParameter(FramebufferAttachment attachment,
18✔
1522
                                                     FramebufferAttachmentParam param,
1523
                                                     int* values,
1524
                                                     FramebufferType type) {
1525
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
18✔
1526

1527
  glGetFramebufferAttachmentParameteriv(static_cast<unsigned int>(type), static_cast<unsigned int>(attachment), static_cast<unsigned int>(param), values);
18✔
1528

1529
  printConditionalErrors();
18✔
1530
}
18✔
1531

1532
void Renderer::setReadBuffer(ReadBuffer buffer) {
×
1533
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1534

1535
  glReadBuffer(static_cast<unsigned int>(buffer));
×
1536

1537
  printConditionalErrors();
×
1538
}
×
1539

1540
void Renderer::setDrawBuffers(unsigned int count, const DrawBuffer* buffers) {
67✔
1541
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
67✔
1542

1543
  glDrawBuffers(static_cast<int>(count), reinterpret_cast<const unsigned int*>(buffers));
67✔
1544

1545
  printConditionalErrors();
67✔
1546
}
67✔
1547

1548
void Renderer::blitFramebuffer(int readMinX, int readMinY, int readMaxX, int readMaxY,
×
1549
                               int writeMinX, int writeMinY, int writeMaxX, int writeMaxY,
1550
                               MaskType mask, BlitFilter filter) {
1551
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1552

1553
  TracyGpuZone("Renderer::blitFramebuffer")
1554

1555
  glBlitFramebuffer(readMinX, readMinY, readMaxX, readMaxY,
×
1556
                    writeMinX, writeMinY, writeMaxX, writeMaxY,
1557
                    static_cast<unsigned int>(mask), static_cast<unsigned int>(filter));
1558

1559
  printConditionalErrors();
×
1560
}
×
1561

1562
void Renderer::deleteFramebuffers(unsigned int count, const unsigned int* indices) {
129✔
1563
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
129✔
1564

1565
  glDeleteFramebuffers(static_cast<int>(count), indices);
129✔
1566

1567
  printConditionalErrors();
129✔
1568
}
129✔
1569

1570
void Renderer::drawArrays(PrimitiveType type, unsigned int first, unsigned int count) {
15✔
1571
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
15✔
1572

1573
  TracyGpuZone("Renderer::drawArrays")
1574

1575
  glDrawArrays(static_cast<unsigned int>(type), static_cast<int>(first), static_cast<int>(count));
15✔
1576

1577
  printConditionalErrors();
15✔
1578
}
15✔
1579

1580
void Renderer::drawArraysInstanced(PrimitiveType type, unsigned int first, unsigned int primitiveCount, unsigned int instanceCount) {
×
1581
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1582

1583
  TracyGpuZone("Renderer::drawArraysInstanced")
1584

1585
  glDrawArraysInstanced(static_cast<unsigned int>(type), static_cast<int>(first), static_cast<int>(primitiveCount), static_cast<int>(instanceCount));
×
1586

1587
  printConditionalErrors();
×
1588
}
×
1589

1590
void Renderer::drawElements(PrimitiveType type, unsigned int count, ElementDataType dataType, const void* indices) {
6✔
1591
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
6✔
1592

1593
  TracyGpuZone("Renderer::drawElements")
1594

1595
  glDrawElements(static_cast<unsigned int>(type), static_cast<int>(count), static_cast<unsigned int>(dataType), indices);
6✔
1596

1597
  printConditionalErrors();
6✔
1598
}
6✔
1599

1600
void Renderer::drawElementsInstanced(PrimitiveType type, unsigned int primitiveCount,
×
1601
                                     ElementDataType dataType, const void* indices,
1602
                                     unsigned int instanceCount) {
1603
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1604

1605
  TracyGpuZone("Renderer::drawElementsInstanced")
1606

1607
  glDrawElementsInstanced(static_cast<unsigned int>(type), static_cast<int>(primitiveCount),
×
1608
                          static_cast<unsigned int>(dataType), indices,
1609
                          static_cast<int>(instanceCount));
1610

1611
  printConditionalErrors();
×
1612
}
×
1613

1614
void Renderer::dispatchCompute(unsigned int groupCountX, unsigned int groupCountY, unsigned int groupCountZ) {
3✔
1615
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
3✔
1616
#if !defined(USE_OPENGL_ES)
1617
  assert("Error: Launching a compute operation requires OpenGL 4.3+ or the 'GL_ARB_compute_shader' extension."
3✔
1618
      && (checkVersion(4, 3) || isExtensionSupported("GL_ARB_compute_shader")));
1619
#else
1620
  assert("Error: Launching a compute operation requires OpenGL ES 3.1+ or the 'GL_ARB_compute_shader' extension."
1621
      && (checkVersion(3, 1) || isExtensionSupported("GL_ARB_compute_shader")));
1622
#endif
1623

1624
  TracyGpuZone("Renderer::dispatchCompute")
1625

1626
  glDispatchCompute(groupCountX, groupCountY, groupCountZ);
3✔
1627

1628
  printConditionalErrors();
3✔
1629
}
3✔
1630

1631
void Renderer::setMemoryBarrier(BarrierType type) {
3✔
1632
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
3✔
1633
#if !defined(USE_OPENGL_ES)
1634
  assert("Error: Setting a memory barrier requires OpenGL 4.2+." && checkVersion(4, 2));
3✔
1635
#else
1636
  assert("Error: Setting a memory barrier requires OpenGL ES 3.1+." && checkVersion(3, 1));
1637
#endif
1638

1639
  TracyGpuZone("Renderer::setMemoryBarrier")
1640

1641
  glMemoryBarrier(static_cast<unsigned int>(type));
3✔
1642

1643
  printConditionalErrors();
3✔
1644
}
3✔
1645

1646
void Renderer::setMemoryBarrierByRegion(RegionBarrierType type) {
×
1647
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1648
#if !defined(USE_OPENGL_ES)
1649
  assert("Error: Setting a memory barrier by region requires OpenGL 4.5+." && checkVersion(4, 5));
×
1650
#else
1651
  assert("Error: Setting a memory barrier by region requires OpenGL ES 3.1+." && checkVersion(3, 1));
1652
#endif
1653

1654
  TracyGpuZone("Renderer::setMemoryBarrierByRegion")
1655

1656
  glMemoryBarrierByRegion(static_cast<unsigned int>(type));
×
1657

1658
  printConditionalErrors();
×
1659
}
×
1660

1661
void Renderer::generateQueries(unsigned int count, unsigned int* indices) {
125✔
1662
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
125✔
1663

1664
  glGenQueries(static_cast<int>(count), indices);
125✔
1665

1666
  printConditionalErrors();
125✔
1667
}
125✔
1668

1669
void Renderer::beginQuery(QueryType type, unsigned int index) {
35✔
1670
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
35✔
1671

1672
  glBeginQuery(static_cast<unsigned int>(type), index);
35✔
1673

1674
  printConditionalErrors();
35✔
1675
}
35✔
1676

1677
void Renderer::endQuery(QueryType type) {
35✔
1678
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
35✔
1679

1680
  glEndQuery(static_cast<unsigned int>(type));
35✔
1681

1682
  printConditionalErrors();
35✔
1683
}
35✔
1684

1685
#if !defined(USE_OPENGL_ES)
1686
void Renderer::recoverQueryResult(unsigned int index, int64_t& result) {
19✔
1687
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
19✔
1688

1689
  glGetQueryObjecti64v(index, GL_QUERY_RESULT, &result);
19✔
1690

1691
  printConditionalErrors();
19✔
1692
}
19✔
1693

1694
void Renderer::recoverQueryResult(unsigned int index, uint64_t& result) {
×
1695
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1696

1697
  glGetQueryObjectui64v(index, GL_QUERY_RESULT, &result);
×
1698

1699
  printConditionalErrors();
×
1700
}
×
1701
#endif
1702

1703
void Renderer::deleteQueries(unsigned int count, const unsigned int* indices) {
125✔
1704
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
125✔
1705

1706
  glDeleteQueries(static_cast<int>(count), indices);
125✔
1707

1708
  printConditionalErrors();
125✔
1709
}
125✔
1710

1711
#if !defined(USE_OPENGL_ES)
1712
void Renderer::setLabel(RenderObjectType type, unsigned int objectIndex, const char* label) {
453✔
1713
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
453✔
1714
  assert("Error: Setting an object label requires OpenGL 4.3+." && checkVersion(4, 3));
453✔
1715

1716
  glObjectLabel(static_cast<unsigned int>(type), objectIndex, -1, label);
453✔
1717

1718
  printConditionalErrors();
453✔
1719
}
453✔
1720

1721
std::string Renderer::recoverLabel(RenderObjectType type, unsigned int objectIndex) {
×
1722
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
×
1723
  assert("Error: Recovering an object label requires OpenGL 4.3+." && checkVersion(4, 3));
×
1724

1725
  int labelLength {};
×
1726
  std::array<char, 256> labelName {};
×
1727

1728
  glGetObjectLabel(static_cast<unsigned int>(type), objectIndex, static_cast<int>(labelName.size()), &labelLength, labelName.data());
×
1729

1730
  std::string label;
×
1731
  label.resize(static_cast<std::size_t>(labelLength));
×
1732
  std::copy(labelName.cbegin(), labelName.cbegin() + labelLength, label.begin());
×
1733

1734
  printConditionalErrors();
×
1735

1736
  return label;
×
1737
}
×
1738

1739
void Renderer::pushDebugGroup(const std::string& name) {
40✔
1740
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
40✔
1741
  assert("Error: Pushing a debug group requires OpenGL 4.3+." && checkVersion(4, 3));
40✔
1742

1743
  glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, static_cast<int>(name.size()), name.c_str());
40✔
1744

1745
  printConditionalErrors();
40✔
1746
}
40✔
1747

1748
void Renderer::popDebugGroup() {
40✔
1749
  assert("Error: The Renderer must be initialized before calling its functions." && isInitialized());
40✔
1750
  assert("Error: Popping a debug group requires OpenGL 4.3+." && checkVersion(4, 3));
40✔
1751

1752
  glPopDebugGroup();
40✔
1753

1754
  printConditionalErrors();
40✔
1755
}
40✔
1756
#endif
1757

1758
ErrorCodes Renderer::recoverErrors() noexcept {
117✔
1759
  static constexpr auto recoverErrorCodeIndex = [] (ErrorCode code) constexpr noexcept -> uint8_t {
1✔
1760
    return static_cast<uint8_t>(static_cast<unsigned int>(code) - static_cast<unsigned int>(ErrorCode::INVALID_ENUM));
1✔
1761
  };
1762

1763
  ErrorCodes errorCodes;
117✔
1764

1765
  while (true) {
1766
    const unsigned int errorCode = glGetError();
118✔
1767

1768
    if (errorCode == GL_NO_ERROR)
118✔
1769
      break;
117✔
1770

1771
    const uint8_t errorCodeIndex = recoverErrorCodeIndex(static_cast<ErrorCode>(errorCode));
1✔
1772

1773
    // An error code cannot be returned twice in a row; if it is, the error checking should be stopped
1774
    if (errorCodes.codes[errorCodeIndex])
1✔
1775
      break;
×
1776

1777
    errorCodes.codes[errorCodeIndex] = true;
1✔
1778
  }
1✔
1779

1780
  return errorCodes;
117✔
1781
}
1782

1783
void Renderer::printErrors() {
×
1784
  const ErrorCodes errorCodes = recoverErrors();
×
1785

1786
  if (errorCodes.isEmpty())
×
1787
    return;
×
1788

1789
  for (uint8_t errorIndex = 0; errorIndex < static_cast<uint8_t>(errorCodes.codes.size()); ++errorIndex) {
×
1790
    if (errorCodes.codes[errorIndex]) {
×
1791
      const unsigned int errorValue = errorIndex + static_cast<unsigned int>(ErrorCode::INVALID_ENUM);
×
NEW
1792
      Logger::error("[OpenGL] {} (code {})", recoverGlErrorStr(errorValue), errorValue);
×
1793
    }
1794
  }
1795
}
1796

1797
void Renderer::recoverDefaultFramebufferColorFormat() {
2✔
1798
  struct ColorInfo {
1799
    int redBitCount {};
1800
    int greenBitCount {};
1801
    int blueBitCount {};
1802
    int alphaBitCount {};
1803
    int compType {};
1804
    int encoding {};
1805
  };
1806

1807
  struct ColorFormat {
1808
    ColorInfo colorInfo {};
1809
    TextureInternalFormat format {};
1810
    std::string_view formatStr;
1811
  };
1812

1813
  constexpr std::array<ColorFormat, 26> formats = {{
2✔
1814
    { ColorInfo{ 8,  8,  8,  0,  GL_UNSIGNED_NORMALIZED, GL_LINEAR }, TextureInternalFormat::RGB8,           "RGB8"           },
1815
    { ColorInfo{ 8,  8,  8,  8,  GL_UNSIGNED_NORMALIZED, GL_LINEAR }, TextureInternalFormat::RGBA8,          "RGBA8"          },
1816
    { ColorInfo{ 8,  8,  8,  0,  GL_UNSIGNED_NORMALIZED, GL_SRGB   }, TextureInternalFormat::SRGB8,          "SRGB8"          },
1817
    { ColorInfo{ 8,  8,  8,  8,  GL_UNSIGNED_NORMALIZED, GL_SRGB   }, TextureInternalFormat::SRGBA8,         "SRGBA8"         },
1818
    { ColorInfo{ 8,  8,  8,  0,  GL_INT,                 GL_LINEAR }, TextureInternalFormat::RGB8I,          "RGB8I"          },
1819
    { ColorInfo{ 8,  8,  8,  8,  GL_INT,                 GL_LINEAR }, TextureInternalFormat::RGBA8I,         "RGBA8I"         },
1820
    { ColorInfo{ 8,  8,  8,  0,  GL_UNSIGNED_INT,        GL_LINEAR }, TextureInternalFormat::RGB8UI,         "RGB8UI"         },
1821
    { ColorInfo{ 8,  8,  8,  8,  GL_UNSIGNED_INT,        GL_LINEAR }, TextureInternalFormat::RGBA8UI,        "RGBA8UI"        },
1822
    { ColorInfo{ 8,  8,  8,  0,  GL_SIGNED_NORMALIZED,   GL_LINEAR }, TextureInternalFormat::RGB8_SNORM,     "RGB8_SNORM"     },
1823
    { ColorInfo{ 8,  8,  8,  8,  GL_SIGNED_NORMALIZED,   GL_LINEAR }, TextureInternalFormat::RGBA8_SNORM,    "RGBA8_SNORM"    },
1824
    { ColorInfo{ 16, 16, 16, 16, GL_UNSIGNED_NORMALIZED, GL_LINEAR }, TextureInternalFormat::RGBA16,         "RGBA16"         },
1825
    { ColorInfo{ 16, 16, 16, 0,  GL_INT,                 GL_LINEAR }, TextureInternalFormat::RGB16I,         "RGB16I"         },
1826
    { ColorInfo{ 16, 16, 16, 16, GL_INT,                 GL_LINEAR }, TextureInternalFormat::RGBA16I,        "RGBA16I"        },
1827
    { ColorInfo{ 16, 16, 16, 0,  GL_UNSIGNED_INT,        GL_LINEAR }, TextureInternalFormat::RGB16UI,        "RGB16UI"        },
1828
    { ColorInfo{ 16, 16, 16, 16, GL_UNSIGNED_INT,        GL_LINEAR }, TextureInternalFormat::RGBA16UI,       "RGBA16UI"       },
1829
    { ColorInfo{ 16, 16, 16, 0,  GL_FLOAT,               GL_LINEAR }, TextureInternalFormat::RGB16F,         "RGB16F"         },
1830
    { ColorInfo{ 16, 16, 16, 16, GL_FLOAT,               GL_LINEAR }, TextureInternalFormat::RGBA16F,        "RGBA16F"        },
1831
    { ColorInfo{ 32, 32, 32, 0,  GL_INT,                 GL_LINEAR }, TextureInternalFormat::RGB32I,         "RGB32I"         },
1832
    { ColorInfo{ 32, 32, 32, 32, GL_INT,                 GL_LINEAR }, TextureInternalFormat::RGBA32I,        "RGBA32I"        },
1833
    { ColorInfo{ 32, 32, 32, 0,  GL_UNSIGNED_INT,        GL_LINEAR }, TextureInternalFormat::RGB32UI,        "RGB32UI"        },
1834
    { ColorInfo{ 32, 32, 32, 32, GL_UNSIGNED_INT,        GL_LINEAR }, TextureInternalFormat::RGBA32UI,       "RGBA32UI"       },
1835
    { ColorInfo{ 32, 32, 32, 0,  GL_FLOAT,               GL_LINEAR }, TextureInternalFormat::RGB32F,         "RGB32F"         },
1836
    { ColorInfo{ 32, 32, 32, 32, GL_FLOAT,               GL_LINEAR }, TextureInternalFormat::RGBA32F,        "RGBA32F"        },
1837
    { ColorInfo{ 10, 10, 10, 2,  GL_UNSIGNED_NORMALIZED, GL_LINEAR }, TextureInternalFormat::RGB10_A2,       "RGB10_A2"       },
1838
    { ColorInfo{ 10, 10, 10, 2,  GL_UNSIGNED_INT,        GL_LINEAR }, TextureInternalFormat::RGB10_A2UI,     "RGB10_A2UI"     },
1839
    { ColorInfo{ 11, 11, 10, 0,  GL_FLOAT,               GL_LINEAR }, TextureInternalFormat::R11F_G11F_B10F, "R11F_G11F_B10F" }
1840
  }};
1841

1842
#if defined(USE_WEBGL)
1843
  // WebGL requires getting a color attachment for the default framebuffer
1844
  // See: https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/getFramebufferAttachmentParameter#attachment
1845
  constexpr FramebufferAttachment attachment = FramebufferAttachment::COLOR0;
1846
#elif defined(USE_OPENGL_ES)
1847
  constexpr FramebufferAttachment attachment = FramebufferAttachment::DEFAULT_BACK;
1848
#else
1849
  constexpr FramebufferAttachment attachment = FramebufferAttachment::DEFAULT_BACK_LEFT;
2✔
1850
#endif
1851
  ColorInfo colorInfo;
2✔
1852
  recoverFramebufferAttachmentParameter(attachment, FramebufferAttachmentParam::RED_SIZE, &colorInfo.redBitCount);
2✔
1853
  recoverFramebufferAttachmentParameter(attachment, FramebufferAttachmentParam::GREEN_SIZE, &colorInfo.greenBitCount);
2✔
1854
  recoverFramebufferAttachmentParameter(attachment, FramebufferAttachmentParam::BLUE_SIZE, &colorInfo.blueBitCount);
2✔
1855
  recoverFramebufferAttachmentParameter(attachment, FramebufferAttachmentParam::ALPHA_SIZE, &colorInfo.alphaBitCount);
2✔
1856
  recoverFramebufferAttachmentParameter(attachment, FramebufferAttachmentParam::COMPONENT_TYPE, &colorInfo.compType);
2✔
1857
  recoverFramebufferAttachmentParameter(attachment, FramebufferAttachmentParam::COLOR_ENCODING, &colorInfo.encoding);
2✔
1858

1859
  const auto colorFormatIter = std::ranges::find_if(formats, [&colorInfo] (const ColorFormat& format) noexcept {
2✔
1860
    return (colorInfo.redBitCount == format.colorInfo.redBitCount
8✔
1861
         && colorInfo.greenBitCount == format.colorInfo.greenBitCount
8✔
1862
         && colorInfo.blueBitCount == format.colorInfo.blueBitCount
8✔
1863
         && colorInfo.alphaBitCount == format.colorInfo.alphaBitCount
8✔
1864
         && colorInfo.compType == format.colorInfo.compType
4✔
1865
         && colorInfo.encoding == format.colorInfo.encoding);
16✔
1866
  });
1867

1868
  if (colorFormatIter == formats.cend()) {
2✔
NEW
1869
    Logger::error("[Renderer] Unknown default framebuffer color bits combination (red {}, green {}, blue {}, alpha {}, component type {}, encoding {})",
×
1870
                  colorInfo.redBitCount, colorInfo.greenBitCount, colorInfo.blueBitCount, colorInfo.alphaBitCount, colorInfo.compType, colorInfo.encoding);
UNCOV
1871
    return;
×
1872
  }
1873

1874
  s_defaultFramebufferColor = colorFormatIter->format;
2✔
1875

1876
  Logger::debug("[Renderer] Found default framebuffer color format {} (value {}; red {}, green {}, blue {}, alpha {}, component type {}, encoding {})",
2✔
1877
                colorFormatIter->formatStr, static_cast<unsigned int>(s_defaultFramebufferColor), colorInfo.redBitCount, colorInfo.greenBitCount,
2✔
1878
                colorInfo.blueBitCount, colorInfo.alphaBitCount, colorInfo.compType, colorInfo.encoding);
1879
}
1880

1881
void Renderer::recoverDefaultFramebufferDepthFormat() {
2✔
1882
  struct DepthInfo {
1883
    int depthBitCount {};
1884
    int stencilBitCount {};
1885
    int compType {};
1886
  };
1887

1888
  struct DepthFormat {
1889
    DepthInfo depthInfo {};
1890
    TextureInternalFormat format {};
1891
    std::string_view formatStr;
1892
  };
1893

1894
  constexpr std::array<DepthFormat, 6> formats = {{
2✔
1895
    { DepthInfo{ 16, 0, GL_UNSIGNED_NORMALIZED }, TextureInternalFormat::DEPTH16,           "DEPTH16"           },
1896
    { DepthInfo{ 24, 0, GL_UNSIGNED_NORMALIZED }, TextureInternalFormat::DEPTH24,           "DEPTH24"           },
1897
    { DepthInfo{ 24, 8, GL_UNSIGNED_NORMALIZED }, TextureInternalFormat::DEPTH24_STENCIL8,  "DEPTH24_STENCIL8"  },
1898
    { DepthInfo{ 32, 0, GL_UNSIGNED_NORMALIZED }, TextureInternalFormat::DEPTH32,           "DEPTH32"           },
1899
    { DepthInfo{ 32, 0, GL_FLOAT               }, TextureInternalFormat::DEPTH32F,          "DEPTH32F"          },
1900
    { DepthInfo{ 32, 8, GL_FLOAT               }, TextureInternalFormat::DEPTH32F_STENCIL8, "DEPTH32F_STENCIL8" }
1901
  }};
1902

1903
#if defined(USE_WEBGL)
1904
  // WebGL requires getting explicitly the depth attachment for the default framebuffer
1905
  // See: https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/getFramebufferAttachmentParameter#attachment
1906
  constexpr FramebufferAttachment attachment = FramebufferAttachment::DEPTH;
1907
#else
1908
  constexpr FramebufferAttachment attachment = FramebufferAttachment::DEFAULT_DEPTH;
2✔
1909
#endif
1910
  DepthInfo depthInfo {};
2✔
1911
  recoverFramebufferAttachmentParameter(attachment, FramebufferAttachmentParam::DEPTH_SIZE, &depthInfo.depthBitCount);
2✔
1912
  recoverFramebufferAttachmentParameter(attachment, FramebufferAttachmentParam::STENCIL_SIZE, &depthInfo.stencilBitCount);
2✔
1913
  recoverFramebufferAttachmentParameter(attachment, FramebufferAttachmentParam::COMPONENT_TYPE, &depthInfo.compType);
2✔
1914

1915
  const auto depthFormatIter = std::ranges::find_if(formats, [&depthInfo] (const DepthFormat& format) noexcept {
2✔
1916
    return (depthInfo.depthBitCount == format.depthInfo.depthBitCount
6✔
1917
         && depthInfo.stencilBitCount == format.depthInfo.stencilBitCount
4✔
1918
         && depthInfo.compType == format.depthInfo.compType);
10✔
1919
  });
1920

1921
  if (depthFormatIter == formats.cend()) {
2✔
NEW
1922
    Logger::error("[Renderer] Unknown default framebuffer depth bits combination (depth {}, stencil {}, component type {})",
×
1923
                  depthInfo.depthBitCount, depthInfo.stencilBitCount, depthInfo.compType);
UNCOV
1924
    return;
×
1925
  }
1926

1927
  s_defaultFramebufferDepth = depthFormatIter->format;
2✔
1928

1929
  Logger::debug("[Renderer] Found default framebuffer depth format {} (value {}; depth {}, stencil {}, component type {})",
2✔
1930
                depthFormatIter->formatStr, static_cast<unsigned int>(s_defaultFramebufferDepth), depthInfo.depthBitCount,
2✔
1931
                depthInfo.stencilBitCount, depthInfo.compType);
1932
}
1933

1934
} // namespace Raz
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc