diff --git a/examples/CHelloTriangle.cpp b/examples/CHelloTriangle.cpp index 8020acb885..2d88274696 100644 --- a/examples/CHelloTriangle.cpp +++ b/examples/CHelloTriangle.cpp @@ -81,8 +81,10 @@ void frame() { { nxtCommandBufferBuilder builder = nxtDeviceCreateCommandBufferBuilder(device); nxtCommandBufferBuilderBeginRenderPass(builder, renderpass, framebuffer); + nxtCommandBufferBuilderBeginRenderSubpass(builder); nxtCommandBufferBuilderSetPipeline(builder, pipeline); nxtCommandBufferBuilderDrawArrays(builder, 3, 1, 0, 0); + nxtCommandBufferBuilderEndRenderSubpass(builder); nxtCommandBufferBuilderEndRenderPass(builder); commands = nxtCommandBufferBuilderGetResult(builder); nxtCommandBufferBuilderRelease(builder); diff --git a/examples/glTFViewer/glTFViewer.cpp b/examples/glTFViewer/glTFViewer.cpp index ccb5ae2200..645a90b56b 100644 --- a/examples/glTFViewer/glTFViewer.cpp +++ b/examples/glTFViewer/glTFViewer.cpp @@ -445,18 +445,7 @@ namespace { device = CreateCppNXTDevice(); queue = device.CreateQueueBuilder().GetResult(); - renderpass = device.CreateRenderPassBuilder() - .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(); + utils::CreateDefaultRenderPass(device, &renderpass, &framebuffer); initBuffers(); initSamplers(); diff --git a/next.json b/next.json index 3f5a4275a9..268043aab3 100644 --- a/next.json +++ b/next.json @@ -591,7 +591,7 @@ "name": "set attachment", "args": [ {"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": "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": { "category": "enum", "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": { diff --git a/src/backend/RenderPass.cpp b/src/backend/RenderPass.cpp index 9765a4532f..6267bcbca3 100644 --- a/src/backend/RenderPass.cpp +++ b/src/backend/RenderPass.cpp @@ -126,6 +126,10 @@ namespace backend { 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; @@ -147,4 +151,30 @@ namespace backend { 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; + } + } diff --git a/src/backend/RenderPass.h b/src/backend/RenderPass.h index 449e5ba3ea..036619cdd4 100644 --- a/src/backend/RenderPass.h +++ b/src/backend/RenderPass.h @@ -39,6 +39,8 @@ namespace backend { struct SubpassInfo { std::bitset colorAttachmentsSet; std::array colorAttachments; + bool depthStencilAttachmentSet = false; + uint32_t depthStencilAttachment = 0; }; uint32_t GetAttachmentCount() const; @@ -64,6 +66,7 @@ namespace backend { void AttachmentSetFormat(uint32_t attachmentSlot, nxt::TextureFormat format); void SetSubpassCount(uint32_t subpassCount); void SubpassSetColorAttachment(uint32_t subpass, uint32_t outputAttachmentLocation, uint32_t attachmentSlot); + void SubpassSetDepthStencilAttachment(uint32_t subpass, uint32_t attachmentSlot); private: friend class RenderPassBase; diff --git a/src/backend/Texture.cpp b/src/backend/Texture.cpp index a7c378b789..b9f93acea7 100644 --- a/src/backend/Texture.cpp +++ b/src/backend/Texture.cpp @@ -23,11 +23,36 @@ namespace backend { switch (format) { case nxt::TextureFormat::R8G8B8A8Unorm: return 4; + case nxt::TextureFormat::D32FloatS8Uint: + return 8; default: 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(TextureBuilder* builder) @@ -95,15 +120,6 @@ namespace backend { currentUsage = usage; } - bool TextureBase::IsDepthFormat(nxt::TextureFormat format) { - switch (format) { - case nxt::TextureFormat::R8G8B8A8Unorm: - return false; - default: - UNREACHABLE(); - } - } - void TextureBase::TransitionUsage(nxt::TextureUsageBit usage) { if (!IsTransitionPossible(usage)) { device->HandleError("Texture frozen or usage not allowed"); diff --git a/src/backend/Texture.h b/src/backend/Texture.h index a6655b4f90..ab1a5d9f23 100644 --- a/src/backend/Texture.h +++ b/src/backend/Texture.h @@ -24,6 +24,8 @@ namespace backend { size_t TextureFormatPixelSize(nxt::TextureFormat format); + bool TextureFormatHasDepth(nxt::TextureFormat format); + bool TextureFormatHasStencil(nxt::TextureFormat format); class TextureBase : public RefCounted { public: @@ -43,8 +45,6 @@ namespace backend { bool IsTransitionPossible(nxt::TextureUsageBit usage) const; void UpdateUsageInternal(nxt::TextureUsageBit usage); - static bool IsDepthFormat(nxt::TextureFormat format); - DeviceBase* GetDevice(); // NXT API diff --git a/src/backend/d3d12/CommandBufferD3D12.cpp b/src/backend/d3d12/CommandBufferD3D12.cpp index 199419cfd5..01f8ed10c8 100644 --- a/src/backend/d3d12/CommandBufferD3D12.cpp +++ b/src/backend/d3d12/CommandBufferD3D12.cpp @@ -204,12 +204,7 @@ namespace d3d12 { d3d12Location.PlacedFootprint.Footprint.Height = textureLocation.height; d3d12Location.PlacedFootprint.Footprint.Depth = textureLocation.depth; - uint32_t texelSize = 0; - switch (texture->GetFormat()) { - case nxt::TextureFormat::R8G8B8A8Unorm: - texelSize = 4; - break; - } + size_t texelSize = TextureFormatPixelSize(texture->GetFormat()); uint32_t rowSize = textureLocation.width * texelSize; d3d12Location.PlacedFootprint.Footprint.RowPitch = ((rowSize - 1) / D3D12_TEXTURE_DATA_PITCH_ALIGNMENT + 1) * D3D12_TEXTURE_DATA_PITCH_ALIGNMENT; diff --git a/src/backend/d3d12/D3D12Backend.cpp b/src/backend/d3d12/D3D12Backend.cpp index 8eb533c487..b5294466f0 100644 --- a/src/backend/d3d12/D3D12Backend.cpp +++ b/src/backend/d3d12/D3D12Backend.cpp @@ -49,9 +49,9 @@ namespace d3d12 { return backendDevice->GetCommandQueue(); } - void SetNextTexture(nxtDevice device, ComPtr resource, ComPtr depthResource) { + void SetNextTexture(nxtDevice device, ComPtr resource) { Device* backendDevice = reinterpret_cast(device); - backendDevice->SetNextTexture(resource, depthResource); + backendDevice->SetNextTexture(resource); } uint64_t GetSerial(const nxtDevice device) { @@ -160,14 +160,10 @@ namespace d3d12 { return nextTexture; } - ComPtr Device::GetCurrentDepthTexture() { - return nextDepthTexture; + void Device::SetNextTexture(ComPtr resource) { + nextTexture = resource; } - void Device::SetNextTexture(ComPtr resource, ComPtr depthResource) { - nextTexture = resource; - nextDepthTexture = depthResource; - } void Device::TickImpl() { // Perform cleanup operations to free unused objects diff --git a/src/backend/d3d12/D3D12Backend.h b/src/backend/d3d12/D3D12Backend.h index 9f1c81f49c..0aae91500b 100644 --- a/src/backend/d3d12/D3D12Backend.h +++ b/src/backend/d3d12/D3D12Backend.h @@ -124,8 +124,7 @@ namespace d3d12 { ComPtr GetPendingCommandList(); ComPtr GetCurrentTexture(); - ComPtr GetCurrentDepthTexture(); - void SetNextTexture(ComPtr resource, ComPtr depthResource); + void SetNextTexture(ComPtr resource); uint64_t GetSerial() const; void NextSerial(); @@ -153,7 +152,6 @@ namespace d3d12 { } pendingCommands; ComPtr nextTexture; - ComPtr nextDepthTexture; }; class DepthStencilState : public DepthStencilStateBase { diff --git a/src/backend/d3d12/FramebufferD3D12.cpp b/src/backend/d3d12/FramebufferD3D12.cpp index 992c336645..ea1ae4f732 100644 --- a/src/backend/d3d12/FramebufferD3D12.cpp +++ b/src/backend/d3d12/FramebufferD3D12.cpp @@ -23,73 +23,79 @@ namespace d3d12 { Framebuffer::Framebuffer(Device* device, FramebufferBuilder* builder) : FramebufferBase(builder), device(device) { - 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 rtvIndex = 0; - - for (uint32_t attachment = 0; attachment < attachmentCount; ++attachment) { + uint32_t rtvCount = 0, dsvCount = 0; + attachmentHeapIndices.resize(renderPass->GetAttachmentCount()); + for (uint32_t attachment = 0; attachment < renderPass->GetAttachmentCount(); ++attachment) { auto* textureView = GetTextureView(attachment); - if (textureView) { - ComPtr texture = ToBackend(textureView->GetTexture())->GetD3D12Resource(); - D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetCPUHandle(rtvIndex++); - D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = ToBackend(textureView)->GetRTVDescriptor(); - - device->GetD3D12Device()->CreateRenderTargetView(texture.Get(), &rtvDesc, rtvHandle); + if (!textureView) { + // TODO(kainino@chromium.org): null=backbuffer hack + attachmentHeapIndices[attachment] = rtvCount++; + continue; + } + auto format = textureView->GetTexture()->GetFormat(); + if (TextureFormatHasDepth(format) || TextureFormatHasStencil(format)) { + attachmentHeapIndices[attachment] = dsvCount++; } else { - // TODO(enga@google.com) no attachment. This will use the backbuffer. Remove when this hack is removed - usingBackbuffer = true; - rtvIndex++; + attachmentHeapIndices[attachment] = rtvCount++; } } - // TODO(enga@google.com): load depth attachment from subpass - if (usingBackbuffer) { - dsvHeap = device->GetDescriptorHeapAllocator()->AllocateCPUHeap(D3D12_DESCRIPTOR_HEAP_TYPE_DSV, 1); - D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = dsvHeap.GetCPUHandle(0); + if (rtvCount) { + rtvHeap = device->GetDescriptorHeapAllocator()->AllocateCPUHeap( + D3D12_DESCRIPTOR_HEAP_TYPE_RTV, rtvCount); + } + if (dsvCount) { + dsvHeap = device->GetDescriptorHeapAllocator()->AllocateCPUHeap( + D3D12_DESCRIPTOR_HEAP_TYPE_DSV, dsvCount); + } - D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc; - dsvDesc.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT; - dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; - dsvDesc.Texture2D.MipSlice = 0; - dsvDesc.Flags = D3D12_DSV_FLAG_NONE; + for (uint32_t attachment = 0; attachment < renderPass->GetAttachmentCount(); ++attachment) { + uint32_t heapIndex = attachmentHeapIndices[attachment]; + auto* textureView = GetTextureView(attachment); + if (!textureView) { + continue; + } - device->GetD3D12Device()->CreateDepthStencilView(device->GetCurrentDepthTexture().Get(), &dsvDesc, dsvHandle); + ComPtr 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) { const auto& subpassInfo = GetRenderPass()->GetSubpassInfo(subpassIndex); - - bool usingBackbuffer = false; // HACK(enga@google.com): workaround for not having depth attachments - - OMSetRenderTargetArgs args; - args.numRTVs = 0; + OMSetRenderTargetArgs args = {}; 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]; - const auto& attachmentInfo = GetRenderPass()->GetAttachmentInfo(attachment); - - D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetCPUHandle(attachment); - args.RTVs[args.numRTVs++] = rtvHandle; if (!GetTextureView(attachment)) { - usingBackbuffer = true; - + // TODO(kainino@chromium.org): null=backbuffer hack D3D12_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = D3D12TextureFormat(attachmentInfo.format); + rtvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; rtvDesc.Texture2D.MipSlice = 0; rtvDesc.Texture2D.PlaneSlice = 0; - device->GetD3D12Device()->CreateRenderTargetView(device->GetCurrentTexture().Get(), &rtvDesc, rtvHandle); } - } - if (usingBackbuffer) { - args.dsv = dsvHeap.GetCPUHandle(0); + args.RTVs[args.numRTVs++] = rtvHandle; + } + if (subpassInfo.depthStencilAttachmentSet) { + uint32_t heapIndex = attachmentHeapIndices[subpassInfo.depthStencilAttachment]; + args.dsv = dsvHeap.GetCPUHandle(heapIndex); } return args; diff --git a/src/backend/d3d12/FramebufferD3D12.h b/src/backend/d3d12/FramebufferD3D12.h index c31daf3fdc..a2a2888be0 100644 --- a/src/backend/d3d12/FramebufferD3D12.h +++ b/src/backend/d3d12/FramebufferD3D12.h @@ -21,6 +21,8 @@ #include "backend/d3d12/d3d12_platform.h" #include "backend/d3d12/DescriptorHeapAllocator.h" +#include + namespace backend { namespace d3d12 { @@ -29,9 +31,9 @@ namespace d3d12 { class Framebuffer : public FramebufferBase { public: struct OMSetRenderTargetArgs { - unsigned int numRTVs; + unsigned int numRTVs = 0; D3D12_CPU_DESCRIPTOR_HANDLE RTVs[kMaxColorAttachments] = {}; - D3D12_CPU_DESCRIPTOR_HANDLE dsv = { 0 }; + D3D12_CPU_DESCRIPTOR_HANDLE dsv = {}; }; Framebuffer(Device* device, FramebufferBuilder* builder); @@ -41,6 +43,9 @@ namespace d3d12 { Device* device; DescriptorHeapHandle rtvHeap; DescriptorHeapHandle dsvHeap; + + // Indices into either the RTV or DSV heap, depending on texture format. + std::vector attachmentHeapIndices; }; } diff --git a/src/backend/d3d12/TextureD3D12.cpp b/src/backend/d3d12/TextureD3D12.cpp index d448946bca..99ab0a70e7 100644 --- a/src/backend/d3d12/TextureD3D12.cpp +++ b/src/backend/d3d12/TextureD3D12.cpp @@ -37,9 +37,10 @@ namespace d3d12 { resourceState |= D3D12_RESOURCE_STATE_UNORDERED_ACCESS; } if (usage & nxt::TextureUsageBit::OutputAttachment) { - resourceState |= D3D12_RESOURCE_STATE_RENDER_TARGET; - if (TextureBase::IsDepthFormat(format)) { + if (TextureFormatHasDepth(format) || TextureFormatHasStencil(format)) { 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; } if (usage & nxt::TextureUsageBit::OutputAttachment) { - flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; - if (TextureBase::IsDepthFormat(format)) { + if (TextureFormatHasDepth(format) || TextureFormatHasStencil(format)) { 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; } @@ -77,6 +81,8 @@ namespace d3d12 { switch (format) { case nxt::TextureFormat::R8G8B8A8Unorm: return DXGI_FORMAT_R8G8B8A8_UNORM; + case nxt::TextureFormat::D32FloatS8Uint: + return DXGI_FORMAT_D32_FLOAT_S8X24_UINT; default: UNREACHABLE(); } @@ -96,7 +102,7 @@ namespace d3d12 { resourceDescriptor.SampleDesc.Count = 1; resourceDescriptor.SampleDesc.Quality = 0; 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())); } @@ -167,5 +173,14 @@ namespace d3d12 { 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; + } + } } diff --git a/src/backend/d3d12/TextureD3D12.h b/src/backend/d3d12/TextureD3D12.h index 5dea5d7241..4987c0f54e 100644 --- a/src/backend/d3d12/TextureD3D12.h +++ b/src/backend/d3d12/TextureD3D12.h @@ -49,6 +49,7 @@ namespace d3d12 { const D3D12_SHADER_RESOURCE_VIEW_DESC& GetSRVDescriptor() const; D3D12_RENDER_TARGET_VIEW_DESC GetRTVDescriptor(); + D3D12_DEPTH_STENCIL_VIEW_DESC GetDSVDescriptor(); private: D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc; diff --git a/src/backend/metal/CommandBufferMTL.mm b/src/backend/metal/CommandBufferMTL.mm index b367d5b9f3..97c135c423 100644 --- a/src/backend/metal/CommandBufferMTL.mm +++ b/src/backend/metal/CommandBufferMTL.mm @@ -86,7 +86,6 @@ namespace metal { const auto& info = currentRenderPass->GetSubpassInfo(subpass); 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) { uint32_t attachment = info.colorAttachments[index]; @@ -98,18 +97,30 @@ namespace metal { texture = ToBackend(textureView->GetTexture())->GetMTLTexture(); } else { texture = device->GetCurrentTexture(); - usingBackbuffer = true; } 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].storeAction = MTLStoreActionStore; } - // TODO(kainino@chromium.org): load depth attachment from subpass - if (usingBackbuffer) { - descriptor.depthAttachment.texture = device->GetCurrentDepthTexture(); - descriptor.depthAttachment.loadAction = MTLLoadActionLoad; - descriptor.depthAttachment.storeAction = MTLStoreActionStore; + if (info.depthStencilAttachmentSet) { + uint32_t attachment = info.depthStencilAttachment; + + auto textureView = currentFramebuffer->GetTextureView(attachment); + id 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]; diff --git a/src/backend/metal/MetalBackend.h b/src/backend/metal/MetalBackend.h index 222bd94103..9f450a2d67 100644 --- a/src/backend/metal/MetalBackend.h +++ b/src/backend/metal/MetalBackend.h @@ -108,7 +108,6 @@ namespace metal { id GetMTLDevice(); id GetCurrentTexture(); - id GetCurrentDepthTexture(); id GetPendingCommandBuffer(); void SubmitPendingCommandBuffer(); @@ -127,7 +126,6 @@ namespace metal { id currentDrawable = nil; id currentTexture = nil; - id currentDepthTexture = nil; Serial finishedCommandSerial = 0; Serial pendingCommandSerial = 1; diff --git a/src/backend/metal/MetalBackend.mm b/src/backend/metal/MetalBackend.mm index 990c4b30e0..e3b5c61ed6 100644 --- a/src/backend/metal/MetalBackend.mm +++ b/src/backend/metal/MetalBackend.mm @@ -74,9 +74,6 @@ namespace metal { [currentTexture release]; currentTexture = nil; - - [currentDepthTexture release]; - currentDepthTexture = nil; } BindGroupBase* Device::CreateBindGroup(BindGroupBuilder* builder) { @@ -146,32 +143,11 @@ namespace metal { currentTexture = drawable.texture; [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]; passDescriptor.colorAttachments[0].texture = currentTexture; passDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear; passDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore; 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 commandBuffer = [commandQueue commandBuffer]; @@ -195,10 +171,6 @@ namespace metal { return currentTexture; } - id Device::GetCurrentDepthTexture() { - return currentDepthTexture; - } - id Device::GetPendingCommandBuffer() { if (pendingCommands == nil) { pendingCommands = [commandQueue commandBuffer]; diff --git a/src/backend/metal/TextureMTL.mm b/src/backend/metal/TextureMTL.mm index 03982089ac..c7d960f81a 100644 --- a/src/backend/metal/TextureMTL.mm +++ b/src/backend/metal/TextureMTL.mm @@ -24,6 +24,8 @@ namespace metal { switch (format) { case nxt::TextureFormat::R8G8B8A8Unorm: return MTLPixelFormatRGBA8Unorm; + case nxt::TextureFormat::D32FloatS8Uint: + return MTLPixelFormatDepth32Float_Stencil8; } } @@ -65,6 +67,7 @@ namespace metal { desc.depth = GetDepth(); desc.mipmapLevelCount = GetNumMipLevels(); desc.arrayLength = 1; + desc.storageMode = MTLStorageModePrivate; auto mtlDevice = ToBackend(builder->GetDevice())->GetMTLDevice(); mtlTexture = [mtlDevice newTextureWithDescriptor:desc]; diff --git a/src/backend/opengl/CommandBufferGL.cpp b/src/backend/opengl/CommandBufferGL.cpp index 970a304f0f..ff63589ba4 100644 --- a/src/backend/opengl/CommandBufferGL.cpp +++ b/src/backend/opengl/CommandBufferGL.cpp @@ -103,7 +103,6 @@ namespace opengl { auto* device = ToBackend(GetDevice()); 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) { uint32_t attachment = info.colorAttachments[index]; @@ -115,16 +114,35 @@ namespace opengl { texture = ToBackend(textureView->GetTexture())->GetHandle(); } else { 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); } - // TODO(kainino@chromium.org): load depth attachment from subpass - if (usingBackbuffer) { - GLuint texture = device->GetCurrentDepthTexture(); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, - GL_TEXTURE_2D, texture, 0); + if (info.depthStencilAttachmentSet) { + uint32_t attachment = info.depthStencilAttachment; + + auto textureView = currentFramebuffer->GetTextureView(attachment); + 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; diff --git a/src/backend/opengl/OpenGLBackend.cpp b/src/backend/opengl/OpenGLBackend.cpp index fd29ae9945..8a7f4d17ed 100644 --- a/src/backend/opengl/OpenGLBackend.cpp +++ b/src/backend/opengl/OpenGLBackend.cpp @@ -111,9 +111,7 @@ namespace opengl { void Device::HACKCLEAR() { glBindFramebuffer(GL_DRAW_FRAMEBUFFER, backFBO); glClearColor(0, 0, 0, 1); - glStencilMask(0xff); - glClearStencil(0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT); } void Device::InitBackbuffer() { @@ -121,16 +119,10 @@ namespace opengl { glBindTexture(GL_TEXTURE_2D, backTexture); 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); glBindFramebuffer(GL_READ_FRAMEBUFFER, backFBO); glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, backTexture, 0); - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, - GL_TEXTURE_2D, backDepthTexture, 0); HACKCLEAR(); } @@ -146,10 +138,6 @@ namespace opengl { return backTexture; } - GLuint Device::GetCurrentDepthTexture() { - return backDepthTexture; - } - // Bind Group BindGroup::BindGroup(BindGroupBuilder* builder) diff --git a/src/backend/opengl/OpenGLBackend.h b/src/backend/opengl/OpenGLBackend.h index 797a20d883..69da108825 100644 --- a/src/backend/opengl/OpenGLBackend.h +++ b/src/backend/opengl/OpenGLBackend.h @@ -103,12 +103,10 @@ namespace opengl { void InitBackbuffer(); void CommitBackbuffer(); GLuint GetCurrentTexture(); - GLuint GetCurrentDepthTexture(); private: GLuint backFBO = 0; GLuint backTexture = 0; - GLuint backDepthTexture = 0; }; class BindGroup : public BindGroupBase { diff --git a/src/backend/opengl/TextureGL.cpp b/src/backend/opengl/TextureGL.cpp index f0eb89dff4..07736771cc 100644 --- a/src/backend/opengl/TextureGL.cpp +++ b/src/backend/opengl/TextureGL.cpp @@ -37,6 +37,8 @@ namespace opengl { switch (format) { case nxt::TextureFormat::R8G8B8A8Unorm: 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: UNREACHABLE(); } diff --git a/src/utils/D3D12Binding.cpp b/src/utils/D3D12Binding.cpp index 8d6d4331e0..b876ffef1a 100644 --- a/src/utils/D3D12Binding.cpp +++ b/src/utils/D3D12Binding.cpp @@ -31,7 +31,7 @@ namespace backend { namespace d3d12 { void Init(ComPtr d3d12Device, nxtProcTable* procs, nxtDevice* device); ComPtr GetCommandQueue(nxtDevice device); - void SetNextTexture(nxtDevice device, ComPtr resource, ComPtr depthResource); + void SetNextTexture(nxtDevice device, ComPtr resource); uint64_t GetSerial(const nxtDevice device); void NextSerial(nxtDevice device); void ExecuteCommandLists(nxtDevice device, std::initializer_list commandLists); @@ -100,44 +100,9 @@ namespace utils { &swapChain1 )); 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; - dsvDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; - 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]))); - } + for (uint32_t n = 0; n < kFrameCount; ++n) { + ASSERT_SUCCESS(swapChain->GetBuffer(n, IID_PPV_ARGS(&renderTargetResources[n]))); } // 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::SetNextTexture(backendDevice, renderTargetResources[renderTargetIndex], depthStencilResources[renderTargetIndex]); + backend::d3d12::SetNextTexture(backendDevice, renderTargetResources[renderTargetIndex]); } void SwapBuffers() override { @@ -217,7 +182,7 @@ namespace utils { lastSerialRenderTargetWasUsed[renderTargetIndex] = backend::d3d12::GetSerial(backendDevice); // 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: @@ -232,7 +197,6 @@ namespace utils { ComPtr commandQueue; ComPtr swapChain; ComPtr renderTargetResources[kFrameCount]; - ComPtr depthStencilResources[kFrameCount]; // Frame synchronization. Updated every frame uint32_t renderTargetIndex; diff --git a/src/utils/NXTHelpers.cpp b/src/utils/NXTHelpers.cpp index d2f7eca54e..12857bb146 100644 --- a/src/utils/NXTHelpers.cpp +++ b/src/utils/NXTHelpers.cpp @@ -88,15 +88,30 @@ namespace utils { } 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() - .SetAttachmentCount(1) + .SetAttachmentCount(2) .AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm) + .AttachmentSetFormat(1, nxt::TextureFormat::D32FloatS8Uint) .SetSubpassCount(1) .SubpassSetColorAttachment(0, 0, 0) + .SubpassSetDepthStencilAttachment(0, 1) .GetResult(); *framebuffer = device.CreateFramebufferBuilder() .SetRenderPass(*renderPass) .SetDimensions(640, 480) + // Attachment 0 is implicit until we add WSI + .SetAttachment(1, depthStencilView) .GetResult(); }