Cogs.Core
RenderTargetsD3D11.cpp
1#include "RenderTargetsD3D11.h"
2
3
4#include "TexturesD3D11.h"
5#include "FormatsD3D11.h"
6#include "GraphicsDeviceD3D11.h"
7
8#include "Foundation/Logging/Logger.h"
9
10namespace
11{
12 Cogs::Logging::Log logger = Cogs::Logging::getLogger("RenderTargetsD3D11");
13
14 D3D11_BLEND Blends[] = {
15 D3D11_BLEND_ZERO,
16 D3D11_BLEND_ONE,
17 D3D11_BLEND_SRC_COLOR,
18 D3D11_BLEND_INV_SRC_COLOR,
19 D3D11_BLEND_SRC_ALPHA,
20 D3D11_BLEND_INV_SRC_ALPHA,
21 D3D11_BLEND_DEST_ALPHA,
22 D3D11_BLEND_INV_DEST_ALPHA,
23 D3D11_BLEND_DEST_COLOR,
24 D3D11_BLEND_INV_DEST_COLOR,
25 D3D11_BLEND_SRC_ALPHA_SAT,
26 D3D11_BLEND_BLEND_FACTOR,
27 D3D11_BLEND_INV_BLEND_FACTOR,
28 };
29 static_assert(sizeof(Blends) == sizeof(Blends[0]) * size_t(Cogs::BlendState::Blend::Count));
30
31 D3D11_BLEND_OP BlendOperations[] = {
32 D3D11_BLEND_OP_ADD,
33 D3D11_BLEND_OP_SUBTRACT,
34 D3D11_BLEND_OP_REV_SUBTRACT,
35 D3D11_BLEND_OP_MIN,
36 D3D11_BLEND_OP_MAX
37 };
38 static_assert(sizeof(BlendOperations) == sizeof(BlendOperations[0]) * size_t(Cogs::BlendState::BlendOperation::Count));
39
40 }
41
42
44{
45#ifdef COGSRENDERING_GFX_ANNOTATE
46 if (name.empty()) {
47 return;
48 }
49 auto & rt = renderTargets[handle];
50
51 for (size_t i = 0; i < rt.numViews; i++) {
52 if (rt.views[i]) {
53 std::string m(name);
54 m.append("[");
55 m.append(std::to_string(i));
56 m.append("]");
57 rt.views[i]->SetPrivateData(WKPDID_D3DDebugObjectName, static_cast<UINT>(m.length()), m.c_str());
58 }
59 }
60#else
61 (void)handle;
62 (void)name;
63#endif
64}
65
67{
68#ifdef COGSRENDERING_GFX_ANNOTATE
69 if (name.empty()) {
70 return;
71 }
72 auto & rt = depthStencilViews[handle];
73 if (rt) {
74 rt->SetPrivateData(WKPDID_D3DDebugObjectName, static_cast<UINT>(name.length()), name.data());
75 }
76#else
77 (void)handle;
78 (void)name;
79#endif
80}
81
82Cogs::RenderTargetHandle Cogs::RenderTargetsD3D11::createRenderTarget(ID3D11Texture2D * texture, bool persistent)
83{
84 if (texture == nullptr) {
86 }
87
88 RenderTargetD3D11 renderTarget;
89 renderTarget.numViews = 1;
90
91 HRESULT hr = graphicsDevice->getDevice()->CreateRenderTargetView(texture, NULL, renderTarget.views[0].internalPointer());
92 if (FAILED(hr)) {
93 LOG_ERROR(logger, "Failed to create render target: %s", direct3D11ReturnCodeAsString(hr));
95 }
96
97 return renderTargets.addResource(std::move(renderTarget), persistent);
98}
99
101{
102 this->renderTargets.removeResource(handle);
103}
104
105Cogs::RenderTargetHandle Cogs::RenderTargetsD3D11::createRenderTarget(const RenderTargetViewDescription * renderTargetViews, const size_t numViews)
106{
107 RenderTargetD3D11 renderTarget;
108 renderTarget.numViews = numViews;
109
110 for (size_t i = 0; i < numViews; ++i) {
111 auto & texture = textures->textures[renderTargetViews[i].texture];
112 renderTarget.texture[i] = renderTargetViews[i].texture;
113
114 D3D11_TEXTURE2D_DESC textureDesc;
115 texture.texture2D->GetDesc(&textureDesc);
116
117 D3D11_RENDER_TARGET_VIEW_DESC renderTargetDesc = {};
118
119 if (textureDesc.Format == DXGI_FORMAT_R8G8B8A8_TYPELESS) {
120 renderTargetDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
121 } else {
122 renderTargetDesc.Format = textureDesc.Format;
123 }
124
125 if (texture.desc.layers > 1) {
126 renderTargetDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
127 renderTargetDesc.Texture2DArray.FirstArraySlice = renderTargetViews[i].layerIndex;
128 renderTargetDesc.Texture2DArray.ArraySize = renderTargetViews[i].numLayers;
129 renderTargetDesc.Texture2DArray.MipSlice = renderTargetViews[i].levelIndex;
130 }
131 else if (textureDesc.SampleDesc.Count > 1) {
132 renderTargetDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS;
133 }
134 else {
135 renderTargetDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
136 renderTargetDesc.Texture2D.MipSlice = renderTargetViews[i].levelIndex;
137 }
138
139 HRESULT hr = graphicsDevice->getDevice()->CreateRenderTargetView(texture.resource(), &renderTargetDesc, renderTarget.views[i].internalPointer());
140 if (FAILED(hr)) {
141 LOG_ERROR(logger, "Failed to create render target: %s", direct3D11ReturnCodeAsString(hr));
143 }
144 }
145
146 return renderTargets.addResource(std::move(renderTarget));
147}
148
150{
151 auto & texture = textures->textures[textureView.texture];
152
153 D3D11_TEXTURE2D_DESC textureDesc;
154 texture.texture2D->GetDesc(&textureDesc);
155
156 D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc = {};
157
158 depthStencilViewDesc.Format = textureDesc.Format;
159
160 if (textureDesc.Format == DXGI_FORMAT_R32_TYPELESS) {
161 depthStencilViewDesc.Format = DXGI_FORMAT_D32_FLOAT;
162 } else if (textureDesc.Format == DXGI_FORMAT_R16_TYPELESS) {
163 depthStencilViewDesc.Format = DXGI_FORMAT_D16_UNORM;
164 }
165
166 if (texture.desc.faces == 6) {
167 depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
168 depthStencilViewDesc.Texture2DArray.FirstArraySlice = textureView.layerIndex;
169 depthStencilViewDesc.Texture2DArray.ArraySize = textureView.numLayers;
170 depthStencilViewDesc.Texture2DArray.MipSlice = textureView.levelIndex;
171 } else {
172 if (texture.desc.layers > 1) {
173 depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
174 depthStencilViewDesc.Texture2DArray.FirstArraySlice = textureView.layerIndex;
175 depthStencilViewDesc.Texture2DArray.ArraySize = textureView.numLayers;
176 depthStencilViewDesc.Texture2DArray.MipSlice = textureView.levelIndex;
177 } else {
178 depthStencilViewDesc.ViewDimension = textureDesc.SampleDesc.Count > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D;
179 }
180 }
181
183 HRESULT hr = graphicsDevice->getDevice()->CreateDepthStencilView(texture.resource(), &depthStencilViewDesc, depthStencilView.internalPointer());
184 if (FAILED(hr)) {
185 LOG_ERROR(logger, "Failed to create depth stencil target: %s", direct3D11ReturnCodeAsString(hr));
187 }
188
189 return depthStencilViews.addResource(std::move(depthStencilView));
190}
191
193{
195 renderTargets[handle].views[0]->GetResource((ID3D11Resource **)&texture);
196
197 D3D11_TEXTURE2D_DESC textureDesc;
198 texture->GetDesc(&textureDesc);
199
200 TextureHandle textureHandle = textures->loadTexture(nullptr,
201 textureDesc.Width,
202 textureDesc.Height,
203 graphicsDevice->getSettings().depthFormat,
204 textureDesc.SampleDesc.Count,
206
207 if (!HandleIsValid(textureHandle)) {
208 LOG_ERROR(logger, "Failed to create depth stencil target: Illegal texture handle.");
210 }
211
212 D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc = {};
213 depthStencilViewDesc.Format = Direct3D11::Formats[(int)graphicsDevice->getSettings().depthFormat];
214 depthStencilViewDesc.ViewDimension = textureDesc.SampleDesc.Count > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D;
215
217 HRESULT hr = graphicsDevice->getDevice()->CreateDepthStencilView(textures->getTexture(textureHandle), &depthStencilViewDesc, depthStencilView.internalPointer());
218 if (FAILED(hr)) {
219 LOG_ERROR(logger, "Failed to create depth stencil target: %s", direct3D11ReturnCodeAsString(hr));
220 textures->releaseTexture(textureHandle);
222 }
223
224 textures->releaseTexture(textureHandle);
225
226 return depthStencilViews.addResource(std::move(depthStencilView));
227}
228
230{
231 auto & texture = this->textures->textures[textureHandle];
232
233 D3D11_TEXTURE2D_DESC textureDesc;
234 texture.texture2D->GetDesc(&textureDesc);
235
236 D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc = {};
237 depthStencilViewDesc.Format = textureDesc.Format;
238
239 if (textureDesc.Format == DXGI_FORMAT_R32_TYPELESS) {
240 depthStencilViewDesc.Format = DXGI_FORMAT_D32_FLOAT;
241 } else if (textureDesc.Format == DXGI_FORMAT_R16_TYPELESS) {
242 depthStencilViewDesc.Format = DXGI_FORMAT_D16_UNORM;
243 }
244
245 depthStencilViewDesc.ViewDimension = textureDesc.SampleDesc.Count > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D;
246
248 HRESULT hr = graphicsDevice->getDevice()->CreateDepthStencilView(texture.resource(), &depthStencilViewDesc, depthStencilView.internalPointer());
249 if(FAILED(hr)) {
250 LOG_ERROR(logger, "Failed to create depth stencil target: %s", direct3D11ReturnCodeAsString(hr));
252 }
253
254 return this->depthStencilViews.addResource(std::move(depthStencilView));
255}
256
258{
259 this->depthStencilViews.removeResource(handle);
260}
261
262namespace Cogs
263{
264 namespace Direct3D11
265 {
266 D3D11_COMPARISON_FUNC DepthFunctions[] = {
267 D3D11_COMPARISON_NEVER,
268 D3D11_COMPARISON_LESS,
269 D3D11_COMPARISON_LESS_EQUAL,
270 D3D11_COMPARISON_EQUAL,
271 D3D11_COMPARISON_GREATER_EQUAL,
272 D3D11_COMPARISON_GREATER,
273 D3D11_COMPARISON_NOT_EQUAL,
274 D3D11_COMPARISON_ALWAYS
275 };
276 }
277}
278
280{
281 D3D11_DEPTH_STENCIL_DESC depthStencilDesc;
282
283 // Depth test parameters
284 depthStencilDesc.DepthEnable = depthStencilState.depthEnabled;
285 depthStencilDesc.DepthWriteMask = depthStencilState.writeEnabled ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
286 depthStencilDesc.DepthFunc = Direct3D11::DepthFunctions[depthStencilState.depthFunction];
287
288 // Stencil test parameters
289 depthStencilDesc.StencilEnable = false;
290 depthStencilDesc.StencilReadMask = 0xFF;
291 depthStencilDesc.StencilWriteMask = 0xFF;
292
293 // Stencil operations if pixel is front-facing
294 depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
295 depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
296 depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
297 depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
298
299 // Stencil operations if pixel is back-facing
300 depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
301 depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
302 depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
303 depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
304
305 // Create depth stencil state
306 ResourcePointer<ID3D11DepthStencilState> d3dDepthStencilState;
307 HRESULT hr = graphicsDevice->getDevice()->CreateDepthStencilState(&depthStencilDesc, d3dDepthStencilState.internalPointer());
308
309 if (FAILED(hr)) {
310 LOG_ERROR(logger, "Failed to load depth stencil state: %s", direct3D11ReturnCodeAsString(hr));
312 }
313
314 return this->depthStencilStates.addResource(std::move(d3dDepthStencilState));
315}
316
318{
319 this->depthStencilStates.removeResource(handle);
320}
321
322namespace Cogs
323{
324 namespace Direct3D11
325 {
326 const D3D11_CULL_MODE CullModes[] = {
327 D3D11_CULL_FRONT,
328 D3D11_CULL_BACK,
329 D3D11_CULL_NONE
330 };
331 }
332}
333
335{
336 D3D11_RASTERIZER_DESC rasterizerDesc = {};
337
338 rasterizerDesc.FillMode = rasterizerState.wireFrame ? D3D11_FILL_WIREFRAME : D3D11_FILL_SOLID;
339 rasterizerDesc.CullMode = Direct3D11::CullModes[rasterizerState.cullMode];
340
341 rasterizerDesc.AntialiasedLineEnable = true;
342 rasterizerDesc.FrontCounterClockwise = rasterizerState.frontCounterClockwise;
343 rasterizerDesc.MultisampleEnable = rasterizerState.wireFrame ? rasterizerState.multiSample : false;
344 rasterizerDesc.DepthClipEnable = rasterizerState.noDepthClip == false;
345
346 rasterizerDesc.DepthBias = static_cast<INT>(rasterizerState.depthBias);
347 rasterizerDesc.SlopeScaledDepthBias = rasterizerState.slopeScaledDepthBias;
348 rasterizerDesc.DepthBiasClamp = rasterizerState.depthBiasClamp;
349 rasterizerDesc.ScissorEnable = rasterizerState.scissor;
350
352 HRESULT hr = graphicsDevice->getDevice()->CreateRasterizerState(&rasterizerDesc, d3dRasterizerState.internalPointer());
353
354 if (FAILED(hr)) {
355 LOG_ERROR(logger, "Failed to load rasterizer state: %s", direct3D11ReturnCodeAsString(hr));
357 }
358
359 return this->rasterizerStates.addResource(std::move(d3dRasterizerState));
360}
361
363{
364 this->rasterizerStates.removeResource(handle);
365}
366
368{
369 return loadBlendState(&blendState, &blendState, 1, BlendFlags::None);
370}
371
373{
374 return loadBlendState(&blendStateColor, &blendStateAlpha, 1, BlendFlags::None);
375}
376
377Cogs::BlendStateHandle Cogs::RenderTargetsD3D11::loadBlendState(const BlendState & blendStateColor, const BlendState& blendStateAlpha, const uint32_t flags)
378{
379 return loadBlendState(&blendStateColor, &blendStateAlpha, 1, flags);
380}
381
382Cogs::BlendStateHandle Cogs::RenderTargetsD3D11::loadBlendState(const BlendState * blendStatesColor, const BlendState * blendStatesAlpha, const uint32_t numBlendStates, const uint32_t flags)
383{
384 if (!blendStatesColor || !numBlendStates) return BlendStateHandle::InvalidHandle;
385
386 D3D11_BLEND_DESC blendDesc = {};
387 blendDesc.AlphaToCoverageEnable = (flags & BlendFlags::AlphaToCoverage) != 0 ? TRUE : FALSE;
388 blendDesc.IndependentBlendEnable = (flags & BlendFlags::IndependentBlend) != 0 ? TRUE : FALSE;
389
390 const BlendState defaultBlendState = BlendState::DefaultState();
391
392 const uint32_t numStates = blendDesc.IndependentBlendEnable ? 8 : 1;
393 for (uint32_t i = 0; i < numStates; ++i) {
394 const Cogs::BlendState& blendStateColor = i < numBlendStates ? blendStatesColor[i] : defaultBlendState;
395 const Cogs::BlendState& blendStateAlpha = blendStatesAlpha ? (i < numBlendStates ? blendStatesAlpha[i] : defaultBlendState) : defaultBlendState;
396
397 blendDesc.RenderTarget[i].BlendEnable = blendStateColor.enabled;
398 blendDesc.RenderTarget[i].SrcBlend = Blends[size_t(blendStateColor.sourceBlend)];
399 blendDesc.RenderTarget[i].DestBlend = Blends[size_t(blendStateColor.destinationBlend)];
400 blendDesc.RenderTarget[i].BlendOp = BlendOperations[size_t(blendStateColor.operation)];
401 blendDesc.RenderTarget[i].SrcBlendAlpha = blendStateAlpha.enabled ? Blends[size_t(blendStateAlpha.sourceBlend)] : D3D11_BLEND_ZERO;
402 blendDesc.RenderTarget[i].DestBlendAlpha = blendStateAlpha.enabled ? Blends[size_t(blendStateAlpha.destinationBlend)] : D3D11_BLEND_ONE;
403 blendDesc.RenderTarget[i].BlendOpAlpha = blendStateAlpha.enabled ? BlendOperations[size_t(blendStateAlpha.operation)] : D3D11_BLEND_OP_ADD;
404 blendDesc.RenderTarget[i].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
405 }
406
407 ResourcePointer<ID3D11BlendState> d3dBlendState;
408 HRESULT hr = graphicsDevice->getDevice()->CreateBlendState(&blendDesc, d3dBlendState.internalPointer());
409
410 if (FAILED(hr)) {
411 LOG_ERROR(logger, "Failed to load blend state: %s", direct3D11ReturnCodeAsString(hr));
413 }
414
415 return this->blendStates.addResource(std::move(d3dBlendState));
416}
417
419{
420 this->blendStates.removeResource(handle);
421}
422
424{
425 this->depthStencilStates.clear();
426 this->rasterizerStates.clear();
427 this->blendStates.clear();
428
429 this->depthStencilViews.clear();
430 this->renderTargets.clear();
431}
Log implementation class.
Definition: LogManager.h:139
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:24
constexpr const char * data() const noexcept
Get the sequence of characters referenced by the string view.
Definition: StringView.h:171
constexpr size_t length() const noexcept
Get the length of the string.
Definition: StringView.h:185
constexpr bool empty() const noexcept
Check if the string is empty.
Definition: StringView.h:122
const DXGI_FORMAT Formats[]
Must match up to Format definition.
Definition: FormatsD3D11.cpp:6
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
@ Direct3D11
Graphics device using the Direct3D 11 API.
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
static BlendState DefaultState()
Creates a blend state object initialized with the default settings.
Definition: BlendState.h:55
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.
bool depthEnabled
If depth testing is enabled/disabled. Default is true.
DepthFunction depthFunction
The depth function to use for depth testing.
bool writeEnabled
If writes to the depth buffer are enabled/disabled. Default is true.
Describes a single depth stencil view and which resources to use from the underlying texture.
TextureHandle texture
Texture handle.
uint16_t numLayers
Number of available layers to write to.
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.
static const Handle_t InvalidHandle
Represents an invalid handle.
Definition: Common.h:80
Encapsulates state for primitive rasterization in a state object.
bool multiSample
If multisample rasterization should be enabled. Default is true.
bool scissor
Enable scissor rect.
bool frontCounterClockwise
If counter clockwise polygon winding is used to specify front facing polygons. Default is false.
bool noDepthClip
Clamp depth value instead of clipping against near and depth planes.
CullMode cullMode
Which face culling mode to apply to primitives before rasterization.
float depthBias
Depth bias to apply to depth values after initial rasterization before depth values are written.
float depthBiasClamp
Value to clamp the depth bias to so that it may not go outside desired values even when applying slop...
float slopeScaledDepthBias
Slope scaled depth bias value controlling the depth bias value based on the area of the polygon on sc...
bool wireFrame
If only wire frames should be rasterized. Default is false.
Describes a single render target view and which resources to use from the underlying texture.
uint16_t layerIndex
Index of the first layer (if array) to render to.
uint16_t numLayers
Number of available layers to render to.
TextureHandle texture
Texture handle.
uint8_t levelIndex
Index of the mipmap level to render to.
void releaseBlendState(BlendStateHandle handle) override
Release the blend state with the given handle.
void releaseRenderTarget(RenderTargetHandle handle)
Release the render target with the given renderTargetHandle.
RasterizerStateHandle loadRasterizerState(const RasterizerState &rasterizerState) override
Load a rasterizer state object.
void releaseDepthStencilState(DepthStencilStateHandle handle) override
Release the depth stencil state with the given handle.
void releaseRasterizerState(RasterizerStateHandle handle) override
Release the rasterizer state with the given handle.
DepthStencilHandle createDepthStencilTarget(const RenderTargetHandle handle, const DepthStencilViewDescription &depthStencilView)
Creates a depth stencil view using the given description.
DepthStencilStateHandle loadDepthStencilState(const DepthStencilState &depthStencilState) override
Load a depth stencil state object.
void releaseResources() override
Release all allocated render target resources.
BlendStateHandle loadBlendState(const BlendState &blendState) override
Load a blend state object.
void annotate(RenderTargetHandle handle, const StringView &name) override
Associate a name with an object for use in graphics debugging.
void releaseDepthStencilTarget(DepthStencilHandle handle) override
Release the depth target with the given depthStencilHandle.
@ DepthBuffer
The texture can be used as a depth target and have depth buffer values written into.
Definition: Flags.h:122