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