Cogs.Core
RenderTargetsGLES30.cpp
1#include "RenderTargetsGLES30.h"
2
3#include "TexturesGLES30.h"
4#include "CapabilitiesGLES30.h"
5
6#ifdef __EMSCRIPTEN__
7#include <emscripten.h>
8
9extern "C" {
10
11 // Hack to work around missing function for multiview in emscripten.
12 // -----------------------------------------------------------------
13 //
14 // These are typically called when setting up a multiview FBO, i.e.
15 // during initialization or when view has been resized. So it
16 // shouldn't be a hot path, and thus unnecessary to cache these
17 // pointers for performance
18
19 void glFramebufferTextureMultiviewOVR(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews)
20 {
21 EM_ASM({
22 const target = $0;
23 const attachment = $1;
24 const texture = Module.GL.textures[$2];
25 const level = $3;
26 const baseViewIndex = $4;
27 const numViews = $5;
28
29 // No idea how to figure out the right key, just use the first and hope for the best.
30 for (const item of Object.values(Module.GL.contexts)) {
31 if (item && item.hasOwnProperty('GLctx')) {
32 const ext = item.GLctx.getExtension("OVR_multiview2");
33 if (ext) {
34 ext.framebufferTextureMultiviewOVR(target, attachment, texture, level, baseViewIndex, numViews);
35 }
36 break;
37 }
38 }
39 }, target, attachment, texture, level, baseViewIndex, numViews);
40 }
41
42 void glFramebufferTextureMultisampleMultiviewOVR(GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei samples, GLint baseViewIndex, GLsizei numViews)
43 {
44 EM_ASM({
45 const target = $0;
46 const attachment = $1;
47 const texture = Module.GL.textures[$2];
48 const level = $3;
49 const samples = $4;
50 const baseViewIndex = $5;
51 const numViews = $6;
52
53 // No idea how to figure out the right key, just use the first and hope for the best.
54 for (const item of Object.values(Module.GL.contexts)) {
55 if (item && item.hasOwnProperty('GLctx')) {
56 // There is no ratified WebGL extension for multisampled multiview,
57 // but Oculus have support in their GL_OCULUS_multiview extension.
58 const ext = item.GLctx.getExtension("OCULUS_multiview");
59 if (ext) {
60 ext.framebufferTextureMultisampleMultiviewOVR(target, attachment, texture, level, samples, baseViewIndex, numViews);
61 }
62 break;
63 }
64 }
65 }, target, attachment, texture, level, samples, baseViewIndex, numViews);
66 }
67
68}
69
70#endif
71
72namespace
73{
74 Cogs::Logging::Log logger = Cogs::Logging::getLogger("RenderTargetsGLES30");
75
76 bool setupFramebuffer(Cogs::TexturesGLES30* textures,
77 GLuint& fbo,
78 GLuint& depthRenderbuffer,
81 size_t colorCount,
83 const Cogs::MultiViewGLES30& multiView,
84 bool enableDepth)
85 {
86 assert((fbo == 0) && (depthRenderbuffer == 0) && (colorCount <= Cogs::OpenGLES30::kMaxRenderTargets));
87 glGenFramebuffers(1, &fbo);
88 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
89
90 // Set up color attachments
91 assert((colorCount == 0) || (colorViewDesc && colorViewData));
92 GLenum drawBuffers[Cogs::OpenGLES30::kMaxRenderTargets];
93 for (size_t i = 0; i < colorCount; i++) {
94 drawBuffers[i] = GL_COLOR_ATTACHMENT0 + static_cast<GLint>(i);
95
96 const Cogs::RenderTargetViewDescription& viewDesc = colorViewDesc[i];
97 Cogs::RenderTargetViewDataGLES30& viewData = colorViewData[i];
98
99 assert(HandleIsValid(viewDesc.texture));
100
101 const Cogs::TextureGLES30& tex = textures->textures[viewDesc.texture];
102
103 switch (tex.format) {
104 case Cogs::Format::R8_UNORM: [[fallthrough]];
105 case Cogs::Format::R8G8_UNORM: [[fallthrough]];
106 case Cogs::Format::R8G8B8_UNORM: [[fallthrough]];
107 case Cogs::Format::R8G8B8A8_UNORM: [[fallthrough]];
108 case Cogs::Format::R16_UNORM: [[fallthrough]];
109 case Cogs::Format::R16G16_UNORM: [[fallthrough]];
110 case Cogs::Format::R16G16B16_UNORM: [[fallthrough]];
111 case Cogs::Format::R16G16B16A16_UNORM: [[fallthrough]];
112 case Cogs::Format::R8_SNORM: [[fallthrough]];
113 case Cogs::Format::R8G8_SNORM: [[fallthrough]];
114 case Cogs::Format::R8G8B8_SNORM: [[fallthrough]];
115 case Cogs::Format::R8G8B8A8_SNORM: [[fallthrough]];
116 case Cogs::Format::R16_SNORM: [[fallthrough]];
117 case Cogs::Format::R16G16_SNORM: [[fallthrough]];
118 case Cogs::Format::R16G16B16_SNORM: [[fallthrough]];
119 case Cogs::Format::R16G16B16A16_SNORM: [[fallthrough]];
120 case Cogs::Format::R16_FLOAT: [[fallthrough]];
121 case Cogs::Format::R16G16_FLOAT: [[fallthrough]];
122 case Cogs::Format::R16G16B16_FLOAT: [[fallthrough]];
123 case Cogs::Format::R16G16B16A16_FLOAT: [[fallthrough]];
124 case Cogs::Format::R32_FLOAT: [[fallthrough]];
125 case Cogs::Format::R32G32_FLOAT: [[fallthrough]];
126 case Cogs::Format::R32G32B32_FLOAT: [[fallthrough]];
127 case Cogs::Format::R32G32B32A32_FLOAT: [[fallthrough]];
128 case Cogs::Format::A8_UNORM: [[fallthrough]];
129 case Cogs::Format::BC1_TYPELESS: [[fallthrough]];
130 case Cogs::Format::BC1_UNORM: [[fallthrough]];
131 case Cogs::Format::BC1_UNORM_SRGB: [[fallthrough]];
132 case Cogs::Format::BC2_UNORM: [[fallthrough]];
133 case Cogs::Format::BC2_UNORM_SRGB: [[fallthrough]];
134 case Cogs::Format::BC3_UNORM: [[fallthrough]];
135 case Cogs::Format::BC3_UNORM_SRGB: [[fallthrough]];
136 case Cogs::Format::BC4_UNORM: [[fallthrough]];
137 case Cogs::Format::BC4_SNORM: [[fallthrough]];
138 case Cogs::Format::BC5_UNORM: [[fallthrough]];
139 case Cogs::Format::BC5_SNORM: [[fallthrough]];
140 case Cogs::Format::R8G8B8A8_UNORM_SRGB: [[fallthrough]];
141 case Cogs::Format::R10G10B10A2_UNORM:
142 viewData.basicType = 1;
143 break;
144
145 case Cogs::Format::R8_UINT: [[fallthrough]];
146 case Cogs::Format::R8G8_UINT: [[fallthrough]];
147 case Cogs::Format::R8G8B8_UINT: [[fallthrough]];
148 case Cogs::Format::R8G8B8A8_UINT: [[fallthrough]];
149 case Cogs::Format::R16_UINT: [[fallthrough]];
150 case Cogs::Format::R16G16_UINT: [[fallthrough]];
151 case Cogs::Format::R16G16B16_UINT: [[fallthrough]];
152 case Cogs::Format::R16G16B16A16_UINT: [[fallthrough]];
153 case Cogs::Format::R32_UINT: [[fallthrough]];
154 case Cogs::Format::R32G32_UINT: [[fallthrough]];
155 case Cogs::Format::R32G32B32_UINT: [[fallthrough]];
156 case Cogs::Format::R32G32B32A32_UINT: [[fallthrough]];
157 case Cogs::Format::R10G10B10A2_UINT:
158 viewData.basicType = 2;
159 break;
160
161 case Cogs::Format::R8_SINT: [[fallthrough]];
162 case Cogs::Format::R8G8_SINT: [[fallthrough]];
163 case Cogs::Format::R8G8B8_SINT: [[fallthrough]];
164 case Cogs::Format::R8G8B8A8_SINT: [[fallthrough]];
165 case Cogs::Format::R16_SINT: [[fallthrough]];
166 case Cogs::Format::R16G16_SINT: [[fallthrough]];
167 case Cogs::Format::R16G16B16_SINT: [[fallthrough]];
168 case Cogs::Format::R16G16B16A16_SINT: [[fallthrough]];
169 case Cogs::Format::R32_SINT: [[fallthrough]];
170 case Cogs::Format::R32G32_SINT: [[fallthrough]];
171 case Cogs::Format::R32G32B32_SINT: [[fallthrough]];
172 case Cogs::Format::R32G32B32A32_SINT:
173 viewData.basicType = 3;
174 break;
175
176 default:
177 viewData.basicType = 0;
178 break;
179 }
180
181 // Multiview setup
182 if (1 < multiView.count) {
183 assert(tex.target == GL_TEXTURE_2D_ARRAY);
184 if (1 < multiView.samples) {
185 glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, drawBuffers[i], tex.textureId, viewDesc.levelIndex, multiView.samples, multiView.baseIndex, multiView.count);
186 }
187 else {
188 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, drawBuffers[i], tex.textureId, viewDesc.levelIndex, multiView.baseIndex, multiView.count);
189 }
190 }
191
192 // Regular non-multiview setup
193 else {
194 switch (tex.target) {
195 case GL_TEXTURE_2D:
196 glFramebufferTexture2D(GL_FRAMEBUFFER, drawBuffers[i], GL_TEXTURE_2D, tex.textureId, viewDesc.levelIndex);
197 break;
198 case GL_TEXTURE_CUBE_MAP:
199 glFramebufferTexture2D(GL_FRAMEBUFFER, drawBuffers[i], GL_TEXTURE_CUBE_MAP_POSITIVE_X + viewDesc.layerIndex, tex.textureId, depth.levelIndex);
200 break;
201 case GL_TEXTURE_3D:
202 case GL_TEXTURE_2D_ARRAY:
203 glFramebufferTextureLayer(GL_FRAMEBUFFER, drawBuffers[i], tex.textureId, viewDesc.levelIndex, viewDesc.layerIndex);
204 break;
205 case GL_TEXTURE_2D_MULTISAMPLE:
206 case GL_RENDERBUFFER:
207 glFramebufferRenderbuffer(GL_FRAMEBUFFER, drawBuffers[i], GL_RENDERBUFFER, tex.renderBuffer);
208 break;
209 default:
210 assert(false && "Invalid texture type");
211 }
212 }
213 }
214 glDrawBuffers(GLsizei(colorCount), drawBuffers);
215
216 if (enableDepth) {
217
218 // Multiview setup
219 if (1 < multiView.count) {
220 assert(HandleIsValid(depth.texture));
221 const Cogs::TextureGLES30& tex = textures->textures[depth.texture];
222 assert(tex.target == GL_TEXTURE_2D_ARRAY);
223 if (1 < multiView.samples) {
224 glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, tex.textureId, depth.levelIndex, multiView.samples, multiView.baseIndex, multiView.count);
225 }
226 else {
227 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, tex.textureId, depth.levelIndex, multiView.baseIndex, multiView.count);
228 }
229 }
230
231 // Regular texture-backed depth-stencil setup
232 else if (HandleIsValid(depth.texture)) {
233 const Cogs::TextureGLES30& tex = textures->textures[depth.texture];
234 switch (tex.target) {
235 case GL_TEXTURE_2D:
236 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, tex.textureId, depth.levelIndex);
237 break;
238 case GL_TEXTURE_CUBE_MAP:
239 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + depth.layerIndex, tex.textureId, depth.levelIndex);
240 break;
241 case GL_TEXTURE_3D:
242 case GL_TEXTURE_2D_ARRAY:
243 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, tex.textureId, depth.levelIndex, depth.layerIndex);
244 break;
245 case GL_TEXTURE_2D_MULTISAMPLE:
246 case GL_RENDERBUFFER:
247 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, tex.renderBuffer);
248 break;
249 default:
250 assert(false && "Invalid texture type");
251 }
252 }
253
254 // Regular renderbuffer-backed depth-stencil setup
255 else {
256 if (colorCount == 0 || colorViewDesc == nullptr || !HandleIsValid(colorViewDesc[0].texture)) {
257 return false;
258 }
259 const Cogs::TextureGLES30& tex = textures->textures[colorViewDesc[0].texture];
260
261 GLenum format = GL_DEPTH_COMPONENT32F;
262 GLsizei width = tex.width;
263 GLsizei height = tex.height;
264
265 glGenRenderbuffers(1, &depthRenderbuffer);
266 glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
267 if (tex.target == GL_TEXTURE_2D_MULTISAMPLE) {
268 GLint maxSampleCount = 0;
269 glGetInternalformativ(GL_RENDERBUFFER, format, GL_SAMPLES, 1, &maxSampleCount);
270 assert(0 <= maxSampleCount);
271 GLsizei numSamples = std::min(maxSampleCount, GLint(tex.numSamples));
272 glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, format, width, height);
273 }
274 else {
275 glRenderbufferStorage(GL_RENDERBUFFER, format, width, height);
276 }
277 glBindRenderbuffer(GL_RENDERBUFFER, 0);
278 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
279 }
280 }
281
282 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
283 if (status != GL_FRAMEBUFFER_COMPLETE) {
284 LOG_ERROR_ONCE(logger, "Failed to create rendertarget: %s", Cogs::OpenGLES30::framebuffersStatusString(status));
285 glBindFramebuffer(GL_FRAMEBUFFER, 0);
286 if (fbo) {
287 glDeleteFramebuffers(1, &fbo);
288 fbo = 0;
289 }
290 if (depthRenderbuffer) {
291 glDeleteRenderbuffers(1, &depthRenderbuffer);
292 depthRenderbuffer = 0;
293 }
294 return false;
295 }
296 return true;
297 }
298
299}
300
301const char* Cogs::OpenGLES30::framebuffersStatusString(GLenum status)
302{
303 switch (status)
304 {
305 case GL_FRAMEBUFFER_UNDEFINED: return "GL_FRAMEBUFFER_UNDEFINED";
306 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
307 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
308 case GL_FRAMEBUFFER_UNSUPPORTED: return "GL_FRAMEBUFFER_UNSUPPORTED";
309 case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: return "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE";
310 case GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR: return "GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR";
311 default: return "<unknown>";
312 }
313}
314
315bool Cogs::RenderTargetsGLES30::bindRenderTargets(RenderTargetHandle renderTargetHandle, DepthStencilHandle depthStencilHandle)
316{
317 if (renderTargetHandle == RenderTargetHandle::InvalidHandle || depthStencilHandle == DepthStencilHandle::InvalidHandle) {
318 return false;
319 }
320
321 if (HandleIsValid(depthStencilHandle)) {
322 DepthStencilTargetGLES30& depthStencil = depthStencils[depthStencilHandle];
323 if (depthStencil.broken) {
324 return false;
325 }
326
327 if (depthStencil.fbo != 0) {
328 glBindFramebuffer(GL_FRAMEBUFFER, depthStencil.fbo);
329 return true;
330 }
331
332 size_t colorViewCount = 0;
333 RenderTargetViewDescription* colorViews = nullptr;
334 RenderTargetViewDataGLES30* colorViewData = nullptr;
335
336 if (HandleIsValid(depthStencil.renderTarget)) {
337 if (depthStencil.renderTarget != renderTargetHandle) {
338 LOG_ERROR_ONCE(logger, "depth-stencil target bound with a different rendertarget than with it was created.");
339 depthStencil.broken = true;
340 return false;
341 }
342
343 RenderTargetGLES30& renderTarget = renderTargets[depthStencil.renderTarget];
344 colorViews = renderTarget.views;
345 colorViewData = renderTarget.viewData;
346 colorViewCount = renderTarget.numViews;
347 }
348
349 if (!setupFramebuffer(textures,
350 depthStencil.fbo,
351 depthStencil.renderBuffer,
352 colorViews, colorViewData, colorViewCount,
353 depthStencil.view,
354 depthStencil.multiView,
355 true))
356 {
357 depthStencil.broken = true;
358 return false;
359 }
360
361 LOG_TRACE(logger, "Created color-depth render target");
362 return true;
363 }
364
365 else if (HandleIsValid(renderTargetHandle)) {
366 RenderTargetGLES30& renderTarget = renderTargets[renderTargetHandle];
367 if (renderTarget.broken) {
368 return false;
369 }
370
371 if (renderTarget.fbo != 0) {
372 glBindFramebuffer(GL_FRAMEBUFFER, renderTarget.fbo);
373 return true;
374 }
375
376 GLuint renderBuffer = 0;
377 DepthStencilViewDescription depthStencilViewDesc{};
378 if(!setupFramebuffer(textures,
379 renderTarget.fbo,
380 renderBuffer,
381 renderTarget.views, renderTarget.viewData, renderTarget.numViews,
382 depthStencilViewDesc,
383 renderTarget.multiView,
384 false))
385 {
386 renderTarget.broken = true;
387 return false;
388 }
389 assert(renderBuffer == 0);
390 LOG_TRACE(logger, "Created color render target");
391 return true;
392 }
393 else {
394 glBindFramebuffer(GL_FRAMEBUFFER, 0);
395 return true;
396 }
397}
398
400{
401 if (OpenGLES30::kMaxRenderTargets < numViews) {
402 LOG_ERROR(logger, "maxRenderTargets (=%zu) < numViews (%zu)", OpenGLES30::kMaxRenderTargets, numViews);
404 }
405
406 RenderTargetGLES30 renderTarget{};
407 renderTarget.numViews = uint8_t(numViews);
408 for (size_t i = 0; i < renderTarget.numViews; i++) {
409 renderTarget.views[i] = renderTargetViews[i];
410 if (!HandleIsValid(renderTarget.views[i].texture)) {
411 LOG_ERROR_ONCE(logger, "Cannot create rendertarget from NULL texture handle");
413 }
414 }
415 renderTarget.multiView.samples = 0;
416 renderTarget.multiView.baseIndex = 0;
417 renderTarget.multiView.count = 1;
418 renderTarget.broken = 0;
419 return renderTargets.addResource(std::move(renderTarget));
420}
421
423{
424 const GraphicsDeviceCapabilities& deviceCaps = caps->getDeviceCapabilities();
425
426 // Multi-view sanity checks
427 if (1 < multiView.count) {
428
429 if (!deviceCaps.MultiView) {
430 LOG_ERROR_ONCE(logger, "Cannot create multiview render target without multiview device support");
432 }
433
434 if (deviceCaps.MaxMultiViews < multiView.count) {
435 LOG_ERROR_ONCE(logger, "Requested %u rendertarget views but only %d is supported", multiView.count, deviceCaps.MaxMultiViews);
437 }
438
439 for (size_t i = 0; i < numViews; i++) {
440 if (!HandleIsValid(renderTargetViews[i].texture) || textures->textures[renderTargetViews->texture].target != GL_TEXTURE_2D_ARRAY) {
441 LOG_ERROR_ONCE(logger, "Multiview rendering requires texture type GL_TEXTURE_2D_ARRAY");
443 }
444 }
445
446 }
447
448 Cogs::RenderTargetHandle renderTargetHandle = createRenderTarget(renderTargetViews, numViews);
449 if (HandleIsValid(renderTargetHandle)) {
450 RenderTargetGLES30& renderTarget = renderTargets[renderTargetHandle];
451 renderTarget.multiView.samples = deviceCaps.MultiSampleMultiView ? std::min(uint8_t(deviceCaps.MaxSamples), multiView.samples) : 1;
452 renderTarget.multiView.baseIndex = multiView.baseIndex;
453 renderTarget.multiView.count = multiView.count;
454 }
455 return renderTargetHandle;
456}
457
459{
460 if (!HandleIsValid(renderTargetHandle)) {
461 return DepthStencilHandle::InvalidHandle; // We need something to pick size from
462 }
463
464 DepthStencilTargetGLES30 depthStencilTarget{};
465 depthStencilTarget.renderTarget = renderTargetHandle;
466 depthStencilTarget.multiView.samples = 1;
467 depthStencilTarget.multiView.baseIndex = 0;
468 depthStencilTarget.multiView.count = 1;
469 depthStencilTarget.broken = 0;
470
471 return this->depthStencils.addResource(std::move(depthStencilTarget));
472}
473
475{
476 if (renderTargetHandle == RenderTargetHandle::InvalidHandle || !HandleIsValid(depthStencilTextureHandle)) {
478 }
479
480 DepthStencilTargetGLES30 depthStencilTarget{};
481 depthStencilTarget.renderTarget = renderTargetHandle;
482 depthStencilTarget.view.texture = depthStencilTextureHandle;
483 depthStencilTarget.view.layerIndex = 0;
484 depthStencilTarget.view.numLayers = 1;
485 depthStencilTarget.view.levelIndex = 0;
486 depthStencilTarget.multiView.samples = 0;
487 depthStencilTarget.multiView.baseIndex = 0;
488 depthStencilTarget.multiView.count = 1;
489 depthStencilTarget.broken = 0;
490 return depthStencils.addResource(std::move(depthStencilTarget));
491}
492
494{
495 // We allow null but not invalid render targets
496 if (renderTargetHandle == RenderTargetHandle::InvalidHandle) {
497 LOG_ERROR_ONCE(logger, "Cannot create depth stencil target from invalid render target");
499 }
500
501 DepthStencilTargetGLES30 depthStencilTarget{};
502 depthStencilTarget.renderTarget = renderTargetHandle;
503 depthStencilTarget.view = depthStencilView;
504 depthStencilTarget.multiView.samples = 0;
505 depthStencilTarget.multiView.baseIndex = 0;
506 depthStencilTarget.multiView.count = 1;
507 depthStencilTarget.broken = 0;
508 return depthStencils.addResource(std::move(depthStencilTarget));
509}
510
512{
513 const GraphicsDeviceCapabilities& deviceCaps = caps->getDeviceCapabilities();
514 if ((multiView.baseIndex != 0 || 1 < multiView.count)) {
515 if (!deviceCaps.MultiView) {
516 LOG_ERROR_ONCE(logger, "Cannot create multiview depth-stencil target without multiview device support");
518 }
519 if (deviceCaps.MaxMultiViews < multiView.count) {
520 LOG_ERROR_ONCE(logger, "Requested %u depth-stencil views but only %d is supported", multiView.count, deviceCaps.MaxMultiViews);
522 }
523 if (HandleIsValid(renderTargetHandle)) {
524 const RenderTargetGLES30& renderTarget = renderTargets[renderTargetHandle];
525 uint32_t samples = deviceCaps.MultiSampleMultiView ? std::min(uint8_t(deviceCaps.MaxSamples), multiView.samples) : 1;
526 if (renderTarget.multiView.count != multiView.count || renderTarget.multiView.samples != samples) {
527 LOG_ERROR_ONCE(logger, "Multiview mis-match count: %u != %u, samples: %u != %u",
528 renderTarget.multiView.count, multiView.count, renderTarget.multiView.samples, samples);
530 }
531 }
532 if (depthStencilView.texture == TextureHandle::InvalidHandle) {
533 LOG_ERROR_ONCE(logger, "Depth stencil texture is invalid");
535 }
536 }
537
538 Cogs::DepthStencilHandle depthStencilHandle = createDepthStencilTarget(renderTargetHandle, depthStencilView);
539 if (HandleIsValid(depthStencilHandle)) {
540 DepthStencilTargetGLES30& depthStencil = depthStencils[depthStencilHandle];
541 depthStencil.multiView.samples = deviceCaps.MultiSampleMultiView ? std::min(uint8_t(deviceCaps.MaxSamples), multiView.samples) : 1;
542 depthStencil.multiView.baseIndex = multiView.baseIndex;
543 depthStencil.multiView.count = multiView.count;
544 }
545 return depthStencilHandle;
546}
547
549{
550 RenderTargetGLES30& renderTarget = renderTargets[renderTargetHandle];
551 if (renderTarget.fbo) {
552 glDeleteFramebuffers(1, &renderTarget.fbo);
553 renderTarget.fbo = 0;
554 }
555 renderTargets.removeResource(renderTargetHandle);
556}
557
559{
560 DepthStencilTargetGLES30 & depthStencilTarget = this->depthStencils[depthStencilHandle];
561 if (depthStencilTarget.fbo) {
562 glDeleteFramebuffers(1, &depthStencilTarget.fbo);
563 depthStencilTarget.fbo = 0;
564 }
565 if (depthStencilTarget.renderBuffer != 0) {
566 glDeleteRenderbuffers(1, &depthStencilTarget.renderBuffer);
567 depthStencilTarget.renderBuffer = 0;
568 }
569 depthStencils.removeResource(depthStencilHandle);
570}
571
573{
574 return loadBlendState(blendState, blendState);
575}
576
578{
579 BlendStateGLES30 blendState{};
580
581 blendState.enabled = blendStateColor.enabled || blendStateAlpha.enabled;
582
583 if (blendStateColor.enabled) {
584 blendState.blend.colorSrc = blendStateColor.sourceBlend;
585 blendState.blend.colorDst = blendStateColor.destinationBlend;
586 blendState.operation.color = blendStateColor.operation;
587 }
588 else {
589 // Default to blending effectively disabled
590 blendState.blend.colorSrc = BlendState::Blend::One;
591 blendState.blend.colorDst = BlendState::Blend::Zero;
592 blendState.operation.color = BlendState::BlendOperation::Add;
593 }
594
595 if (blendStateAlpha.enabled) {
596 blendState.blend.alphaSrc = blendStateAlpha.sourceBlend;
597 blendState.blend.alphaDst = blendStateAlpha.destinationBlend;
598 blendState.operation.alpha = blendStateAlpha.operation;
599 }
600 else {
601 // Default to blending effectively disabled
602 blendState.blend.alphaSrc = BlendState::Blend::One;
603 blendState.blend.alphaDst = BlendState::Blend::Zero;
604 blendState.operation.alpha = BlendState::BlendOperation::Add;
605 }
606
607 return this->blendStates.addResource(std::move(blendState));
608}
609
610
612{
613 blendStates.removeResource(handle);
614}
615
617{
618 return rasterizerStates.addResource(rasterizerState);
619}
620
622{
623 rasterizerStates.removeResource(handle);
624}
625
627{
628 return depthStencilStates.addResource(depthStencilState);
629}
630
632{
633 depthStencilStates.removeResource(handle);
634}
635
637{
638 {
639 std::vector<RenderTargetHandle> renderTargetHandles;
640 for (auto& renderTarget : renderTargets) {
641 renderTargetHandles.push_back(renderTargets.getHandle(renderTarget));
642 }
643 for (auto& renderTarget : renderTargetHandles) {
644 releaseRenderTarget(renderTarget);
645 }
646 }
647 {
648 std::vector<DepthStencilHandle> depthStencilHandles;
649 for (auto& depthStencil : depthStencils) {
650 depthStencilHandles.push_back(depthStencils.getHandle(depthStencil));
651 }
652 for (auto& depthStencil : depthStencilHandles) {
653 releaseDepthStencilTarget(depthStencil);
654 }
655 }
656}
Log implementation class.
Definition: LogManager.h:140
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:181
Encapsulates blend state for the graphics pipeline in a state object.
Definition: BlendState.h:9
uint8_t enabled
If blending is enabled.
Definition: BlendState.h:41
Blend destinationBlend
Blend option for the blend destination data.
Definition: BlendState.h:47
BlendOperation operation
How the two blend values are combined.
Definition: BlendState.h:50
Blend sourceBlend
Blend option for the blend source data.
Definition: BlendState.h:44
Encapsulates state for depth buffer usage and stencil buffer usage in a state object.
Describes a single depth stencil view and which resources to use from the underlying texture.
TextureHandle texture
Texture handle.
uint8_t levelIndex
Index of the mipmap level to render to.
uint16_t layerIndex
Index of the first layer (if array) to write depth to.
Contains device capabilities.
Definition: ICapabilities.h:67
static const Handle_t InvalidHandle
Represents an invalid handle.
Definition: Common.h:81
Describes multiview framebuffer layout.
uint8_t samples
Number of multisample samples, 0 and 1 implies no multisampling.
uint8_t baseIndex
Texture array index for first texture slice to render into.
uint8_t count
Number of texture array slices to render into.
Encapsulates state for primitive rasterization in a state object.
Describes a single render target view and which resources to use from the underlying texture.
TextureHandle texture
Texture handle.
BlendStateHandle loadBlendState(const BlendState &blendState) override
Load a blend state object.
virtual RenderTargetHandle createRenderTarget(const RenderTargetViewDescription *renderTargetViews, const size_t numViews) override
Create a render target using the given view descriptions.
RasterizerStateHandle loadRasterizerState(const RasterizerState &rasterizerState) override
Load a rasterizer state object.
void releaseDepthStencilTarget(DepthStencilHandle depthStencilHandle) override
Release the depth target with the given depthStencilHandle.
DepthStencilStateHandle loadDepthStencilState(const DepthStencilState &depthStencilState) override
Load a depth stencil state object.
void releaseRasterizerState(RasterizerStateHandle handle) override
Release the rasterizer state with the given handle.
void releaseRenderTarget(RenderTargetHandle renderTargetHandle) override
Release the render target with the given renderTargetHandle.
DepthStencilHandle createDepthStencilTarget(const RenderTargetHandle handle) override
Creates a depth/stencil target to back the render target with the given handle.
void releaseBlendState(BlendStateHandle handle) override
Release the blend state with the given handle.
void releaseDepthStencilState(DepthStencilStateHandle handle) override
Release the depth stencil state with the given handle.
void releaseResources() override
Release all allocated render target resources.