1#include "RenderTargetsGLES30.h"
3#include "TexturesGLES30.h"
4#include "CapabilitiesGLES30.h"
19 void glFramebufferTextureMultiviewOVR(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews)
23 const attachment = $1;
24 const texture = Module.GL.textures[$2];
26 const baseViewIndex = $4;
30 for (
const item of Object.values(Module.GL.contexts)) {
31 if (item && item.hasOwnProperty(
'GLctx')) {
32 const ext = item.GLctx.getExtension(
"OVR_multiview2");
34 ext.framebufferTextureMultiviewOVR(target, attachment, texture, level, baseViewIndex, numViews);
39 }, target, attachment, texture, level, baseViewIndex, numViews);
42 void glFramebufferTextureMultisampleMultiviewOVR(GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei samples, GLint baseViewIndex, GLsizei numViews)
46 const attachment = $1;
47 const texture = Module.GL.textures[$2];
50 const baseViewIndex = $5;
54 for (
const item of Object.values(Module.GL.contexts)) {
55 if (item && item.hasOwnProperty(
'GLctx')) {
58 const ext = item.GLctx.getExtension(
"OCULUS_multiview");
60 ext.framebufferTextureMultisampleMultiviewOVR(target, attachment, texture, level, samples, baseViewIndex, numViews);
65 }, target, attachment, texture, level, samples, baseViewIndex, numViews);
78 GLuint& depthRenderbuffer,
86 assert((fbo == 0) && (depthRenderbuffer == 0) && (colorCount <= Cogs::OpenGLES30::kMaxRenderTargets));
87 glGenFramebuffers(1, &fbo);
88 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
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);
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;
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;
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;
177 viewData.basicType = 0;
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);
188 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, drawBuffers[i], tex.textureId, viewDesc.levelIndex, multiView.baseIndex, multiView.count);
194 switch (tex.target) {
196 glFramebufferTexture2D(GL_FRAMEBUFFER, drawBuffers[i], GL_TEXTURE_2D, tex.textureId, viewDesc.levelIndex);
198 case GL_TEXTURE_CUBE_MAP:
199 glFramebufferTexture2D(GL_FRAMEBUFFER, drawBuffers[i], GL_TEXTURE_CUBE_MAP_POSITIVE_X + viewDesc.layerIndex, tex.textureId, depth.
levelIndex);
202 case GL_TEXTURE_2D_ARRAY:
203 glFramebufferTextureLayer(GL_FRAMEBUFFER, drawBuffers[i], tex.textureId, viewDesc.levelIndex, viewDesc.layerIndex);
205 case GL_TEXTURE_2D_MULTISAMPLE:
206 case GL_RENDERBUFFER:
207 glFramebufferRenderbuffer(GL_FRAMEBUFFER, drawBuffers[i], GL_RENDERBUFFER, tex.renderBuffer);
210 assert(
false &&
"Invalid texture type");
214 glDrawBuffers(GLsizei(colorCount), drawBuffers);
219 if (1 < multiView.count) {
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);
227 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, tex.textureId, depth.
levelIndex, multiView.baseIndex, multiView.count);
234 switch (tex.target) {
236 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, tex.textureId, depth.
levelIndex);
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);
242 case GL_TEXTURE_2D_ARRAY:
243 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, tex.textureId, depth.
levelIndex, depth.
layerIndex);
245 case GL_TEXTURE_2D_MULTISAMPLE:
246 case GL_RENDERBUFFER:
247 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, tex.renderBuffer);
250 assert(
false &&
"Invalid texture type");
256 if (colorCount == 0 || colorViewDesc ==
nullptr || !
HandleIsValid(colorViewDesc[0].texture)) {
261 GLenum format = GL_DEPTH_COMPONENT32F;
262 GLsizei width = tex.width;
263 GLsizei height = tex.height;
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);
275 glRenderbufferStorage(GL_RENDERBUFFER, format, width, height);
277 glBindRenderbuffer(GL_RENDERBUFFER, 0);
278 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
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);
287 glDeleteFramebuffers(1, &fbo);
290 if (depthRenderbuffer) {
291 glDeleteRenderbuffers(1, &depthRenderbuffer);
292 depthRenderbuffer = 0;
301const char* Cogs::OpenGLES30::framebuffersStatusString(GLenum status)
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>";
315bool Cogs::RenderTargetsGLES30::bindRenderTargets(RenderTargetHandle renderTargetHandle, DepthStencilHandle depthStencilHandle)
322 DepthStencilTargetGLES30& depthStencil = depthStencils[depthStencilHandle];
323 if (depthStencil.broken) {
327 if (depthStencil.fbo != 0) {
328 glBindFramebuffer(GL_FRAMEBUFFER, depthStencil.fbo);
332 size_t colorViewCount = 0;
333 RenderTargetViewDescription* colorViews =
nullptr;
334 RenderTargetViewDataGLES30* colorViewData =
nullptr;
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;
343 RenderTargetGLES30& renderTarget = renderTargets[depthStencil.renderTarget];
344 colorViews = renderTarget.views;
345 colorViewData = renderTarget.viewData;
346 colorViewCount = renderTarget.numViews;
349 if (!setupFramebuffer(textures,
351 depthStencil.renderBuffer,
352 colorViews, colorViewData, colorViewCount,
354 depthStencil.multiView,
357 depthStencil.broken =
true;
361 LOG_TRACE(logger,
"Created color-depth render target");
366 RenderTargetGLES30& renderTarget = renderTargets[renderTargetHandle];
367 if (renderTarget.broken) {
371 if (renderTarget.fbo != 0) {
372 glBindFramebuffer(GL_FRAMEBUFFER, renderTarget.fbo);
376 GLuint renderBuffer = 0;
377 DepthStencilViewDescription depthStencilViewDesc{};
378 if(!setupFramebuffer(textures,
381 renderTarget.views, renderTarget.viewData, renderTarget.numViews,
382 depthStencilViewDesc,
383 renderTarget.multiView,
386 renderTarget.broken =
true;
389 assert(renderBuffer == 0);
390 LOG_TRACE(logger,
"Created color render target");
394 glBindFramebuffer(GL_FRAMEBUFFER, 0);
401 if (OpenGLES30::kMaxRenderTargets < numViews) {
402 LOG_ERROR(logger,
"maxRenderTargets (=%zu) < numViews (%zu)", OpenGLES30::kMaxRenderTargets, numViews);
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");
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));
427 if (1 < multiView.
count) {
429 if (!deviceCaps.MultiView) {
430 LOG_ERROR_ONCE(logger,
"Cannot create multiview render target without multiview device support");
434 if (deviceCaps.MaxMultiViews < multiView.
count) {
435 LOG_ERROR_ONCE(logger,
"Requested %u rendertarget views but only %d is supported", multiView.
count, deviceCaps.MaxMultiViews);
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");
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;
455 return renderTargetHandle;
460 if (!HandleIsValid(renderTargetHandle)) {
465 depthStencilTarget.renderTarget = renderTargetHandle;
466 depthStencilTarget.multiView.samples = 1;
467 depthStencilTarget.multiView.baseIndex = 0;
468 depthStencilTarget.multiView.count = 1;
469 depthStencilTarget.broken = 0;
471 return this->depthStencils.addResource(std::move(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));
497 LOG_ERROR_ONCE(logger,
"Cannot create depth stencil target from invalid render target");
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));
515 if (!deviceCaps.MultiView) {
516 LOG_ERROR_ONCE(logger,
"Cannot create multiview depth-stencil target without multiview device support");
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);
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);
533 LOG_ERROR_ONCE(logger,
"Depth stencil texture is invalid");
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;
545 return depthStencilHandle;
551 if (renderTarget.fbo) {
552 glDeleteFramebuffers(1, &renderTarget.fbo);
553 renderTarget.fbo = 0;
555 renderTargets.removeResource(renderTargetHandle);
561 if (depthStencilTarget.fbo) {
562 glDeleteFramebuffers(1, &depthStencilTarget.fbo);
563 depthStencilTarget.fbo = 0;
565 if (depthStencilTarget.renderBuffer != 0) {
566 glDeleteRenderbuffers(1, &depthStencilTarget.renderBuffer);
567 depthStencilTarget.renderBuffer = 0;
569 depthStencils.removeResource(depthStencilHandle);
574 return loadBlendState(blendState, blendState);
581 blendState.enabled = blendStateColor.
enabled || blendStateAlpha.
enabled;
584 blendState.blend.colorSrc = blendStateColor.
sourceBlend;
586 blendState.operation.color = blendStateColor.
operation;
590 blendState.blend.colorSrc = BlendState::Blend::One;
591 blendState.blend.colorDst = BlendState::Blend::Zero;
592 blendState.operation.color = BlendState::BlendOperation::Add;
596 blendState.blend.alphaSrc = blendStateAlpha.
sourceBlend;
598 blendState.operation.alpha = blendStateAlpha.
operation;
602 blendState.blend.alphaSrc = BlendState::Blend::One;
603 blendState.blend.alphaDst = BlendState::Blend::Zero;
604 blendState.operation.alpha = BlendState::BlendOperation::Add;
607 return this->blendStates.addResource(std::move(blendState));
613 blendStates.removeResource(handle);
618 return rasterizerStates.addResource(rasterizerState);
623 rasterizerStates.removeResource(handle);
628 return depthStencilStates.addResource(depthStencilState);
633 depthStencilStates.removeResource(handle);
639 std::vector<RenderTargetHandle> renderTargetHandles;
640 for (
auto& renderTarget : renderTargets) {
641 renderTargetHandles.push_back(renderTargets.getHandle(renderTarget));
643 for (
auto& renderTarget : renderTargetHandles) {
644 releaseRenderTarget(renderTarget);
648 std::vector<DepthStencilHandle> depthStencilHandles;
649 for (
auto& depthStencil : depthStencils) {
650 depthStencilHandles.push_back(depthStencils.getHandle(depthStencil));
652 for (
auto& depthStencil : depthStencilHandles) {
653 releaseDepthStencilTarget(depthStencil);
Log implementation class.
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
Encapsulates blend state for the graphics pipeline in a state object.
uint8_t enabled
If blending is enabled.
Blend destinationBlend
Blend option for the blend destination data.
BlendOperation operation
How the two blend values are combined.
Blend sourceBlend
Blend option for the blend source data.
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.
static const Handle_t InvalidHandle
Represents an invalid handle.
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.