mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-08-09 13:39:20 +00:00
Implement D3D12 Native Render Passes
Uses D3D12 native render pass API when possible. On pre-RS5 builds of Windows, Dawn will fall back to a software emulated render pass. A toggle was added to provide test coverage to the emulated render pass implementation and used in tests that test render pass functionality in particular. Bug: dawn:36 Change-Id: I297a3ec7655b68d28204db2d3ab78cb82bb4e7a5 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/13082 Reviewed-by: Austin Eng <enga@chromium.org> Commit-Queue: Brandon Jones <brandon1.jones@intel.com>
This commit is contained in:
parent
eac7382eb2
commit
700cfe7664
2
BUILD.gn
2
BUILD.gn
@ -291,6 +291,8 @@ source_set("libdawn_native_sources") {
|
|||||||
"src/dawn_native/d3d12/PlatformFunctions.h",
|
"src/dawn_native/d3d12/PlatformFunctions.h",
|
||||||
"src/dawn_native/d3d12/QueueD3D12.cpp",
|
"src/dawn_native/d3d12/QueueD3D12.cpp",
|
||||||
"src/dawn_native/d3d12/QueueD3D12.h",
|
"src/dawn_native/d3d12/QueueD3D12.h",
|
||||||
|
"src/dawn_native/d3d12/RenderPassBuilderD3D12.cpp",
|
||||||
|
"src/dawn_native/d3d12/RenderPassBuilderD3D12.h",
|
||||||
"src/dawn_native/d3d12/RenderPipelineD3D12.cpp",
|
"src/dawn_native/d3d12/RenderPipelineD3D12.cpp",
|
||||||
"src/dawn_native/d3d12/RenderPipelineD3D12.h",
|
"src/dawn_native/d3d12/RenderPipelineD3D12.h",
|
||||||
"src/dawn_native/d3d12/ResourceAllocatorManagerD3D12.cpp",
|
"src/dawn_native/d3d12/ResourceAllocatorManagerD3D12.cpp",
|
||||||
|
@ -75,8 +75,12 @@ namespace dawn_native {
|
|||||||
{"use_d3d12_resource_heap_tier2",
|
{"use_d3d12_resource_heap_tier2",
|
||||||
"Enable support for resource heap tier 2. Resource heap tier 2 allows mixing of "
|
"Enable support for resource heap tier 2. Resource heap tier 2 allows mixing of "
|
||||||
"texture and buffers in the same heap. This allows better heap re-use and reduces "
|
"texture and buffers in the same heap. This allows better heap re-use and reduces "
|
||||||
"fragmentation."}}}};
|
"fragmentation."}},
|
||||||
|
{Toggle::UseD3D12RenderPass,
|
||||||
|
{"use_d3d12_render_pass",
|
||||||
|
"Use the D3D12 render pass API introduced in Windows build 1809 by default. On "
|
||||||
|
"versions of Windows prior to build 1809, or when this toggle is turned off, Dawn "
|
||||||
|
"will emulate a render pass."}}}};
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
void TogglesSet::SetToggle(Toggle toggle, bool enabled) {
|
void TogglesSet::SetToggle(Toggle toggle, bool enabled) {
|
||||||
|
@ -31,6 +31,7 @@ namespace dawn_native {
|
|||||||
TurnOffVsync,
|
TurnOffVsync,
|
||||||
UseTemporaryBufferInCompressedTextureToTextureCopy,
|
UseTemporaryBufferInCompressedTextureToTextureCopy,
|
||||||
UseD3D12ResourceHeapTier2,
|
UseD3D12ResourceHeapTier2,
|
||||||
|
UseD3D12RenderPass,
|
||||||
|
|
||||||
EnumCount,
|
EnumCount,
|
||||||
InvalidEnum = EnumCount,
|
InvalidEnum = EnumCount,
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "dawn_native/d3d12/DeviceD3D12.h"
|
#include "dawn_native/d3d12/DeviceD3D12.h"
|
||||||
#include "dawn_native/d3d12/PipelineLayoutD3D12.h"
|
#include "dawn_native/d3d12/PipelineLayoutD3D12.h"
|
||||||
#include "dawn_native/d3d12/PlatformFunctions.h"
|
#include "dawn_native/d3d12/PlatformFunctions.h"
|
||||||
|
#include "dawn_native/d3d12/RenderPassBuilderD3D12.h"
|
||||||
#include "dawn_native/d3d12/RenderPipelineD3D12.h"
|
#include "dawn_native/d3d12/RenderPipelineD3D12.h"
|
||||||
#include "dawn_native/d3d12/SamplerD3D12.h"
|
#include "dawn_native/d3d12/SamplerD3D12.h"
|
||||||
#include "dawn_native/d3d12/TextureCopySplitter.h"
|
#include "dawn_native/d3d12/TextureCopySplitter.h"
|
||||||
@ -65,12 +66,6 @@ namespace dawn_native { namespace d3d12 {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OMSetRenderTargetArgs {
|
|
||||||
unsigned int numRTVs = 0;
|
|
||||||
std::array<D3D12_CPU_DESCRIPTOR_HANDLE, kMaxColorAttachments> RTVs = {};
|
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE dsv = {};
|
|
||||||
};
|
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
class BindGroupStateTracker : public BindGroupAndStorageBarrierTrackerBase<false, uint64_t> {
|
class BindGroupStateTracker : public BindGroupAndStorageBarrierTrackerBase<false, uint64_t> {
|
||||||
@ -601,11 +596,13 @@ namespace dawn_native { namespace d3d12 {
|
|||||||
|
|
||||||
// Records the necessary barriers for the resource usage pre-computed by the frontend
|
// Records the necessary barriers for the resource usage pre-computed by the frontend
|
||||||
auto TransitionForPass = [](CommandRecordingContext* commandContext,
|
auto TransitionForPass = [](CommandRecordingContext* commandContext,
|
||||||
const PassResourceUsage& usages) {
|
const PassResourceUsage& usages) -> bool {
|
||||||
std::vector<D3D12_RESOURCE_BARRIER> barriers;
|
std::vector<D3D12_RESOURCE_BARRIER> barriers;
|
||||||
|
|
||||||
ID3D12GraphicsCommandList* commandList = commandContext->GetCommandList();
|
ID3D12GraphicsCommandList* commandList = commandContext->GetCommandList();
|
||||||
|
|
||||||
|
wgpu::BufferUsage bufferUsages = wgpu::BufferUsage::None;
|
||||||
|
|
||||||
for (size_t i = 0; i < usages.buffers.size(); ++i) {
|
for (size_t i = 0; i < usages.buffers.size(); ++i) {
|
||||||
D3D12_RESOURCE_BARRIER barrier;
|
D3D12_RESOURCE_BARRIER barrier;
|
||||||
if (ToBackend(usages.buffers[i])
|
if (ToBackend(usages.buffers[i])
|
||||||
@ -613,6 +610,7 @@ namespace dawn_native { namespace d3d12 {
|
|||||||
usages.bufferUsages[i])) {
|
usages.bufferUsages[i])) {
|
||||||
barriers.push_back(barrier);
|
barriers.push_back(barrier);
|
||||||
}
|
}
|
||||||
|
bufferUsages |= usages.bufferUsages[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < usages.textures.size(); ++i) {
|
for (size_t i = 0; i < usages.textures.size(); ++i) {
|
||||||
@ -627,6 +625,8 @@ namespace dawn_native { namespace d3d12 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wgpu::TextureUsage textureUsages = wgpu::TextureUsage::None;
|
||||||
|
|
||||||
for (size_t i = 0; i < usages.textures.size(); ++i) {
|
for (size_t i = 0; i < usages.textures.size(); ++i) {
|
||||||
D3D12_RESOURCE_BARRIER barrier;
|
D3D12_RESOURCE_BARRIER barrier;
|
||||||
if (ToBackend(usages.textures[i])
|
if (ToBackend(usages.textures[i])
|
||||||
@ -634,11 +634,15 @@ namespace dawn_native { namespace d3d12 {
|
|||||||
usages.textureUsages[i])) {
|
usages.textureUsages[i])) {
|
||||||
barriers.push_back(barrier);
|
barriers.push_back(barrier);
|
||||||
}
|
}
|
||||||
|
textureUsages |= usages.textureUsages[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (barriers.size()) {
|
if (barriers.size()) {
|
||||||
commandList->ResourceBarrier(barriers.size(), barriers.data());
|
commandList->ResourceBarrier(barriers.size(), barriers.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (bufferUsages & wgpu::BufferUsage::Storage ||
|
||||||
|
textureUsages & wgpu::TextureUsage::Storage);
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::vector<PassResourceUsage>& passResourceUsages = GetResourceUsages().perPass;
|
const std::vector<PassResourceUsage>& passResourceUsages = GetResourceUsages().perPass;
|
||||||
@ -661,10 +665,11 @@ namespace dawn_native { namespace d3d12 {
|
|||||||
BeginRenderPassCmd* beginRenderPassCmd =
|
BeginRenderPassCmd* beginRenderPassCmd =
|
||||||
mCommands.NextCommand<BeginRenderPassCmd>();
|
mCommands.NextCommand<BeginRenderPassCmd>();
|
||||||
|
|
||||||
TransitionForPass(commandContext, passResourceUsages[nextPassNumber]);
|
const bool passHasUAV =
|
||||||
|
TransitionForPass(commandContext, passResourceUsages[nextPassNumber]);
|
||||||
bindingTracker.SetInComputePass(false);
|
bindingTracker.SetInComputePass(false);
|
||||||
RecordRenderPass(commandContext, &bindingTracker, &renderPassTracker,
|
RecordRenderPass(commandContext, &bindingTracker, &renderPassTracker,
|
||||||
beginRenderPassCmd);
|
beginRenderPassCmd, passHasUAV);
|
||||||
|
|
||||||
nextPassNumber++;
|
nextPassNumber++;
|
||||||
} break;
|
} break;
|
||||||
@ -912,126 +917,194 @@ namespace dawn_native { namespace d3d12 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandBuffer::RecordRenderPass(CommandRecordingContext* commandContext,
|
void CommandBuffer::SetupRenderPass(CommandRecordingContext* commandContext,
|
||||||
BindGroupStateTracker* bindingTracker,
|
BeginRenderPassCmd* renderPass,
|
||||||
RenderPassDescriptorHeapTracker* renderPassTracker,
|
RenderPassBuilder* renderPassBuilder) {
|
||||||
BeginRenderPassCmd* renderPass) {
|
for (uint32_t i : IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
|
||||||
OMSetRenderTargetArgs args = renderPassTracker->GetSubpassOMSetRenderTargetArgs(renderPass);
|
RenderPassColorAttachmentInfo& attachmentInfo = renderPass->colorAttachments[i];
|
||||||
|
TextureView* view = ToBackend(attachmentInfo.view.Get());
|
||||||
|
Texture* texture = ToBackend(view->GetTexture());
|
||||||
|
|
||||||
|
// Load operation is changed to clear when the texture is uninitialized.
|
||||||
|
if (!texture->IsSubresourceContentInitialized(view->GetBaseMipLevel(), 1,
|
||||||
|
view->GetBaseArrayLayer(), 1) &&
|
||||||
|
attachmentInfo.loadOp == wgpu::LoadOp::Load) {
|
||||||
|
attachmentInfo.loadOp = wgpu::LoadOp::Clear;
|
||||||
|
attachmentInfo.clearColor = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set color load operation.
|
||||||
|
renderPassBuilder->SetRenderTargetBeginningAccess(
|
||||||
|
i, attachmentInfo.loadOp, attachmentInfo.clearColor, view->GetD3D12Format());
|
||||||
|
|
||||||
|
// Set color store operation.
|
||||||
|
if (attachmentInfo.resolveTarget.Get() != nullptr) {
|
||||||
|
TextureView* resolveDestinationView = ToBackend(attachmentInfo.resolveTarget.Get());
|
||||||
|
Texture* resolveDestinationTexture =
|
||||||
|
ToBackend(resolveDestinationView->GetTexture());
|
||||||
|
|
||||||
|
resolveDestinationTexture->TransitionUsageNow(commandContext,
|
||||||
|
D3D12_RESOURCE_STATE_RESOLVE_DEST);
|
||||||
|
|
||||||
|
// Mark resolve target as initialized to prevent clearing later.
|
||||||
|
resolveDestinationTexture->SetIsSubresourceContentInitialized(
|
||||||
|
true, resolveDestinationView->GetBaseMipLevel(), 1,
|
||||||
|
resolveDestinationView->GetBaseArrayLayer(), 1);
|
||||||
|
|
||||||
|
renderPassBuilder->SetRenderTargetEndingAccessResolve(i, attachmentInfo.storeOp,
|
||||||
|
view, resolveDestinationView);
|
||||||
|
} else {
|
||||||
|
renderPassBuilder->SetRenderTargetEndingAccess(i, attachmentInfo.storeOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set whether or not the texture requires initialization after the pass.
|
||||||
|
bool isInitialized = attachmentInfo.storeOp == wgpu::StoreOp::Store;
|
||||||
|
texture->SetIsSubresourceContentInitialized(isInitialized, view->GetBaseMipLevel(), 1,
|
||||||
|
view->GetBaseArrayLayer(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (renderPass->attachmentState->HasDepthStencilAttachment()) {
|
||||||
|
RenderPassDepthStencilAttachmentInfo& attachmentInfo =
|
||||||
|
renderPass->depthStencilAttachment;
|
||||||
|
TextureView* view = ToBackend(renderPass->depthStencilAttachment.view.Get());
|
||||||
|
Texture* texture = ToBackend(view->GetTexture());
|
||||||
|
|
||||||
|
const bool hasDepth = view->GetTexture()->GetFormat().HasDepth();
|
||||||
|
const bool hasStencil = view->GetTexture()->GetFormat().HasStencil();
|
||||||
|
|
||||||
|
// Load operations are changed to clear when the texture is uninitialized.
|
||||||
|
if (!view->GetTexture()->IsSubresourceContentInitialized(
|
||||||
|
view->GetBaseMipLevel(), view->GetLevelCount(), view->GetBaseArrayLayer(),
|
||||||
|
view->GetLayerCount())) {
|
||||||
|
if (hasDepth && attachmentInfo.depthLoadOp == wgpu::LoadOp::Load) {
|
||||||
|
attachmentInfo.clearDepth = 0.0f;
|
||||||
|
attachmentInfo.depthLoadOp = wgpu::LoadOp::Clear;
|
||||||
|
}
|
||||||
|
if (hasStencil && attachmentInfo.stencilLoadOp == wgpu::LoadOp::Load) {
|
||||||
|
attachmentInfo.clearStencil = 0u;
|
||||||
|
attachmentInfo.stencilLoadOp = wgpu::LoadOp::Clear;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set depth/stencil load operations.
|
||||||
|
if (hasDepth) {
|
||||||
|
renderPassBuilder->SetDepthAccess(
|
||||||
|
attachmentInfo.depthLoadOp, attachmentInfo.depthStoreOp,
|
||||||
|
attachmentInfo.clearDepth, view->GetD3D12Format());
|
||||||
|
} else {
|
||||||
|
renderPassBuilder->SetDepthNoAccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasStencil) {
|
||||||
|
renderPassBuilder->SetStencilAccess(
|
||||||
|
attachmentInfo.stencilLoadOp, attachmentInfo.stencilStoreOp,
|
||||||
|
attachmentInfo.clearStencil, view->GetD3D12Format());
|
||||||
|
} else {
|
||||||
|
renderPassBuilder->SetStencilNoAccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set whether or not the texture requires initialization.
|
||||||
|
ASSERT(!hasDepth || !hasStencil ||
|
||||||
|
attachmentInfo.depthStoreOp == attachmentInfo.stencilStoreOp);
|
||||||
|
bool isInitialized = attachmentInfo.depthStoreOp == wgpu::StoreOp::Store;
|
||||||
|
texture->SetIsSubresourceContentInitialized(isInitialized, view->GetBaseMipLevel(), 1,
|
||||||
|
view->GetBaseArrayLayer(), 1);
|
||||||
|
} else {
|
||||||
|
renderPassBuilder->SetDepthStencilNoAccess();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandBuffer::EmulateBeginRenderPass(CommandRecordingContext* commandContext,
|
||||||
|
const RenderPassBuilder* renderPassBuilder) const {
|
||||||
ID3D12GraphicsCommandList* commandList = commandContext->GetCommandList();
|
ID3D12GraphicsCommandList* commandList = commandContext->GetCommandList();
|
||||||
|
|
||||||
// Clear framebuffer attachments as needed and transition to render target
|
// Clear framebuffer attachments as needed.
|
||||||
{
|
{
|
||||||
for (uint32_t i :
|
for (uint32_t i = 0; i < renderPassBuilder->GetColorAttachmentCount(); i++) {
|
||||||
IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
|
|
||||||
auto& attachmentInfo = renderPass->colorAttachments[i];
|
|
||||||
TextureView* view = ToBackend(attachmentInfo.view.Get());
|
|
||||||
|
|
||||||
// Load op - color
|
// Load op - color
|
||||||
ASSERT(view->GetLevelCount() == 1);
|
if (renderPassBuilder->GetRenderPassRenderTargetDescriptors()[i]
|
||||||
ASSERT(view->GetLayerCount() == 1);
|
.BeginningAccess.Type == D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR) {
|
||||||
if (attachmentInfo.loadOp == wgpu::LoadOp::Clear ||
|
commandList->ClearRenderTargetView(
|
||||||
(attachmentInfo.loadOp == wgpu::LoadOp::Load &&
|
renderPassBuilder->GetRenderPassRenderTargetDescriptors()[i].cpuDescriptor,
|
||||||
!view->GetTexture()->IsSubresourceContentInitialized(
|
renderPassBuilder->GetRenderPassRenderTargetDescriptors()[i]
|
||||||
view->GetBaseMipLevel(), 1, view->GetBaseArrayLayer(), 1))) {
|
.BeginningAccess.Clear.ClearValue.Color,
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE handle = args.RTVs[i];
|
0, nullptr);
|
||||||
commandList->ClearRenderTargetView(handle, &attachmentInfo.clearColor.r, 0,
|
|
||||||
nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureView* resolveView = ToBackend(attachmentInfo.resolveTarget.Get());
|
|
||||||
if (resolveView != nullptr) {
|
|
||||||
// We need to set the resolve target to initialized so that it does not get
|
|
||||||
// cleared later in the pipeline. The texture will be resolved from the source
|
|
||||||
// color attachment, which will be correctly initialized.
|
|
||||||
ToBackend(resolveView->GetTexture())
|
|
||||||
->SetIsSubresourceContentInitialized(
|
|
||||||
true, resolveView->GetBaseMipLevel(), resolveView->GetLevelCount(),
|
|
||||||
resolveView->GetBaseArrayLayer(), resolveView->GetLayerCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (attachmentInfo.storeOp) {
|
|
||||||
case wgpu::StoreOp::Store: {
|
|
||||||
view->GetTexture()->SetIsSubresourceContentInitialized(
|
|
||||||
true, view->GetBaseMipLevel(), 1, view->GetBaseArrayLayer(), 1);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case wgpu::StoreOp::Clear: {
|
|
||||||
view->GetTexture()->SetIsSubresourceContentInitialized(
|
|
||||||
false, view->GetBaseMipLevel(), 1, view->GetBaseArrayLayer(), 1);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default: { UNREACHABLE(); } break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (renderPass->attachmentState->HasDepthStencilAttachment()) {
|
if (renderPassBuilder->HasDepth()) {
|
||||||
auto& attachmentInfo = renderPass->depthStencilAttachment;
|
D3D12_CLEAR_FLAGS clearFlags = {};
|
||||||
Texture* texture = ToBackend(renderPass->depthStencilAttachment.view->GetTexture());
|
float depthClear = 0.0f;
|
||||||
TextureView* view = ToBackend(attachmentInfo.view.Get());
|
uint8_t stencilClear = 0u;
|
||||||
float clearDepth = attachmentInfo.clearDepth;
|
|
||||||
|
if (renderPassBuilder->GetRenderPassDepthStencilDescriptor()
|
||||||
|
->DepthBeginningAccess.Type ==
|
||||||
|
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR) {
|
||||||
|
clearFlags |= D3D12_CLEAR_FLAG_DEPTH;
|
||||||
|
depthClear = renderPassBuilder->GetRenderPassDepthStencilDescriptor()
|
||||||
|
->DepthBeginningAccess.Clear.ClearValue.DepthStencil.Depth;
|
||||||
|
}
|
||||||
|
if (renderPassBuilder->GetRenderPassDepthStencilDescriptor()
|
||||||
|
->StencilBeginningAccess.Type ==
|
||||||
|
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR) {
|
||||||
|
clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
|
||||||
|
stencilClear =
|
||||||
|
renderPassBuilder->GetRenderPassDepthStencilDescriptor()
|
||||||
|
->StencilBeginningAccess.Clear.ClearValue.DepthStencil.Stencil;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(kainino@chromium.org): investigate: should the Dawn clear
|
// TODO(kainino@chromium.org): investigate: should the Dawn clear
|
||||||
// stencil type be uint8_t?
|
// stencil type be uint8_t?
|
||||||
uint8_t clearStencil = static_cast<uint8_t>(attachmentInfo.clearStencil);
|
|
||||||
|
|
||||||
// Load op - depth/stencil
|
|
||||||
bool doDepthClear = texture->GetFormat().HasDepth() &&
|
|
||||||
(attachmentInfo.depthLoadOp == wgpu::LoadOp::Clear);
|
|
||||||
bool doStencilClear = texture->GetFormat().HasStencil() &&
|
|
||||||
(attachmentInfo.stencilLoadOp == wgpu::LoadOp::Clear);
|
|
||||||
|
|
||||||
D3D12_CLEAR_FLAGS clearFlags = {};
|
|
||||||
if (doDepthClear) {
|
|
||||||
clearFlags |= D3D12_CLEAR_FLAG_DEPTH;
|
|
||||||
}
|
|
||||||
if (doStencilClear) {
|
|
||||||
clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
|
|
||||||
}
|
|
||||||
// If the depth stencil texture has not been initialized, we want to use loadop
|
|
||||||
// clear to init the contents to 0's
|
|
||||||
if (!texture->IsSubresourceContentInitialized(
|
|
||||||
view->GetBaseMipLevel(), view->GetLevelCount(), view->GetBaseArrayLayer(),
|
|
||||||
view->GetLayerCount())) {
|
|
||||||
if (texture->GetFormat().HasDepth() &&
|
|
||||||
attachmentInfo.depthLoadOp == wgpu::LoadOp::Load) {
|
|
||||||
clearDepth = 0.0f;
|
|
||||||
clearFlags |= D3D12_CLEAR_FLAG_DEPTH;
|
|
||||||
}
|
|
||||||
if (texture->GetFormat().HasStencil() &&
|
|
||||||
attachmentInfo.stencilLoadOp == wgpu::LoadOp::Load) {
|
|
||||||
clearStencil = 0u;
|
|
||||||
clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clearFlags) {
|
if (clearFlags) {
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE handle = args.dsv;
|
commandList->ClearDepthStencilView(
|
||||||
commandList->ClearDepthStencilView(handle, clearFlags, clearDepth, clearStencil,
|
renderPassBuilder->GetRenderPassDepthStencilDescriptor()->cpuDescriptor,
|
||||||
0, nullptr);
|
clearFlags, depthClear, stencilClear, 0, nullptr);
|
||||||
}
|
|
||||||
|
|
||||||
if (attachmentInfo.depthStoreOp == wgpu::StoreOp::Store &&
|
|
||||||
attachmentInfo.stencilStoreOp == wgpu::StoreOp::Store) {
|
|
||||||
texture->SetIsSubresourceContentInitialized(
|
|
||||||
true, view->GetBaseMipLevel(), view->GetLevelCount(),
|
|
||||||
view->GetBaseArrayLayer(), view->GetLayerCount());
|
|
||||||
} else if (attachmentInfo.depthStoreOp == wgpu::StoreOp::Clear &&
|
|
||||||
attachmentInfo.stencilStoreOp == wgpu::StoreOp::Clear) {
|
|
||||||
texture->SetIsSubresourceContentInitialized(
|
|
||||||
false, view->GetBaseMipLevel(), view->GetLevelCount(),
|
|
||||||
view->GetBaseArrayLayer(), view->GetLayerCount());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up render targets
|
commandList->OMSetRenderTargets(
|
||||||
{
|
renderPassBuilder->GetColorAttachmentCount(), renderPassBuilder->GetRenderTargetViews(),
|
||||||
if (args.dsv.ptr) {
|
FALSE,
|
||||||
commandList->OMSetRenderTargets(args.numRTVs, args.RTVs.data(), FALSE, &args.dsv);
|
renderPassBuilder->HasDepth()
|
||||||
} else {
|
? &renderPassBuilder->GetRenderPassDepthStencilDescriptor()->cpuDescriptor
|
||||||
commandList->OMSetRenderTargets(args.numRTVs, args.RTVs.data(), FALSE, nullptr);
|
: nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CommandBuffer::RecordRenderPass(
|
||||||
|
CommandRecordingContext* commandContext,
|
||||||
|
BindGroupStateTracker* bindingTracker,
|
||||||
|
RenderPassDescriptorHeapTracker* renderPassDescriptorHeapTracker,
|
||||||
|
BeginRenderPassCmd* renderPass,
|
||||||
|
const bool passHasUAV) {
|
||||||
|
OMSetRenderTargetArgs args =
|
||||||
|
renderPassDescriptorHeapTracker->GetSubpassOMSetRenderTargetArgs(renderPass);
|
||||||
|
|
||||||
|
const bool useRenderPass = GetDevice()->IsToggleEnabled(Toggle::UseD3D12RenderPass);
|
||||||
|
|
||||||
|
// renderPassBuilder must be scoped to RecordRenderPass because any underlying
|
||||||
|
// D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS structs must remain
|
||||||
|
// valid until after EndRenderPass() has been called.
|
||||||
|
RenderPassBuilder renderPassBuilder(args, passHasUAV);
|
||||||
|
|
||||||
|
SetupRenderPass(commandContext, renderPass, &renderPassBuilder);
|
||||||
|
|
||||||
|
// Use D3D12's native render pass API if it's available, otherwise emulate the
|
||||||
|
// beginning and ending access operations.
|
||||||
|
if (useRenderPass) {
|
||||||
|
commandContext->GetCommandList4()->BeginRenderPass(
|
||||||
|
renderPassBuilder.GetColorAttachmentCount(),
|
||||||
|
renderPassBuilder.GetRenderPassRenderTargetDescriptors(),
|
||||||
|
renderPassBuilder.HasDepth()
|
||||||
|
? renderPassBuilder.GetRenderPassDepthStencilDescriptor()
|
||||||
|
: nullptr,
|
||||||
|
renderPassBuilder.GetRenderPassFlags());
|
||||||
|
} else {
|
||||||
|
EmulateBeginRenderPass(commandContext, &renderPassBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ID3D12GraphicsCommandList* commandList = commandContext->GetCommandList();
|
||||||
|
|
||||||
// Set up default dynamic state
|
// Set up default dynamic state
|
||||||
{
|
{
|
||||||
uint32_t width = renderPass->width;
|
uint32_t width = renderPass->width;
|
||||||
@ -1189,10 +1262,9 @@ namespace dawn_native { namespace d3d12 {
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case Command::EndRenderPass: {
|
case Command::EndRenderPass: {
|
||||||
mCommands.NextCommand<EndRenderPassCmd>();
|
mCommands.NextCommand<EndRenderPassCmd>();
|
||||||
|
if (useRenderPass) {
|
||||||
// TODO(brandon1.jones@intel.com): avoid calling this function and enable MSAA
|
commandContext->GetCommandList4()->EndRenderPass();
|
||||||
// resolve in D3D12 render pass on the platforms that support this feature.
|
} else if (renderPass->attachmentState->GetSampleCount() > 1) {
|
||||||
if (renderPass->attachmentState->GetSampleCount() > 1) {
|
|
||||||
ResolveMultisampledRenderPass(commandContext, renderPass);
|
ResolveMultisampledRenderPass(commandContext, renderPass);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -31,10 +31,17 @@ namespace dawn_native {
|
|||||||
|
|
||||||
namespace dawn_native { namespace d3d12 {
|
namespace dawn_native { namespace d3d12 {
|
||||||
|
|
||||||
|
struct OMSetRenderTargetArgs {
|
||||||
|
unsigned int numRTVs = 0;
|
||||||
|
std::array<D3D12_CPU_DESCRIPTOR_HANDLE, kMaxColorAttachments> RTVs = {};
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE dsv = {};
|
||||||
|
};
|
||||||
|
|
||||||
class BindGroupStateTracker;
|
class BindGroupStateTracker;
|
||||||
class CommandRecordingContext;
|
class CommandRecordingContext;
|
||||||
class Device;
|
class Device;
|
||||||
class RenderPassDescriptorHeapTracker;
|
class RenderPassDescriptorHeapTracker;
|
||||||
|
class RenderPassBuilder;
|
||||||
class RenderPipeline;
|
class RenderPipeline;
|
||||||
|
|
||||||
class CommandBuffer : public CommandBufferBase {
|
class CommandBuffer : public CommandBufferBase {
|
||||||
@ -49,8 +56,14 @@ namespace dawn_native { namespace d3d12 {
|
|||||||
BindGroupStateTracker* bindingTracker);
|
BindGroupStateTracker* bindingTracker);
|
||||||
void RecordRenderPass(CommandRecordingContext* commandContext,
|
void RecordRenderPass(CommandRecordingContext* commandContext,
|
||||||
BindGroupStateTracker* bindingTracker,
|
BindGroupStateTracker* bindingTracker,
|
||||||
RenderPassDescriptorHeapTracker* renderPassTracker,
|
RenderPassDescriptorHeapTracker* renderPassDescriptorHeapTracker,
|
||||||
BeginRenderPassCmd* renderPass);
|
BeginRenderPassCmd* renderPass,
|
||||||
|
bool passHasUAV);
|
||||||
|
void SetupRenderPass(CommandRecordingContext* commandContext,
|
||||||
|
BeginRenderPassCmd* renderPass,
|
||||||
|
RenderPassBuilder* renderPassBuilder);
|
||||||
|
void EmulateBeginRenderPass(CommandRecordingContext* commandContext,
|
||||||
|
const RenderPassBuilder* renderPassBuilder) const;
|
||||||
|
|
||||||
CommandIterator mCommands;
|
CommandIterator mCommands;
|
||||||
};
|
};
|
||||||
|
@ -41,6 +41,9 @@ namespace dawn_native { namespace d3d12 {
|
|||||||
nullptr, IID_PPV_ARGS(&d3d12GraphicsCommandList)),
|
nullptr, IID_PPV_ARGS(&d3d12GraphicsCommandList)),
|
||||||
"D3D12 creating direct command list"));
|
"D3D12 creating direct command list"));
|
||||||
mD3d12CommandList = std::move(d3d12GraphicsCommandList);
|
mD3d12CommandList = std::move(d3d12GraphicsCommandList);
|
||||||
|
// Store a cast to ID3D12GraphicsCommandList4. This is required to use the D3D12 render
|
||||||
|
// pass APIs introduced in Windows build 1809.
|
||||||
|
mD3d12CommandList.As(&mD3d12CommandList4);
|
||||||
}
|
}
|
||||||
|
|
||||||
mIsOpen = true;
|
mIsOpen = true;
|
||||||
@ -80,8 +83,17 @@ namespace dawn_native { namespace d3d12 {
|
|||||||
return mD3d12CommandList.Get();
|
return mD3d12CommandList.Get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This function will fail on Windows versions prior to 1809. Support must be queried through
|
||||||
|
// the device before calling.
|
||||||
|
ID3D12GraphicsCommandList4* CommandRecordingContext::GetCommandList4() const {
|
||||||
|
ASSERT(IsOpen());
|
||||||
|
ASSERT(mD3d12CommandList.Get() != nullptr);
|
||||||
|
return mD3d12CommandList4.Get();
|
||||||
|
}
|
||||||
|
|
||||||
void CommandRecordingContext::Release() {
|
void CommandRecordingContext::Release() {
|
||||||
mD3d12CommandList.Reset();
|
mD3d12CommandList.Reset();
|
||||||
|
mD3d12CommandList4.Reset();
|
||||||
mIsOpen = false;
|
mIsOpen = false;
|
||||||
mSharedTextures.clear();
|
mSharedTextures.clear();
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ namespace dawn_native { namespace d3d12 {
|
|||||||
CommandAllocatorManager* commandAllocationManager);
|
CommandAllocatorManager* commandAllocationManager);
|
||||||
|
|
||||||
ID3D12GraphicsCommandList* GetCommandList() const;
|
ID3D12GraphicsCommandList* GetCommandList() const;
|
||||||
|
ID3D12GraphicsCommandList4* GetCommandList4() const;
|
||||||
void Release();
|
void Release();
|
||||||
bool IsOpen() const;
|
bool IsOpen() const;
|
||||||
|
|
||||||
@ -38,6 +39,7 @@ namespace dawn_native { namespace d3d12 {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
ComPtr<ID3D12GraphicsCommandList> mD3d12CommandList;
|
ComPtr<ID3D12GraphicsCommandList> mD3d12CommandList;
|
||||||
|
ComPtr<ID3D12GraphicsCommandList4> mD3d12CommandList4;
|
||||||
bool mIsOpen = false;
|
bool mIsOpen = false;
|
||||||
std::set<Texture*> mSharedTextures;
|
std::set<Texture*> mSharedTextures;
|
||||||
};
|
};
|
||||||
|
@ -24,25 +24,33 @@ namespace dawn_native { namespace d3d12 {
|
|||||||
ResultOrError<D3D12DeviceInfo> GatherDeviceInfo(const Adapter& adapter) {
|
ResultOrError<D3D12DeviceInfo> GatherDeviceInfo(const Adapter& adapter) {
|
||||||
D3D12DeviceInfo info = {};
|
D3D12DeviceInfo info = {};
|
||||||
|
|
||||||
// Gather info about device memory
|
// Newer builds replace D3D_FEATURE_DATA_ARCHITECTURE with
|
||||||
{
|
// D3D_FEATURE_DATA_ARCHITECTURE1. However, D3D_FEATURE_DATA_ARCHITECTURE can be used
|
||||||
// Newer builds replace D3D_FEATURE_DATA_ARCHITECTURE with
|
// for backwards compat.
|
||||||
// D3D_FEATURE_DATA_ARCHITECTURE1. However, D3D_FEATURE_DATA_ARCHITECTURE can be used
|
// https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ne-d3d12-d3d12_feature
|
||||||
// for backwards compat.
|
D3D12_FEATURE_DATA_ARCHITECTURE arch = {};
|
||||||
// https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ne-d3d12-d3d12_feature
|
DAWN_TRY(CheckHRESULT(adapter.GetDevice()->CheckFeatureSupport(D3D12_FEATURE_ARCHITECTURE,
|
||||||
D3D12_FEATURE_DATA_ARCHITECTURE arch = {};
|
&arch, sizeof(arch)),
|
||||||
DAWN_TRY(CheckHRESULT(adapter.GetDevice()->CheckFeatureSupport(
|
"ID3D12Device::CheckFeatureSupport"));
|
||||||
D3D12_FEATURE_ARCHITECTURE, &arch, sizeof(arch)),
|
|
||||||
"ID3D12Device::CheckFeatureSupport"));
|
|
||||||
|
|
||||||
info.isUMA = arch.UMA;
|
info.isUMA = arch.UMA;
|
||||||
|
|
||||||
D3D12_FEATURE_DATA_D3D12_OPTIONS options = {};
|
D3D12_FEATURE_DATA_D3D12_OPTIONS options = {};
|
||||||
DAWN_TRY(CheckHRESULT(adapter.GetDevice()->CheckFeatureSupport(
|
DAWN_TRY(CheckHRESULT(adapter.GetDevice()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS,
|
||||||
D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options)),
|
&options, sizeof(options)),
|
||||||
"ID3D12Device::CheckFeatureSupport"));
|
"ID3D12Device::CheckFeatureSupport"));
|
||||||
|
|
||||||
info.resourceHeapTier = options.ResourceHeapTier;
|
info.resourceHeapTier = options.ResourceHeapTier;
|
||||||
|
|
||||||
|
// Windows builds 1809 and above can use the D3D12 render pass API. If we query
|
||||||
|
// CheckFeatureSupport for D3D12_FEATURE_D3D12_OPTIONS5 successfully, then we can use
|
||||||
|
// the render pass API.
|
||||||
|
D3D12_FEATURE_DATA_D3D12_OPTIONS5 featureOptions5 = {};
|
||||||
|
if (SUCCEEDED(adapter.GetDevice()->CheckFeatureSupport(
|
||||||
|
D3D12_FEATURE_D3D12_OPTIONS5, &featureOptions5, sizeof(featureOptions5)))) {
|
||||||
|
info.supportsRenderPass = true;
|
||||||
|
} else {
|
||||||
|
info.supportsRenderPass = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
|
@ -25,6 +25,7 @@ namespace dawn_native { namespace d3d12 {
|
|||||||
struct D3D12DeviceInfo {
|
struct D3D12DeviceInfo {
|
||||||
bool isUMA;
|
bool isUMA;
|
||||||
uint32_t resourceHeapTier;
|
uint32_t resourceHeapTier;
|
||||||
|
bool supportsRenderPass;
|
||||||
};
|
};
|
||||||
|
|
||||||
ResultOrError<D3D12DeviceInfo> GatherDeviceInfo(const Adapter& adapter);
|
ResultOrError<D3D12DeviceInfo> GatherDeviceInfo(const Adapter& adapter);
|
||||||
|
@ -414,6 +414,7 @@ namespace dawn_native { namespace d3d12 {
|
|||||||
void Device::InitTogglesFromDriver() {
|
void Device::InitTogglesFromDriver() {
|
||||||
const bool useResourceHeapTier2 = (GetDeviceInfo().resourceHeapTier >= 2);
|
const bool useResourceHeapTier2 = (GetDeviceInfo().resourceHeapTier >= 2);
|
||||||
SetToggle(Toggle::UseD3D12ResourceHeapTier2, useResourceHeapTier2);
|
SetToggle(Toggle::UseD3D12ResourceHeapTier2, useResourceHeapTier2);
|
||||||
|
SetToggle(Toggle::UseD3D12RenderPass, GetDeviceInfo().supportsRenderPass);
|
||||||
}
|
}
|
||||||
|
|
||||||
}} // namespace dawn_native::d3d12
|
}} // namespace dawn_native::d3d12
|
||||||
|
229
src/dawn_native/d3d12/RenderPassBuilderD3D12.cpp
Normal file
229
src/dawn_native/d3d12/RenderPassBuilderD3D12.cpp
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
// Copyright 2019 The Dawn Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "dawn_native/d3d12/RenderPassBuilderD3D12.h"
|
||||||
|
|
||||||
|
#include "dawn_native/Format.h"
|
||||||
|
#include "dawn_native/d3d12/CommandBufferD3D12.h"
|
||||||
|
#include "dawn_native/d3d12/Forward.h"
|
||||||
|
#include "dawn_native/d3d12/TextureD3D12.h"
|
||||||
|
|
||||||
|
#include "dawn_native/dawn_platform.h"
|
||||||
|
|
||||||
|
namespace dawn_native { namespace d3d12 {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE D3D12BeginningAccessType(wgpu::LoadOp loadOp) {
|
||||||
|
switch (loadOp) {
|
||||||
|
case wgpu::LoadOp::Clear:
|
||||||
|
return D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR;
|
||||||
|
case wgpu::LoadOp::Load:
|
||||||
|
return D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE D3D12EndingAccessType(wgpu::StoreOp storeOp) {
|
||||||
|
switch (storeOp) {
|
||||||
|
case wgpu::StoreOp::Clear:
|
||||||
|
return D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD;
|
||||||
|
case wgpu::StoreOp::Store:
|
||||||
|
return D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_PARAMETERS D3D12EndingAccessResolveParameters(
|
||||||
|
wgpu::StoreOp storeOp,
|
||||||
|
TextureView* resolveSource,
|
||||||
|
TextureView* resolveDestination) {
|
||||||
|
D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_PARAMETERS resolveParameters;
|
||||||
|
|
||||||
|
resolveParameters.Format = resolveDestination->GetD3D12Format();
|
||||||
|
resolveParameters.pSrcResource =
|
||||||
|
ToBackend(resolveSource->GetTexture())->GetD3D12Resource();
|
||||||
|
resolveParameters.pDstResource =
|
||||||
|
ToBackend(resolveDestination->GetTexture())->GetD3D12Resource();
|
||||||
|
|
||||||
|
// Clear or preserve the resolve source.
|
||||||
|
if (storeOp == wgpu::StoreOp::Clear) {
|
||||||
|
resolveParameters.PreserveResolveSource = false;
|
||||||
|
} else if (storeOp == wgpu::StoreOp::Store) {
|
||||||
|
resolveParameters.PreserveResolveSource = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// RESOLVE_MODE_AVERAGE is only valid for non-integer formats.
|
||||||
|
// TODO: Investigate and determine how integer format resolves should work in WebGPU.
|
||||||
|
switch (resolveDestination->GetFormat().type) {
|
||||||
|
case Format::Type::Sint:
|
||||||
|
case Format::Type::Uint:
|
||||||
|
resolveParameters.ResolveMode = D3D12_RESOLVE_MODE_MAX;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
resolveParameters.ResolveMode = D3D12_RESOLVE_MODE_AVERAGE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolveParameters.SubresourceCount = 1;
|
||||||
|
|
||||||
|
return resolveParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS
|
||||||
|
D3D12EndingAccessResolveSubresourceParameters(TextureView* resolveDestination) {
|
||||||
|
D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS subresourceParameters;
|
||||||
|
Texture* resolveDestinationTexture = ToBackend(resolveDestination->GetTexture());
|
||||||
|
|
||||||
|
subresourceParameters.DstX = 0;
|
||||||
|
subresourceParameters.DstY = 0;
|
||||||
|
subresourceParameters.SrcSubresource = 0;
|
||||||
|
subresourceParameters.DstSubresource = resolveDestinationTexture->GetSubresourceIndex(
|
||||||
|
resolveDestination->GetBaseMipLevel(), resolveDestination->GetBaseArrayLayer());
|
||||||
|
subresourceParameters.SrcRect = {0, 0, resolveDestinationTexture->GetSize().width,
|
||||||
|
resolveDestinationTexture->GetSize().height};
|
||||||
|
|
||||||
|
return subresourceParameters;
|
||||||
|
}
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
RenderPassBuilder::RenderPassBuilder(const OMSetRenderTargetArgs& args, bool hasUAV)
|
||||||
|
: mColorAttachmentCount(args.numRTVs), mRenderTargetViews(args.RTVs.data()) {
|
||||||
|
for (uint32_t i = 0; i < mColorAttachmentCount; i++) {
|
||||||
|
mRenderPassRenderTargetDescriptors[i].cpuDescriptor = args.RTVs[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
mRenderPassDepthStencilDesc.cpuDescriptor = args.dsv;
|
||||||
|
|
||||||
|
if (hasUAV) {
|
||||||
|
mRenderPassFlags = D3D12_RENDER_PASS_FLAG_ALLOW_UAV_WRITES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t RenderPassBuilder::GetColorAttachmentCount() const {
|
||||||
|
return mColorAttachmentCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RenderPassBuilder::HasDepth() const {
|
||||||
|
return mHasDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
const D3D12_RENDER_PASS_RENDER_TARGET_DESC*
|
||||||
|
RenderPassBuilder::GetRenderPassRenderTargetDescriptors() const {
|
||||||
|
return mRenderPassRenderTargetDescriptors.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
const D3D12_RENDER_PASS_DEPTH_STENCIL_DESC*
|
||||||
|
RenderPassBuilder::GetRenderPassDepthStencilDescriptor() const {
|
||||||
|
return &mRenderPassDepthStencilDesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12_RENDER_PASS_FLAGS RenderPassBuilder::GetRenderPassFlags() const {
|
||||||
|
return mRenderPassFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
const D3D12_CPU_DESCRIPTOR_HANDLE* RenderPassBuilder::GetRenderTargetViews() const {
|
||||||
|
return mRenderTargetViews;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderPassBuilder::SetRenderTargetBeginningAccess(uint32_t attachment,
|
||||||
|
wgpu::LoadOp loadOp,
|
||||||
|
dawn_native::Color clearColor,
|
||||||
|
DXGI_FORMAT format) {
|
||||||
|
mRenderPassRenderTargetDescriptors[attachment].BeginningAccess.Type =
|
||||||
|
D3D12BeginningAccessType(loadOp);
|
||||||
|
if (loadOp == wgpu::LoadOp::Clear) {
|
||||||
|
mRenderPassRenderTargetDescriptors[attachment]
|
||||||
|
.BeginningAccess.Clear.ClearValue.Color[0] = clearColor.r;
|
||||||
|
mRenderPassRenderTargetDescriptors[attachment]
|
||||||
|
.BeginningAccess.Clear.ClearValue.Color[1] = clearColor.g;
|
||||||
|
mRenderPassRenderTargetDescriptors[attachment]
|
||||||
|
.BeginningAccess.Clear.ClearValue.Color[2] = clearColor.b;
|
||||||
|
mRenderPassRenderTargetDescriptors[attachment]
|
||||||
|
.BeginningAccess.Clear.ClearValue.Color[3] = clearColor.a;
|
||||||
|
mRenderPassRenderTargetDescriptors[attachment].BeginningAccess.Clear.ClearValue.Format =
|
||||||
|
format;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderPassBuilder::SetRenderTargetEndingAccess(uint32_t attachment,
|
||||||
|
wgpu::StoreOp storeOp) {
|
||||||
|
mRenderPassRenderTargetDescriptors[attachment].EndingAccess.Type =
|
||||||
|
D3D12EndingAccessType(storeOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderPassBuilder::SetRenderTargetEndingAccessResolve(uint32_t attachment,
|
||||||
|
wgpu::StoreOp storeOp,
|
||||||
|
TextureView* resolveSource,
|
||||||
|
TextureView* resolveDestination) {
|
||||||
|
mRenderPassRenderTargetDescriptors[attachment].EndingAccess.Type =
|
||||||
|
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_RESOLVE;
|
||||||
|
mRenderPassRenderTargetDescriptors[attachment].EndingAccess.Resolve =
|
||||||
|
D3D12EndingAccessResolveParameters(storeOp, resolveSource, resolveDestination);
|
||||||
|
|
||||||
|
mSubresourceParams[attachment] =
|
||||||
|
D3D12EndingAccessResolveSubresourceParameters(resolveDestination);
|
||||||
|
|
||||||
|
mRenderPassRenderTargetDescriptors[attachment].EndingAccess.Resolve.pSubresourceParameters =
|
||||||
|
&mSubresourceParams[attachment];
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderPassBuilder::SetDepthAccess(wgpu::LoadOp loadOp,
|
||||||
|
wgpu::StoreOp storeOp,
|
||||||
|
float clearDepth,
|
||||||
|
DXGI_FORMAT format) {
|
||||||
|
mHasDepth = true;
|
||||||
|
mRenderPassDepthStencilDesc.DepthBeginningAccess.Type = D3D12BeginningAccessType(loadOp);
|
||||||
|
if (loadOp == wgpu::LoadOp::Clear) {
|
||||||
|
mRenderPassDepthStencilDesc.DepthBeginningAccess.Clear.ClearValue.DepthStencil.Depth =
|
||||||
|
clearDepth;
|
||||||
|
mRenderPassDepthStencilDesc.DepthBeginningAccess.Clear.ClearValue.Format = format;
|
||||||
|
}
|
||||||
|
mRenderPassDepthStencilDesc.DepthEndingAccess.Type = D3D12EndingAccessType(storeOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderPassBuilder::SetStencilAccess(wgpu::LoadOp loadOp,
|
||||||
|
wgpu::StoreOp storeOp,
|
||||||
|
uint8_t clearStencil,
|
||||||
|
DXGI_FORMAT format) {
|
||||||
|
mRenderPassDepthStencilDesc.StencilBeginningAccess.Type = D3D12BeginningAccessType(loadOp);
|
||||||
|
if (loadOp == wgpu::LoadOp::Clear) {
|
||||||
|
mRenderPassDepthStencilDesc.StencilBeginningAccess.Clear.ClearValue.DepthStencil
|
||||||
|
.Stencil = clearStencil;
|
||||||
|
mRenderPassDepthStencilDesc.StencilBeginningAccess.Clear.ClearValue.Format = format;
|
||||||
|
}
|
||||||
|
mRenderPassDepthStencilDesc.StencilEndingAccess.Type = D3D12EndingAccessType(storeOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderPassBuilder::SetDepthNoAccess() {
|
||||||
|
mRenderPassDepthStencilDesc.DepthBeginningAccess.Type =
|
||||||
|
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS;
|
||||||
|
mRenderPassDepthStencilDesc.DepthEndingAccess.Type =
|
||||||
|
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderPassBuilder::SetDepthStencilNoAccess() {
|
||||||
|
SetDepthNoAccess();
|
||||||
|
SetStencilNoAccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderPassBuilder::SetStencilNoAccess() {
|
||||||
|
mRenderPassDepthStencilDesc.StencilBeginningAccess.Type =
|
||||||
|
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS;
|
||||||
|
mRenderPassDepthStencilDesc.StencilEndingAccess.Type =
|
||||||
|
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
}} // namespace dawn_native::d3d12
|
89
src/dawn_native/d3d12/RenderPassBuilderD3D12.h
Normal file
89
src/dawn_native/d3d12/RenderPassBuilderD3D12.h
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
// Copyright 2019 The Dawn Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef DAWNNATIVE_D3D12_RENDERPASSBUILDERD3D12_H_
|
||||||
|
#define DAWNNATIVE_D3D12_RENDERPASSBUILDERD3D12_H_
|
||||||
|
|
||||||
|
#include "common/Constants.h"
|
||||||
|
#include "dawn_native/d3d12/d3d12_platform.h"
|
||||||
|
#include "dawn_native/dawn_platform.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
namespace dawn_native { namespace d3d12 {
|
||||||
|
|
||||||
|
class TextureView;
|
||||||
|
|
||||||
|
struct OMSetRenderTargetArgs;
|
||||||
|
|
||||||
|
// RenderPassBuilder stores parameters related to render pass load and store operations.
|
||||||
|
// When the D3D12 render pass API is available, the needed descriptors can be fetched
|
||||||
|
// directly from the RenderPassBuilder. When the D3D12 render pass API is not available, the
|
||||||
|
// descriptors are still fetched and any information necessary to emulate the load and store
|
||||||
|
// operations is extracted from the descriptors.
|
||||||
|
class RenderPassBuilder {
|
||||||
|
public:
|
||||||
|
RenderPassBuilder(const OMSetRenderTargetArgs& args, bool hasUAV);
|
||||||
|
|
||||||
|
uint32_t GetColorAttachmentCount() const;
|
||||||
|
|
||||||
|
// Returns descriptors that are fed directly to BeginRenderPass, or are used as parameter
|
||||||
|
// storage if D3D12 render pass API is unavailable.
|
||||||
|
const D3D12_RENDER_PASS_RENDER_TARGET_DESC* GetRenderPassRenderTargetDescriptors() const;
|
||||||
|
const D3D12_RENDER_PASS_DEPTH_STENCIL_DESC* GetRenderPassDepthStencilDescriptor() const;
|
||||||
|
|
||||||
|
D3D12_RENDER_PASS_FLAGS GetRenderPassFlags() const;
|
||||||
|
|
||||||
|
// Returns attachment RTVs to use with OMSetRenderTargets.
|
||||||
|
const D3D12_CPU_DESCRIPTOR_HANDLE* GetRenderTargetViews() const;
|
||||||
|
|
||||||
|
bool HasDepth() const;
|
||||||
|
|
||||||
|
// Functions that set the appropriate values in the render pass descriptors.
|
||||||
|
void SetDepthAccess(wgpu::LoadOp loadOp,
|
||||||
|
wgpu::StoreOp storeOp,
|
||||||
|
float clearDepth,
|
||||||
|
DXGI_FORMAT format);
|
||||||
|
void SetDepthNoAccess();
|
||||||
|
void SetDepthStencilNoAccess();
|
||||||
|
void SetRenderTargetBeginningAccess(uint32_t attachment,
|
||||||
|
wgpu::LoadOp loadOp,
|
||||||
|
dawn_native::Color clearColor,
|
||||||
|
DXGI_FORMAT format);
|
||||||
|
void SetRenderTargetEndingAccess(uint32_t attachment, wgpu::StoreOp storeOp);
|
||||||
|
void SetRenderTargetEndingAccessResolve(uint32_t attachment,
|
||||||
|
wgpu::StoreOp storeOp,
|
||||||
|
TextureView* resolveSource,
|
||||||
|
TextureView* resolveDestination);
|
||||||
|
void SetStencilAccess(wgpu::LoadOp loadOp,
|
||||||
|
wgpu::StoreOp storeOp,
|
||||||
|
uint8_t clearStencil,
|
||||||
|
DXGI_FORMAT format);
|
||||||
|
void SetStencilNoAccess();
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t mColorAttachmentCount = 0;
|
||||||
|
bool mHasDepth = false;
|
||||||
|
D3D12_RENDER_PASS_FLAGS mRenderPassFlags = D3D12_RENDER_PASS_FLAG_NONE;
|
||||||
|
D3D12_RENDER_PASS_DEPTH_STENCIL_DESC mRenderPassDepthStencilDesc;
|
||||||
|
std::array<D3D12_RENDER_PASS_RENDER_TARGET_DESC, kMaxColorAttachments>
|
||||||
|
mRenderPassRenderTargetDescriptors;
|
||||||
|
const D3D12_CPU_DESCRIPTOR_HANDLE* mRenderTargetViews;
|
||||||
|
std::array<D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS,
|
||||||
|
kMaxColorAttachments>
|
||||||
|
mSubresourceParams;
|
||||||
|
};
|
||||||
|
}} // namespace dawn_native::d3d12
|
||||||
|
|
||||||
|
#endif // DAWNNATIVE_D3D12_RENDERPASSBUILDERD3D12_H_
|
@ -506,6 +506,7 @@ TEST_P(MultisampledRenderingTest, ResolveInto2DArrayTexture) {
|
|||||||
DAWN_INSTANTIATE_TEST(MultisampledRenderingTest,
|
DAWN_INSTANTIATE_TEST(MultisampledRenderingTest,
|
||||||
D3D12Backend,
|
D3D12Backend,
|
||||||
ForceWorkarounds(D3D12Backend, {}, {"use_d3d12_resource_heap_tier2"}),
|
ForceWorkarounds(D3D12Backend, {}, {"use_d3d12_resource_heap_tier2"}),
|
||||||
|
ForceWorkarounds(D3D12Backend, {}, {"use_d3d12_render_pass"}),
|
||||||
MetalBackend,
|
MetalBackend,
|
||||||
OpenGLBackend,
|
OpenGLBackend,
|
||||||
VulkanBackend,
|
VulkanBackend,
|
||||||
|
@ -171,4 +171,9 @@ TEST_P(RenderPassTest, NoCorrespondingFragmentShaderOutputs) {
|
|||||||
EXPECT_PIXEL_RGBA8_EQ(kRed, renderTarget, kRTSize - 1, 1);
|
EXPECT_PIXEL_RGBA8_EQ(kRed, renderTarget, kRTSize - 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
DAWN_INSTANTIATE_TEST(RenderPassTest, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend);
|
DAWN_INSTANTIATE_TEST(RenderPassTest,
|
||||||
|
D3D12Backend,
|
||||||
|
ForceWorkarounds(D3D12Backend, {}, {"use_d3d12_render_pass"}),
|
||||||
|
MetalBackend,
|
||||||
|
OpenGLBackend,
|
||||||
|
VulkanBackend);
|
||||||
|
@ -779,5 +779,8 @@ TEST_P(TextureZeroInitTest, RenderingLoadingDepthStencilStoreOpClear) {
|
|||||||
DAWN_INSTANTIATE_TEST(
|
DAWN_INSTANTIATE_TEST(
|
||||||
TextureZeroInitTest,
|
TextureZeroInitTest,
|
||||||
ForceWorkarounds(D3D12Backend, {"nonzero_clear_resources_on_creation_for_testing"}),
|
ForceWorkarounds(D3D12Backend, {"nonzero_clear_resources_on_creation_for_testing"}),
|
||||||
|
ForceWorkarounds(D3D12Backend,
|
||||||
|
{"nonzero_clear_resources_on_creation_for_testing"},
|
||||||
|
{"use_d3d12_render_pass"}),
|
||||||
ForceWorkarounds(OpenGLBackend, {"nonzero_clear_resources_on_creation_for_testing"}),
|
ForceWorkarounds(OpenGLBackend, {"nonzero_clear_resources_on_creation_for_testing"}),
|
||||||
ForceWorkarounds(VulkanBackend, {"nonzero_clear_resources_on_creation_for_testing"}));
|
ForceWorkarounds(VulkanBackend, {"nonzero_clear_resources_on_creation_for_testing"}));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user