Cogs.Core
ContextD3D12.cpp
1#include "ContextD3D12.h"
2
3#include "GraphicsDeviceD3D12.h"
4
5#include "Foundation/Logging/LogManager.h"
6
7#include "Foundation/HashFunctions.h"
8
9namespace
10{
11 Cogs::Logging::Log logger = Cogs::Logging::getLogger("ContextD3D12");
12
13 struct RenderStats
14 {
15 size_t numVertices;
16 size_t numIndices;
17 size_t numFaces;
18 };
19
20 RenderStats renderStats;
21}
22
23namespace Cogs
24{
25 namespace Direct3D12
26 {
27 const D3D_PRIMITIVE_TOPOLOGY Topologies[] = {
28 D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
29 D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
30 D3D_PRIMITIVE_TOPOLOGY_LINELIST,
31 D3D_PRIMITIVE_TOPOLOGY_LINESTRIP,
32 D3D_PRIMITIVE_TOPOLOGY_POINTLIST,
33 D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ,
34 D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ,
35 D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ,
36 D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ,
37 D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST,
38 D3D11_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST,
39 D3D11_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST,
40 D3D11_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST,
41 };
42
43 const D3D12_PRIMITIVE_TOPOLOGY_TYPE TopologyTypes[] = {
44 D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
45 D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
46 D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
47 D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
48 D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT,
49 D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
50 D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
51 D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
52 D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
53 D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH,
54 D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH,
55 D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH,
56 D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH,
57 };
58 }
59}
60
61Cogs::ContextD3D12::ContextD3D12() :
62 defaultBlendState(BlendStateHandle::InvalidHandle),
63 defaultDepthStencilState(DepthStencilStateHandle::InvalidHandle),
64 defaultRasterizerState(RasterizerStateHandle::InvalidHandle),
65 defaultRenderTarget(RenderTargetHandle::InvalidHandle),
66 defaultDepthStencil(DepthStencilHandle::InvalidHandle),
67 currentFrameResources(frameResources.data())
68{
69
70}
71
72Cogs::ContextD3D12::~ContextD3D12()
73{
74 destroy();
75
76 CloseHandle(eventHandle);
77}
78
79void Cogs::ContextD3D12::destroy()
80{
81 auto fenceValue = currentFenceValue;
82 auto completedFenceValue = fence->GetCompletedValue();
83
84 graphicsDevice->commandQueue->Signal(fence, fenceValue);
85
86 if (fenceValue > completedFenceValue) {
87 fence->SetEventOnCompletion(fenceValue, eventHandle);
88 WaitForSingleObject(eventHandle, INFINITE);
89 }
90}
91
92void Cogs::ContextD3D12::initialize(GraphicsDeviceD3D12 * graphicsDevice)
93{
94 this->device = graphicsDevice->device;
95 this->graphicsDevice = graphicsDevice;
96
97 HRESULT hr = S_OK;
98
99 for (auto & frameResource : frameResources) {
100 hr = device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(frameResource.commandAllocator.internalPointer()));
101
102 if (FAILED(hr)) {
103 LOG_ERROR(logger, "Could not create command allocator.");
104 return;
105 }
106
107 hr = device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, frameResource.commandAllocator, nullptr, IID_PPV_ARGS(frameResource.commandList.internalPointer()));
108
109 if (FAILED(hr)) {
110 LOG_ERROR(logger, "Could not create command list.");
111 return;
112 }
113
114 frameResource.commandList->Close();
115 }
116
117 eventHandle = CreateEventEx(NULL, FALSE, FALSE, EVENT_ALL_ACCESS);
118 assert(eventHandle != NULL);
119
120 ++currentFenceValue;
121
122 D3D12_DESCRIPTOR_HEAP_DESC descHeapCbv = {};
123 descHeapCbv.NumDescriptors = 96000;
124 descHeapCbv.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
125 descHeapCbv.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
126
127 hr = device->CreateDescriptorHeap(&descHeapCbv, IID_PPV_ARGS(descriptorHeap.internalPointer()));
128
129 descHeapCbv.NumDescriptors = 256;
130 descHeapCbv.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
131 descHeapCbv.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
132
133 hr = device->CreateDescriptorHeap(&descHeapCbv, IID_PPV_ARGS(descriptorHeapCPU.internalPointer()));
134
135 D3D12_DESCRIPTOR_HEAP_DESC descHeapSampler = {};
136 descHeapSampler.NumDescriptors = 2048;
137 descHeapSampler.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER;
138 descHeapSampler.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
139
140 hr = device->CreateDescriptorHeap(&descHeapSampler, IID_PPV_ARGS(samplerDescriptorHeap.internalPointer()));
141
142 hr = device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(fence.internalPointer()));
143
144 constantBuffersUpdated = false;
145
146 buffers = &graphicsDevice->buffers;
147 textures = &graphicsDevice->textures;
148 effects = &graphicsDevice->effects;
149 renderTargets = &graphicsDevice->renderTargets;
150
151 // Ensure all default resources are pinned and not released by user code.
152
153 defaultRasterizerState = renderTargets->loadRasterizerState(RasterizerState::DefaultState());
154 renderTargets->rasterizerStates.pin(defaultRasterizerState);
155
156 defaultBlendState = renderTargets->loadBlendState(BlendState::DefaultState());
157 renderTargets->blendStates.pin(defaultBlendState);
158
159 defaultDepthStencilState = renderTargets->loadDepthStencilState(DepthStencilState::DefaultState());
160 renderTargets->depthStencilStates.pin(defaultDepthStencilState);
161
162 defaultSamplerState = textures->loadSamplerState(SamplerState::DefaultState());
163 textures->samplerStates.pin(defaultSamplerState);
164}
165
167{
168 if (HandleIsValid(fenceHandle)) {
169 FenceD3D12& fence = graphicsDevice->syncObjects.fences[fenceHandle];
170 graphicsDevice->commandQueue->Signal(fence.fence, ++fence.value);
171 }
172}
173
174void Cogs::ContextD3D12::beginFrame()
175{
176 ID3D12DescriptorHeap * heaps[2] = {
177 descriptorHeap,
178 samplerDescriptorHeap,
179 };
180
181 commandList->SetDescriptorHeaps(2, heaps);
182
183 constantBuffersUpdated = false;
184 currentEffect = EffectHandle::NoHandle;
185 state.currentStateHash = 0;
186 state.dirty = true;
187
188 ContextCommon::setCurrentEffect(nullptr);
189
190 setBlendState(defaultBlendState, nullptr);
191 setRasterizerState(defaultRasterizerState);
192 setDepthStencilState(defaultDepthStencilState);
193
194 setRenderTarget(defaultRenderTarget, defaultDepthStencil);
195
196 constantBuffersUpdated = false;
197 shaderState = {};
198
199 renderStats = {};
200}
201
202void Cogs::ContextD3D12::updateFrameResources()
203{
204 if (frameResourceIndex == frameResources.size()) frameResourceIndex = 0;
205
206 if (frameResourceIndex == 0) {
207 descriptorSize = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
208
209 cbvCurrentCpuHandleCPU = descriptorHeapCPU->GetCPUDescriptorHandleForHeapStart();
210
211 cbvCurrentCpuHandle = descriptorHeap->GetCPUDescriptorHandleForHeapStart();
212 cbvCurrentGpuHandle = descriptorHeap->GetGPUDescriptorHandleForHeapStart();
213
214 srvCurrentCpuHandle.InitOffsetted(cbvCurrentCpuHandle, 32000, descriptorSize);
215 srvCurrentGpuHandle.InitOffsetted(cbvCurrentGpuHandle, 32000, descriptorSize);
216
217 uavCurrentCpuHandle.InitOffsetted(srvCurrentCpuHandle, 32000, descriptorSize);
218 uavCurrentGpuHandle.InitOffsetted(srvCurrentGpuHandle, 32000, descriptorSize);
219
220 samplerHandleIncrement = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
221 samplerCurrentCpuHandle = samplerDescriptorHeap->GetCPUDescriptorHandleForHeapStart();
222 samplerCurrentGpuHandle = samplerDescriptorHeap->GetGPUDescriptorHandleForHeapStart();
223 }
224
225 currentFrameResources = &frameResources[frameResourceIndex++];
226
227 currentFrameResources->closed = false;
228
229 if (currentFrameResources->fenceValue > fence->GetCompletedValue()) {
230 fence->SetEventOnCompletion(currentFrameResources->fenceValue, eventHandle);
231 WaitForSingleObject(eventHandle, INFINITE);
232 }
233
234 for (auto & orphan : currentFrameResources->orphanedBuffers) {
235 orphan.pool->deallocate(orphan.poolHandle);
236 }
237
238 for (auto & orphan : currentFrameResources->orphanedRTVs) {
239 renderTargets->rtvPool.deallocate(orphan.poolHandle);
240 }
241
242 currentFrameResources->orphanedRTVs.clear();
243 currentFrameResources->orphanedResources.clear();
244 currentFrameResources->orphanedBuffers.clear();
245
246 commandAllocator = currentFrameResources->commandAllocator;
247 commandList = currentFrameResources->commandList;
248
249 commandAllocator->Reset();
250
251 // Reset our command list, with no initial pipeline state.
252 commandList->Reset(commandAllocator, nullptr);
253}
254
255void Cogs::ContextD3D12::endFrame()
256{
257 executeCommandList();
258
259 currentFrameResources->closed = true;
260
261 renderStats = {};
262}
263
264void Cogs::ContextD3D12::executeCommandList()
265{
266 commandList->Close();
267
268 ID3D12CommandList * ppCommandLists[] = { commandList };
269 graphicsDevice->commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
270
271 currentFrameResources->fenceValue = currentFenceValue;
272
273 graphicsDevice->commandQueue->Signal(fence, currentFenceValue);
274
275 ++currentFenceValue;
276}
277
278void Cogs::ContextD3D12::flush()
279{
280 if (!currentFrameResources->closed) {
281 executeCommandList();
282 }
283
284 if (currentFrameResources->fenceValue > fence->GetCompletedValue()) {
285 fence->SetEventOnCompletion(currentFrameResources->fenceValue, eventHandle);
286 WaitForSingleObject(eventHandle, INFINITE);
287 }
288
289 if (!currentFrameResources->closed) {
290 commandList->Reset(commandAllocator, PSOs[state.currentStateHash]);
291
292 ID3D12DescriptorHeap * heaps[2] = {
293 descriptorHeap,
294 samplerDescriptorHeap,
295 };
296
297 commandList->SetDescriptorHeaps(2, heaps);
298 }
299}
300
301Cogs::IEffects * Cogs::ContextD3D12::getEffects()
302{
303 return graphicsDevice->getEffects();
304}
305
306void Cogs::ContextD3D12::setVertexBuffers(const VertexBufferHandle * handles, const size_t count)
307{
308 uint32_t strides[kMaxVertexInputSlots];
309 uint32_t offsets[kMaxVertexInputSlots];
310
311 for (size_t i = 0; i < count; i++) {
312 auto & buffer = buffers->buffers[BufferHandle(handles[i].handle)];
313
314 assert(buffer.vertexFormat && "Vertex buffer must have been created with format information attached.");
315
316 strides[i] = getSize(*buffer.vertexFormat);
317 offsets[i] = 0;
318 }
319
320 setVertexBuffers(handles, count, strides, offsets);
321}
322
323void Cogs::ContextD3D12::setVertexBuffers(const VertexBufferHandle * handles, const size_t count, const uint32_t * strides, const uint32_t * offsets)
324{
325 iaState.numVertexBuffers = count;
326
327 for (size_t i = 0; i < count; i++) {
328 auto & buffer = buffers->buffers[BufferHandle(handles[i].handle)];
329
330 assert(buffer.bindFlags & BindFlags::VertexBuffer && "Buffer not bindable as vertex buffer.");
331
332 iaState.currentVertexBuffers[i] = &buffer;
333 iaState.formats[i] = buffer.vertexFormat;
334 iaState.strides[i] = strides[i];
335 iaState.offsets[i] = offsets ? offsets[i] : 0;
336 }
337
338 setupDrawBuffers();
339}
340
341void Cogs::ContextD3D12::setIndexBuffer(IndexBufferHandle indexBufferHandle, uint32_t stride, uint32_t offset)
342{
343 iaState.currentIndexBuffer = &buffers->buffers[indexBufferHandle];
344
345 commandList->IASetIndexBuffer(&iaState.currentIndexBuffer->indexBufferView);
346}
347
348namespace
349{
350 void decode(int64_t handle, uint32_t & vsSlot, uint32_t & gsSlot, uint32_t & psSlot)
351 {
352 const uint64_t value = static_cast<uint64_t>(handle);
353
354 vsSlot = (value >> 32) & 0xFFFF;
355 gsSlot = (value >> 48);
356 psSlot = value & 0xFFFF;
357 }
358}
359
360void Cogs::ContextD3D12::setConstantBuffer(const ConstantBufferBindingHandle bufferBinding, const BufferHandle bufferHandle, const uint32_t offset, const uint32_t size)
361{
362 assert(offset == 0 && size == ~0u && "Offset into constant buffers is not implemented");
363 uint32_t slots[ShaderType::NumShaderTypes];
364 decode(bufferBinding.handle, slots);
365
366 auto & buffer = buffers->buffers[bufferHandle];
367
368 for (size_t i = 0; i < ShaderType::NumShaderTypes; ++i) {
369 if (slots[i] != NoBinding) {
370 shaderState.CBVs[i].setChanged(slots[i], &buffer, false);
371 }
372 }
373
374 constantBuffersUpdated = true;
375}
376
377void Cogs::ContextD3D12::setupDrawBuffers()
378{
379 D3D12_VERTEX_BUFFER_VIEW views[32];
380
381 for (size_t i = 0; i < iaState.numVertexBuffers; ++i) {
382 views[i] = iaState.currentVertexBuffers[i]->vertexBufferView;
383 views[i].StrideInBytes = iaState.strides[i];
384 }
385
386 commandList->IASetVertexBuffers(0, static_cast<UINT>(iaState.numVertexBuffers), views);
387}
388
389void Cogs::ContextD3D12::setupPipelineState(PrimitiveType::EPrimitiveType topology)
390{
391 checkState(topology);
392
393 setupConstantBuffers();
394
395 {
396 D3D12_CONSTANT_BUFFER_VIEW_DESC nullCbvDesc = {};
397 UINT offset = 0;
398
399 for (UINT j = 0; j < ShaderType::NumShaderTypes; ++j) {
400 const UINT slots = shaderState.effectSignature.slots[SlotType::CBV].values[j];
401
402 if (slots && shaderState.CBVs[j].hasChanged()) {
403 for (UINT i = 0; i < slots; ++i) {
404 const auto & bindings = shaderState.CBVs[j];
405
406 if (bindings.getChanged(i)) {
407 if (bindings[i]) {
408 device->CreateConstantBufferView(&bindings[i]->cbvDesc, CD3DX12_CPU_DESCRIPTOR_HANDLE(cbvCurrentCpuHandleCPU, offset + i, descriptorSize));
409 } else {
410 device->CreateConstantBufferView(&nullCbvDesc, CD3DX12_CPU_DESCRIPTOR_HANDLE(cbvCurrentCpuHandleCPU, offset + i, descriptorSize));
411 }
412 }
413 }
414
415 device->CopyDescriptorsSimple(slots, cbvCurrentCpuHandle, CD3DX12_CPU_DESCRIPTOR_HANDLE(cbvCurrentCpuHandleCPU, offset, descriptorSize), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
416
417 commandList->SetGraphicsRootDescriptorTable(shaderState.effectSignature.slots[SlotType::CBV].rangeIndex[j], cbvCurrentGpuHandle);
418
419 offset += slots;
420
421 shaderState.CBVs[j].setUnchanged();
422
423 cbvCurrentCpuHandle.Offset(slots, descriptorSize);
424 cbvCurrentGpuHandle.Offset(slots, descriptorSize);
425 }
426 }
427 }
428
429 {
430 D3D12_UNORDERED_ACCESS_VIEW_DESC nullUavDesc{};
431 nullUavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
432 nullUavDesc.Format = DXGI_FORMAT_R32_FLOAT;
433
434 for (UINT j = 0; j < ShaderType::NumShaderTypes; ++j) {
435 const UINT slots = shaderState.effectSignature.slots[SlotType::UAV].values[j];
436
437 if (slots && shaderState.UAVs[j].hasChanged()) {
438 for (UINT i = 0; i < slots; ++i) {
439 const auto & bindings = shaderState.UAVs[j];
440
441 if (bindings.getChanged(i)) {
442 if (bindings[i]) {
443 auto buffer = bindings[i];
444 device->CreateUnorderedAccessView(buffer->resource, buffer->counterResource, &buffer->uavDesc, CD3DX12_CPU_DESCRIPTOR_HANDLE(uavCurrentCpuHandle, i, descriptorSize));
445 } else {
446 device->CreateUnorderedAccessView(nullptr, nullptr, &nullUavDesc, CD3DX12_CPU_DESCRIPTOR_HANDLE(uavCurrentCpuHandle, i, descriptorSize));
447 }
448 }
449 }
450
451 commandList->SetGraphicsRootDescriptorTable(shaderState.effectSignature.slots[SlotType::UAV].rangeIndex[j], uavCurrentGpuHandle);
452
453 shaderState.UAVs[j].setUnchanged();
454
455 uavCurrentCpuHandle.Offset(slots, descriptorSize);
456 uavCurrentGpuHandle.Offset(slots, descriptorSize);
457 }
458 }
459 }
460
461 {
462 D3D12_SHADER_RESOURCE_VIEW_DESC nullShaderResourceViewDesc = {};
463 nullShaderResourceViewDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
464 nullShaderResourceViewDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
465 nullShaderResourceViewDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
466 nullShaderResourceViewDesc.Texture2D.MipLevels = 1;
467 nullShaderResourceViewDesc.Texture2D.MostDetailedMip = 0;
468 nullShaderResourceViewDesc.Texture2D.ResourceMinLODClamp = 0.0f;
469
470 for (UINT j = 0; j < ShaderType::NumShaderTypes; ++j) {
471 const UINT slots = shaderState.effectSignature.slots[SlotType::SRV].values[j];
472
473 if (slots && shaderState.SRVs[j].hasChanged()) {
474 for (UINT i = 0; i < slots; ++i) {
475 const auto & bindings = shaderState.SRVs[j];
476
477 if (bindings[i]) {
478 auto & resource = bindings[i];
479 device->CreateShaderResourceView(resource->resource, &resource->srvDesc, CD3DX12_CPU_DESCRIPTOR_HANDLE(srvCurrentCpuHandle, i, descriptorSize));
480 } else {
481 device->CreateShaderResourceView(nullptr, &nullShaderResourceViewDesc, CD3DX12_CPU_DESCRIPTOR_HANDLE(srvCurrentCpuHandle, i, descriptorSize));
482 }
483 }
484
485 commandList->SetGraphicsRootDescriptorTable(shaderState.effectSignature.slots[SlotType::SRV].rangeIndex[j], srvCurrentGpuHandle);
486
487 shaderState.SRVs[j].setUnchanged();
488
489 srvCurrentCpuHandle.Offset(slots, descriptorSize);
490 srvCurrentGpuHandle.Offset(slots, descriptorSize);
491 }
492 }
493 }
494
495 {
496 D3D12_SAMPLER_DESC nullSamplerDesc = {};
497 nullSamplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
498 nullSamplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
499 nullSamplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
500 nullSamplerDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS;
501 nullSamplerDesc.Filter = D3D12_FILTER_ANISOTROPIC;
502 nullSamplerDesc.MaxAnisotropy = 0;
503 nullSamplerDesc.MaxLOD = 16;
504
505 for (UINT j = 0; j < ShaderType::NumShaderTypes; ++j) {
506 const UINT slots = shaderState.effectSignature.slots[SlotType::Sampler].values[j];
507
508 if (slots && shaderState.Samplers[j].hasChanged()) {
509 for (UINT i = 0; i < slots; ++i) {
510 const auto & bindings = shaderState.Samplers[j];
511 const auto sampler = bindings[i];
512
513 if (sampler) {
514 device->CreateSampler(sampler, CD3DX12_CPU_DESCRIPTOR_HANDLE(samplerCurrentCpuHandle, i, samplerHandleIncrement));
515 } else {
516 device->CreateSampler(&nullSamplerDesc, CD3DX12_CPU_DESCRIPTOR_HANDLE(samplerCurrentCpuHandle, i, samplerHandleIncrement));
517 }
518 }
519
520 commandList->SetGraphicsRootDescriptorTable(shaderState.effectSignature.slots[SlotType::Sampler].rangeIndex[j], samplerCurrentGpuHandle);
521
522 shaderState.Samplers[j].setUnchanged();
523
524 samplerCurrentCpuHandle.Offset(slots, samplerHandleIncrement);
525 samplerCurrentGpuHandle.Offset(slots, samplerHandleIncrement);
526 }
527 }
528 }
529}
530
531void Cogs::ContextD3D12::draw(PrimitiveType::EPrimitiveType primitiveType, const size_t startVertex, const size_t numVertexes)
532{
533 setupPipelineState(primitiveType);
534
535 commandList->IASetPrimitiveTopology(Direct3D12::Topologies[primitiveType]);
536
537 commandList->DrawInstanced(static_cast<UINT>(numVertexes), 1, static_cast<UINT>(startVertex), 0);
538}
539
540void Cogs::ContextD3D12::drawIndexed(PrimitiveType::EPrimitiveType primitiveType, const size_t startIndex, const size_t numIndexes, const size_t startVertex)
541{
542 setupPipelineState(primitiveType);
543
544 commandList->IASetPrimitiveTopology(Direct3D12::Topologies[primitiveType]);
545
546 const size_t indexCount = numIndexes ? numIndexes : iaState.currentIndexBuffer->count;
547
548 commandList->DrawIndexedInstanced(static_cast<UINT>(indexCount), 1, static_cast<UINT>(startIndex), static_cast<UINT>(startVertex), 0);
549}
550
552{
553 state.currentRasterizerState = &renderTargets->rasterizerStates[handle];
554 state.dirty = true;
555}
556
557void Cogs::ContextD3D12::setBlendState(const BlendStateHandle handle, const float* constant)
558{
559 state.currentBlendState = &renderTargets->blendStates[handle];
560
561 // Even though doc indicates that NULL is OK, it segfaults
562 const float white[4] = { 1.f, 1.f, 1.f, 1.f };
563 commandList->OMSetBlendFactor(constant ? constant : white);
564
565 state.dirty = true;
566}
567
569{
570 state.currentDepthStencilState = &renderTargets->depthStencilStates[HandleIsValid(handle) ? handle : defaultDepthStencilState];
571 state.dirty = true;
572}
573
574void Cogs::ContextD3D12::setRenderTarget(const RenderTargetHandle renderTargetHandle, const DepthStencilHandle depthStencilHandle)
575{
576 auto rtHandle = (renderTargetHandle == RenderTargetHandle::NoHandle) ? defaultRenderTarget : renderTargetHandle;
577 auto dsHandle = (depthStencilHandle == DepthStencilHandle::NoHandle) ? defaultDepthStencil : depthStencilHandle;
578
579 state.currentRenderTarget = rtHandle != RenderTargetHandle::InvalidHandle ? &renderTargets->renderTargets[rtHandle] : nullptr;
580 state.currentDepthStencil = dsHandle != DepthStencilHandle::InvalidHandle ? &renderTargets->depthStencilTargets[dsHandle] : nullptr;
581 state.dirty = true;
582
583 if (state.currentRenderTarget && !state.currentRenderTarget->resource) {
584 auto & renderTarget = *state.currentRenderTarget;
585
586 for (int i = 0; i < renderTarget.numViews; ++i) {
587 if (HandleIsValid(renderTarget.textures[i])) {
588 auto & renderTexture = textures->textures[renderTarget.textures[i]];
589 setResourceState(commandList, renderTexture, D3D12_RESOURCE_STATE_RENDER_TARGET);
590 }
591 }
592 }
593
594 if (state.currentDepthStencil && HandleIsValid(state.currentDepthStencil->texture)) {
595 auto & depthTexture = textures->textures[state.currentDepthStencil->texture];
596 setResourceState(commandList, depthTexture, D3D12_RESOURCE_STATE_DEPTH_WRITE);
597 }
598
599 if (state.currentRenderTarget) {
600 auto & renderTarget = *state.currentRenderTarget;
601
602 commandList->OMSetRenderTargets(renderTarget.numViews, renderTarget.descriptorHandle, renderTarget.numViews == 1, state.currentDepthStencil ? &state.currentDepthStencil->descriptorHandle : nullptr);
603 } else {
604 commandList->OMSetRenderTargets(0, nullptr, false, state.currentDepthStencil ? &state.currentDepthStencil->descriptorHandle : nullptr);
605 }
606}
607
608void Cogs::ContextD3D12::setViewport(const float x, const float y, const float width, const float height)
609{
610 D3D12_VIEWPORT viewPort = {
611 0.0f,
612 0.0f,
613 static_cast<float>(width),
614 static_cast<float>(height),
615 0.0f,
616 1.0f
617 };
618
619 D3D12_RECT mRectScissor = { 0, 0, static_cast<LONG>(width), static_cast<LONG>(height) };
620
621 commandList->RSSetViewports(1, &viewPort);
622 commandList->RSSetScissorRects(1, &mRectScissor);
623}
624
625void Cogs::ContextD3D12::setScissor(const int x, const int y, const int width, const int height)
626{
627 D3D12_RECT mRectScissor = { static_cast<LONG>(x), static_cast<LONG>(y), static_cast<LONG>(width), static_cast<LONG>(height) };
628 commandList->RSSetScissorRects(1, &mRectScissor);
629}
630
632{
633 auto renderTarget = state.currentRenderTarget;
634
635 for (size_t i = 0; i < renderTarget->numViews; ++i) {
636 commandList->ClearRenderTargetView(renderTarget->descriptorHandle[i], color, 0, nullptr);
637 }
638}
639
640void Cogs::ContextD3D12::clearRenderTarget(const float ** colors, const int count)
641{
642 auto renderTarget = state.currentRenderTarget;
643
644 for (size_t i = 0; i < count; ++i) {
645 commandList->ClearRenderTargetView(renderTarget->descriptorHandle[i], colors[i], 0, nullptr);
646 }
647}
648
649void Cogs::ContextD3D12::clearDepth(const float depth)
650{
651 auto depthTarget = state.currentDepthStencil;
652
653 if (depthTarget) {
654 commandList->ClearDepthStencilView(depthTarget->descriptorHandle, D3D12_CLEAR_FLAG_DEPTH, depth, 0, 0, nullptr);
655 }
656}
657
659{
660 currentEffect = effectHandle;
661
662 state.currentEffect = &effects->effects[effectHandle];
663 state.dirty = true;
664
665 ContextCommon::setCurrentEffect(state.currentEffect);
666
667 assert(state.currentEffect->rootSignature && "Effect signature not valid.");
668
669 shaderState.effectSignature = state.currentEffect->signature;
670
671 if (true) { // Root signature changed
672 shaderState.rootSignature = state.currentEffect->rootSignature;
673
674 commandList->SetGraphicsRootSignature(state.currentEffect->rootSignature);
675
676 for (uint32_t i = 0; i < ShaderType::NumShaderTypes; ++i) {
677 for (uint32_t j = 0; j < shaderState.effectSignature.slots[SlotType::CBV].values[i]; ++j) {
678 shaderState.CBVs[i].setChanged();
679 }
680
681 for (uint32_t j = 0; j < shaderState.effectSignature.slots[SlotType::Sampler].values[i]; ++j) {
682 shaderState.Samplers[i].setChanged();
683 }
684
685 for (uint32_t j = 0; j < shaderState.effectSignature.slots[SlotType::SRV].values[i]; ++j) {
686 shaderState.SRVs[i].setChanged();
687 }
688
689 for (uint32_t j = 0; j < shaderState.effectSignature.slots[SlotType::UAV].values[i]; ++j) {
690 shaderState.UAVs[i].setChanged();
691 }
692 }
693 }
694}
695
697{
698 state.currentInputLayout = &buffers->inputLayouts[inputLayoutHandle];
699 state.dirty = true;
700}
701
702void Cogs::ContextD3D12::checkState(PrimitiveType::EPrimitiveType topology)
703{
704 if (!state.dirty) return;
705
706 const auto topologyType = Direct3D12::TopologyTypes[topology];
707 size_t hashCode = fnv1a(reinterpret_cast<const uint8_t *>(&state), sizeof(Direct3D12::PipelineState)) + topologyType;
708
709 if (hashCode != state.currentStateHash) {
710 auto it = PSOs.find(hashCode);
711
712 if (it == PSOs.end()) {
713 auto & inputLayout = *state.currentInputLayout;
714 auto & effect = *state.currentEffect;
715
716 D3D12_GRAPHICS_PIPELINE_STATE_DESC descPso = {};
717 descPso.InputLayout = { inputLayout.inputElements, inputLayout.inputElementCount };
718 descPso.pRootSignature = state.currentEffect->rootSignature;
719
720 descPso.VS = { reinterpret_cast<BYTE *>(effect.vertexShader.byteCode->GetBufferPointer()), effect.vertexShader.byteCode->GetBufferSize() };
721
722 if (effect.hullShader.byteCode) {
723 descPso.HS = { reinterpret_cast<BYTE *>(effect.hullShader.byteCode->GetBufferPointer()), effect.hullShader.byteCode->GetBufferSize() };
724 }
725
726 if (effect.domainShader.byteCode) {
727 descPso.DS = { reinterpret_cast<BYTE *>(effect.domainShader.byteCode->GetBufferPointer()), effect.domainShader.byteCode->GetBufferSize() };
728 }
729
730 if (effect.geometryShader.byteCode) {
731 descPso.GS = { reinterpret_cast<BYTE *>(effect.geometryShader.byteCode->GetBufferPointer()), effect.geometryShader.byteCode->GetBufferSize() };
732 }
733
734 if (effect.pixelShader.byteCode) {
735 descPso.PS = { reinterpret_cast<BYTE *>(effect.pixelShader.byteCode->GetBufferPointer()), effect.pixelShader.byteCode->GetBufferSize() };
736 }
737
738 descPso.RasterizerState = state.currentRasterizerState->rasterizerDesc;
739 descPso.BlendState = state.currentBlendState->blendDesc;
740 descPso.DepthStencilState = state.currentDepthStencilState->depthStencilDesc;
741
742 descPso.SampleMask = UINT_MAX;
743 descPso.PrimitiveTopologyType = Direct3D12::TopologyTypes[topology];
744
745 if (state.currentRenderTarget) {
746 descPso.NumRenderTargets = state.currentRenderTarget->numViews;
747
748 //TODO: Fetch render target sample count.
749 if (HandleIsValid(state.currentRenderTarget->textures[0])) {
750 descPso.SampleDesc.Count = textures->textures[state.currentRenderTarget->textures[0]].numSamples;
751 } else {
752 descPso.SampleDesc.Count = state.currentRenderTarget->numSamples;
753 }
754
755 for (size_t i = 0; i < state.currentRenderTarget->numViews; ++i) {
756 descPso.RTVFormats[i] = state.currentRenderTarget->viewDesc[i].Format;
757 }
758 }
759
760 if (state.currentDepthStencil) {
761 if (!state.currentRenderTarget) {
762 auto & texture = textures->textures[state.currentDepthStencil->texture];
763 descPso.SampleDesc.Count = texture.numSamples;
764 }
765 descPso.DSVFormat = state.currentDepthStencil->viewDesc.Format;
766 }
767
768 device->CreateGraphicsPipelineState(&descPso, IID_PPV_ARGS(PSOs[hashCode].internalPointer()));
769
770 commandList->SetPipelineState(PSOs[hashCode]);
771 } else {
772 commandList->SetPipelineState(it->second);
773 }
774
775 state.currentStateHash = hashCode;
776 }
777}
778
780{
781 auto & sourceTexture = textures->textures[source];
782 auto & destination = textures->textures[destinationTexture];
783
784 setResourceState(commandList, sourceTexture, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
785 setResourceState(commandList, destination, D3D12_RESOURCE_STATE_RESOLVE_DEST);
786
787 commandList->ResolveSubresource(destination.resource, 0, sourceTexture.resource, 0, sourceTexture.srvDesc.Format);
788}
789
790void Cogs::ContextD3D12::drawInstanced(PrimitiveType::EPrimitiveType primitiveType, const size_t startVertex, const size_t numVertexes, const size_t startInstance, const size_t numInstances)
791{
792 setupPipelineState(primitiveType);
793
794 commandList->IASetPrimitiveTopology(Direct3D12::Topologies[primitiveType]);
795
796 commandList->DrawInstanced(static_cast<UINT>(numVertexes), static_cast<UINT>(numInstances), static_cast<UINT>(startVertex), static_cast<UINT>(startInstance));
797}
798
799void Cogs::ContextD3D12::drawInstancedIndexed(PrimitiveType::EPrimitiveType primitiveType, const size_t startInstance, const size_t numInstances, const size_t startIndex, const size_t numIndexes)
800{
801 setupPipelineState(primitiveType);
802
803 commandList->IASetPrimitiveTopology(Direct3D12::Topologies[primitiveType]);
804
805 const size_t indexCount = numIndexes ? numIndexes : iaState.currentIndexBuffer->count;
806
807 commandList->DrawIndexedInstanced(static_cast<UINT>(indexCount), static_cast<UINT>(numInstances), static_cast<UINT>(startIndex), 0, static_cast<UINT>(startInstance));
808}
809
810void Cogs::ContextD3D12::readDepthBuffer(BufferHandle bufferHandle, int x, int y, int width, int height, Framebuffer::EFrameBuffer)
811{
812 auto & buffer = buffers->buffers[bufferHandle];
813
814 auto & texture = textures->textures[state.currentDepthStencil->texture];
815 setResourceState(commandList, texture, D3D12_RESOURCE_STATE_COPY_SOURCE);
816 auto resource = texture.resource;
817
818 auto desc = resource->GetDesc();
819
820 if (desc.Format == DXGI_FORMAT_D32_FLOAT || desc.Format == DXGI_FORMAT_D24_UNORM_S8_UINT) {
821 D3D12_RESOURCE_DESC textureDesc;
822 textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
823 textureDesc.DepthOrArraySize = 1;
824 textureDesc.Alignment = 0;
825 textureDesc.Width = desc.Width;
826 textureDesc.Height = desc.Height;
827 textureDesc.Format = DXGI_FORMAT_R32_FLOAT;
828 textureDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
829 textureDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
830 textureDesc.MipLevels = static_cast<UINT16>(1);
831 textureDesc.SampleDesc.Count = desc.SampleDesc.Count;
832 textureDesc.SampleDesc.Quality = 0;
833
835 if (FAILED(device->CreateCommittedResource(
836 &defaultHeapProperties,
837 D3D12_HEAP_FLAG_NONE,
838 &textureDesc,
839 D3D12_RESOURCE_STATE_COMMON,
840 nullptr,
841 IID_PPV_ARGS(copyTexture.internalPointer())))) {
842 // LOG ERROR
843 return;
844 }
845
846 currentFrameResources->orphanedResources.push_back(copyTexture);
847
848 setResourceState(commandList, texture, D3D12_RESOURCE_STATE_COPY_SOURCE);
849 setResourceBarrier(commandList, copyTexture, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COPY_DEST);
850
851 commandList->CopyResource(copyTexture, resource);
852
853 setResourceBarrier(commandList, copyTexture, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COMMON);
854
855 resource = copyTexture;
856 desc = resource->GetDesc();
857 }
858
859 if (desc.SampleDesc.Count > 1) {
860 D3D12_RESOURCE_DESC textureDesc;
861 textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
862 textureDesc.DepthOrArraySize = 1;
863 textureDesc.Alignment = 0;
864 textureDesc.Width = desc.Width;
865 textureDesc.Height = desc.Height;
866 textureDesc.Format = DXGI_FORMAT_R32_FLOAT;
867 textureDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
868 textureDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
869 textureDesc.MipLevels = static_cast<UINT16>(1);
870 textureDesc.SampleDesc.Count = 1;
871 textureDesc.SampleDesc.Quality = 0;
872
873 ResourcePointer<ID3D12Resource> resolveTexture;
874 if (FAILED(device->CreateCommittedResource(
875 &defaultHeapProperties,
876 D3D12_HEAP_FLAG_NONE,
877 &textureDesc,
878 D3D12_RESOURCE_STATE_COMMON,
879 nullptr,
880 IID_PPV_ARGS(resolveTexture.internalPointer())))) {
881 // LOG ERROR
882 return;
883 }
884
885 currentFrameResources->orphanedResources.push_back(resolveTexture);
886
887 if (resource == texture.resource) {
888 setResourceState(commandList, texture, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
889 } else {
890 setResourceBarrier(commandList, resource, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
891 }
892
893 setResourceBarrier(commandList, resolveTexture, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_RESOLVE_DEST);
894
895 commandList->ResolveSubresource(resolveTexture, 0, resource, 0, textureDesc.Format);
896
897 setResourceBarrier(commandList, resolveTexture, D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE);
898
899 resource = resolveTexture;
900 desc = resource->GetDesc();
901 }
902
903 const int maxSubresources = 16;
904 UINT firstSubresource = 0;
905 UINT64 requiredSize = 0;
906 D3D12_PLACED_SUBRESOURCE_FOOTPRINT layouts[maxSubresources];
907 UINT numRows[maxSubresources];
908 UINT64 rowSizesInBytes[maxSubresources];
909
910 device->GetCopyableFootprints(&desc, 0, 1, 0, layouts, numRows, rowSizesInBytes, &requiredSize);
911
912 CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(requiredSize);
914
915 device->CreateCommittedResource(
916 &defaultHeapProperties,
917 D3D12_HEAP_FLAG_NONE,
918 &bufferDesc,
919 D3D12_RESOURCE_STATE_GENERIC_READ,
920 nullptr,
921 IID_PPV_ARGS(temp.internalPointer()));
922
923 currentFrameResources->orphanedResources.push_back(temp);
924
925 setResourceBarrier(commandList, temp, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_COPY_DEST);
926
927 CD3DX12_TEXTURE_COPY_LOCATION src(resource, firstSubresource);
928 CD3DX12_TEXTURE_COPY_LOCATION dst(temp, layouts[0]);
929
930 D3D12_BOX box;
931 box.left = x;
932 box.right = x + width;
933 box.top = y;
934 box.bottom = y + height;
935 box.front = 0;
936 box.back = 1;
937
938 commandList->CopyTextureRegion(&dst, x, y, 0, &src, &box);
939
940 setResourceState(commandList, texture, D3D12_RESOURCE_STATE_DEPTH_WRITE);
941
942 setResourceState(commandList, buffer, D3D12_RESOURCE_STATE_COPY_DEST);
943 setResourceBarrier(commandList, temp, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE);
944
945 for (int i = 0; i < height; ++i) {
946 auto sourceOffset = layouts[0].Footprint.RowPitch * (y + i) + 4 * x;
947
948 commandList->CopyBufferRegion(buffer.resource, i * width * 4, temp, sourceOffset, width * 4);
949 }
950}
951
952void Cogs::ContextD3D12::readColorBuffer(BufferHandle bufferHandle, int x, int y, int width, int height, Framebuffer::EFrameBuffer)
953{
954 auto & buffer = buffers->buffers[bufferHandle];
955
957 if (state.currentRenderTarget->resource) {
958 resource = state.currentRenderTarget->resource;
959 setResourceBarrier(commandList, resource, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
960 } else {
961 auto & texture = textures->textures[state.currentRenderTarget->textures[0]];
962 setResourceState(commandList, texture, D3D12_RESOURCE_STATE_COPY_SOURCE);
963 resource = texture.resource;
964 }
965
966 auto desc = resource->GetDesc();
967 if (desc.SampleDesc.Count > 1) {
968 D3D12_RESOURCE_DESC textureDesc;
969 textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
970 textureDesc.DepthOrArraySize = static_cast<UINT16>(1);
971 textureDesc.Alignment = 0;
972 textureDesc.Width = desc.Width;
973 textureDesc.Height = desc.Height;
974 textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
975 textureDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
976 textureDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
977 textureDesc.MipLevels = static_cast<UINT16>(1);
978 textureDesc.SampleDesc.Count = 1;
979 textureDesc.SampleDesc.Quality = 0;
980
981 ResourcePointer<ID3D12Resource> resolveTexture;
982 if (FAILED(device->CreateCommittedResource(
983 &defaultHeapProperties,
984 D3D12_HEAP_FLAG_NONE,
985 &textureDesc,
986 D3D12_RESOURCE_STATE_COMMON,
987 nullptr,
988 IID_PPV_ARGS(resolveTexture.internalPointer())))) {
989 // LOG ERROR
990 return;
991 }
992
993 currentFrameResources->orphanedResources.push_back(resolveTexture);
994
995 setResourceBarrier(commandList, resource, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
996 setResourceBarrier(commandList, resolveTexture, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_RESOLVE_DEST);
997
998 commandList->ResolveSubresource(resolveTexture, 0, resource, 0, textureDesc.Format);
999
1000 setResourceBarrier(commandList, resource, D3D12_RESOURCE_STATE_RESOLVE_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
1001 setResourceBarrier(commandList, resolveTexture, D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE);
1002
1003 resource = resolveTexture;
1004 desc = resource->GetDesc();
1005 }
1006
1007 const int maxSubresources = 16;
1008 UINT firstSubresource = 0;
1009 UINT64 requiredSize = 0;
1010 D3D12_PLACED_SUBRESOURCE_FOOTPRINT layouts[maxSubresources];
1011 UINT numRows[maxSubresources];
1012 UINT64 rowSizesInBytes[maxSubresources];
1013
1014 device->GetCopyableFootprints(&desc, 0, 1, 0, layouts, numRows, rowSizesInBytes, &requiredSize);
1015
1016 CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(requiredSize);
1018
1019 device->CreateCommittedResource(
1020 &defaultHeapProperties,
1021 D3D12_HEAP_FLAG_NONE,
1022 &bufferDesc,
1023 D3D12_RESOURCE_STATE_GENERIC_READ,
1024 nullptr,
1025 IID_PPV_ARGS(temp.internalPointer()));
1026
1027 currentFrameResources->orphanedResources.push_back(temp);
1028
1029 setResourceBarrier(commandList, temp, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_COPY_DEST);
1030
1031 CD3DX12_TEXTURE_COPY_LOCATION src(resource, firstSubresource);
1032 CD3DX12_TEXTURE_COPY_LOCATION dst(temp, layouts[0]);
1033
1034 D3D12_BOX box;
1035 box.left = x;
1036 box.right = x + width;
1037 box.top = y;
1038 box.bottom = y + height;
1039 box.front = 0;
1040 box.back = 1;
1041
1042 commandList->CopyTextureRegion(&dst, x, y, 0, &src, &box);
1043
1044 if (state.currentRenderTarget->resource && state.currentRenderTarget->numSamples == 1) {
1045 resource = state.currentRenderTarget->resource;
1046 setResourceBarrier(commandList, resource, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
1047 }
1048
1049 setResourceState(commandList, buffer, D3D12_RESOURCE_STATE_COPY_DEST);
1050 setResourceBarrier(commandList, temp, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE);
1051
1052 for (int i = 0; i < height; ++i) {
1053 auto sourceOffset = layouts[0].Footprint.RowPitch * (y + i) + 4 * x;
1054
1055 commandList->CopyBufferRegion(buffer.resource, i * width * 4, temp, sourceOffset, width * 4);
1056 }
1057}
1058
1059void * Cogs::ContextD3D12::map(BufferHandle bufferHandle, MapMode::EMapMode accessMode, uint32_t * stride)
1060{
1061 auto & buffer = buffers->buffers[bufferHandle];
1062
1063 if (accessMode == MapMode::WriteDiscard) {
1064 if (buffer.resource) {
1065 UINT8 * resourceData;
1066 buffer.resource->Map(0, nullptr, reinterpret_cast<void **>(&resourceData));
1067 return resourceData;
1068 } else {
1069 currentFrameResources->orphanedBuffers.push_back(OrphanBufferD3D12{ buffer.pooledResource, &buffers->getBufferPool(buffer.size) });
1070
1071 buffer.pooledResource = buffers->getBufferPool(buffer.size).allocate();
1072 buffer.cbvDesc.BufferLocation = buffer.pooledResource->mappedGpuRegion;
1073
1074 for (auto & cbv : shaderState.CBVs) {
1075 cbv.setAnyChanged(&buffer);
1076 }
1077
1078 return buffer.pooledResource->mappedRegion;
1079 }
1080 } else if (accessMode == MapMode::Write) {
1081 if (buffer.resource) {
1082 UINT8 * resourcePointer;
1083
1084 buffer.resource->Map(0, nullptr, reinterpret_cast<void **>(&resourcePointer));
1085
1086 return resourcePointer;
1087 } else {
1088 return buffer.pooledResource->mappedRegion;
1089 }
1090 } else if (accessMode == MapMode::Read) {
1091 flush();
1092
1093 if (buffer.resource) {
1094 UINT8 * resourcePointer;
1095
1096 D3D12_RANGE range{};
1097 range.Begin = 0;
1098 range.End = buffer.size;
1099
1100 buffer.resource->Map(0, &range, reinterpret_cast<void **>(&resourcePointer));
1101
1102 return resourcePointer;
1103 }
1104 }
1105
1106 return nullptr;
1107}
1108
1110{
1111 auto & buffer = buffers->buffers[bufferHandle];
1112
1113 if (buffer.resource) {
1114 buffer.resource->Unmap(0, nullptr);
1115 }
1116}
1117
1118void Cogs::ContextD3D12::updateSubTexture(TextureHandle textureHandle, const size_t level, const void * data)
1119{
1120 assert(HandleIsValid(textureHandle) && "Texture handle must be a valid texture.");
1121
1122 auto & texture = this->textures->textures[textureHandle];
1123
1124 const uint32_t width = std::max(1u, texture.width / static_cast<uint32_t>(std::pow(2, level)));
1125 const uint32_t height = std::max(1u, texture.height / static_cast<uint32_t>(std::pow(2, level)));
1126
1127 D3D12_BOX rectangle;
1128 rectangle.left = 0;
1129 rectangle.right = width;
1130 rectangle.top = 0;
1131 rectangle.bottom = height;
1132 rectangle.front = 0;
1133 rectangle.back = 1;
1134
1135 D3D12_SUBRESOURCE_DATA d{};
1136 d.pData = data;
1137 d.RowPitch = width * static_cast<uint32_t>(getBlockSize(texture.format));
1138
1139 if (!texture.uploadResource) {
1140 ResourceD3D12 buffer;
1141 buffers->allocateBuffer(buffer, height * width * getBlockSize(texture.format), nullptr);
1142 texture.uploadResource = buffer.resource;
1143 }
1144
1145 setResourceState(commandList, texture, D3D12_RESOURCE_STATE_COPY_DEST);
1146
1147 UpdateSubresources(commandList, texture.resource, texture.uploadResource, 0, 0, 1, &d);
1148}
1149
1150void Cogs::ContextD3D12::updateSubBuffer(BufferHandle bufferHandle, const size_t offset, const size_t size, const void * data)
1151{
1152 auto & buffer = buffers->buffers[bufferHandle];
1153
1154 auto tempBufferHandle = buffers->loadBuffer(data, size, Usage::Default, AccessMode::Write, BindFlags::None);
1155 auto & tempBuffer = buffers->buffers[tempBufferHandle];
1156
1157 setResourceState(commandList, buffer, D3D12_RESOURCE_STATE_COPY_DEST);
1158 commandList->CopyBufferRegion(buffer.resource, offset, tempBuffer.resource, 0, size);
1159
1160 buffers->releaseBuffer(tempBufferHandle);
1161}
1162
1163void Cogs::ContextD3D12::copyResource(BufferHandle destinationHandle, BufferHandle sourceHandle)
1164{
1165 auto & destination = buffers->buffers[destinationHandle];
1166 auto & source = buffers->buffers[sourceHandle];
1167
1168 setResourceState(commandList, destination, D3D12_RESOURCE_STATE_COPY_DEST);
1169 commandList->CopyResource(destination.resource, source.resource);
1170}
1171
1172void Cogs::ContextD3D12::copyResource(TextureHandle destinationHandle, TextureHandle sourceHandle)
1173{
1174}
1175
1176void Cogs::ContextD3D12::setTexture(const TextureBindingHandle textureBindingHandle, const TextureHandle textureHandle)
1177{
1178 uint32_t slots[ShaderType::NumShaderTypes];
1179 decode(textureBindingHandle.handle, slots);
1180
1181 if (!HandleIsValid(textureHandle)) return;
1182
1183 auto & texture = textures->textures[textureHandle];
1184
1185 checkTextureState(texture);
1186
1187 for (size_t i = 0; i < ShaderType::NumShaderTypes; ++i) {
1188 if (slots[i] != NoBinding) {
1189 shaderState.SRVs[i].setChanged(slots[i], &texture, true);
1190 }
1191 }
1192}
1193
1194void Cogs::ContextD3D12::setTexture(const TextureBindingHandle textureBindingHandle, TextureViewHandle textureViewHandle)
1195{
1196 uint32_t slots[ShaderType::NumShaderTypes];
1197 decode(textureBindingHandle.handle, slots);
1198
1199 if (!HandleIsValid(textureViewHandle)) return;
1200
1201 auto & textureView = textures->textureViews[textureViewHandle];
1202 auto & texture = textures->textures[textureView.texture];
1203
1204 checkTextureState(texture);
1205
1206 for (size_t i = 0; i < ShaderType::NumShaderTypes; ++i) {
1207 if (slots[i] != NoBinding) {
1208 shaderState.SRVs[i].setChanged(slots[i], &texture, true);
1209 }
1210 }
1211}
1212
1213void Cogs::ContextD3D12::checkTextureState(TextureD3D12 & texture)
1214{
1215 if (texture.needsUpload) {
1216 setResourceState(commandList, texture, D3D12_RESOURCE_STATE_COPY_DEST);
1217
1218 const int maxSubresources = 16;
1219 UINT numSubresources = texture.numSubResources;
1220 UINT firstSubresource = 0;
1221 UINT64 requiredSize = 0;
1222 D3D12_PLACED_SUBRESOURCE_FOOTPRINT layouts[maxSubresources];
1223 UINT numRows[maxSubresources];
1224 UINT64 rowSizesInBytes[maxSubresources];
1225
1226 auto desc = texture.resource->GetDesc();
1227 device->GetCopyableFootprints(&desc, 0, texture.numSubResources, 0, layouts, numRows, rowSizesInBytes, &requiredSize);
1228
1229 for (UINT i = 0; i < numSubresources; ++i)
1230 {
1231 CD3DX12_TEXTURE_COPY_LOCATION dst(texture.resource, i + firstSubresource);
1232 CD3DX12_TEXTURE_COPY_LOCATION src(texture.uploadResource, layouts[i]);
1233
1234 commandList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr);
1235 }
1236
1237 texture.needsUpload = false;
1238 }
1239
1240 if (texture.usage != D3D12_RESOURCE_STATE_GENERIC_READ) {
1241 setResourceState(commandList, texture, D3D12_RESOURCE_STATE_GENERIC_READ);
1242 }
1243}
1244
1245void Cogs::ContextD3D12::setBufferCounter(BufferHandle bufferHandle, uint32_t value)
1246{
1247 auto sourceBufferHandle = buffers->loadBuffer(&value, sizeof(uint32_t), Usage::Staging, AccessMode::Write, BindFlags::None);
1248
1249 setBufferCounter(bufferHandle, sourceBufferHandle);
1250
1251 //TODO: Release when safe.
1252 //buffers->releaseBuffer(sourceBufferHandle);
1253}
1254
1256{
1257 auto & buffer = buffers->buffers[bufferHandle];
1258 auto & sourceBuffer = buffers->buffers[sourceBufferHandle];
1259
1260 assert(buffer.bindFlags == BindFlags::StructuredBufferWithCounter && "Buffer does not have atomic counter associated with it.");
1261
1262 setResourceBarrier(commandList, buffer.counterResource, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_DEST);
1263
1264 if (sourceBuffer.pooledResource) {
1265 commandList->CopyBufferRegion(buffer.counterResource, 0, sourceBuffer.pooledResource->resource, sourceBuffer.pooledResource->offset, 4);
1266 } else {
1267 commandList->CopyResource(buffer.counterResource, sourceBuffer.resource);
1268 }
1269
1270 setResourceBarrier(commandList, buffer.counterResource, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1271}
1272
1274{
1275 auto destinationBufferHandle = buffers->loadBuffer(nullptr, sizeof(uint32_t), Usage::Staging, AccessMode::Read, BindFlags::None);
1276
1277 return 0;
1278}
1279
1280void Cogs::ContextD3D12::getBufferCounter(BufferHandle bufferHandle, BufferHandle destinationBufferHandle)
1281{
1282
1283}
1284
1285void Cogs::ContextD3D12::setBuffer(const BufferBindingHandle bufferBindingHandle, BufferHandle bufferHandle)
1286{
1287 auto & binding = effects->bufferBindings[bufferBindingHandle];
1288 auto & buffer = buffers->buffers[bufferHandle];
1289
1290 if (buffer.uploadResource.resource) {
1291 setResourceState(commandList, buffer, D3D12_RESOURCE_STATE_COPY_DEST);
1292 commandList->CopyResource(buffer.resource, buffer.uploadResource.resource);
1293 setResourceState(commandList, buffer, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
1294
1295 currentFrameResources->orphanedResources.push_back(buffer.uploadResource.resource);
1296 buffer.uploadResource.resource = nullptr;
1297 }
1298
1299 if (false) {
1300 //TODO: Implement CS Support. 2015-08-11, oyshole.
1301 } else {
1302 {
1303 uint32_t slots[ShaderType::NumShaderTypes];
1304 decode(binding.uavBindings, slots);
1305
1306 for (size_t i = 0; i < ShaderType::NumShaderTypes; ++i) {
1307 if (slots[i] != NoBinding) {
1308 shaderState.UAVs[i].setChanged(slots[i], &buffer, false);
1309 }
1310 }
1311 }
1312
1313 {
1314 uint32_t slots[ShaderType::NumShaderTypes];
1315 decode(binding.srvBindings, slots);
1316
1317 for (size_t i = 0; i < ShaderType::NumShaderTypes; ++i) {
1318 if (slots[i] != NoBinding) {
1319 shaderState.SRVs[i].setChanged(slots[i], &buffer, false);
1320 }
1321 }
1322 }
1323
1324 if (buffer.usage != D3D12_RESOURCE_STATE_UNORDERED_ACCESS) {
1325 setResourceState(commandList, buffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1326 }
1327 }
1328}
1329
1330void Cogs::ContextD3D12::setSamplerState(const SamplerStateBindingHandle samplerStateBindingHandle, const SamplerStateHandle samplerStateHandle)
1331{
1332 auto handle = HandleIsValid(samplerStateHandle) ? samplerStateHandle : defaultSamplerState;
1333
1334 uint32_t slots[ShaderType::NumShaderTypes];
1335 decode(samplerStateBindingHandle.handle, slots);
1336
1337 auto & sampler = textures->samplerStates[handle];
1338
1339 for (size_t i = 0; i < ShaderType::NumShaderTypes; ++i) {
1340 if (slots[i] != NoBinding) {
1341 shaderState.Samplers[i].setChanged(slots[i], &sampler.samplerDesc, false);
1342 }
1343 }
1344}
1345
1346void Cogs::ContextD3D12::setupConstantBuffers()
1347{
1348 if (constantBuffersUpdated) return;
1349
1350 ContextCommon::updateConstantBuffers();
1351
1352 auto & effect = this->effects->effects[this->currentEffect];
1353
1354 auto updateConstantBuffer = [&](ShaderConstantBuffer & constantBuffer) {
1355 if (!constantBuffer.dirty) return;
1356
1357 MappedBuffer<UINT8> mappedBuffer(this, constantBuffer.buffer, MapMode::WriteDiscard);
1358
1359 std::memcpy(mappedBuffer, constantBuffer.memoryBuffer.data(), constantBuffer.memoryBuffer.size());
1360
1361 constantBuffer.dirty = false;
1362 };
1363
1364 for (auto & shader : effect.shaders) {
1365 for (auto & constantBuffer : shader.reflection.constantBuffers) {
1366 if (HandleIsValid(constantBuffer.buffer)) {
1367 updateConstantBuffer(constantBuffer);
1368 }
1369 }
1370 }
1371
1372 for (size_t i = 0; i < ShaderType::NumShaderTypes; ++i) {
1373 for (auto & cb : effect.shaders[i].reflection.constantBuffers) {
1374 shaderState.CBVs[i].setChanged(cb.slot, &buffers->buffers[cb.buffer]);
1375 }
1376 }
1377}
1378
1379void Cogs::ContextD3D12::dispatchCompute(const unsigned int threadGroupsX, const unsigned int threadGroupsY, const unsigned int threadGroupsZ)
1380{
1381
1382}
Log implementation class.
Definition: LogManager.h:139
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:180
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
@ Direct3D12
Graphics device using the Direct3D 12 API.
constexpr size_t fnv1a(uint8_t data, size_t hashValue) noexcept
Hashes a single byte using the fnv1a algorithm.
Definition: HashFunctions.h:37
@ Read
The buffer can be mapped and read from by the CPU after creation.
Definition: Flags.h:48
@ Write
The buffer can be mapped and written to by the CPU after creation.
Definition: Flags.h:50
@ StructuredBufferWithCounter
The buffer can be bound as a structured buffer and read or written from shaders, with an additional a...
Definition: Flags.h:82
@ VertexBuffer
The buffer can be bound as input to the vertex shader stage as a vertex buffer.
Definition: Flags.h:68
@ None
The buffer will not be bound to the graphics pipeline. Suitable for staging resources.
Definition: Flags.h:66
static BlendState DefaultState()
Creates a blend state object initialized with the default settings.
Definition: BlendState.h:55
void setRasterizerState(const RasterizerStateHandle handle) override
Set the current rasterizer state.
void dispatchCompute(const unsigned int threadGroupsX, const unsigned int threadGroupsY, const unsigned int threadGroupsZ) override
Dispatch computing work on the graphics device using the desired thread group count.
void updateSubBuffer(BufferHandle bufferHandle, const size_t offset, const size_t size, const void *data) override
Update a region of data in a buffer.
void clearDepth(const float depth=1.0f) override
Clear the currently set depth/stencil target to the given depth.
void clearRenderTarget(const float *color) override
Clear the currently set render target to the given value (4 component floating point RGBA).
void setBufferCounter(BufferHandle bufferHandle, uint32_t value)
Set the associated counter of a buffer.
void draw(PrimitiveType::EPrimitiveType primitiveType, const size_t startVertex, const size_t numVertexes) override
Draws non-indexed, non-instanced primitives.
void resolveResource(TextureHandle source, TextureHandle destination) override
Resolves the given source resource target into the given destination texture.
void setSamplerState(const SamplerStateBindingHandle samplerStateBindingHandle, const SamplerStateHandle samplerStateHandle) override
Sets the sampler state binding given to the given sampler state.
void setDepthStencilState(const DepthStencilStateHandle handle) override
Set the current depth stencil state.
void drawInstanced(PrimitiveType::EPrimitiveType primitiveType, const size_t startVertex, const size_t numVertexes, const size_t startInstance, const size_t numInstances) override
Draws non-indexed, instanced primitives.
void readColorBuffer(BufferHandle bufferHandle, int x, int y, int width, int height, Framebuffer::EFrameBuffer framebuffer) override
Reads data from the current render target into the given bufferHandle.
void setEffect(EffectHandle handle) override
Set the current effect.
void drawInstancedIndexed(PrimitiveType::EPrimitiveType primitiveType, const size_t startInstance, const size_t numInstances, const size_t startIndex, const size_t numIndexes) override
Draws indexed, instanced primitives.
void setBlendState(const BlendStateHandle handle, const float *constant) override
Set the current blend state.
void setConstantBuffer(const ConstantBufferBindingHandle bufferBinding, const BufferHandle bufferHandle, const uint32_t offset, const uint32_t size) override
Sets a constant buffer to the given constant buffer binding.
void setTexture(const TextureBindingHandle textureBindingHandle, const TextureHandle textureHandle) override
Sets the texture given to the binding given by textureBindingHandle.
uint32_t getBufferCounter(BufferHandle bufferHandle)
Get the associated counter of a buffer.
void signal(FenceHandle fenceHandle) override
Insert a fence in the command stream that will signal when all commands before the fence are complete...
void drawIndexed(PrimitiveType::EPrimitiveType primitiveType, const size_t startIndex, const size_t numIndexes, const size_t startVertex) override
Draws indexed, non-instanced primitives.
void setVertexBuffers(const VertexBufferHandle *vertexBufferHandles, const size_t count) override
Overload provided to support transitioning.
void setRenderTarget(const RenderTargetHandle handle, const DepthStencilHandle depthStencilHandle) override
Sets the current render target and an associated depth stencil target.
void unmap(BufferHandle bufferHandle) override
Unmaps the given buffer, applying any synchronization necessary to reflect changes in the mapped memo...
void setIndexBuffer(IndexBufferHandle indexBufferHandle, uint32_t stride, uint32_t offset) override
Sets the current index buffer.
void setScissor(const int x, const int y, const int width, const int height) override
Sets the current scissor rectangle.
void setViewport(const float x, const float y, const float width, const float height) override
Sets the current viewport to the given location and dimensions.
void readDepthBuffer(BufferHandle bufferHandle, int x, int y, int width, int height, Framebuffer::EFrameBuffer framebuffer) override
Reads data from the current depth target into the given bufferHandle.
void setInputLayout(const InputLayoutHandle inputLayoutHandle) override
Sets the current input layout.
void * map(BufferHandle bufferHandle, MapMode::EMapMode accessMode, uint32_t *stride=0) override
Maps the given buffer so it can be accessed.
void setBuffer(const BufferBindingHandle bufferBindingHandle, BufferHandle bufferHandle) override
Sets a buffer to bind to the given binding.
void updateSubTexture(TextureHandle textureHandle, const size_t level, const void *data) override
Update the data of a level in the given texture.
static DepthStencilState DefaultState()
Constructs a depth stencil state object initialized with the default values.
Handle template class used to provide opaque, non-converting handles.
Definition: Common.h:22
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:77
handle_type handle
Internal resource handle.
Definition: Common.h:74
static const Handle_t InvalidHandle
Represents an invalid handle.
Definition: Common.h:80
Provides effects and shader management functionality.
Definition: IEffects.h:148
EMapMode
Mapping mode enumeration.
Definition: Flags.h:93
@ WriteDiscard
Write access. When unmapping the graphics system will discard the old contents of the resource.
Definition: Flags.h:103
Provides RAII style mapping of a buffer resource.
Definition: IBuffers.h:160
EPrimitiveType
Primitive type enumeration.
Definition: Common.h:114
static RasterizerState DefaultState()
Constructs a rasterizer state initialized with the default values.
static SamplerState & DefaultState()
Constructs a sampler state initialized with the default values.
Definition: SamplerState.h:85
@ Default
Default usage.
Definition: Flags.h:26
@ Staging
Definition: Flags.h:33