Add depth-stencil textures and attachments (#77)

Related: #29
This commit is contained in:
Kai Ninomiya 2017-07-17 12:03:16 -04:00 committed by GitHub
parent 28684d93ed
commit fec8c58a97
24 changed files with 227 additions and 194 deletions

View File

@ -81,8 +81,10 @@ void frame() {
{ {
nxtCommandBufferBuilder builder = nxtDeviceCreateCommandBufferBuilder(device); nxtCommandBufferBuilder builder = nxtDeviceCreateCommandBufferBuilder(device);
nxtCommandBufferBuilderBeginRenderPass(builder, renderpass, framebuffer); nxtCommandBufferBuilderBeginRenderPass(builder, renderpass, framebuffer);
nxtCommandBufferBuilderBeginRenderSubpass(builder);
nxtCommandBufferBuilderSetPipeline(builder, pipeline); nxtCommandBufferBuilderSetPipeline(builder, pipeline);
nxtCommandBufferBuilderDrawArrays(builder, 3, 1, 0, 0); nxtCommandBufferBuilderDrawArrays(builder, 3, 1, 0, 0);
nxtCommandBufferBuilderEndRenderSubpass(builder);
nxtCommandBufferBuilderEndRenderPass(builder); nxtCommandBufferBuilderEndRenderPass(builder);
commands = nxtCommandBufferBuilderGetResult(builder); commands = nxtCommandBufferBuilderGetResult(builder);
nxtCommandBufferBuilderRelease(builder); nxtCommandBufferBuilderRelease(builder);

View File

@ -445,18 +445,7 @@ namespace {
device = CreateCppNXTDevice(); device = CreateCppNXTDevice();
queue = device.CreateQueueBuilder().GetResult(); queue = device.CreateQueueBuilder().GetResult();
renderpass = device.CreateRenderPassBuilder() utils::CreateDefaultRenderPass(device, &renderpass, &framebuffer);
.SetAttachmentCount(1)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetSubpassCount(1)
.SubpassSetColorAttachment(0, 0, 0)
.GetResult();
framebuffer = device.CreateFramebufferBuilder()
.SetRenderPass(renderpass)
// attachment 0 -> back buffer
// (implicit) // TODO(kainino@chromium.org): use the texture provided by WSI
.SetDimensions(640, 480)
.GetResult();
initBuffers(); initBuffers();
initSamplers(); initSamplers();

View File

@ -591,7 +591,7 @@
"name": "set attachment", "name": "set attachment",
"args": [ "args": [
{"name": "attachment slot", "type": "uint32_t"}, {"name": "attachment slot", "type": "uint32_t"},
{"name": "texture views", "type": "texture view"} {"name": "texture view", "type": "texture view"}
] ]
} }
] ]
@ -762,6 +762,13 @@
{"name": "output attachment location", "type": "uint32_t"}, {"name": "output attachment location", "type": "uint32_t"},
{"name": "attachment slot", "type": "uint32_t"} {"name": "attachment slot", "type": "uint32_t"}
] ]
},
{
"name": "subpass set depth stencil attachment",
"args": [
{"name": "subpass index", "type": "uint32_t"},
{"name": "attachment slot", "type": "uint32_t"}
]
} }
] ]
}, },
@ -936,7 +943,8 @@
"texture format": { "texture format": {
"category": "enum", "category": "enum",
"values": [ "values": [
{"value": 0, "name": "r8 g8 b8 a8 unorm"} {"value": 0, "name": "r8 g8 b8 a8 unorm"},
{"value": 1, "name": "d32 float s8 uint"}
] ]
}, },
"vertex format": { "vertex format": {

View File

@ -126,6 +126,10 @@ namespace backend {
HandleError("Render pass subpass count not set yet"); HandleError("Render pass subpass count not set yet");
return; return;
} }
if ((propertiesSet & RENDERPASS_PROPERTY_ATTACHMENT_COUNT) == 0) {
HandleError("Render pass attachment count not set yet");
return;
}
if (subpass >= subpasses.size()) { if (subpass >= subpasses.size()) {
HandleError("Subpass index out of bounds"); HandleError("Subpass index out of bounds");
return; return;
@ -147,4 +151,30 @@ namespace backend {
subpasses[subpass].colorAttachments[outputAttachmentLocation] = attachmentSlot; subpasses[subpass].colorAttachments[outputAttachmentLocation] = attachmentSlot;
} }
void RenderPassBuilder::SubpassSetDepthStencilAttachment(uint32_t subpass, uint32_t attachmentSlot) {
if ((propertiesSet & RENDERPASS_PROPERTY_SUBPASS_COUNT) == 0) {
HandleError("Render pass subpass count not set yet");
return;
}
if ((propertiesSet & RENDERPASS_PROPERTY_ATTACHMENT_COUNT) == 0) {
HandleError("Render pass attachment count not set yet");
return;
}
if (subpass >= subpasses.size()) {
HandleError("Subpass index out of bounds");
return;
}
if (attachmentSlot >= attachments.size()) {
HandleError("Subpass attachment slot out of bounds");
return;
}
if (subpasses[subpass].depthStencilAttachmentSet) {
HandleError("Subpass depth-stencil attachment already set");
return;
}
subpasses[subpass].depthStencilAttachmentSet = true;
subpasses[subpass].depthStencilAttachment = attachmentSlot;
}
} }

View File

@ -39,6 +39,8 @@ namespace backend {
struct SubpassInfo { struct SubpassInfo {
std::bitset<kMaxColorAttachments> colorAttachmentsSet; std::bitset<kMaxColorAttachments> colorAttachmentsSet;
std::array<uint32_t, kMaxColorAttachments> colorAttachments; std::array<uint32_t, kMaxColorAttachments> colorAttachments;
bool depthStencilAttachmentSet = false;
uint32_t depthStencilAttachment = 0;
}; };
uint32_t GetAttachmentCount() const; uint32_t GetAttachmentCount() const;
@ -64,6 +66,7 @@ namespace backend {
void AttachmentSetFormat(uint32_t attachmentSlot, nxt::TextureFormat format); void AttachmentSetFormat(uint32_t attachmentSlot, nxt::TextureFormat format);
void SetSubpassCount(uint32_t subpassCount); void SetSubpassCount(uint32_t subpassCount);
void SubpassSetColorAttachment(uint32_t subpass, uint32_t outputAttachmentLocation, uint32_t attachmentSlot); void SubpassSetColorAttachment(uint32_t subpass, uint32_t outputAttachmentLocation, uint32_t attachmentSlot);
void SubpassSetDepthStencilAttachment(uint32_t subpass, uint32_t attachmentSlot);
private: private:
friend class RenderPassBase; friend class RenderPassBase;

View File

@ -23,11 +23,36 @@ namespace backend {
switch (format) { switch (format) {
case nxt::TextureFormat::R8G8B8A8Unorm: case nxt::TextureFormat::R8G8B8A8Unorm:
return 4; return 4;
case nxt::TextureFormat::D32FloatS8Uint:
return 8;
default: default:
UNREACHABLE(); UNREACHABLE();
} }
} }
bool TextureFormatHasDepth(nxt::TextureFormat format) {
switch (format) {
case nxt::TextureFormat::R8G8B8A8Unorm:
return false;
case nxt::TextureFormat::D32FloatS8Uint:
return true;
default:
UNREACHABLE();
}
}
bool TextureFormatHasStencil(nxt::TextureFormat format) {
switch (format) {
case nxt::TextureFormat::R8G8B8A8Unorm:
return false;
case nxt::TextureFormat::D32FloatS8Uint:
return true;
default:
UNREACHABLE();
}
}
// TextureBase // TextureBase
TextureBase::TextureBase(TextureBuilder* builder) TextureBase::TextureBase(TextureBuilder* builder)
@ -95,15 +120,6 @@ namespace backend {
currentUsage = usage; currentUsage = usage;
} }
bool TextureBase::IsDepthFormat(nxt::TextureFormat format) {
switch (format) {
case nxt::TextureFormat::R8G8B8A8Unorm:
return false;
default:
UNREACHABLE();
}
}
void TextureBase::TransitionUsage(nxt::TextureUsageBit usage) { void TextureBase::TransitionUsage(nxt::TextureUsageBit usage) {
if (!IsTransitionPossible(usage)) { if (!IsTransitionPossible(usage)) {
device->HandleError("Texture frozen or usage not allowed"); device->HandleError("Texture frozen or usage not allowed");

View File

@ -24,6 +24,8 @@
namespace backend { namespace backend {
size_t TextureFormatPixelSize(nxt::TextureFormat format); size_t TextureFormatPixelSize(nxt::TextureFormat format);
bool TextureFormatHasDepth(nxt::TextureFormat format);
bool TextureFormatHasStencil(nxt::TextureFormat format);
class TextureBase : public RefCounted { class TextureBase : public RefCounted {
public: public:
@ -43,8 +45,6 @@ namespace backend {
bool IsTransitionPossible(nxt::TextureUsageBit usage) const; bool IsTransitionPossible(nxt::TextureUsageBit usage) const;
void UpdateUsageInternal(nxt::TextureUsageBit usage); void UpdateUsageInternal(nxt::TextureUsageBit usage);
static bool IsDepthFormat(nxt::TextureFormat format);
DeviceBase* GetDevice(); DeviceBase* GetDevice();
// NXT API // NXT API

View File

@ -204,12 +204,7 @@ namespace d3d12 {
d3d12Location.PlacedFootprint.Footprint.Height = textureLocation.height; d3d12Location.PlacedFootprint.Footprint.Height = textureLocation.height;
d3d12Location.PlacedFootprint.Footprint.Depth = textureLocation.depth; d3d12Location.PlacedFootprint.Footprint.Depth = textureLocation.depth;
uint32_t texelSize = 0; size_t texelSize = TextureFormatPixelSize(texture->GetFormat());
switch (texture->GetFormat()) {
case nxt::TextureFormat::R8G8B8A8Unorm:
texelSize = 4;
break;
}
uint32_t rowSize = textureLocation.width * texelSize; uint32_t rowSize = textureLocation.width * texelSize;
d3d12Location.PlacedFootprint.Footprint.RowPitch = ((rowSize - 1) / D3D12_TEXTURE_DATA_PITCH_ALIGNMENT + 1) * D3D12_TEXTURE_DATA_PITCH_ALIGNMENT; d3d12Location.PlacedFootprint.Footprint.RowPitch = ((rowSize - 1) / D3D12_TEXTURE_DATA_PITCH_ALIGNMENT + 1) * D3D12_TEXTURE_DATA_PITCH_ALIGNMENT;

View File

@ -49,9 +49,9 @@ namespace d3d12 {
return backendDevice->GetCommandQueue(); return backendDevice->GetCommandQueue();
} }
void SetNextTexture(nxtDevice device, ComPtr<ID3D12Resource> resource, ComPtr<ID3D12Resource> depthResource) { void SetNextTexture(nxtDevice device, ComPtr<ID3D12Resource> resource) {
Device* backendDevice = reinterpret_cast<Device*>(device); Device* backendDevice = reinterpret_cast<Device*>(device);
backendDevice->SetNextTexture(resource, depthResource); backendDevice->SetNextTexture(resource);
} }
uint64_t GetSerial(const nxtDevice device) { uint64_t GetSerial(const nxtDevice device) {
@ -160,14 +160,10 @@ namespace d3d12 {
return nextTexture; return nextTexture;
} }
ComPtr<ID3D12Resource> Device::GetCurrentDepthTexture() { void Device::SetNextTexture(ComPtr<ID3D12Resource> resource) {
return nextDepthTexture; nextTexture = resource;
} }
void Device::SetNextTexture(ComPtr<ID3D12Resource> resource, ComPtr<ID3D12Resource> depthResource) {
nextTexture = resource;
nextDepthTexture = depthResource;
}
void Device::TickImpl() { void Device::TickImpl() {
// Perform cleanup operations to free unused objects // Perform cleanup operations to free unused objects

View File

@ -124,8 +124,7 @@ namespace d3d12 {
ComPtr<ID3D12GraphicsCommandList> GetPendingCommandList(); ComPtr<ID3D12GraphicsCommandList> GetPendingCommandList();
ComPtr<ID3D12Resource> GetCurrentTexture(); ComPtr<ID3D12Resource> GetCurrentTexture();
ComPtr<ID3D12Resource> GetCurrentDepthTexture(); void SetNextTexture(ComPtr<ID3D12Resource> resource);
void SetNextTexture(ComPtr<ID3D12Resource> resource, ComPtr<ID3D12Resource> depthResource);
uint64_t GetSerial() const; uint64_t GetSerial() const;
void NextSerial(); void NextSerial();
@ -153,7 +152,6 @@ namespace d3d12 {
} pendingCommands; } pendingCommands;
ComPtr<ID3D12Resource> nextTexture; ComPtr<ID3D12Resource> nextTexture;
ComPtr<ID3D12Resource> nextDepthTexture;
}; };
class DepthStencilState : public DepthStencilStateBase { class DepthStencilState : public DepthStencilStateBase {

View File

@ -23,73 +23,79 @@ namespace d3d12 {
Framebuffer::Framebuffer(Device* device, FramebufferBuilder* builder) Framebuffer::Framebuffer(Device* device, FramebufferBuilder* builder)
: FramebufferBase(builder), device(device) { : FramebufferBase(builder), device(device) {
RenderPass* renderPass = ToBackend(GetRenderPass()); RenderPass* renderPass = ToBackend(GetRenderPass());
uint32_t attachmentCount = renderPass->GetAttachmentCount();
rtvHeap = device->GetDescriptorHeapAllocator()->AllocateCPUHeap(D3D12_DESCRIPTOR_HEAP_TYPE_RTV, attachmentCount);
bool usingBackbuffer = false; // HACK(enga@google.com): workaround for not having depth attachments uint32_t rtvCount = 0, dsvCount = 0;
uint32_t rtvIndex = 0; attachmentHeapIndices.resize(renderPass->GetAttachmentCount());
for (uint32_t attachment = 0; attachment < renderPass->GetAttachmentCount(); ++attachment) {
for (uint32_t attachment = 0; attachment < attachmentCount; ++attachment) {
auto* textureView = GetTextureView(attachment); auto* textureView = GetTextureView(attachment);
if (textureView) { if (!textureView) {
ComPtr<ID3D12Resource> texture = ToBackend(textureView->GetTexture())->GetD3D12Resource(); // TODO(kainino@chromium.org): null=backbuffer hack
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetCPUHandle(rtvIndex++); attachmentHeapIndices[attachment] = rtvCount++;
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = ToBackend(textureView)->GetRTVDescriptor(); continue;
}
device->GetD3D12Device()->CreateRenderTargetView(texture.Get(), &rtvDesc, rtvHandle); auto format = textureView->GetTexture()->GetFormat();
if (TextureFormatHasDepth(format) || TextureFormatHasStencil(format)) {
attachmentHeapIndices[attachment] = dsvCount++;
} else { } else {
// TODO(enga@google.com) no attachment. This will use the backbuffer. Remove when this hack is removed attachmentHeapIndices[attachment] = rtvCount++;
usingBackbuffer = true;
rtvIndex++;
} }
} }
// TODO(enga@google.com): load depth attachment from subpass if (rtvCount) {
if (usingBackbuffer) { rtvHeap = device->GetDescriptorHeapAllocator()->AllocateCPUHeap(
dsvHeap = device->GetDescriptorHeapAllocator()->AllocateCPUHeap(D3D12_DESCRIPTOR_HEAP_TYPE_DSV, 1); D3D12_DESCRIPTOR_HEAP_TYPE_RTV, rtvCount);
D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = dsvHeap.GetCPUHandle(0); }
if (dsvCount) {
dsvHeap = device->GetDescriptorHeapAllocator()->AllocateCPUHeap(
D3D12_DESCRIPTOR_HEAP_TYPE_DSV, dsvCount);
}
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc; for (uint32_t attachment = 0; attachment < renderPass->GetAttachmentCount(); ++attachment) {
dsvDesc.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT; uint32_t heapIndex = attachmentHeapIndices[attachment];
dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; auto* textureView = GetTextureView(attachment);
dsvDesc.Texture2D.MipSlice = 0; if (!textureView) {
dsvDesc.Flags = D3D12_DSV_FLAG_NONE; continue;
}
device->GetD3D12Device()->CreateDepthStencilView(device->GetCurrentDepthTexture().Get(), &dsvDesc, dsvHandle); ComPtr<ID3D12Resource> texture = ToBackend(textureView->GetTexture())->GetD3D12Resource();
auto format = textureView->GetTexture()->GetFormat();
if (TextureFormatHasDepth(format) || TextureFormatHasStencil(format)) {
D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = dsvHeap.GetCPUHandle(heapIndex);
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = ToBackend(textureView)->GetDSVDescriptor();
device->GetD3D12Device()->CreateDepthStencilView(texture.Get(), &dsvDesc, dsvHandle);
} else {
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetCPUHandle(heapIndex);
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = ToBackend(textureView)->GetRTVDescriptor();
device->GetD3D12Device()->CreateRenderTargetView(texture.Get(), &rtvDesc, rtvHandle);
}
} }
} }
Framebuffer::OMSetRenderTargetArgs Framebuffer::GetSubpassOMSetRenderTargetArgs(uint32_t subpassIndex) { Framebuffer::OMSetRenderTargetArgs Framebuffer::GetSubpassOMSetRenderTargetArgs(uint32_t subpassIndex) {
const auto& subpassInfo = GetRenderPass()->GetSubpassInfo(subpassIndex); const auto& subpassInfo = GetRenderPass()->GetSubpassInfo(subpassIndex);
OMSetRenderTargetArgs args = {};
bool usingBackbuffer = false; // HACK(enga@google.com): workaround for not having depth attachments
OMSetRenderTargetArgs args;
args.numRTVs = 0;
for (uint32_t index : IterateBitSet(subpassInfo.colorAttachmentsSet)) { for (uint32_t index : IterateBitSet(subpassInfo.colorAttachmentsSet)) {
uint32_t heapIndex = attachmentHeapIndices[subpassInfo.colorAttachments[index]];
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetCPUHandle(heapIndex);
uint32_t attachment = subpassInfo.colorAttachments[index]; uint32_t attachment = subpassInfo.colorAttachments[index];
const auto& attachmentInfo = GetRenderPass()->GetAttachmentInfo(attachment);
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetCPUHandle(attachment);
args.RTVs[args.numRTVs++] = rtvHandle;
if (!GetTextureView(attachment)) { if (!GetTextureView(attachment)) {
usingBackbuffer = true; // TODO(kainino@chromium.org): null=backbuffer hack
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc; D3D12_RENDER_TARGET_VIEW_DESC rtvDesc;
rtvDesc.Format = D3D12TextureFormat(attachmentInfo.format); rtvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
rtvDesc.Texture2D.MipSlice = 0; rtvDesc.Texture2D.MipSlice = 0;
rtvDesc.Texture2D.PlaneSlice = 0; rtvDesc.Texture2D.PlaneSlice = 0;
device->GetD3D12Device()->CreateRenderTargetView(device->GetCurrentTexture().Get(), &rtvDesc, rtvHandle); device->GetD3D12Device()->CreateRenderTargetView(device->GetCurrentTexture().Get(), &rtvDesc, rtvHandle);
} }
}
if (usingBackbuffer) { args.RTVs[args.numRTVs++] = rtvHandle;
args.dsv = dsvHeap.GetCPUHandle(0); }
if (subpassInfo.depthStencilAttachmentSet) {
uint32_t heapIndex = attachmentHeapIndices[subpassInfo.depthStencilAttachment];
args.dsv = dsvHeap.GetCPUHandle(heapIndex);
} }
return args; return args;

View File

@ -21,6 +21,8 @@
#include "backend/d3d12/d3d12_platform.h" #include "backend/d3d12/d3d12_platform.h"
#include "backend/d3d12/DescriptorHeapAllocator.h" #include "backend/d3d12/DescriptorHeapAllocator.h"
#include <vector>
namespace backend { namespace backend {
namespace d3d12 { namespace d3d12 {
@ -29,9 +31,9 @@ namespace d3d12 {
class Framebuffer : public FramebufferBase { class Framebuffer : public FramebufferBase {
public: public:
struct OMSetRenderTargetArgs { struct OMSetRenderTargetArgs {
unsigned int numRTVs; unsigned int numRTVs = 0;
D3D12_CPU_DESCRIPTOR_HANDLE RTVs[kMaxColorAttachments] = {}; D3D12_CPU_DESCRIPTOR_HANDLE RTVs[kMaxColorAttachments] = {};
D3D12_CPU_DESCRIPTOR_HANDLE dsv = { 0 }; D3D12_CPU_DESCRIPTOR_HANDLE dsv = {};
}; };
Framebuffer(Device* device, FramebufferBuilder* builder); Framebuffer(Device* device, FramebufferBuilder* builder);
@ -41,6 +43,9 @@ namespace d3d12 {
Device* device; Device* device;
DescriptorHeapHandle rtvHeap; DescriptorHeapHandle rtvHeap;
DescriptorHeapHandle dsvHeap; DescriptorHeapHandle dsvHeap;
// Indices into either the RTV or DSV heap, depending on texture format.
std::vector<uint32_t> attachmentHeapIndices;
}; };
} }

View File

@ -37,9 +37,10 @@ namespace d3d12 {
resourceState |= D3D12_RESOURCE_STATE_UNORDERED_ACCESS; resourceState |= D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
} }
if (usage & nxt::TextureUsageBit::OutputAttachment) { if (usage & nxt::TextureUsageBit::OutputAttachment) {
resourceState |= D3D12_RESOURCE_STATE_RENDER_TARGET; if (TextureFormatHasDepth(format) || TextureFormatHasStencil(format)) {
if (TextureBase::IsDepthFormat(format)) {
resourceState |= D3D12_RESOURCE_STATE_DEPTH_WRITE; resourceState |= D3D12_RESOURCE_STATE_DEPTH_WRITE;
} else {
resourceState |= D3D12_RESOURCE_STATE_RENDER_TARGET;
} }
} }
@ -53,12 +54,15 @@ namespace d3d12 {
flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
} }
if (usage & nxt::TextureUsageBit::OutputAttachment) { if (usage & nxt::TextureUsageBit::OutputAttachment) {
flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; if (TextureFormatHasDepth(format) || TextureFormatHasStencil(format)) {
if (TextureBase::IsDepthFormat(format)) {
flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
} else {
flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
} }
} }
ASSERT(!(flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) ||
flags == D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL);
return flags; return flags;
} }
@ -77,6 +81,8 @@ namespace d3d12 {
switch (format) { switch (format) {
case nxt::TextureFormat::R8G8B8A8Unorm: case nxt::TextureFormat::R8G8B8A8Unorm:
return DXGI_FORMAT_R8G8B8A8_UNORM; return DXGI_FORMAT_R8G8B8A8_UNORM;
case nxt::TextureFormat::D32FloatS8Uint:
return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
default: default:
UNREACHABLE(); UNREACHABLE();
} }
@ -96,7 +102,7 @@ namespace d3d12 {
resourceDescriptor.SampleDesc.Count = 1; resourceDescriptor.SampleDesc.Count = 1;
resourceDescriptor.SampleDesc.Quality = 0; resourceDescriptor.SampleDesc.Quality = 0;
resourceDescriptor.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; resourceDescriptor.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
resourceDescriptor.Flags = D3D12ResourceFlags(GetUsage(), GetFormat()); resourceDescriptor.Flags = D3D12ResourceFlags(GetAllowedUsage(), GetFormat());
resource = device->GetResourceAllocator()->Allocate(D3D12_HEAP_TYPE_DEFAULT, resourceDescriptor, D3D12TextureUsage(GetUsage(), GetFormat())); resource = device->GetResourceAllocator()->Allocate(D3D12_HEAP_TYPE_DEFAULT, resourceDescriptor, D3D12TextureUsage(GetUsage(), GetFormat()));
} }
@ -167,5 +173,14 @@ namespace d3d12 {
return rtvDesc; return rtvDesc;
} }
D3D12_DEPTH_STENCIL_VIEW_DESC TextureView::GetDSVDescriptor() {
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc;
dsvDesc.Format = ToBackend(GetTexture())->GetD3D12Format();
dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
dsvDesc.Texture2D.MipSlice = 0;
dsvDesc.Flags = D3D12_DSV_FLAG_NONE;
return dsvDesc;
}
} }
} }

View File

@ -49,6 +49,7 @@ namespace d3d12 {
const D3D12_SHADER_RESOURCE_VIEW_DESC& GetSRVDescriptor() const; const D3D12_SHADER_RESOURCE_VIEW_DESC& GetSRVDescriptor() const;
D3D12_RENDER_TARGET_VIEW_DESC GetRTVDescriptor(); D3D12_RENDER_TARGET_VIEW_DESC GetRTVDescriptor();
D3D12_DEPTH_STENCIL_VIEW_DESC GetDSVDescriptor();
private: private:
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc; D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;

View File

@ -86,7 +86,6 @@ namespace metal {
const auto& info = currentRenderPass->GetSubpassInfo(subpass); const auto& info = currentRenderPass->GetSubpassInfo(subpass);
MTLRenderPassDescriptor* descriptor = [MTLRenderPassDescriptor renderPassDescriptor]; MTLRenderPassDescriptor* descriptor = [MTLRenderPassDescriptor renderPassDescriptor];
bool usingBackbuffer = false; // HACK(kainino@chromium.org): workaround for not having depth attachments
for (uint32_t index = 0; index < info.colorAttachments.size(); ++index) { for (uint32_t index = 0; index < info.colorAttachments.size(); ++index) {
uint32_t attachment = info.colorAttachments[index]; uint32_t attachment = info.colorAttachments[index];
@ -98,18 +97,30 @@ namespace metal {
texture = ToBackend(textureView->GetTexture())->GetMTLTexture(); texture = ToBackend(textureView->GetTexture())->GetMTLTexture();
} else { } else {
texture = device->GetCurrentTexture(); texture = device->GetCurrentTexture();
usingBackbuffer = true;
} }
descriptor.colorAttachments[index].texture = texture; descriptor.colorAttachments[index].texture = texture;
descriptor.colorAttachments[index].loadAction = MTLLoadActionClear; descriptor.colorAttachments[index].loadAction = MTLLoadActionLoad;
descriptor.colorAttachments[index].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 0.0); descriptor.colorAttachments[index].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 0.0);
descriptor.colorAttachments[index].storeAction = MTLStoreActionStore; descriptor.colorAttachments[index].storeAction = MTLStoreActionStore;
} }
// TODO(kainino@chromium.org): load depth attachment from subpass if (info.depthStencilAttachmentSet) {
if (usingBackbuffer) { uint32_t attachment = info.depthStencilAttachment;
descriptor.depthAttachment.texture = device->GetCurrentDepthTexture();
descriptor.depthAttachment.loadAction = MTLLoadActionLoad; auto textureView = currentFramebuffer->GetTextureView(attachment);
descriptor.depthAttachment.storeAction = MTLStoreActionStore; id<MTLTexture> texture = ToBackend(textureView->GetTexture())->GetMTLTexture();
nxt::TextureFormat format = textureView->GetTexture()->GetFormat();
if (TextureFormatHasDepth(format)) {
descriptor.depthAttachment.texture = texture;
descriptor.depthAttachment.loadAction = MTLLoadActionClear;
descriptor.depthAttachment.clearDepth = 1.0;
descriptor.depthAttachment.storeAction = MTLStoreActionStore;
}
if (TextureFormatHasStencil(format)) {
descriptor.stencilAttachment.texture = texture;
descriptor.stencilAttachment.loadAction = MTLLoadActionClear;
descriptor.stencilAttachment.clearStencil = 0;
descriptor.stencilAttachment.storeAction = MTLStoreActionStore;
}
} }
render = [commandBuffer renderCommandEncoderWithDescriptor:descriptor]; render = [commandBuffer renderCommandEncoderWithDescriptor:descriptor];

View File

@ -108,7 +108,6 @@ namespace metal {
id<MTLDevice> GetMTLDevice(); id<MTLDevice> GetMTLDevice();
id<MTLTexture> GetCurrentTexture(); id<MTLTexture> GetCurrentTexture();
id<MTLTexture> GetCurrentDepthTexture();
id<MTLCommandBuffer> GetPendingCommandBuffer(); id<MTLCommandBuffer> GetPendingCommandBuffer();
void SubmitPendingCommandBuffer(); void SubmitPendingCommandBuffer();
@ -127,7 +126,6 @@ namespace metal {
id<CAMetalDrawable> currentDrawable = nil; id<CAMetalDrawable> currentDrawable = nil;
id<MTLTexture> currentTexture = nil; id<MTLTexture> currentTexture = nil;
id<MTLTexture> currentDepthTexture = nil;
Serial finishedCommandSerial = 0; Serial finishedCommandSerial = 0;
Serial pendingCommandSerial = 1; Serial pendingCommandSerial = 1;

View File

@ -74,9 +74,6 @@ namespace metal {
[currentTexture release]; [currentTexture release];
currentTexture = nil; currentTexture = nil;
[currentDepthTexture release];
currentDepthTexture = nil;
} }
BindGroupBase* Device::CreateBindGroup(BindGroupBuilder* builder) { BindGroupBase* Device::CreateBindGroup(BindGroupBuilder* builder) {
@ -146,32 +143,11 @@ namespace metal {
currentTexture = drawable.texture; currentTexture = drawable.texture;
[currentTexture retain]; [currentTexture retain];
if (currentDepthTexture == nil ||
currentTexture.width != currentDepthTexture.width ||
currentTexture.height != currentDepthTexture.height) {
if (currentDepthTexture != nil) {
[currentDepthTexture release];
}
MTLTextureDescriptor* depthDescriptor = [MTLTextureDescriptor
texture2DDescriptorWithPixelFormat:MTLPixelFormatDepth32Float
width:currentTexture.width
height:currentTexture.height
mipmapped:NO];
depthDescriptor.textureType = MTLTextureType2D;
depthDescriptor.usage = MTLTextureUsageRenderTarget;
depthDescriptor.storageMode = MTLStorageModePrivate;
currentDepthTexture = [mtlDevice newTextureWithDescriptor:depthDescriptor];
}
MTLRenderPassDescriptor* passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor]; MTLRenderPassDescriptor* passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
passDescriptor.colorAttachments[0].texture = currentTexture; passDescriptor.colorAttachments[0].texture = currentTexture;
passDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear; passDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
passDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore; passDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
passDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 1.0); passDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 1.0);
passDescriptor.depthAttachment.texture = currentDepthTexture;
passDescriptor.depthAttachment.loadAction = MTLLoadActionClear;
passDescriptor.depthAttachment.storeAction = MTLStoreActionStore;
passDescriptor.depthAttachment.clearDepth = 1.0;
id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer]; id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
@ -195,10 +171,6 @@ namespace metal {
return currentTexture; return currentTexture;
} }
id<MTLTexture> Device::GetCurrentDepthTexture() {
return currentDepthTexture;
}
id<MTLCommandBuffer> Device::GetPendingCommandBuffer() { id<MTLCommandBuffer> Device::GetPendingCommandBuffer() {
if (pendingCommands == nil) { if (pendingCommands == nil) {
pendingCommands = [commandQueue commandBuffer]; pendingCommands = [commandQueue commandBuffer];

View File

@ -24,6 +24,8 @@ namespace metal {
switch (format) { switch (format) {
case nxt::TextureFormat::R8G8B8A8Unorm: case nxt::TextureFormat::R8G8B8A8Unorm:
return MTLPixelFormatRGBA8Unorm; return MTLPixelFormatRGBA8Unorm;
case nxt::TextureFormat::D32FloatS8Uint:
return MTLPixelFormatDepth32Float_Stencil8;
} }
} }
@ -65,6 +67,7 @@ namespace metal {
desc.depth = GetDepth(); desc.depth = GetDepth();
desc.mipmapLevelCount = GetNumMipLevels(); desc.mipmapLevelCount = GetNumMipLevels();
desc.arrayLength = 1; desc.arrayLength = 1;
desc.storageMode = MTLStorageModePrivate;
auto mtlDevice = ToBackend(builder->GetDevice())->GetMTLDevice(); auto mtlDevice = ToBackend(builder->GetDevice())->GetMTLDevice();
mtlTexture = [mtlDevice newTextureWithDescriptor:desc]; mtlTexture = [mtlDevice newTextureWithDescriptor:desc];

View File

@ -103,7 +103,6 @@ namespace opengl {
auto* device = ToBackend(GetDevice()); auto* device = ToBackend(GetDevice());
const auto& info = currentRenderPass->GetSubpassInfo(currentSubpass); const auto& info = currentRenderPass->GetSubpassInfo(currentSubpass);
bool usingBackbuffer = false; // HACK(kainino@chromium.org): workaround for not having depth attachments
for (uint32_t index = 0; index < info.colorAttachments.size(); ++index) { for (uint32_t index = 0; index < info.colorAttachments.size(); ++index) {
uint32_t attachment = info.colorAttachments[index]; uint32_t attachment = info.colorAttachments[index];
@ -115,16 +114,35 @@ namespace opengl {
texture = ToBackend(textureView->GetTexture())->GetHandle(); texture = ToBackend(textureView->GetTexture())->GetHandle();
} else { } else {
texture = device->GetCurrentTexture(); texture = device->GetCurrentTexture();
usingBackbuffer = true;
} }
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + index, glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0 + index,
GL_TEXTURE_2D, texture, 0); GL_TEXTURE_2D, texture, 0);
} }
// TODO(kainino@chromium.org): load depth attachment from subpass if (info.depthStencilAttachmentSet) {
if (usingBackbuffer) { uint32_t attachment = info.depthStencilAttachment;
GLuint texture = device->GetCurrentDepthTexture();
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, auto textureView = currentFramebuffer->GetTextureView(attachment);
GL_TEXTURE_2D, texture, 0); GLuint texture = ToBackend(textureView->GetTexture())->GetHandle();
nxt::TextureFormat format = textureView->GetTexture()->GetFormat();
GLenum glAttachment = 0;
if (TextureFormatHasDepth(format)) {
if (TextureFormatHasStencil(format)) {
glAttachment = GL_DEPTH_STENCIL_ATTACHMENT;
} else {
glAttachment = GL_DEPTH_ATTACHMENT;
}
} else {
glAttachment = GL_STENCIL_ATTACHMENT;
}
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
glAttachment, GL_TEXTURE_2D, texture, 0);
// Load action
glClearStencil(0);
glClearDepth(1.0);
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
} }
} }
break; break;

View File

@ -111,9 +111,7 @@ namespace opengl {
void Device::HACKCLEAR() { void Device::HACKCLEAR() {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, backFBO); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, backFBO);
glClearColor(0, 0, 0, 1); glClearColor(0, 0, 0, 1);
glStencilMask(0xff); glClear(GL_COLOR_BUFFER_BIT);
glClearStencil(0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
} }
void Device::InitBackbuffer() { void Device::InitBackbuffer() {
@ -121,16 +119,10 @@ namespace opengl {
glBindTexture(GL_TEXTURE_2D, backTexture); glBindTexture(GL_TEXTURE_2D, backTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 640, 480, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 640, 480, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glGenTextures(1, &backDepthTexture);
glBindTexture(GL_TEXTURE_2D, backDepthTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 640, 480, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr);
glGenFramebuffers(1, &backFBO); glGenFramebuffers(1, &backFBO);
glBindFramebuffer(GL_READ_FRAMEBUFFER, backFBO); glBindFramebuffer(GL_READ_FRAMEBUFFER, backFBO);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, backTexture, 0); GL_TEXTURE_2D, backTexture, 0);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
GL_TEXTURE_2D, backDepthTexture, 0);
HACKCLEAR(); HACKCLEAR();
} }
@ -146,10 +138,6 @@ namespace opengl {
return backTexture; return backTexture;
} }
GLuint Device::GetCurrentDepthTexture() {
return backDepthTexture;
}
// Bind Group // Bind Group
BindGroup::BindGroup(BindGroupBuilder* builder) BindGroup::BindGroup(BindGroupBuilder* builder)

View File

@ -103,12 +103,10 @@ namespace opengl {
void InitBackbuffer(); void InitBackbuffer();
void CommitBackbuffer(); void CommitBackbuffer();
GLuint GetCurrentTexture(); GLuint GetCurrentTexture();
GLuint GetCurrentDepthTexture();
private: private:
GLuint backFBO = 0; GLuint backFBO = 0;
GLuint backTexture = 0; GLuint backTexture = 0;
GLuint backDepthTexture = 0;
}; };
class BindGroup : public BindGroupBase { class BindGroup : public BindGroupBase {

View File

@ -37,6 +37,8 @@ namespace opengl {
switch (format) { switch (format) {
case nxt::TextureFormat::R8G8B8A8Unorm: case nxt::TextureFormat::R8G8B8A8Unorm:
return {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}; return {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE};
case nxt::TextureFormat::D32FloatS8Uint:
return {GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV};
default: default:
UNREACHABLE(); UNREACHABLE();
} }

View File

@ -31,7 +31,7 @@ namespace backend {
namespace d3d12 { namespace d3d12 {
void Init(ComPtr<ID3D12Device> d3d12Device, nxtProcTable* procs, nxtDevice* device); void Init(ComPtr<ID3D12Device> d3d12Device, nxtProcTable* procs, nxtDevice* device);
ComPtr<ID3D12CommandQueue> GetCommandQueue(nxtDevice device); ComPtr<ID3D12CommandQueue> GetCommandQueue(nxtDevice device);
void SetNextTexture(nxtDevice device, ComPtr<ID3D12Resource> resource, ComPtr<ID3D12Resource> depthResource); void SetNextTexture(nxtDevice device, ComPtr<ID3D12Resource> resource);
uint64_t GetSerial(const nxtDevice device); uint64_t GetSerial(const nxtDevice device);
void NextSerial(nxtDevice device); void NextSerial(nxtDevice device);
void ExecuteCommandLists(nxtDevice device, std::initializer_list<ID3D12CommandList*> commandLists); void ExecuteCommandLists(nxtDevice device, std::initializer_list<ID3D12CommandList*> commandLists);
@ -100,44 +100,9 @@ namespace utils {
&swapChain1 &swapChain1
)); ));
ASSERT_SUCCESS(swapChain1.As(&swapChain)); ASSERT_SUCCESS(swapChain1.As(&swapChain));
// Create a render target and depth stencil resource for each frame.
{
D3D12_HEAP_PROPERTIES dsvHeapProperties;
dsvHeapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
dsvHeapProperties.CreationNodeMask = 0;
dsvHeapProperties.VisibleNodeMask = 0;
dsvHeapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
dsvHeapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
D3D12_RESOURCE_DESC dsvDesc; for (uint32_t n = 0; n < kFrameCount; ++n) {
dsvDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; ASSERT_SUCCESS(swapChain->GetBuffer(n, IID_PPV_ARGS(&renderTargetResources[n])));
dsvDesc.Alignment = 0;
dsvDesc.Width = width;
dsvDesc.Height = height;
dsvDesc.DepthOrArraySize = 1;
dsvDesc.MipLevels = 0;
dsvDesc.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
dsvDesc.SampleDesc.Count = 1;
dsvDesc.SampleDesc.Quality = 0;
dsvDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
dsvDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
D3D12_CLEAR_VALUE dsvClear;
dsvClear.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
dsvClear.DepthStencil.Depth = 1.0f;
dsvClear.DepthStencil.Stencil = 0;
for (uint32_t n = 0; n < kFrameCount; ++n) {
ASSERT_SUCCESS(swapChain->GetBuffer(n, IID_PPV_ARGS(&renderTargetResources[n])));
ASSERT_SUCCESS(d3d12Device->CreateCommittedResource(
&dsvHeapProperties,
D3D12_HEAP_FLAG_NONE,
&dsvDesc,
D3D12_RESOURCE_STATE_DEPTH_WRITE,
&dsvClear,
IID_PPV_ARGS(&depthStencilResources[n])));
}
} }
// Get the initial render target and arbitrarily choose a "previous" render target that's different // Get the initial render target and arbitrarily choose a "previous" render target that's different
@ -168,7 +133,7 @@ namespace utils {
backend::d3d12::NextSerial(backendDevice); backend::d3d12::NextSerial(backendDevice);
} }
backend::d3d12::SetNextTexture(backendDevice, renderTargetResources[renderTargetIndex], depthStencilResources[renderTargetIndex]); backend::d3d12::SetNextTexture(backendDevice, renderTargetResources[renderTargetIndex]);
} }
void SwapBuffers() override { void SwapBuffers() override {
@ -217,7 +182,7 @@ namespace utils {
lastSerialRenderTargetWasUsed[renderTargetIndex] = backend::d3d12::GetSerial(backendDevice); lastSerialRenderTargetWasUsed[renderTargetIndex] = backend::d3d12::GetSerial(backendDevice);
// Tell the backend to render to the current render target // Tell the backend to render to the current render target
backend::d3d12::SetNextTexture(backendDevice, renderTargetResources[renderTargetIndex], depthStencilResources[renderTargetIndex]); backend::d3d12::SetNextTexture(backendDevice, renderTargetResources[renderTargetIndex]);
} }
private: private:
@ -232,7 +197,6 @@ namespace utils {
ComPtr<ID3D12CommandQueue> commandQueue; ComPtr<ID3D12CommandQueue> commandQueue;
ComPtr<IDXGISwapChain3> swapChain; ComPtr<IDXGISwapChain3> swapChain;
ComPtr<ID3D12Resource> renderTargetResources[kFrameCount]; ComPtr<ID3D12Resource> renderTargetResources[kFrameCount];
ComPtr<ID3D12Resource> depthStencilResources[kFrameCount];
// Frame synchronization. Updated every frame // Frame synchronization. Updated every frame
uint32_t renderTargetIndex; uint32_t renderTargetIndex;

View File

@ -88,15 +88,30 @@ namespace utils {
} }
void CreateDefaultRenderPass(const nxt::Device& device, nxt::RenderPass* renderPass, nxt::Framebuffer* framebuffer) { void CreateDefaultRenderPass(const nxt::Device& device, nxt::RenderPass* renderPass, nxt::Framebuffer* framebuffer) {
auto depthStencilTexture = device.CreateTextureBuilder()
.SetDimension(nxt::TextureDimension::e2D)
.SetExtent(640, 480, 1)
.SetFormat(nxt::TextureFormat::D32FloatS8Uint)
.SetMipLevels(1)
.SetAllowedUsage(nxt::TextureUsageBit::OutputAttachment)
.GetResult();
depthStencilTexture.FreezeUsage(nxt::TextureUsageBit::OutputAttachment);
auto depthStencilView = depthStencilTexture.CreateTextureViewBuilder()
.GetResult();
*renderPass = device.CreateRenderPassBuilder() *renderPass = device.CreateRenderPassBuilder()
.SetAttachmentCount(1) .SetAttachmentCount(2)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm) .AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.AttachmentSetFormat(1, nxt::TextureFormat::D32FloatS8Uint)
.SetSubpassCount(1) .SetSubpassCount(1)
.SubpassSetColorAttachment(0, 0, 0) .SubpassSetColorAttachment(0, 0, 0)
.SubpassSetDepthStencilAttachment(0, 1)
.GetResult(); .GetResult();
*framebuffer = device.CreateFramebufferBuilder() *framebuffer = device.CreateFramebufferBuilder()
.SetRenderPass(*renderPass) .SetRenderPass(*renderPass)
.SetDimensions(640, 480) .SetDimensions(640, 480)
// Attachment 0 is implicit until we add WSI
.SetAttachment(1, depthStencilView)
.GetResult(); .GetResult();
} }