Change render passes from multi to single pass.
This as an API change to get closer to the direction in which WebGPU is
headed. The API change in next.json caused a ton of files to be changed
in the same commit to keep things compiling.
API: the Framebuffer and RenderPass objects are now merged in a single
RenderPassInfo that contains the attachments, loadOps and clear values
for a BeginRenderPass command. The concept of subpass is removed.
The RenderPass creation argument to RenderPipelines is replaced by
explicitly setting the format of attachments for RenderPipeline.
Validation: SetPipeline checks are changed to check that the attachments
info set on a RenderPipeline matches the attachments of the render pass.
Backends: Most changes are simplifications of the backends that no
longer require and indirection to query the current subpass out of the
render pass in BeginSubpass, and don't need to get the attachment info
from a RenderPass when creating RenderPipelines. In the Vulkan backend,
a VkRenderPass cache is added to reuse VkRenderPasses between
RenderPassInfos and RenderPipelines.
Tests and examples: they are updated with the simplified API. Tests
specific to the Framebuffer and RenderPass objects were removed and
validation tests for RenderPassInfo were added.
Tested by running CppHelloTriangle on all backends, end2end tests on all
platforms and all examples on the GL backend.
diff --git a/src/backend/BindGroupLayout.cpp b/src/backend/BindGroupLayout.cpp
index 94ef08f..a554385 100644
--- a/src/backend/BindGroupLayout.cpp
+++ b/src/backend/BindGroupLayout.cpp
@@ -40,7 +40,8 @@
}
for (uint32_t binding : IterateBitSet(a.mask)) {
- if ((a.visibilities[binding] != b.visibilities[binding]) || (a.types[binding] != b.types[binding])) {
+ if ((a.visibilities[binding] != b.visibilities[binding]) ||
+ (a.types[binding] != b.types[binding])) {
return false;
}
}
diff --git a/src/backend/CMakeLists.txt b/src/backend/CMakeLists.txt
index 77c7d5a..5a0635d 100644
--- a/src/backend/CMakeLists.txt
+++ b/src/backend/CMakeLists.txt
@@ -241,8 +241,6 @@
${D3D12_DIR}/DescriptorHeapAllocator.h
${D3D12_DIR}/D3D12Backend.cpp
${D3D12_DIR}/D3D12Backend.h
- ${D3D12_DIR}/FramebufferD3D12.cpp
- ${D3D12_DIR}/FramebufferD3D12.h
${D3D12_DIR}/InputStateD3D12.cpp
${D3D12_DIR}/InputStateD3D12.h
${D3D12_DIR}/NativeSwapChainImplD3D12.cpp
@@ -251,6 +249,8 @@
${D3D12_DIR}/PipelineLayoutD3D12.h
${D3D12_DIR}/QueueD3D12.cpp
${D3D12_DIR}/QueueD3D12.h
+ ${D3D12_DIR}/RenderPassInfoD3D12.cpp
+ ${D3D12_DIR}/RenderPassInfoD3D12.h
${D3D12_DIR}/RenderPipelineD3D12.cpp
${D3D12_DIR}/RenderPipelineD3D12.h
${D3D12_DIR}/ResourceAllocator.cpp
@@ -308,8 +308,6 @@
${VULKAN_DIR}/DepthStencilStateVk.h
${VULKAN_DIR}/FencedDeleter.cpp
${VULKAN_DIR}/FencedDeleter.h
- ${VULKAN_DIR}/FramebufferVk.cpp
- ${VULKAN_DIR}/FramebufferVk.h
${VULKAN_DIR}/InputStateVk.cpp
${VULKAN_DIR}/InputStateVk.h
${VULKAN_DIR}/MemoryAllocator.cpp
@@ -318,8 +316,10 @@
${VULKAN_DIR}/NativeSwapChainImplVk.h
${VULKAN_DIR}/PipelineLayoutVk.cpp
${VULKAN_DIR}/PipelineLayoutVk.h
- ${VULKAN_DIR}/RenderPassVk.cpp
- ${VULKAN_DIR}/RenderPassVk.h
+ ${VULKAN_DIR}/RenderPassCache.cpp
+ ${VULKAN_DIR}/RenderPassCache.h
+ ${VULKAN_DIR}/RenderPassInfoVk.cpp
+ ${VULKAN_DIR}/RenderPassInfoVk.h
${VULKAN_DIR}/RenderPipelineVk.cpp
${VULKAN_DIR}/RenderPipelineVk.h
${VULKAN_DIR}/SamplerVk.cpp
@@ -367,8 +367,6 @@
${BACKEND_DIR}/Device.cpp
${BACKEND_DIR}/Device.h
${BACKEND_DIR}/Forward.h
- ${BACKEND_DIR}/Framebuffer.cpp
- ${BACKEND_DIR}/Framebuffer.h
${BACKEND_DIR}/InputState.cpp
${BACKEND_DIR}/InputState.h
${BACKEND_DIR}/RenderPipeline.cpp
@@ -381,8 +379,8 @@
${BACKEND_DIR}/PipelineLayout.h
${BACKEND_DIR}/Queue.cpp
${BACKEND_DIR}/Queue.h
- ${BACKEND_DIR}/RenderPass.cpp
- ${BACKEND_DIR}/RenderPass.h
+ ${BACKEND_DIR}/RenderPassInfo.cpp
+ ${BACKEND_DIR}/RenderPassInfo.h
${BACKEND_DIR}/RefCounted.cpp
${BACKEND_DIR}/RefCounted.h
${BACKEND_DIR}/Sampler.cpp
diff --git a/src/backend/CommandBuffer.cpp b/src/backend/CommandBuffer.cpp
index 948fc5b..747fa92 100644
--- a/src/backend/CommandBuffer.cpp
+++ b/src/backend/CommandBuffer.cpp
@@ -162,10 +162,6 @@
BeginRenderPassCmd* begin = commands->NextCommand<BeginRenderPassCmd>();
begin->~BeginRenderPassCmd();
} break;
- case Command::BeginRenderSubpass: {
- BeginRenderSubpassCmd* begin = commands->NextCommand<BeginRenderSubpassCmd>();
- begin->~BeginRenderSubpassCmd();
- } break;
case Command::CopyBufferToBuffer: {
CopyBufferToBufferCmd* copy = commands->NextCommand<CopyBufferToBufferCmd>();
copy->~CopyBufferToBufferCmd();
@@ -198,10 +194,6 @@
EndRenderPassCmd* cmd = commands->NextCommand<EndRenderPassCmd>();
cmd->~EndRenderPassCmd();
} break;
- case Command::EndRenderSubpass: {
- EndRenderSubpassCmd* cmd = commands->NextCommand<EndRenderSubpassCmd>();
- cmd->~EndRenderSubpassCmd();
- } break;
case Command::SetComputePipeline: {
SetComputePipelineCmd* cmd = commands->NextCommand<SetComputePipelineCmd>();
cmd->~SetComputePipelineCmd();
@@ -269,10 +261,6 @@
commands->NextCommand<BeginRenderPassCmd>();
break;
- case Command::BeginRenderSubpass:
- commands->NextCommand<BeginRenderSubpassCmd>();
- break;
-
case Command::CopyBufferToBuffer:
commands->NextCommand<CopyBufferToBufferCmd>();
break;
@@ -305,10 +293,6 @@
commands->NextCommand<EndRenderPassCmd>();
break;
- case Command::EndRenderSubpass:
- commands->NextCommand<EndRenderSubpassCmd>();
- break;
-
case Command::SetComputePipeline:
commands->NextCommand<SetComputePipelineCmd>();
break;
@@ -384,25 +368,8 @@
case Command::BeginRenderPass: {
BeginRenderPassCmd* cmd = mIterator.NextCommand<BeginRenderPassCmd>();
- auto* renderPass = cmd->renderPass.Get();
- auto* framebuffer = cmd->framebuffer.Get();
- // TODO(kainino@chromium.org): null checks should not be necessary
- if (renderPass == nullptr) {
- HandleError("Render pass is invalid");
- return false;
- }
- if (framebuffer == nullptr) {
- HandleError("Framebuffer is invalid");
- return false;
- }
- if (!mState->BeginRenderPass(renderPass, framebuffer)) {
- return false;
- }
- } break;
-
- case Command::BeginRenderSubpass: {
- mIterator.NextCommand<BeginRenderSubpassCmd>();
- if (!mState->BeginSubpass()) {
+ RenderPassInfoBase* info = cmd->info.Get();
+ if (!mState->BeginRenderPass(info)) {
return false;
}
} break;
@@ -495,13 +462,6 @@
}
} break;
- case Command::EndRenderSubpass: {
- mIterator.NextCommand<EndRenderSubpassCmd>();
- if (!mState->EndSubpass()) {
- return false;
- }
- } break;
-
case Command::SetComputePipeline: {
SetComputePipelineCmd* cmd = mIterator.NextCommand<SetComputePipelineCmd>();
ComputePipelineBase* pipeline = cmd->pipeline.Get();
@@ -531,24 +491,24 @@
case Command::SetStencilReference: {
mIterator.NextCommand<SetStencilReferenceCmd>();
- if (!mState->HaveRenderSubpass()) {
- HandleError("Can't set stencil reference without an active render subpass");
+ if (!mState->HaveRenderPass()) {
+ HandleError("Can't set stencil reference without an active render pass");
return false;
}
} break;
case Command::SetBlendColor: {
mIterator.NextCommand<SetBlendColorCmd>();
- if (!mState->HaveRenderSubpass()) {
- HandleError("Can't set blend color without an active render subpass");
+ if (!mState->HaveRenderPass()) {
+ HandleError("Can't set blend color without an active render pass");
return false;
}
} break;
case Command::SetScissorRect: {
mIterator.NextCommand<SetScissorRectCmd>();
- if (!mState->HaveRenderSubpass()) {
- HandleError("Can't set scissor rect without an active render subpass");
+ if (!mState->HaveRenderPass()) {
+ HandleError("Can't set scissor rect without an active render pass");
return false;
}
} break;
@@ -618,16 +578,10 @@
mAllocator.Allocate<BeginComputePassCmd>(Command::BeginComputePass);
}
- void CommandBufferBuilder::BeginRenderPass(RenderPassBase* renderPass,
- FramebufferBase* framebuffer) {
+ void CommandBufferBuilder::BeginRenderPass(RenderPassInfoBase* info) {
BeginRenderPassCmd* cmd = mAllocator.Allocate<BeginRenderPassCmd>(Command::BeginRenderPass);
new (cmd) BeginRenderPassCmd;
- cmd->renderPass = renderPass;
- cmd->framebuffer = framebuffer;
- }
-
- void CommandBufferBuilder::BeginRenderSubpass() {
- mAllocator.Allocate<BeginRenderSubpassCmd>(Command::BeginRenderSubpass);
+ cmd->info = info;
}
void CommandBufferBuilder::CopyBufferToBuffer(BufferBase* source,
@@ -745,10 +699,6 @@
mAllocator.Allocate<EndRenderPassCmd>(Command::EndRenderPass);
}
- void CommandBufferBuilder::EndRenderSubpass() {
- mAllocator.Allocate<EndRenderSubpassCmd>(Command::EndRenderSubpass);
- }
-
void CommandBufferBuilder::SetComputePipeline(ComputePipelineBase* pipeline) {
SetComputePipelineCmd* cmd =
mAllocator.Allocate<SetComputePipelineCmd>(Command::SetComputePipeline);
diff --git a/src/backend/CommandBuffer.h b/src/backend/CommandBuffer.h
index 2501898..4375cd6 100644
--- a/src/backend/CommandBuffer.h
+++ b/src/backend/CommandBuffer.h
@@ -62,8 +62,7 @@
// NXT API
void BeginComputePass();
- void BeginRenderPass(RenderPassBase* renderPass, FramebufferBase* framebuffer);
- void BeginRenderSubpass();
+ void BeginRenderPass(RenderPassInfoBase* info);
void CopyBufferToBuffer(BufferBase* source,
uint32_t sourceOffset,
BufferBase* destination,
@@ -102,7 +101,6 @@
uint32_t firstInstance);
void EndComputePass();
void EndRenderPass();
- void EndRenderSubpass();
void SetPushConstants(nxt::ShaderStageBit stages,
uint32_t offset,
uint32_t count,
diff --git a/src/backend/CommandBufferStateTracker.cpp b/src/backend/CommandBufferStateTracker.cpp
index ca375aa..fe4822f 100644
--- a/src/backend/CommandBufferStateTracker.cpp
+++ b/src/backend/CommandBufferStateTracker.cpp
@@ -19,10 +19,9 @@
#include "backend/Buffer.h"
#include "backend/ComputePipeline.h"
#include "backend/Forward.h"
-#include "backend/Framebuffer.h"
#include "backend/InputState.h"
#include "backend/PipelineLayout.h"
-#include "backend/RenderPass.h"
+#include "backend/RenderPassInfo.h"
#include "backend/RenderPipeline.h"
#include "backend/Texture.h"
#include "common/Assert.h"
@@ -37,10 +36,6 @@
return mCurrentRenderPass != nullptr;
}
- bool CommandBufferStateTracker::HaveRenderSubpass() const {
- return mAspects[VALIDATION_ASPECT_RENDER_SUBPASS];
- }
-
bool CommandBufferStateTracker::ValidateCanCopy() const {
if (mCurrentRenderPass) {
mBuilder->HandleError("Copy cannot occur during a render pass");
@@ -91,7 +86,7 @@
bool CommandBufferStateTracker::ValidateCanDrawArrays() {
// TODO(kainino@chromium.org): Check for a current render pass
constexpr ValidationAspects requiredAspects =
- 1 << VALIDATION_ASPECT_RENDER_PIPELINE | // implicitly requires RENDER_SUBPASS
+ 1 << VALIDATION_ASPECT_RENDER_PIPELINE | // implicitly requires RENDER_PASS
1 << VALIDATION_ASPECT_BIND_GROUPS | 1 << VALIDATION_ASPECT_VERTEX_BUFFERS;
if ((requiredAspects & ~mAspects).none()) {
// Fast return-true path if everything is good
@@ -137,15 +132,16 @@
"SetPushConstants stage must be compute or 0 in compute passes");
return false;
}
- } else if (mAspects[VALIDATION_ASPECT_RENDER_SUBPASS]) {
+ } else if (mAspects[VALIDATION_ASPECT_RENDER_PASS]) {
if (stages & ~(nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment)) {
mBuilder->HandleError(
- "SetPushConstants stage must be a subset if (vertex|fragment) in subpasses");
+ "SetPushConstants stage must be a subset if (vertex|fragment) in render "
+ "passes");
return false;
}
} else {
mBuilder->HandleError(
- "PushConstants must be set in either compute passes or subpasses");
+ "PushConstants must be set in either compute passes or render passes");
return false;
}
return true;
@@ -170,64 +166,7 @@
return true;
}
- bool CommandBufferStateTracker::BeginSubpass() {
- if (mCurrentRenderPass == nullptr) {
- mBuilder->HandleError("Can't begin a subpass without an active render pass");
- return false;
- }
- if (mAspects[VALIDATION_ASPECT_RENDER_SUBPASS]) {
- mBuilder->HandleError("Can't begin a subpass without ending the previous subpass");
- return false;
- }
- if (mCurrentSubpass >= mCurrentRenderPass->GetSubpassCount()) {
- mBuilder->HandleError("Can't begin a subpass beyond the last subpass");
- return false;
- }
-
- auto& subpassInfo = mCurrentRenderPass->GetSubpassInfo(mCurrentSubpass);
- for (auto location : IterateBitSet(subpassInfo.colorAttachmentsSet)) {
- auto attachmentSlot = subpassInfo.colorAttachments[location];
- auto* tv = mCurrentFramebuffer->GetTextureView(attachmentSlot);
- auto* texture = tv->GetTexture();
- if (!EnsureTextureUsage(texture, nxt::TextureUsageBit::OutputAttachment)) {
- mBuilder->HandleError("Unable to ensure texture has OutputAttachment usage");
- return false;
- }
- mTexturesAttached.insert(texture);
- }
-
- mAspects.set(VALIDATION_ASPECT_RENDER_SUBPASS);
- return true;
- }
-
- bool CommandBufferStateTracker::EndSubpass() {
- if (!mAspects[VALIDATION_ASPECT_RENDER_SUBPASS]) {
- mBuilder->HandleError("Can't end a subpass without beginning one");
- return false;
- }
- ASSERT(mCurrentRenderPass != nullptr);
-
- auto& subpassInfo = mCurrentRenderPass->GetSubpassInfo(mCurrentSubpass);
- for (auto location : IterateBitSet(subpassInfo.colorAttachmentsSet)) {
- auto attachmentSlot = subpassInfo.colorAttachments[location];
- auto* tv = mCurrentFramebuffer->GetTextureView(attachmentSlot);
- auto* texture = tv->GetTexture();
- if (texture->IsFrozen()) {
- continue;
- }
- }
- // Everything in mTexturesAttached should be for the current render subpass.
- mTexturesAttached.clear();
-
- mCurrentSubpass += 1;
- mInputsSet.reset();
- mAspects.reset(VALIDATION_ASPECT_RENDER_SUBPASS);
- UnsetPipeline();
- return true;
- }
-
- bool CommandBufferStateTracker::BeginRenderPass(RenderPassBase* renderPass,
- FramebufferBase* framebuffer) {
+ bool CommandBufferStateTracker::BeginRenderPass(RenderPassInfoBase* info) {
if (mAspects[VALIDATION_ASPECT_COMPUTE_PASS]) {
mBuilder->HandleError("Cannot begin a render pass while a compute pass is active");
return false;
@@ -236,15 +175,27 @@
mBuilder->HandleError("A render pass is already active");
return false;
}
- ASSERT(!mAspects[VALIDATION_ASPECT_RENDER_SUBPASS]);
- if (!framebuffer->GetRenderPass()->IsCompatibleWith(renderPass)) {
- mBuilder->HandleError("Framebuffer is incompatible with this render pass");
- return false;
+
+ mCurrentRenderPass = info;
+ mAspects.set(VALIDATION_ASPECT_RENDER_PASS);
+
+ for (uint32_t i : IterateBitSet(info->GetColorAttachmentMask())) {
+ TextureBase* texture = info->GetColorAttachment(i).view->GetTexture();
+ if (!EnsureTextureUsage(texture, nxt::TextureUsageBit::OutputAttachment)) {
+ mBuilder->HandleError("Unable to ensure texture has OutputAttachment usage");
+ return false;
+ }
+ mTexturesAttached.insert(texture);
}
- mCurrentRenderPass = renderPass;
- mCurrentFramebuffer = framebuffer;
- mCurrentSubpass = 0;
+ if (info->HasDepthStencilAttachment()) {
+ TextureBase* texture = info->GetDepthStencilAttachment().view->GetTexture();
+ if (!EnsureTextureUsage(texture, nxt::TextureUsageBit::OutputAttachment)) {
+ mBuilder->HandleError("Unable to ensure texture has OutputAttachment usage");
+ return false;
+ }
+ mTexturesAttached.insert(texture);
+ }
return true;
}
@@ -254,16 +205,15 @@
mBuilder->HandleError("No render pass is currently active");
return false;
}
- if (mAspects[VALIDATION_ASPECT_RENDER_SUBPASS]) {
- mBuilder->HandleError("Can't end a render pass while a subpass is active");
- return false;
- }
- if (mCurrentSubpass < mCurrentRenderPass->GetSubpassCount() - 1) {
- mBuilder->HandleError("Can't end a render pass before the last subpass");
- return false;
- }
+
+ // Everything in mTexturesAttached should be for the current render pass.
+ mTexturesAttached.clear();
+
+ mInputsSet.reset();
+ UnsetPipeline();
+
+ mAspects.reset(VALIDATION_ASPECT_RENDER_PASS);
mCurrentRenderPass = nullptr;
- mCurrentFramebuffer = nullptr;
return true;
}
@@ -284,11 +234,11 @@
}
bool CommandBufferStateTracker::SetRenderPipeline(RenderPipelineBase* pipeline) {
- if (!mAspects[VALIDATION_ASPECT_RENDER_SUBPASS]) {
- mBuilder->HandleError("A render subpass must be active when a render pipeline is set");
+ if (!mAspects[VALIDATION_ASPECT_RENDER_PASS]) {
+ mBuilder->HandleError("A render pass must be active when a render pipeline is set");
return false;
}
- if (!pipeline->GetRenderPass()->IsCompatibleWith(mCurrentRenderPass)) {
+ if (!pipeline->IsCompatibleWith(mCurrentRenderPass)) {
mBuilder->HandleError("Pipeline is incompatible with this render pass");
return false;
}
diff --git a/src/backend/CommandBufferStateTracker.h b/src/backend/CommandBufferStateTracker.h
index 584026e..c2af36f 100644
--- a/src/backend/CommandBufferStateTracker.h
+++ b/src/backend/CommandBufferStateTracker.h
@@ -30,7 +30,6 @@
// Non-state-modifying validation functions
bool HaveRenderPass() const;
- bool HaveRenderSubpass() const;
bool ValidateCanCopy() const;
bool ValidateCanUseBufferAs(BufferBase* buffer, nxt::BufferUsageBit usage) const;
bool ValidateCanUseTextureAs(TextureBase* texture, nxt::TextureUsageBit usage) const;
@@ -43,9 +42,7 @@
// State-modifying methods
bool BeginComputePass();
bool EndComputePass();
- bool BeginSubpass();
- bool EndSubpass();
- bool BeginRenderPass(RenderPassBase* renderPass, FramebufferBase* framebuffer);
+ bool BeginRenderPass(RenderPassInfoBase* info);
bool EndRenderPass();
bool SetComputePipeline(ComputePipelineBase* pipeline);
bool SetRenderPipeline(RenderPipelineBase* pipeline);
@@ -70,7 +67,7 @@
VALIDATION_ASPECT_BIND_GROUPS,
VALIDATION_ASPECT_VERTEX_BUFFERS,
VALIDATION_ASPECT_INDEX_BUFFER,
- VALIDATION_ASPECT_RENDER_SUBPASS,
+ VALIDATION_ASPECT_RENDER_PASS,
VALIDATION_ASPECT_COMPUTE_PASS,
VALIDATION_ASPECT_COUNT
@@ -109,9 +106,7 @@
std::map<BufferBase*, nxt::BufferUsageBit> mMostRecentBufferUsages;
std::map<TextureBase*, nxt::TextureUsageBit> mMostRecentTextureUsages;
- RenderPassBase* mCurrentRenderPass = nullptr;
- FramebufferBase* mCurrentFramebuffer = nullptr;
- uint32_t mCurrentSubpass = 0;
+ RenderPassInfoBase* mCurrentRenderPass = nullptr;
};
} // namespace backend
diff --git a/src/backend/Commands.h b/src/backend/Commands.h
index f15b783..e90397c 100644
--- a/src/backend/Commands.h
+++ b/src/backend/Commands.h
@@ -15,8 +15,7 @@
#ifndef BACKEND_COMMANDS_H_
#define BACKEND_COMMANDS_H_
-#include "backend/Framebuffer.h"
-#include "backend/RenderPass.h"
+#include "backend/RenderPassInfo.h"
#include "backend/Texture.h"
#include "nxt/nxtcpp.h"
@@ -30,7 +29,6 @@
enum class Command {
BeginComputePass,
BeginRenderPass,
- BeginRenderSubpass,
CopyBufferToBuffer,
CopyBufferToTexture,
CopyTextureToBuffer,
@@ -39,7 +37,6 @@
DrawElements,
EndComputePass,
EndRenderPass,
- EndRenderSubpass,
SetComputePipeline,
SetRenderPipeline,
SetPushConstants,
@@ -56,12 +53,9 @@
struct BeginComputePassCmd {};
struct BeginRenderPassCmd {
- Ref<RenderPassBase> renderPass;
- Ref<FramebufferBase> framebuffer;
+ Ref<RenderPassInfoBase> info;
};
- struct BeginRenderSubpassCmd {};
-
struct BufferCopyLocation {
Ref<BufferBase> buffer;
uint32_t offset;
@@ -116,8 +110,6 @@
struct EndRenderPassCmd {};
- struct EndRenderSubpassCmd {};
-
struct SetComputePipelineCmd {
Ref<ComputePipelineBase> pipeline;
};
diff --git a/src/backend/Device.cpp b/src/backend/Device.cpp
index 98f794d..8a02c56 100644
--- a/src/backend/Device.cpp
+++ b/src/backend/Device.cpp
@@ -21,11 +21,10 @@
#include "backend/CommandBuffer.h"
#include "backend/ComputePipeline.h"
#include "backend/DepthStencilState.h"
-#include "backend/Framebuffer.h"
#include "backend/InputState.h"
#include "backend/PipelineLayout.h"
#include "backend/Queue.h"
-#include "backend/RenderPass.h"
+#include "backend/RenderPassInfo.h"
#include "backend/RenderPipeline.h"
#include "backend/Sampler.h"
#include "backend/ShaderModule.h"
@@ -116,9 +115,6 @@
DepthStencilStateBuilder* DeviceBase::CreateDepthStencilStateBuilder() {
return new DepthStencilStateBuilder(this);
}
- FramebufferBuilder* DeviceBase::CreateFramebufferBuilder() {
- return new FramebufferBuilder(this);
- }
InputStateBuilder* DeviceBase::CreateInputStateBuilder() {
return new InputStateBuilder(this);
}
@@ -128,8 +124,8 @@
QueueBuilder* DeviceBase::CreateQueueBuilder() {
return new QueueBuilder(this);
}
- RenderPassBuilder* DeviceBase::CreateRenderPassBuilder() {
- return new RenderPassBuilder(this);
+ RenderPassInfoBuilder* DeviceBase::CreateRenderPassInfoBuilder() {
+ return new RenderPassInfoBuilder(this);
}
RenderPipelineBuilder* DeviceBase::CreateRenderPipelineBuilder() {
return new RenderPipelineBuilder(this);
diff --git a/src/backend/Device.h b/src/backend/Device.h
index 6b7e37d..df23d22 100644
--- a/src/backend/Device.h
+++ b/src/backend/Device.h
@@ -43,11 +43,10 @@
virtual ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) = 0;
virtual DepthStencilStateBase* CreateDepthStencilState(
DepthStencilStateBuilder* builder) = 0;
- virtual FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) = 0;
virtual InputStateBase* CreateInputState(InputStateBuilder* builder) = 0;
virtual PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) = 0;
virtual QueueBase* CreateQueue(QueueBuilder* builder) = 0;
- virtual RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) = 0;
+ virtual RenderPassInfoBase* CreateRenderPassInfo(RenderPassInfoBuilder* builder) = 0;
virtual RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) = 0;
virtual SamplerBase* CreateSampler(SamplerBuilder* builder) = 0;
virtual ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) = 0;
@@ -83,11 +82,10 @@
CommandBufferBuilder* CreateCommandBufferBuilder();
ComputePipelineBuilder* CreateComputePipelineBuilder();
DepthStencilStateBuilder* CreateDepthStencilStateBuilder();
- FramebufferBuilder* CreateFramebufferBuilder();
InputStateBuilder* CreateInputStateBuilder();
PipelineLayoutBuilder* CreatePipelineLayoutBuilder();
QueueBuilder* CreateQueueBuilder();
- RenderPassBuilder* CreateRenderPassBuilder();
+ RenderPassInfoBuilder* CreateRenderPassInfoBuilder();
RenderPipelineBuilder* CreateRenderPipelineBuilder();
SamplerBuilder* CreateSamplerBuilder();
ShaderModuleBuilder* CreateShaderModuleBuilder();
diff --git a/src/backend/Forward.h b/src/backend/Forward.h
index 7c9cd67..418dd68 100644
--- a/src/backend/Forward.h
+++ b/src/backend/Forward.h
@@ -35,16 +35,14 @@
class CommandBufferBuilder;
class DepthStencilStateBase;
class DepthStencilStateBuilder;
- class FramebufferBase;
- class FramebufferBuilder;
class InputStateBase;
class InputStateBuilder;
class PipelineLayoutBase;
class PipelineLayoutBuilder;
class QueueBase;
class QueueBuilder;
- class RenderPassBase;
- class RenderPassBuilder;
+ class RenderPassInfoBase;
+ class RenderPassInfoBuilder;
class RenderPipelineBase;
class RenderPipelineBuilder;
class SamplerBase;
diff --git a/src/backend/Framebuffer.cpp b/src/backend/Framebuffer.cpp
deleted file mode 100644
index 5338392..0000000
--- a/src/backend/Framebuffer.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-// Copyright 2017 The NXT 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 "backend/Framebuffer.h"
-
-#include "backend/Buffer.h"
-#include "backend/Device.h"
-#include "backend/RenderPass.h"
-#include "backend/Texture.h"
-#include "common/Assert.h"
-
-namespace backend {
-
- // Framebuffer
-
- FramebufferBase::FramebufferBase(FramebufferBuilder* builder)
- : mDevice(builder->mDevice),
- mRenderPass(std::move(builder->mRenderPass)),
- mWidth(builder->mWidth),
- mHeight(builder->mHeight),
- mTextureViews(std::move(builder->mTextureViews)),
- mClearColors(mTextureViews.size()),
- mClearDepthStencils(mTextureViews.size()) {
- }
-
- DeviceBase* FramebufferBase::GetDevice() {
- return mDevice;
- }
-
- RenderPassBase* FramebufferBase::GetRenderPass() {
- return mRenderPass.Get();
- }
-
- TextureViewBase* FramebufferBase::GetTextureView(uint32_t attachmentSlot) {
- ASSERT(attachmentSlot < mTextureViews.size());
- return mTextureViews[attachmentSlot].Get();
- }
-
- FramebufferBase::ClearColor FramebufferBase::GetClearColor(uint32_t attachmentSlot) {
- ASSERT(attachmentSlot < mClearColors.size());
- return mClearColors[attachmentSlot];
- }
-
- FramebufferBase::ClearDepthStencil FramebufferBase::GetClearDepthStencil(
- uint32_t attachmentSlot) {
- ASSERT(attachmentSlot < mClearDepthStencils.size());
- return mClearDepthStencils[attachmentSlot];
- }
-
- uint32_t FramebufferBase::GetWidth() const {
- return mWidth;
- }
-
- uint32_t FramebufferBase::GetHeight() const {
- return mHeight;
- }
-
- void FramebufferBase::AttachmentSetClearColor(uint32_t attachmentSlot,
- float clearR,
- float clearG,
- float clearB,
- float clearA) {
- if (attachmentSlot >= mRenderPass->GetAttachmentCount()) {
- mDevice->HandleError("Framebuffer attachment out of bounds");
- return;
- }
- ASSERT(attachmentSlot < mClearColors.size());
- auto& c = mClearColors[attachmentSlot];
- c.color[0] = clearR;
- c.color[1] = clearG;
- c.color[2] = clearB;
- c.color[3] = clearA;
- }
-
- void FramebufferBase::AttachmentSetClearDepthStencil(uint32_t attachmentSlot,
- float clearDepth,
- uint32_t clearStencil) {
- if (attachmentSlot >= mRenderPass->GetAttachmentCount()) {
- mDevice->HandleError("Framebuffer attachment out of bounds");
- return;
- }
- ASSERT(attachmentSlot < mClearDepthStencils.size());
- auto& c = mClearDepthStencils[attachmentSlot];
- c.depth = clearDepth;
- c.stencil = clearStencil;
- }
-
- // FramebufferBuilder
-
- enum FramebufferSetProperties {
- FRAMEBUFFER_PROPERTY_RENDER_PASS = 0x1,
- FRAMEBUFFER_PROPERTY_DIMENSIONS = 0x2,
- };
-
- FramebufferBuilder::FramebufferBuilder(DeviceBase* device) : Builder(device) {
- }
-
- FramebufferBase* FramebufferBuilder::GetResultImpl() {
- constexpr int requiredProperties =
- FRAMEBUFFER_PROPERTY_RENDER_PASS | FRAMEBUFFER_PROPERTY_DIMENSIONS;
- if ((mPropertiesSet & requiredProperties) != requiredProperties) {
- HandleError("Framebuffer missing properties");
- return nullptr;
- }
-
- for (auto& textureView : mTextureViews) {
- if (!textureView) {
- HandleError("Framebuffer attachment not set");
- return nullptr;
- }
-
- // TODO(cwallez@chromium.org): Adjust for the mip-level once that is supported.
- if (textureView->GetTexture()->GetWidth() != mWidth ||
- textureView->GetTexture()->GetHeight() != mHeight) {
- HandleError("Framebuffer size doesn't match attachment size");
- return nullptr;
- }
- }
-
- return mDevice->CreateFramebuffer(this);
- }
-
- void FramebufferBuilder::SetRenderPass(RenderPassBase* renderPass) {
- if ((mPropertiesSet & FRAMEBUFFER_PROPERTY_RENDER_PASS) != 0) {
- HandleError("Framebuffer render pass property set multiple times");
- return;
- }
- // TODO(kainino@chromium.org): null checks should not be necessary
- if (renderPass == nullptr) {
- HandleError("Render pass invalid");
- return;
- }
-
- mRenderPass = renderPass;
- mTextureViews.resize(renderPass->GetAttachmentCount());
- mPropertiesSet |= FRAMEBUFFER_PROPERTY_RENDER_PASS;
- }
-
- void FramebufferBuilder::SetDimensions(uint32_t width, uint32_t height) {
- if ((mPropertiesSet & FRAMEBUFFER_PROPERTY_DIMENSIONS) != 0) {
- HandleError("Framebuffer dimensions property set multiple times");
- return;
- }
-
- mWidth = width;
- mHeight = height;
- mPropertiesSet |= FRAMEBUFFER_PROPERTY_DIMENSIONS;
- }
-
- void FramebufferBuilder::SetAttachment(uint32_t attachmentSlot, TextureViewBase* textureView) {
- if ((mPropertiesSet & FRAMEBUFFER_PROPERTY_RENDER_PASS) == 0) {
- HandleError("Render pass must be set before framebuffer attachments");
- return;
- }
- if (attachmentSlot >= mTextureViews.size()) {
- HandleError("Attachment slot out of bounds");
- return;
- }
- if (mTextureViews[attachmentSlot]) {
- HandleError("Framebuffer attachment[i] set multiple times");
- return;
- }
- const auto& attachmentInfo = mRenderPass->GetAttachmentInfo(attachmentSlot);
- const auto* texture = textureView->GetTexture();
- if (attachmentInfo.format != texture->GetFormat()) {
- HandleError("Texture format does not match attachment format");
- return;
- }
- // TODO(kainino@chromium.org): also check attachment samples, etc.
-
- mTextureViews[attachmentSlot] = textureView;
- }
-} // namespace backend
diff --git a/src/backend/Framebuffer.h b/src/backend/Framebuffer.h
deleted file mode 100644
index a4dc4cb..0000000
--- a/src/backend/Framebuffer.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2017 The NXT 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 BACKEND_FRAMEBUFFER_H_
-#define BACKEND_FRAMEBUFFER_H_
-
-#include "backend/Builder.h"
-#include "backend/Forward.h"
-#include "backend/RefCounted.h"
-#include "backend/Texture.h"
-
-#include "nxt/nxtcpp.h"
-
-#include <type_traits>
-#include <vector>
-
-namespace backend {
-
- class FramebufferBase : public RefCounted {
- public:
- struct ClearColor {
- float color[4] = {};
- };
-
- struct ClearDepthStencil {
- float depth = 1.0f;
- uint32_t stencil = 0;
- };
-
- FramebufferBase(FramebufferBuilder* builder);
-
- DeviceBase* GetDevice();
- RenderPassBase* GetRenderPass();
- TextureViewBase* GetTextureView(uint32_t attachmentSlot);
- ClearColor GetClearColor(uint32_t attachmentSlot);
- ClearDepthStencil GetClearDepthStencil(uint32_t attachmentSlot);
- uint32_t GetWidth() const;
- uint32_t GetHeight() const;
-
- // NXT API
- void AttachmentSetClearColor(uint32_t attachmentSlot,
- float clearR,
- float clearG,
- float clearB,
- float clearA);
- void AttachmentSetClearDepthStencil(uint32_t attachmentSlot,
- float clearDepth,
- uint32_t clearStencil);
-
- private:
- DeviceBase* mDevice;
- Ref<RenderPassBase> mRenderPass;
- uint32_t mWidth = 0;
- uint32_t mHeight = 0;
- std::vector<Ref<TextureViewBase>> mTextureViews;
- std::vector<ClearColor> mClearColors;
- std::vector<ClearDepthStencil> mClearDepthStencils;
- };
-
- class FramebufferBuilder : public Builder<FramebufferBase> {
- public:
- FramebufferBuilder(DeviceBase* device);
-
- // NXT API
- FramebufferBase* GetResultImpl() override;
- void SetRenderPass(RenderPassBase* renderPass);
- void SetDimensions(uint32_t width, uint32_t height);
- void SetAttachment(uint32_t attachmentSlot, TextureViewBase* textureView);
-
- private:
- friend class FramebufferBase;
-
- Ref<RenderPassBase> mRenderPass;
- uint32_t mWidth = 0;
- uint32_t mHeight = 0;
- std::vector<Ref<TextureViewBase>> mTextureViews;
- int mPropertiesSet = 0;
- };
-
-} // namespace backend
-
-#endif // BACKEND_FRAMEBUFFER_H_
diff --git a/src/backend/Pipeline.cpp b/src/backend/Pipeline.cpp
index 177a2ba..67275e3 100644
--- a/src/backend/Pipeline.cpp
+++ b/src/backend/Pipeline.cpp
@@ -18,7 +18,6 @@
#include "backend/Device.h"
#include "backend/InputState.h"
#include "backend/PipelineLayout.h"
-#include "backend/RenderPass.h"
#include "backend/ShaderModule.h"
namespace backend {
diff --git a/src/backend/RenderPass.cpp b/src/backend/RenderPass.cpp
deleted file mode 100644
index d4e0c95..0000000
--- a/src/backend/RenderPass.cpp
+++ /dev/null
@@ -1,252 +0,0 @@
-// Copyright 2017 The NXT 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 "backend/RenderPass.h"
-
-#include "backend/Buffer.h"
-#include "backend/Device.h"
-#include "backend/Texture.h"
-#include "common/Assert.h"
-#include "common/BitSetIterator.h"
-
-namespace backend {
-
- // RenderPass
-
- RenderPassBase::RenderPassBase(RenderPassBuilder* builder)
- : mAttachments(std::move(builder->mAttachments)),
- mSubpasses(std::move(builder->mSubpasses)) {
- for (uint32_t s = 0; s < GetSubpassCount(); ++s) {
- const auto& subpass = GetSubpassInfo(s);
- for (auto location : IterateBitSet(subpass.colorAttachmentsSet)) {
- auto attachmentSlot = subpass.colorAttachments[location];
- auto& firstSubpass = mAttachments[attachmentSlot].firstSubpass;
- if (firstSubpass == UINT32_MAX) {
- firstSubpass = s;
- }
- }
- if (subpass.depthStencilAttachmentSet) {
- auto attachmentSlot = subpass.depthStencilAttachment;
- auto& firstSubpass = mAttachments[attachmentSlot].firstSubpass;
- if (firstSubpass == UINT32_MAX) {
- firstSubpass = s;
- }
- }
- }
- }
-
- uint32_t RenderPassBase::GetAttachmentCount() const {
- return static_cast<uint32_t>(mAttachments.size());
- }
-
- const RenderPassBase::AttachmentInfo& RenderPassBase::GetAttachmentInfo(
- uint32_t attachment) const {
- ASSERT(attachment < mAttachments.size());
- return mAttachments[attachment];
- }
-
- uint32_t RenderPassBase::GetSubpassCount() const {
- return static_cast<uint32_t>(mSubpasses.size());
- }
-
- const RenderPassBase::SubpassInfo& RenderPassBase::GetSubpassInfo(uint32_t subpass) const {
- ASSERT(subpass < mSubpasses.size());
- return mSubpasses[subpass];
- }
-
- bool RenderPassBase::IsCompatibleWith(const RenderPassBase* other) const {
- // TODO(kainino@chromium.org): This check is overly strict; need actual
- // compatibility checking (different load and store ops, etc.)
- return other == this;
- }
-
- // RenderPassBuilder
-
- enum RenderPassSetProperties {
- RENDERPASS_PROPERTY_ATTACHMENT_COUNT = 0x1,
- RENDERPASS_PROPERTY_SUBPASS_COUNT = 0x2,
- };
-
- RenderPassBuilder::RenderPassBuilder(DeviceBase* device) : Builder(device), mSubpasses(1) {
- }
-
- RenderPassBase* RenderPassBuilder::GetResultImpl() {
- constexpr int requiredProperties =
- RENDERPASS_PROPERTY_ATTACHMENT_COUNT | RENDERPASS_PROPERTY_SUBPASS_COUNT;
- if ((mPropertiesSet & requiredProperties) != requiredProperties) {
- HandleError("Render pass missing properties");
- return nullptr;
- }
-
- for (const auto& prop : mAttachmentProperties) {
- if (!prop.all()) {
- HandleError("A render pass attachment is missing some property");
- return nullptr;
- }
- }
-
- for (const auto& subpass : mSubpasses) {
- for (unsigned int location : IterateBitSet(subpass.colorAttachmentsSet)) {
- uint32_t slot = subpass.colorAttachments[location];
- if (TextureFormatHasDepthOrStencil(mAttachments[slot].format)) {
- HandleError("Render pass color attachment is not of a color format");
- return nullptr;
- }
- }
- if (subpass.depthStencilAttachmentSet) {
- uint32_t slot = subpass.depthStencilAttachment;
- if (!TextureFormatHasDepthOrStencil(mAttachments[slot].format)) {
- HandleError(
- "Render pass depth/stencil attachment is not of a depth/stencil format");
- return nullptr;
- }
- }
- }
-
- return mDevice->CreateRenderPass(this);
- }
-
- void RenderPassBuilder::SetAttachmentCount(uint32_t attachmentCount) {
- if ((mPropertiesSet & RENDERPASS_PROPERTY_ATTACHMENT_COUNT) != 0) {
- HandleError("Render pass attachment count property set multiple times");
- return;
- }
-
- mAttachmentProperties.resize(attachmentCount);
- mAttachments.resize(attachmentCount);
- mPropertiesSet |= RENDERPASS_PROPERTY_ATTACHMENT_COUNT;
- }
-
- void RenderPassBuilder::AttachmentSetFormat(uint32_t attachmentSlot,
- nxt::TextureFormat format) {
- if ((mPropertiesSet & RENDERPASS_PROPERTY_ATTACHMENT_COUNT) == 0) {
- HandleError("Render pass attachment count not set yet");
- return;
- }
- if (attachmentSlot >= mAttachments.size()) {
- HandleError("Render pass attachment slot out of bounds");
- return;
- }
- if (mAttachmentProperties[attachmentSlot][ATTACHMENT_PROPERTY_FORMAT]) {
- HandleError("Render pass attachment format already set");
- return;
- }
-
- mAttachments[attachmentSlot].format = format;
- mAttachmentProperties[attachmentSlot].set(ATTACHMENT_PROPERTY_FORMAT);
- }
-
- void RenderPassBuilder::AttachmentSetColorLoadOp(uint32_t attachmentSlot, nxt::LoadOp op) {
- if ((mPropertiesSet & RENDERPASS_PROPERTY_ATTACHMENT_COUNT) == 0) {
- HandleError("Render pass attachment count not set yet");
- return;
- }
- if (attachmentSlot >= mAttachments.size()) {
- HandleError("Render pass attachment slot out of bounds");
- return;
- }
-
- mAttachments[attachmentSlot].colorLoadOp = op;
- }
-
- void RenderPassBuilder::AttachmentSetDepthStencilLoadOps(uint32_t attachmentSlot,
- nxt::LoadOp depthOp,
- nxt::LoadOp stencilOp) {
- if ((mPropertiesSet & RENDERPASS_PROPERTY_ATTACHMENT_COUNT) == 0) {
- HandleError("Render pass attachment count not set yet");
- return;
- }
- if (attachmentSlot >= mAttachments.size()) {
- HandleError("Render pass attachment slot out of bounds");
- return;
- }
-
- mAttachments[attachmentSlot].depthLoadOp = depthOp;
- mAttachments[attachmentSlot].stencilLoadOp = stencilOp;
- }
-
- void RenderPassBuilder::SetSubpassCount(uint32_t subpassCount) {
- if ((mPropertiesSet & RENDERPASS_PROPERTY_SUBPASS_COUNT) != 0) {
- HandleError("Render pass subpass count property set multiple times");
- return;
- }
- if (subpassCount < 1) {
- HandleError("Render pass cannot have fewer than one subpass");
- return;
- }
-
- mSubpasses.resize(subpassCount);
- mPropertiesSet |= RENDERPASS_PROPERTY_SUBPASS_COUNT;
- }
-
- void RenderPassBuilder::SubpassSetColorAttachment(uint32_t subpass,
- uint32_t outputAttachmentLocation,
- uint32_t attachmentSlot) {
- if ((mPropertiesSet & RENDERPASS_PROPERTY_SUBPASS_COUNT) == 0) {
- HandleError("Render pass subpass count not set yet");
- return;
- }
- if ((mPropertiesSet & RENDERPASS_PROPERTY_ATTACHMENT_COUNT) == 0) {
- HandleError("Render pass attachment count not set yet");
- return;
- }
- if (subpass >= mSubpasses.size()) {
- HandleError("Subpass index out of bounds");
- return;
- }
- if (outputAttachmentLocation >= kMaxColorAttachments) {
- HandleError("Subpass output attachment location out of bounds");
- return;
- }
- if (attachmentSlot >= mAttachments.size()) {
- HandleError("Subpass attachment slot out of bounds");
- return;
- }
- if (mSubpasses[subpass].colorAttachmentsSet[outputAttachmentLocation]) {
- HandleError("Subpass color attachment already set");
- return;
- }
-
- mSubpasses[subpass].colorAttachmentsSet.set(outputAttachmentLocation);
- mSubpasses[subpass].colorAttachments[outputAttachmentLocation] = attachmentSlot;
- }
-
- void RenderPassBuilder::SubpassSetDepthStencilAttachment(uint32_t subpass,
- uint32_t attachmentSlot) {
- if ((mPropertiesSet & RENDERPASS_PROPERTY_SUBPASS_COUNT) == 0) {
- HandleError("Render pass subpass count not set yet");
- return;
- }
- if ((mPropertiesSet & RENDERPASS_PROPERTY_ATTACHMENT_COUNT) == 0) {
- HandleError("Render pass attachment count not set yet");
- return;
- }
- if (subpass >= mSubpasses.size()) {
- HandleError("Subpass index out of bounds");
- return;
- }
- if (attachmentSlot >= mAttachments.size()) {
- HandleError("Subpass attachment slot out of bounds");
- return;
- }
- if (mSubpasses[subpass].depthStencilAttachmentSet) {
- HandleError("Subpass depth-stencil attachment already set");
- return;
- }
-
- mSubpasses[subpass].depthStencilAttachmentSet = true;
- mSubpasses[subpass].depthStencilAttachment = attachmentSlot;
- }
-
-} // namespace backend
diff --git a/src/backend/RenderPass.h b/src/backend/RenderPass.h
deleted file mode 100644
index 94de20f..0000000
--- a/src/backend/RenderPass.h
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2017 The NXT 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 BACKEND_RENDERPASS_H_
-#define BACKEND_RENDERPASS_H_
-
-#include "backend/Builder.h"
-#include "backend/Forward.h"
-#include "backend/RefCounted.h"
-#include "common/Constants.h"
-
-#include "nxt/nxtcpp.h"
-
-#include <array>
-#include <bitset>
-#include <vector>
-
-namespace backend {
-
- class RenderPassBase : public RefCounted {
- public:
- RenderPassBase(RenderPassBuilder* builder);
-
- struct AttachmentInfo {
- nxt::TextureFormat format;
- nxt::LoadOp colorLoadOp = nxt::LoadOp::Load;
- nxt::LoadOp depthLoadOp = nxt::LoadOp::Load;
- nxt::LoadOp stencilLoadOp = nxt::LoadOp::Load;
- // The first subpass that this attachment is used in. This is used to determine, for
- // each subpass, whether each of its attachments is being used for the first time.
- uint32_t firstSubpass = UINT32_MAX;
- };
-
- struct SubpassInfo {
- // Set of locations which are set
- std::bitset<kMaxColorAttachments> colorAttachmentsSet;
- // Mapping from location to attachment slot
- std::array<uint32_t, kMaxColorAttachments> colorAttachments;
- bool depthStencilAttachmentSet = false;
- uint32_t depthStencilAttachment = 0;
- };
-
- uint32_t GetAttachmentCount() const;
- const AttachmentInfo& GetAttachmentInfo(uint32_t attachment) const;
- uint32_t GetSubpassCount() const;
- const SubpassInfo& GetSubpassInfo(uint32_t subpass) const;
- bool IsCompatibleWith(const RenderPassBase* other) const;
-
- private:
- std::vector<AttachmentInfo> mAttachments;
- std::vector<SubpassInfo> mSubpasses;
- };
-
- class RenderPassBuilder : public Builder<RenderPassBase> {
- public:
- RenderPassBuilder(DeviceBase* device);
-
- // NXT API
- RenderPassBase* GetResultImpl() override;
- void SetAttachmentCount(uint32_t attachmentCount);
- void AttachmentSetFormat(uint32_t attachmentSlot, nxt::TextureFormat format);
- void AttachmentSetColorLoadOp(uint32_t attachmentSlot, nxt::LoadOp op);
- void AttachmentSetDepthStencilLoadOps(uint32_t attachmentSlot,
- nxt::LoadOp depthOp,
- nxt::LoadOp stencilOp);
- 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;
-
- enum AttachmentProperty { ATTACHMENT_PROPERTY_FORMAT, ATTACHMENT_PROPERTY_COUNT };
-
- std::vector<std::bitset<ATTACHMENT_PROPERTY_COUNT>> mAttachmentProperties;
- std::vector<RenderPassBase::AttachmentInfo> mAttachments;
- std::vector<RenderPassBase::SubpassInfo> mSubpasses;
- int mPropertiesSet = 0;
- };
-
-} // namespace backend
-
-#endif // BACKEND_RENDERPASS_H_
diff --git a/src/backend/RenderPassInfo.cpp b/src/backend/RenderPassInfo.cpp
new file mode 100644
index 0000000..1bf0903
--- /dev/null
+++ b/src/backend/RenderPassInfo.cpp
@@ -0,0 +1,180 @@
+// Copyright 2017 The NXT 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 "backend/RenderPassInfo.h"
+
+#include "backend/Device.h"
+#include "backend/Texture.h"
+#include "common/Assert.h"
+#include "common/BitSetIterator.h"
+
+namespace backend {
+
+ // RenderPassInfo
+
+ RenderPassInfoBase::RenderPassInfoBase(RenderPassInfoBuilder* builder)
+ : mColorAttachmentsSet(builder->mColorAttachmentsSet),
+ mColorAttachments(builder->mColorAttachments),
+ mDepthStencilAttachmentSet(builder->mDepthStencilAttachmentSet),
+ mDepthStencilAttachment(builder->mDepthStencilAttachment),
+ mWidth(builder->mWidth),
+ mHeight(builder->mHeight) {
+ }
+
+ std::bitset<kMaxColorAttachments> RenderPassInfoBase::GetColorAttachmentMask() const {
+ return mColorAttachmentsSet;
+ }
+
+ bool RenderPassInfoBase::HasDepthStencilAttachment() const {
+ return mDepthStencilAttachmentSet;
+ }
+
+ const RenderPassColorAttachmentInfo& RenderPassInfoBase::GetColorAttachment(
+ uint32_t attachment) const {
+ ASSERT(attachment < kMaxColorAttachments);
+ ASSERT(mColorAttachmentsSet[attachment]);
+
+ return mColorAttachments[attachment];
+ }
+
+ RenderPassColorAttachmentInfo& RenderPassInfoBase::GetColorAttachment(uint32_t attachment) {
+ ASSERT(attachment < kMaxColorAttachments);
+ ASSERT(mColorAttachmentsSet[attachment]);
+
+ return mColorAttachments[attachment];
+ }
+
+ const RenderPassDepthStencilAttachmentInfo& RenderPassInfoBase::GetDepthStencilAttachment()
+ const {
+ ASSERT(mDepthStencilAttachmentSet);
+
+ return mDepthStencilAttachment;
+ }
+
+ RenderPassDepthStencilAttachmentInfo& RenderPassInfoBase::GetDepthStencilAttachment() {
+ ASSERT(mDepthStencilAttachmentSet);
+
+ return mDepthStencilAttachment;
+ }
+
+ uint32_t RenderPassInfoBase::GetWidth() const {
+ return mWidth;
+ }
+
+ uint32_t RenderPassInfoBase::GetHeight() const {
+ return mHeight;
+ }
+
+ // RenderPassInfoBuilder
+
+ RenderPassInfoBuilder::RenderPassInfoBuilder(DeviceBase* device) : Builder(device) {
+ }
+
+ RenderPassInfoBase* RenderPassInfoBuilder::GetResultImpl() {
+ auto CheckOrSetSize = [this](const TextureViewBase* attachment) -> bool {
+ if (this->mWidth == 0) {
+ ASSERT(this->mHeight == 0);
+
+ this->mWidth = attachment->GetTexture()->GetWidth();
+ this->mHeight = attachment->GetTexture()->GetHeight();
+ ASSERT(this->mWidth != 0 && this->mHeight != 0);
+
+ return true;
+ }
+
+ ASSERT(this->mWidth != 0 && this->mHeight != 0);
+ return this->mWidth == attachment->GetTexture()->GetWidth() &&
+ this->mHeight == attachment->GetTexture()->GetHeight();
+ };
+
+ uint32_t attachmentCount = 0;
+ for (uint32_t i : IterateBitSet(mColorAttachmentsSet)) {
+ attachmentCount++;
+ if (!CheckOrSetSize(mColorAttachments[i].view.Get())) {
+ HandleError("Attachment size mismatch");
+ return nullptr;
+ }
+ }
+
+ if (mDepthStencilAttachmentSet) {
+ attachmentCount++;
+ if (!CheckOrSetSize(mDepthStencilAttachment.view.Get())) {
+ HandleError("Attachment size mismatch");
+ return nullptr;
+ }
+ }
+
+ if (attachmentCount == 0) {
+ HandleError("Should have at least one attachment");
+ return nullptr;
+ }
+
+ return mDevice->CreateRenderPassInfo(this);
+ }
+
+ void RenderPassInfoBuilder::SetColorAttachment(uint32_t attachment,
+ TextureViewBase* textureView,
+ nxt::LoadOp loadOp) {
+ if (attachment >= kMaxColorAttachments) {
+ HandleError("Setting color attachment out of bounds");
+ return;
+ }
+
+ if (TextureFormatHasDepthOrStencil(textureView->GetTexture()->GetFormat())) {
+ HandleError("Using depth stencil texture as color attachment");
+ return;
+ }
+
+ mColorAttachmentsSet.set(attachment);
+ mColorAttachments[attachment].loadOp = loadOp;
+ mColorAttachments[attachment].view = textureView;
+ }
+
+ void RenderPassInfoBuilder::SetColorAttachmentClearColor(uint32_t attachment,
+ float clearR,
+ float clearG,
+ float clearB,
+ float clearA) {
+ if (attachment >= kMaxColorAttachments) {
+ HandleError("Setting color attachment out of bounds");
+ return;
+ }
+
+ mColorAttachments[attachment].clearColor[0] = clearR;
+ mColorAttachments[attachment].clearColor[1] = clearG;
+ mColorAttachments[attachment].clearColor[2] = clearB;
+ mColorAttachments[attachment].clearColor[3] = clearA;
+ }
+
+ void RenderPassInfoBuilder::SetDepthStencilAttachment(TextureViewBase* textureView,
+ nxt::LoadOp depthLoadOp,
+ nxt::LoadOp stencilLoadOp) {
+ if (!TextureFormatHasDepthOrStencil(textureView->GetTexture()->GetFormat())) {
+ HandleError("Using color texture as depth stencil attachment");
+ return;
+ }
+
+ mDepthStencilAttachmentSet = true;
+ mDepthStencilAttachment.depthLoadOp = depthLoadOp;
+ mDepthStencilAttachment.stencilLoadOp = stencilLoadOp;
+ mDepthStencilAttachment.view = textureView;
+ }
+
+ void RenderPassInfoBuilder::SetDepthStencilAttachmentClearValue(float clearDepth,
+ uint32_t clearStencil) {
+ mDepthStencilAttachment.clearDepth = clearDepth;
+ mDepthStencilAttachment.clearStencil = clearStencil;
+ }
+
+} // namespace backend
diff --git a/src/backend/RenderPassInfo.h b/src/backend/RenderPassInfo.h
new file mode 100644
index 0000000..09962d4
--- /dev/null
+++ b/src/backend/RenderPassInfo.h
@@ -0,0 +1,109 @@
+// Copyright 2017 The NXT 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 BACKEND_RENDERPASSINFO_H_
+#define BACKEND_RENDERPASSINFO_H_
+
+#include "backend/Builder.h"
+#include "backend/Forward.h"
+#include "backend/RefCounted.h"
+#include "common/Constants.h"
+
+#include "nxt/nxtcpp.h"
+
+#include <array>
+#include <bitset>
+#include <vector>
+
+namespace backend {
+
+ struct RenderPassColorAttachmentInfo {
+ nxt::LoadOp loadOp;
+ std::array<float, 4> clearColor = {{0.0f, 0.0f, 0.0f, 0.0f}};
+ Ref<TextureViewBase> view;
+ };
+
+ struct RenderPassDepthStencilAttachmentInfo {
+ nxt::LoadOp depthLoadOp;
+ nxt::LoadOp stencilLoadOp;
+ float clearDepth = 1.0f;
+ uint32_t clearStencil = 0;
+ Ref<TextureViewBase> view;
+ };
+
+ // RenderPassInfo contains the list of attachments for a renderpass along with data such as the
+ // load operation and the clear values for the attachments.
+
+ class RenderPassInfoBase : public RefCounted {
+ public:
+ RenderPassInfoBase(RenderPassInfoBuilder* builder);
+
+ std::bitset<kMaxColorAttachments> GetColorAttachmentMask() const;
+ bool HasDepthStencilAttachment() const;
+
+ const RenderPassColorAttachmentInfo& GetColorAttachment(uint32_t attachment) const;
+ RenderPassColorAttachmentInfo& GetColorAttachment(uint32_t attachment);
+ const RenderPassDepthStencilAttachmentInfo& GetDepthStencilAttachment() const;
+ RenderPassDepthStencilAttachmentInfo& GetDepthStencilAttachment();
+
+ // All attachments of the render pass have the same size, these return that size.
+ uint32_t GetWidth() const;
+ uint32_t GetHeight() const;
+
+ private:
+ std::bitset<kMaxColorAttachments> mColorAttachmentsSet;
+ std::array<RenderPassColorAttachmentInfo, kMaxColorAttachments> mColorAttachments;
+
+ bool mDepthStencilAttachmentSet;
+ RenderPassDepthStencilAttachmentInfo mDepthStencilAttachment;
+
+ uint32_t mWidth;
+ uint32_t mHeight;
+ };
+
+ class RenderPassInfoBuilder : public Builder<RenderPassInfoBase> {
+ public:
+ RenderPassInfoBuilder(DeviceBase* device);
+
+ // NXT API
+ RenderPassInfoBase* GetResultImpl() override;
+ void SetColorAttachment(uint32_t attachment,
+ TextureViewBase* textureView,
+ nxt::LoadOp loadOp);
+ void SetColorAttachmentClearColor(uint32_t attachment,
+ float clearR,
+ float clearG,
+ float clearB,
+ float clearA);
+ void SetDepthStencilAttachment(TextureViewBase* textureView,
+ nxt::LoadOp depthLoadOp,
+ nxt::LoadOp stencilLoadOp);
+ void SetDepthStencilAttachmentClearValue(float clearDepth, uint32_t clearStencil);
+
+ private:
+ friend class RenderPassInfoBase;
+
+ std::bitset<kMaxColorAttachments> mColorAttachmentsSet;
+ std::array<RenderPassColorAttachmentInfo, kMaxColorAttachments> mColorAttachments;
+
+ bool mDepthStencilAttachmentSet = false;
+ RenderPassDepthStencilAttachmentInfo mDepthStencilAttachment;
+
+ uint32_t mWidth = 0;
+ uint32_t mHeight = 0;
+ };
+
+} // namespace backend
+
+#endif // BACKEND_RENDERPASS_H_
diff --git a/src/backend/RenderPipeline.cpp b/src/backend/RenderPipeline.cpp
index 0c21b71..a3aeba5 100644
--- a/src/backend/RenderPipeline.cpp
+++ b/src/backend/RenderPipeline.cpp
@@ -18,7 +18,8 @@
#include "backend/DepthStencilState.h"
#include "backend/Device.h"
#include "backend/InputState.h"
-#include "backend/RenderPass.h"
+#include "backend/RenderPassInfo.h"
+#include "backend/Texture.h"
#include "common/BitSetIterator.h"
namespace backend {
@@ -32,8 +33,10 @@
mInputState(std::move(builder->mInputState)),
mPrimitiveTopology(builder->mPrimitiveTopology),
mBlendStates(builder->mBlendStates),
- mRenderPass(std::move(builder->mRenderPass)),
- mSubpass(builder->mSubpass) {
+ mColorAttachmentsSet(builder->mColorAttachmentsSet),
+ mColorAttachmentFormats(builder->mColorAttachmentFormats),
+ mDepthStencilFormatSet(builder->mDepthStencilFormatSet),
+ mDepthStencilFormat(builder->mDepthStencilFormat) {
if (GetStageMask() != (nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment)) {
builder->HandleError("Render pipeline should have exactly a vertex and fragment stage");
return;
@@ -47,6 +50,19 @@
builder->HandleError("Pipeline vertex stage uses inputs not in the input state");
return;
}
+
+ // TODO(cwallez@chromium.org): Check against the shader module that the correct color
+ // attachment are set?
+
+ size_t attachmentCount = mColorAttachmentsSet.count();
+ if (mDepthStencilFormatSet) {
+ attachmentCount++;
+ }
+
+ if (attachmentCount == 0) {
+ builder->HandleError("Should have at least one attachment");
+ return;
+ }
}
BlendStateBase* RenderPipelineBase::GetBlendState(uint32_t attachmentSlot) {
@@ -70,12 +86,49 @@
return mPrimitiveTopology;
}
- RenderPassBase* RenderPipelineBase::GetRenderPass() {
- return mRenderPass.Get();
+ std::bitset<kMaxColorAttachments> RenderPipelineBase::GetColorAttachmentsMask() const {
+ return mColorAttachmentsSet;
}
- uint32_t RenderPipelineBase::GetSubPass() {
- return mSubpass;
+ bool RenderPipelineBase::HasDepthStencilAttachment() const {
+ return mDepthStencilFormatSet;
+ }
+
+ nxt::TextureFormat RenderPipelineBase::GetColorAttachmentFormat(uint32_t attachment) const {
+ return mColorAttachmentFormats[attachment];
+ }
+
+ nxt::TextureFormat RenderPipelineBase::GetDepthStencilFormat() const {
+ return mDepthStencilFormat;
+ }
+
+ bool RenderPipelineBase::IsCompatibleWith(const RenderPassInfoBase* renderPass) const {
+ // TODO(cwallez@chromium.org): This is called on every SetPipeline command. Optimize it for
+ // example by caching some "attachment compatibility" object that would make the
+ // compatibility check a single pointer comparison.
+
+ if (renderPass->GetColorAttachmentMask() != mColorAttachmentsSet) {
+ return false;
+ }
+
+ for (uint32_t i : IterateBitSet(mColorAttachmentsSet)) {
+ if (renderPass->GetColorAttachment(i).view->GetTexture()->GetFormat() !=
+ mColorAttachmentFormats[i]) {
+ return false;
+ }
+ }
+
+ if (renderPass->HasDepthStencilAttachment() != mDepthStencilFormatSet) {
+ return false;
+ }
+
+ if (mDepthStencilFormatSet &&
+ (renderPass->GetDepthStencilAttachment().view->GetTexture()->GetFormat() !=
+ mDepthStencilFormat)) {
+ return false;
+ }
+
+ return true;
}
// RenderPipelineBuilder
@@ -101,21 +154,15 @@
mDepthStencilState->Release();
builder->Release();
}
- if (!mRenderPass) {
- HandleError("Pipeline render pass not set");
- return nullptr;
- }
- const auto& subpassInfo = mRenderPass->GetSubpassInfo(mSubpass);
- if ((mBlendStatesSet | subpassInfo.colorAttachmentsSet) !=
- subpassInfo.colorAttachmentsSet) {
+
+ if ((mBlendStatesSet | mColorAttachmentsSet) != mColorAttachmentsSet) {
HandleError("Blend state set on unset color attachment");
return nullptr;
}
// Assign all color attachments without a blend state the default state
// TODO(enga@google.com): Put the default objects in the device
- for (uint32_t attachmentSlot :
- IterateBitSet(subpassInfo.colorAttachmentsSet & ~mBlendStatesSet)) {
+ for (uint32_t attachmentSlot : IterateBitSet(mColorAttachmentsSet & ~mBlendStatesSet)) {
mBlendStates[attachmentSlot] = mDevice->CreateBlendStateBuilder()->GetResult();
// Remove the external ref objects are created with
mBlendStates[attachmentSlot]->Release();
@@ -124,9 +171,20 @@
return mDevice->CreateRenderPipeline(this);
}
+ void RenderPipelineBuilder::SetColorAttachmentFormat(uint32_t attachmentSlot,
+ nxt::TextureFormat format) {
+ if (attachmentSlot >= kMaxColorAttachments) {
+ HandleError("Attachment index out of bounds");
+ return;
+ }
+
+ mColorAttachmentsSet.set(attachmentSlot);
+ mColorAttachmentFormats[attachmentSlot] = format;
+ }
+
void RenderPipelineBuilder::SetColorAttachmentBlendState(uint32_t attachmentSlot,
BlendStateBase* blendState) {
- if (attachmentSlot > mBlendStates.size()) {
+ if (attachmentSlot >= kMaxColorAttachments) {
HandleError("Attachment index out of bounds");
return;
}
@@ -143,6 +201,11 @@
mDepthStencilState = depthStencilState;
}
+ void RenderPipelineBuilder::SetDepthStencilAttachmentFormat(nxt::TextureFormat format) {
+ mDepthStencilFormatSet = true;
+ mDepthStencilFormat = format;
+ }
+
void RenderPipelineBuilder::SetIndexFormat(nxt::IndexFormat format) {
mIndexFormat = format;
}
@@ -155,9 +218,4 @@
mPrimitiveTopology = primitiveTopology;
}
- void RenderPipelineBuilder::SetSubpass(RenderPassBase* renderPass, uint32_t subpass) {
- mRenderPass = renderPass;
- mSubpass = subpass;
- }
-
} // namespace backend
diff --git a/src/backend/RenderPipeline.h b/src/backend/RenderPipeline.h
index 9e34e7a..ad08d18 100644
--- a/src/backend/RenderPipeline.h
+++ b/src/backend/RenderPipeline.h
@@ -19,7 +19,6 @@
#include "backend/DepthStencilState.h"
#include "backend/InputState.h"
#include "backend/Pipeline.h"
-#include "backend/RenderPass.h"
#include "nxt/nxtcpp.h"
@@ -37,8 +36,15 @@
nxt::IndexFormat GetIndexFormat() const;
InputStateBase* GetInputState();
nxt::PrimitiveTopology GetPrimitiveTopology() const;
- RenderPassBase* GetRenderPass();
- uint32_t GetSubPass();
+
+ std::bitset<kMaxColorAttachments> GetColorAttachmentsMask() const;
+ bool HasDepthStencilAttachment() const;
+ nxt::TextureFormat GetColorAttachmentFormat(uint32_t attachment) const;
+ nxt::TextureFormat GetDepthStencilFormat() const;
+
+ // A pipeline can be used in a render pass if its attachment info matches the actual
+ // attachments in the render pass. This returns whether it is the case.
+ bool IsCompatibleWith(const RenderPassInfoBase* renderPass) const;
private:
Ref<DepthStencilStateBase> mDepthStencilState;
@@ -46,8 +52,11 @@
Ref<InputStateBase> mInputState;
nxt::PrimitiveTopology mPrimitiveTopology;
std::array<Ref<BlendStateBase>, kMaxColorAttachments> mBlendStates;
- Ref<RenderPassBase> mRenderPass;
- uint32_t mSubpass;
+
+ std::bitset<kMaxColorAttachments> mColorAttachmentsSet;
+ std::array<nxt::TextureFormat, kMaxColorAttachments> mColorAttachmentFormats;
+ bool mDepthStencilFormatSet = false;
+ nxt::TextureFormat mDepthStencilFormat;
};
class RenderPipelineBuilder : public Builder<RenderPipelineBase>, public PipelineBuilder {
@@ -55,12 +64,13 @@
RenderPipelineBuilder(DeviceBase* device);
// NXT API
+ void SetColorAttachmentFormat(uint32_t attachmentSlot, nxt::TextureFormat format);
void SetColorAttachmentBlendState(uint32_t attachmentSlot, BlendStateBase* blendState);
+ void SetDepthStencilAttachmentFormat(nxt::TextureFormat format);
void SetDepthStencilState(DepthStencilStateBase* depthStencilState);
void SetPrimitiveTopology(nxt::PrimitiveTopology primitiveTopology);
void SetIndexFormat(nxt::IndexFormat format);
void SetInputState(InputStateBase* inputState);
- void SetSubpass(RenderPassBase* renderPass, uint32_t subpass);
private:
friend class RenderPipelineBase;
@@ -75,8 +85,10 @@
nxt::IndexFormat mIndexFormat = nxt::IndexFormat::Uint32;
std::bitset<kMaxColorAttachments> mBlendStatesSet;
std::array<Ref<BlendStateBase>, kMaxColorAttachments> mBlendStates;
- Ref<RenderPassBase> mRenderPass;
- uint32_t mSubpass;
+ std::bitset<kMaxColorAttachments> mColorAttachmentsSet;
+ std::array<nxt::TextureFormat, kMaxColorAttachments> mColorAttachmentFormats;
+ bool mDepthStencilFormatSet = false;
+ nxt::TextureFormat mDepthStencilFormat;
};
} // namespace backend
diff --git a/src/backend/Texture.cpp b/src/backend/Texture.cpp
index 79b71ae..dd64279 100644
--- a/src/backend/Texture.cpp
+++ b/src/backend/Texture.cpp
@@ -267,6 +267,10 @@
TextureViewBase::TextureViewBase(TextureViewBuilder* builder) : mTexture(builder->mTexture) {
}
+ const TextureBase* TextureViewBase::GetTexture() const {
+ return mTexture.Get();
+ }
+
TextureBase* TextureViewBase::GetTexture() {
return mTexture.Get();
}
diff --git a/src/backend/Texture.h b/src/backend/Texture.h
index 97389ef..0d6c01f 100644
--- a/src/backend/Texture.h
+++ b/src/backend/Texture.h
@@ -99,6 +99,7 @@
public:
TextureViewBase(TextureViewBuilder* builder);
+ const TextureBase* GetTexture() const;
TextureBase* GetTexture();
private:
diff --git a/src/backend/ToBackend.h b/src/backend/ToBackend.h
index b8ed161..2478e53 100644
--- a/src/backend/ToBackend.h
+++ b/src/backend/ToBackend.h
@@ -69,11 +69,6 @@
};
template <typename BackendTraits>
- struct ToBackendTraits<FramebufferBase, BackendTraits> {
- using BackendType = typename BackendTraits::FramebufferType;
- };
-
- template <typename BackendTraits>
struct ToBackendTraits<InputStateBase, BackendTraits> {
using BackendType = typename BackendTraits::InputStateType;
};
@@ -89,8 +84,8 @@
};
template <typename BackendTraits>
- struct ToBackendTraits<RenderPassBase, BackendTraits> {
- using BackendType = typename BackendTraits::RenderPassType;
+ struct ToBackendTraits<RenderPassInfoBase, BackendTraits> {
+ using BackendType = typename BackendTraits::RenderPassInfoType;
};
template <typename BackendTraits>
diff --git a/src/backend/d3d12/CommandBufferD3D12.cpp b/src/backend/d3d12/CommandBufferD3D12.cpp
index fd0d4c0..c106537 100644
--- a/src/backend/d3d12/CommandBufferD3D12.cpp
+++ b/src/backend/d3d12/CommandBufferD3D12.cpp
@@ -21,9 +21,9 @@
#include "backend/d3d12/ComputePipelineD3D12.h"
#include "backend/d3d12/D3D12Backend.h"
#include "backend/d3d12/DescriptorHeapAllocator.h"
-#include "backend/d3d12/FramebufferD3D12.h"
#include "backend/d3d12/InputStateD3D12.h"
#include "backend/d3d12/PipelineLayoutD3D12.h"
+#include "backend/d3d12/RenderPassInfoD3D12.h"
#include "backend/d3d12/RenderPipelineD3D12.h"
#include "backend/d3d12/ResourceAllocator.h"
#include "backend/d3d12/SamplerD3D12.h"
@@ -255,10 +255,6 @@
RenderPipeline* lastRenderPipeline = nullptr;
PipelineLayout* lastLayout = nullptr;
- RenderPass* currentRenderPass = nullptr;
- Framebuffer* currentFramebuffer = nullptr;
- uint32_t currentSubpass = 0;
-
while (mCommands.NextCommandId(&type)) {
switch (type) {
case Command::BeginComputePass: {
@@ -269,26 +265,10 @@
case Command::BeginRenderPass: {
BeginRenderPassCmd* beginRenderPassCmd =
mCommands.NextCommand<BeginRenderPassCmd>();
- currentRenderPass = ToBackend(beginRenderPassCmd->renderPass.Get());
- currentFramebuffer = ToBackend(beginRenderPassCmd->framebuffer.Get());
- currentSubpass = 0;
+ RenderPassInfo* info = ToBackend(beginRenderPassCmd->info.Get());
- uint32_t width = currentFramebuffer->GetWidth();
- uint32_t height = currentFramebuffer->GetHeight();
- D3D12_VIEWPORT viewport = {
- 0.f, 0.f, static_cast<float>(width), static_cast<float>(height), 0.f, 1.f};
- D3D12_RECT scissorRect = {0, 0, static_cast<long>(width),
- static_cast<long>(height)};
- commandList->RSSetViewports(1, &viewport);
- commandList->RSSetScissorRects(1, &scissorRect);
- } break;
-
- case Command::BeginRenderSubpass: {
- mCommands.NextCommand<BeginRenderSubpassCmd>();
- const auto& subpass = currentRenderPass->GetSubpassInfo(currentSubpass);
-
- Framebuffer::OMSetRenderTargetArgs args =
- currentFramebuffer->GetSubpassOMSetRenderTargetArgs(currentSubpass);
+ RenderPassInfo::OMSetRenderTargetArgs args =
+ info->GetSubpassOMSetRenderTargetArgs();
if (args.dsv.ptr) {
commandList->OMSetRenderTargets(args.numRTVs, args.RTVs.data(), FALSE,
&args.dsv);
@@ -297,69 +277,77 @@
nullptr);
}
- // Clear framebuffer attachments as needed
+ // Clear framebuffer attachments as needed and transition to render target
- for (unsigned int location : IterateBitSet(subpass.colorAttachmentsSet)) {
- uint32_t attachmentSlot = subpass.colorAttachments[location];
- const auto& attachmentInfo =
- currentRenderPass->GetAttachmentInfo(attachmentSlot);
+ for (uint32_t i : IterateBitSet(info->GetColorAttachmentMask())) {
+ auto& attachmentInfo = info->GetColorAttachment(i);
+ Texture* texture = ToBackend(attachmentInfo.view->GetTexture());
- Texture* texture = ToBackend(
- currentFramebuffer->GetTextureView(attachmentSlot)->GetTexture());
- constexpr auto usage = nxt::TextureUsageBit::OutputAttachment;
// It's already validated that this texture is either frozen to the correct
// usage, or not frozen.
if (!texture->IsFrozen()) {
- texture->TransitionUsageImpl(texture->GetUsage(), usage);
- texture->UpdateUsageInternal(usage);
+ texture->TransitionUsageImpl(texture->GetUsage(),
+ nxt::TextureUsageBit::OutputAttachment);
+ texture->UpdateUsageInternal(nxt::TextureUsageBit::OutputAttachment);
}
- // Only perform load op on first use
- if (attachmentInfo.firstSubpass == currentSubpass) {
- // Load op - color
- if (attachmentInfo.colorLoadOp == nxt::LoadOp::Clear) {
- auto handle = currentFramebuffer->GetRTVDescriptor(attachmentSlot);
- const auto& clear =
- currentFramebuffer->GetClearColor(attachmentSlot);
- commandList->ClearRenderTargetView(handle, clear.color, 0, nullptr);
- }
+ // Load op - color
+ if (attachmentInfo.loadOp == nxt::LoadOp::Clear) {
+ D3D12_CPU_DESCRIPTOR_HANDLE handle = info->GetRTVDescriptor(i);
+ commandList->ClearRenderTargetView(
+ handle, attachmentInfo.clearColor.data(), 0, nullptr);
}
}
- if (subpass.depthStencilAttachmentSet) {
- uint32_t attachmentSlot = subpass.depthStencilAttachment;
- const auto& attachmentInfo =
- currentRenderPass->GetAttachmentInfo(attachmentSlot);
+ if (info->HasDepthStencilAttachment()) {
+ auto& attachmentInfo = info->GetDepthStencilAttachment();
+ Texture* texture = ToBackend(attachmentInfo.view->GetTexture());
- // Only perform load op on first use
- if (attachmentInfo.firstSubpass == currentSubpass) {
- // Load op - depth/stencil
- bool doDepthClear = TextureFormatHasDepth(attachmentInfo.format) &&
- (attachmentInfo.depthLoadOp == nxt::LoadOp::Clear);
- bool doStencilClear =
- TextureFormatHasStencil(attachmentInfo.format) &&
- (attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear);
+ // It's already validated that this texture is either frozen to the correct
+ // usage, or not frozen.
+ if (!texture->IsFrozen()) {
+ texture->TransitionUsageImpl(texture->GetUsage(),
+ nxt::TextureUsageBit::OutputAttachment);
+ texture->UpdateUsageInternal(nxt::TextureUsageBit::OutputAttachment);
+ }
- D3D12_CLEAR_FLAGS clearFlags = {};
- if (doDepthClear) {
- clearFlags |= D3D12_CLEAR_FLAG_DEPTH;
- }
- if (doStencilClear) {
- clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
- }
- if (clearFlags) {
- auto handle = currentFramebuffer->GetDSVDescriptor(attachmentSlot);
- const auto& clear =
- currentFramebuffer->GetClearDepthStencil(attachmentSlot);
- // TODO(kainino@chromium.org): investigate: should the NXT clear
- // stencil type be uint8_t?
- uint8_t clearStencil = static_cast<uint8_t>(clear.stencil);
- commandList->ClearDepthStencilView(handle, clearFlags, clear.depth,
- clearStencil, 0, nullptr);
- }
+ // Load op - depth/stencil
+ bool doDepthClear = TextureFormatHasDepth(texture->GetFormat()) &&
+ (attachmentInfo.depthLoadOp == nxt::LoadOp::Clear);
+ bool doStencilClear = TextureFormatHasStencil(texture->GetFormat()) &&
+ (attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear);
+
+ D3D12_CLEAR_FLAGS clearFlags = {};
+ if (doDepthClear) {
+ clearFlags |= D3D12_CLEAR_FLAG_DEPTH;
+ }
+ if (doStencilClear) {
+ clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
+ }
+
+ if (clearFlags) {
+ auto handle = info->GetDSVDescriptor();
+ // TODO(kainino@chromium.org): investigate: should the NXT clear
+ // stencil type be uint8_t?
+ uint8_t clearStencil =
+ static_cast<uint8_t>(attachmentInfo.clearStencil);
+ commandList->ClearDepthStencilView(handle, clearFlags,
+ attachmentInfo.clearDepth,
+ clearStencil, 0, nullptr);
}
}
+ // Set up the default render pass dynamic state
+
+ uint32_t width = info->GetWidth();
+ uint32_t height = info->GetHeight();
+ D3D12_VIEWPORT viewport = {
+ 0.f, 0.f, static_cast<float>(width), static_cast<float>(height), 0.f, 1.f};
+ D3D12_RECT scissorRect = {0, 0, static_cast<long>(width),
+ static_cast<long>(height)};
+ commandList->RSSetViewports(1, &viewport);
+ commandList->RSSetScissorRects(1, &scissorRect);
+
static constexpr std::array<float, 4> defaultBlendFactor = {0, 0, 0, 0};
commandList->OMSetBlendFactor(&defaultBlendFactor[0]);
} break;
@@ -485,11 +473,6 @@
mCommands.NextCommand<EndRenderPassCmd>();
} break;
- case Command::EndRenderSubpass: {
- mCommands.NextCommand<EndRenderSubpassCmd>();
- currentSubpass += 1;
- } break;
-
case Command::SetComputePipeline: {
SetComputePipelineCmd* cmd = mCommands.NextCommand<SetComputePipelineCmd>();
ComputePipeline* pipeline = ToBackend(cmd->pipeline).Get();
diff --git a/src/backend/d3d12/D3D12Backend.cpp b/src/backend/d3d12/D3D12Backend.cpp
index 0648b67..eea2af5 100644
--- a/src/backend/d3d12/D3D12Backend.cpp
+++ b/src/backend/d3d12/D3D12Backend.cpp
@@ -23,11 +23,11 @@
#include "backend/d3d12/ComputePipelineD3D12.h"
#include "backend/d3d12/DepthStencilStateD3D12.h"
#include "backend/d3d12/DescriptorHeapAllocator.h"
-#include "backend/d3d12/FramebufferD3D12.h"
#include "backend/d3d12/InputStateD3D12.h"
#include "backend/d3d12/NativeSwapChainImplD3D12.h"
#include "backend/d3d12/PipelineLayoutD3D12.h"
#include "backend/d3d12/QueueD3D12.h"
+#include "backend/d3d12/RenderPassInfoD3D12.h"
#include "backend/d3d12/RenderPipelineD3D12.h"
#include "backend/d3d12/ResourceAllocator.h"
#include "backend/d3d12/ResourceUploader.h"
@@ -282,9 +282,6 @@
DepthStencilStateBase* Device::CreateDepthStencilState(DepthStencilStateBuilder* builder) {
return new DepthStencilState(this, builder);
}
- FramebufferBase* Device::CreateFramebuffer(FramebufferBuilder* builder) {
- return new Framebuffer(this, builder);
- }
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
return new InputState(this, builder);
}
@@ -294,8 +291,8 @@
QueueBase* Device::CreateQueue(QueueBuilder* builder) {
return new Queue(this, builder);
}
- RenderPassBase* Device::CreateRenderPass(RenderPassBuilder* builder) {
- return new RenderPass(this, builder);
+ RenderPassInfoBase* Device::CreateRenderPassInfo(RenderPassInfoBuilder* builder) {
+ return new RenderPassInfo(this, builder);
}
RenderPipelineBase* Device::CreateRenderPipeline(RenderPipelineBuilder* builder) {
return new RenderPipeline(builder);
@@ -316,10 +313,4 @@
return new TextureView(builder);
}
- // RenderPass
-
- RenderPass::RenderPass(Device* device, RenderPassBuilder* builder)
- : RenderPassBase(builder), mDevice(device) {
- }
-
}} // namespace backend::d3d12
diff --git a/src/backend/d3d12/D3D12Backend.h b/src/backend/d3d12/D3D12Backend.h
index c76b050..fd13777 100644
--- a/src/backend/d3d12/D3D12Backend.h
+++ b/src/backend/d3d12/D3D12Backend.h
@@ -19,7 +19,6 @@
#include "backend/DepthStencilState.h"
#include "backend/Device.h"
-#include "backend/RenderPass.h"
#include "backend/ToBackend.h"
#include "backend/d3d12/d3d12_platform.h"
#include "common/SerialQueue.h"
@@ -35,11 +34,10 @@
class ComputePipeline;
class DepthStencilState;
class Device;
- class Framebuffer;
class InputState;
class PipelineLayout;
class Queue;
- class RenderPass;
+ class RenderPassInfo;
class RenderPipeline;
class Sampler;
class ShaderModule;
@@ -63,11 +61,10 @@
using ComputePipelineType = ComputePipeline;
using DepthStencilStateType = DepthStencilState;
using DeviceType = Device;
- using FramebufferType = Framebuffer;
using InputStateType = InputState;
using PipelineLayoutType = PipelineLayout;
using QueueType = Queue;
- using RenderPassType = RenderPass;
+ using RenderPassInfoType = RenderPassInfo;
using RenderPipelineType = RenderPipeline;
using SamplerType = Sampler;
using ShaderModuleType = ShaderModule;
@@ -97,11 +94,10 @@
CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) override;
ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override;
DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
- FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) override;
InputStateBase* CreateInputState(InputStateBuilder* builder) override;
PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override;
QueueBase* CreateQueue(QueueBuilder* builder) override;
- RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) override;
+ RenderPassInfoBase* CreateRenderPassInfo(RenderPassInfoBuilder* builder) override;
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
SamplerBase* CreateSampler(SamplerBuilder* builder) override;
ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override;
@@ -155,14 +151,6 @@
SerialQueue<ComPtr<IUnknown>> mUsedComObjectRefs;
};
- class RenderPass : public RenderPassBase {
- public:
- RenderPass(Device* device, RenderPassBuilder* builder);
-
- private:
- Device* mDevice;
- };
-
}} // namespace backend::d3d12
#endif // BACKEND_D3D12_D3D12BACKEND_H_
diff --git a/src/backend/d3d12/FramebufferD3D12.cpp b/src/backend/d3d12/FramebufferD3D12.cpp
deleted file mode 100644
index 9b15d0d..0000000
--- a/src/backend/d3d12/FramebufferD3D12.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2017 The NXT 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 "backend/d3d12/FramebufferD3D12.h"
-
-#include "backend/d3d12/D3D12Backend.h"
-#include "backend/d3d12/TextureD3D12.h"
-#include "common/BitSetIterator.h"
-
-namespace backend { namespace d3d12 {
-
- Framebuffer::Framebuffer(Device* device, FramebufferBuilder* builder)
- : FramebufferBase(builder), mDevice(device) {
- RenderPass* renderPass = ToBackend(GetRenderPass());
-
- uint32_t rtvCount = 0, dsvCount = 0;
- mAttachmentHeapIndices.resize(renderPass->GetAttachmentCount());
- for (uint32_t attachment = 0; attachment < renderPass->GetAttachmentCount(); ++attachment) {
- auto* textureView = GetTextureView(attachment);
- auto format = textureView->GetTexture()->GetFormat();
- if (TextureFormatHasDepth(format) || TextureFormatHasStencil(format)) {
- mAttachmentHeapIndices[attachment] = dsvCount++;
- } else {
- mAttachmentHeapIndices[attachment] = rtvCount++;
- }
- }
-
- if (rtvCount) {
- mRtvHeap = device->GetDescriptorHeapAllocator()->AllocateCPUHeap(
- D3D12_DESCRIPTOR_HEAP_TYPE_RTV, rtvCount);
- }
- if (dsvCount) {
- mDsvHeap = device->GetDescriptorHeapAllocator()->AllocateCPUHeap(
- D3D12_DESCRIPTOR_HEAP_TYPE_DSV, dsvCount);
- }
-
- for (uint32_t attachment = 0; attachment < renderPass->GetAttachmentCount(); ++attachment) {
- uint32_t heapIndex = mAttachmentHeapIndices[attachment];
- auto* textureView = GetTextureView(attachment);
-
- ComPtr<ID3D12Resource> texture =
- ToBackend(textureView->GetTexture())->GetD3D12Resource();
- auto format = textureView->GetTexture()->GetFormat();
- if (TextureFormatHasDepth(format) || TextureFormatHasStencil(format)) {
- D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = mDsvHeap.GetCPUHandle(heapIndex);
- D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = ToBackend(textureView)->GetDSVDescriptor();
- device->GetD3D12Device()->CreateDepthStencilView(texture.Get(), &dsvDesc,
- dsvHandle);
- } else {
- D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = mRtvHeap.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);
- OMSetRenderTargetArgs args = {};
-
- for (uint32_t location : IterateBitSet(subpassInfo.colorAttachmentsSet)) {
- uint32_t slot = subpassInfo.colorAttachments[location];
- args.RTVs[args.numRTVs] = GetRTVDescriptor(slot);
- args.numRTVs++;
- }
- if (subpassInfo.depthStencilAttachmentSet) {
- uint32_t slot = subpassInfo.depthStencilAttachment;
- args.dsv = GetDSVDescriptor(slot);
- }
-
- return args;
- }
-
- D3D12_CPU_DESCRIPTOR_HANDLE Framebuffer::GetRTVDescriptor(uint32_t attachmentSlot) {
- return mRtvHeap.GetCPUHandle(mAttachmentHeapIndices[attachmentSlot]);
- }
-
- D3D12_CPU_DESCRIPTOR_HANDLE Framebuffer::GetDSVDescriptor(uint32_t attachmentSlot) {
- return mDsvHeap.GetCPUHandle(mAttachmentHeapIndices[attachmentSlot]);
- }
-
-}} // namespace backend::d3d12
diff --git a/src/backend/d3d12/GeneratedCodeIncludes.h b/src/backend/d3d12/GeneratedCodeIncludes.h
index dbd0559..d54873a 100644
--- a/src/backend/d3d12/GeneratedCodeIncludes.h
+++ b/src/backend/d3d12/GeneratedCodeIncludes.h
@@ -20,10 +20,10 @@
#include "backend/d3d12/ComputePipelineD3D12.h"
#include "backend/d3d12/D3D12Backend.h"
#include "backend/d3d12/DepthStencilStateD3D12.h"
-#include "backend/d3d12/FramebufferD3D12.h"
#include "backend/d3d12/InputStateD3D12.h"
#include "backend/d3d12/PipelineLayoutD3D12.h"
#include "backend/d3d12/QueueD3D12.h"
+#include "backend/d3d12/RenderPassInfoD3D12.h"
#include "backend/d3d12/RenderPipelineD3D12.h"
#include "backend/d3d12/SamplerD3D12.h"
#include "backend/d3d12/ShaderModuleD3D12.h"
diff --git a/src/backend/d3d12/RenderPassInfoD3D12.cpp b/src/backend/d3d12/RenderPassInfoD3D12.cpp
new file mode 100644
index 0000000..c4a9b8e
--- /dev/null
+++ b/src/backend/d3d12/RenderPassInfoD3D12.cpp
@@ -0,0 +1,81 @@
+// Copyright 2017 The NXT 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 "backend/d3d12/RenderPassInfoD3D12.h"
+
+#include "backend/d3d12/D3D12Backend.h"
+#include "backend/d3d12/TextureD3D12.h"
+#include "common/BitSetIterator.h"
+
+namespace backend { namespace d3d12 {
+
+ RenderPassInfo::RenderPassInfo(Device* device, RenderPassInfoBuilder* builder)
+ : RenderPassInfoBase(builder), mDevice(device) {
+ // Get and fill an RTV heap with the color attachments
+ uint32_t colorAttachmentCount = static_cast<uint32_t>(GetColorAttachmentMask().count());
+ if (colorAttachmentCount != 0) {
+ mRtvHeap = device->GetDescriptorHeapAllocator()->AllocateCPUHeap(
+ D3D12_DESCRIPTOR_HEAP_TYPE_RTV, colorAttachmentCount);
+
+ for (uint32_t i : IterateBitSet(GetColorAttachmentMask())) {
+ TextureView* view = ToBackend(GetColorAttachment(i).view.Get());
+ ComPtr<ID3D12Resource> resource = ToBackend(view->GetTexture())->GetD3D12Resource();
+
+ D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = mRtvHeap.GetCPUHandle(i);
+ D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = view->GetRTVDescriptor();
+ device->GetD3D12Device()->CreateRenderTargetView(resource.Get(), &rtvDesc,
+ rtvHandle);
+ }
+ }
+
+ // Get and fill a DSV heap with the depth stencil attachment
+ if (HasDepthStencilAttachment()) {
+ mDsvHeap = device->GetDescriptorHeapAllocator()->AllocateCPUHeap(
+ D3D12_DESCRIPTOR_HEAP_TYPE_DSV, 1);
+
+ TextureView* view = ToBackend(GetDepthStencilAttachment().view.Get());
+ ComPtr<ID3D12Resource> resource = ToBackend(view->GetTexture())->GetD3D12Resource();
+
+ D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = mDsvHeap.GetCPUHandle(0);
+ D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = view->GetDSVDescriptor();
+ device->GetD3D12Device()->CreateDepthStencilView(resource.Get(), &dsvDesc, dsvHandle);
+ }
+ }
+
+ RenderPassInfo::OMSetRenderTargetArgs RenderPassInfo::GetSubpassOMSetRenderTargetArgs() {
+ OMSetRenderTargetArgs args = {};
+
+ size_t rtvIndex = 0;
+ for (uint32_t i : IterateBitSet(GetColorAttachmentMask())) {
+ args.RTVs[rtvIndex] = GetRTVDescriptor(i);
+ rtvIndex++;
+ }
+ args.numRTVs = rtvIndex;
+
+ if (HasDepthStencilAttachment()) {
+ args.dsv = GetDSVDescriptor();
+ }
+
+ return args;
+ }
+
+ D3D12_CPU_DESCRIPTOR_HANDLE RenderPassInfo::GetRTVDescriptor(uint32_t attachmentSlot) {
+ return mRtvHeap.GetCPUHandle(attachmentSlot);
+ }
+
+ D3D12_CPU_DESCRIPTOR_HANDLE RenderPassInfo::GetDSVDescriptor() {
+ return mDsvHeap.GetCPUHandle(0);
+ }
+
+}} // namespace backend::d3d12
diff --git a/src/backend/d3d12/FramebufferD3D12.h b/src/backend/d3d12/RenderPassInfoD3D12.h
similarity index 69%
rename from src/backend/d3d12/FramebufferD3D12.h
rename to src/backend/d3d12/RenderPassInfoD3D12.h
index 4393b4c..fcd7011 100644
--- a/src/backend/d3d12/FramebufferD3D12.h
+++ b/src/backend/d3d12/RenderPassInfoD3D12.h
@@ -12,10 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef BACKEND_D3D12_FRAMEBUFFERD3D12_H_
-#define BACKEND_D3D12_FRAMEBUFFERD3D12_H_
+#ifndef BACKEND_D3D12_RENDERPASSINFOD3D12_H_
+#define BACKEND_D3D12_RENDERPASSINFOD3D12_H_
-#include "backend/Framebuffer.h"
+#include "backend/RenderPassInfo.h"
#include "backend/d3d12/DescriptorHeapAllocator.h"
#include "backend/d3d12/d3d12_platform.h"
@@ -28,7 +28,7 @@
class Device;
- class Framebuffer : public FramebufferBase {
+ class RenderPassInfo : public RenderPassInfoBase {
public:
struct OMSetRenderTargetArgs {
unsigned int numRTVs = 0;
@@ -36,20 +36,17 @@
D3D12_CPU_DESCRIPTOR_HANDLE dsv = {};
};
- Framebuffer(Device* device, FramebufferBuilder* builder);
- OMSetRenderTargetArgs GetSubpassOMSetRenderTargetArgs(uint32_t subpassIndex);
+ RenderPassInfo(Device* device, RenderPassInfoBuilder* builder);
+ OMSetRenderTargetArgs GetSubpassOMSetRenderTargetArgs();
D3D12_CPU_DESCRIPTOR_HANDLE GetRTVDescriptor(uint32_t attachmentSlot);
- D3D12_CPU_DESCRIPTOR_HANDLE GetDSVDescriptor(uint32_t attachmentSlot);
+ D3D12_CPU_DESCRIPTOR_HANDLE GetDSVDescriptor();
private:
Device* mDevice = nullptr;
DescriptorHeapHandle mRtvHeap = {};
DescriptorHeapHandle mDsvHeap = {};
-
- // Indices into either the RTV or DSV heap, depending on texture format.
- std::vector<uint32_t> mAttachmentHeapIndices;
};
}} // namespace backend::d3d12
-#endif // BACKEND_D3D12_FRAMEBUFFERD3D12_H_
+#endif // BACKEND_D3D12_RENDERPASSINFOD3D12_H_
diff --git a/src/backend/d3d12/RenderPipelineD3D12.cpp b/src/backend/d3d12/RenderPipelineD3D12.cpp
index f093722..358df42 100644
--- a/src/backend/d3d12/RenderPipelineD3D12.cpp
+++ b/src/backend/d3d12/RenderPipelineD3D12.cpp
@@ -136,26 +136,16 @@
descriptor.RasterizerState.ForcedSampleCount = 0;
descriptor.RasterizerState.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
- RenderPass* renderPass = ToBackend(GetRenderPass());
- auto& subpassInfo = renderPass->GetSubpassInfo(GetSubPass());
-
- if (subpassInfo.depthStencilAttachmentSet) {
- const auto& attachmentInfo =
- renderPass->GetAttachmentInfo(subpassInfo.depthStencilAttachment);
- descriptor.DSVFormat = D3D12TextureFormat(attachmentInfo.format);
+ if (HasDepthStencilAttachment()) {
+ descriptor.DSVFormat = D3D12TextureFormat(GetDepthStencilFormat());
}
- unsigned int attachmentCount = 0;
- for (unsigned int attachmentSlot : IterateBitSet(subpassInfo.colorAttachmentsSet)) {
- uint32_t attachment = subpassInfo.colorAttachments[attachmentSlot];
- const auto& attachmentInfo = renderPass->GetAttachmentInfo(attachment);
-
- descriptor.RTVFormats[attachmentSlot] = D3D12TextureFormat(attachmentInfo.format);
- descriptor.BlendState.RenderTarget[attachmentSlot] =
- ToBackend(GetBlendState(attachmentSlot))->GetD3D12BlendDesc();
- attachmentCount = attachmentSlot + 1;
+ for (uint32_t i : IterateBitSet(GetColorAttachmentsMask())) {
+ descriptor.RTVFormats[i] = D3D12TextureFormat(GetColorAttachmentFormat(i));
+ descriptor.BlendState.RenderTarget[i] =
+ ToBackend(GetBlendState(i))->GetD3D12BlendDesc();
}
- descriptor.NumRenderTargets = attachmentCount;
+ descriptor.NumRenderTargets = static_cast<uint32_t>(GetColorAttachmentsMask().count());
descriptor.BlendState.AlphaToCoverageEnable = FALSE;
descriptor.BlendState.IndependentBlendEnable = TRUE;
diff --git a/src/backend/metal/CommandBufferMTL.mm b/src/backend/metal/CommandBufferMTL.mm
index ef5045f..e26efbd 100644
--- a/src/backend/metal/CommandBufferMTL.mm
+++ b/src/backend/metal/CommandBufferMTL.mm
@@ -35,9 +35,6 @@
id<MTLComputeCommandEncoder> compute = nil;
id<MTLRenderCommandEncoder> render = nil;
- RenderPass* currentRenderPass = nullptr;
- Framebuffer* currentFramebuffer = nullptr;
-
void EnsureNoBlitEncoder() {
ASSERT(render == nil);
ASSERT(compute == nil);
@@ -67,59 +64,46 @@
compute = nil; // This will be autoreleased.
}
- void BeginSubpass(id<MTLCommandBuffer> commandBuffer, uint32_t subpass) {
- ASSERT(currentRenderPass);
+ void BeginRenderPass(id<MTLCommandBuffer> commandBuffer, RenderPassInfo* info) {
if (render != nil) {
[render endEncoding];
render = nil; // This will be autoreleased.
}
- const auto& info = currentRenderPass->GetSubpassInfo(subpass);
-
MTLRenderPassDescriptor* descriptor =
[MTLRenderPassDescriptor renderPassDescriptor];
- for (unsigned int location : IterateBitSet(info.colorAttachmentsSet)) {
- uint32_t attachment = info.colorAttachments[location];
- const auto& attachmentInfo = currentRenderPass->GetAttachmentInfo(attachment);
- auto textureView = currentFramebuffer->GetTextureView(attachment);
- auto texture = ToBackend(textureView->GetTexture())->GetMTLTexture();
+ for (uint32_t i : IterateBitSet(info->GetColorAttachmentMask())) {
+ auto& attachmentInfo = info->GetColorAttachment(i);
- bool isFirstUse = attachmentInfo.firstSubpass == subpass;
- bool shouldClearOnFirstUse = attachmentInfo.colorLoadOp == nxt::LoadOp::Clear;
- if (isFirstUse && shouldClearOnFirstUse) {
- auto clearValue = currentFramebuffer->GetClearColor(location);
- descriptor.colorAttachments[location].loadAction = MTLLoadActionClear;
- descriptor.colorAttachments[location].clearColor =
- MTLClearColorMake(clearValue.color[0], clearValue.color[1],
- clearValue.color[2], clearValue.color[3]);
+ if (attachmentInfo.loadOp == nxt::LoadOp::Clear) {
+ descriptor.colorAttachments[i].loadAction = MTLLoadActionClear;
+ descriptor.colorAttachments[i].clearColor = MTLClearColorMake(
+ attachmentInfo.clearColor[0], attachmentInfo.clearColor[1],
+ attachmentInfo.clearColor[2], attachmentInfo.clearColor[3]);
} else {
- descriptor.colorAttachments[location].loadAction = MTLLoadActionLoad;
+ descriptor.colorAttachments[i].loadAction = MTLLoadActionLoad;
}
- descriptor.colorAttachments[location].texture = texture;
- descriptor.colorAttachments[location].storeAction = MTLStoreActionStore;
+ descriptor.colorAttachments[i].texture =
+ ToBackend(attachmentInfo.view->GetTexture())->GetMTLTexture();
+ descriptor.colorAttachments[i].storeAction = MTLStoreActionStore;
}
- if (info.depthStencilAttachmentSet) {
- uint32_t attachment = info.depthStencilAttachment;
- const auto& attachmentInfo = currentRenderPass->GetAttachmentInfo(attachment);
- auto textureView = currentFramebuffer->GetTextureView(attachment);
- id<MTLTexture> texture = ToBackend(textureView->GetTexture())->GetMTLTexture();
- nxt::TextureFormat format = textureView->GetTexture()->GetFormat();
+ if (info->HasDepthStencilAttachment()) {
+ auto& attachmentInfo = info->GetDepthStencilAttachment();
- bool isFirstUse = attachmentInfo.firstSubpass == subpass;
- const auto& clearValues = currentFramebuffer->GetClearDepthStencil(attachment);
+ id<MTLTexture> texture =
+ ToBackend(attachmentInfo.view->GetTexture())->GetMTLTexture();
+ nxt::TextureFormat format = attachmentInfo.view->GetTexture()->GetFormat();
if (TextureFormatHasDepth(format)) {
descriptor.depthAttachment.texture = texture;
descriptor.depthAttachment.storeAction = MTLStoreActionStore;
- bool shouldClearDepthOnFirstUse =
- attachmentInfo.depthLoadOp == nxt::LoadOp::Clear;
- if (isFirstUse && shouldClearDepthOnFirstUse) {
+ if (attachmentInfo.depthLoadOp == nxt::LoadOp::Clear) {
descriptor.depthAttachment.loadAction = MTLLoadActionClear;
- descriptor.depthAttachment.clearDepth = clearValues.depth;
+ descriptor.depthAttachment.clearDepth = attachmentInfo.clearDepth;
} else {
descriptor.depthAttachment.loadAction = MTLLoadActionLoad;
}
@@ -129,11 +113,9 @@
descriptor.stencilAttachment.texture = texture;
descriptor.stencilAttachment.storeAction = MTLStoreActionStore;
- bool shouldClearStencilOnFirstUse =
- attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear;
- if (isFirstUse && shouldClearStencilOnFirstUse) {
+ if (attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear) {
descriptor.stencilAttachment.loadAction = MTLLoadActionClear;
- descriptor.stencilAttachment.clearStencil = clearValues.stencil;
+ descriptor.stencilAttachment.clearStencil = attachmentInfo.clearStencil;
} else {
descriptor.stencilAttachment.loadAction = MTLLoadActionLoad;
}
@@ -144,7 +126,7 @@
// TODO(cwallez@chromium.org): does any state need to be reset?
}
- void EndSubpass() {
+ void EndRenderPass() {
ASSERT(render != nil);
[render endEncoding];
render = nil; // This will be autoreleased.
@@ -174,7 +156,6 @@
PerStage<std::array<uint32_t, kMaxPushConstants>> pushConstants;
- uint32_t currentSubpass = 0;
while (mCommands.NextCommandId(&type)) {
switch (type) {
case Command::BeginComputePass: {
@@ -190,15 +171,11 @@
case Command::BeginRenderPass: {
BeginRenderPassCmd* beginRenderPassCmd =
mCommands.NextCommand<BeginRenderPassCmd>();
- encoders.currentRenderPass = ToBackend(beginRenderPassCmd->renderPass.Get());
- encoders.currentFramebuffer = ToBackend(beginRenderPassCmd->framebuffer.Get());
- encoders.EnsureNoBlitEncoder();
- currentSubpass = 0;
- } break;
- case Command::BeginRenderSubpass: {
- mCommands.NextCommand<BeginRenderSubpassCmd>();
- encoders.BeginSubpass(commandBuffer, currentSubpass);
+ RenderPassInfo* info = ToBackend(beginRenderPassCmd->info.Get());
+
+ encoders.EnsureNoBlitEncoder();
+ encoders.BeginRenderPass(commandBuffer, info);
pushConstants[nxt::ShaderStage::Vertex].fill(0);
pushConstants[nxt::ShaderStage::Fragment].fill(0);
@@ -325,12 +302,7 @@
case Command::EndRenderPass: {
mCommands.NextCommand<EndRenderPassCmd>();
- } break;
-
- case Command::EndRenderSubpass: {
- mCommands.NextCommand<EndRenderSubpassCmd>();
- encoders.EndSubpass();
- currentSubpass += 1;
+ encoders.EndRenderPass();
} break;
case Command::SetComputePipeline: {
diff --git a/src/backend/metal/MetalBackend.h b/src/backend/metal/MetalBackend.h
index f32e791..2b0e330 100644
--- a/src/backend/metal/MetalBackend.h
+++ b/src/backend/metal/MetalBackend.h
@@ -20,9 +20,8 @@
#include "backend/BindGroup.h"
#include "backend/BindGroupLayout.h"
#include "backend/Device.h"
-#include "backend/Framebuffer.h"
#include "backend/Queue.h"
-#include "backend/RenderPass.h"
+#include "backend/RenderPassInfo.h"
#include "backend/ToBackend.h"
#include "common/Serial.h"
@@ -45,7 +44,7 @@
class InputState;
class PipelineLayout;
class Queue;
- class RenderPass;
+ class RenderPassInfo;
class RenderPipeline;
class Sampler;
class ShaderModule;
@@ -63,11 +62,10 @@
using ComputePipelineType = ComputePipeline;
using DepthStencilStateType = DepthStencilState;
using DeviceType = Device;
- using FramebufferType = Framebuffer;
using InputStateType = InputState;
using PipelineLayoutType = PipelineLayout;
using QueueType = Queue;
- using RenderPassType = RenderPass;
+ using RenderPassInfoType = RenderPassInfo;
using RenderPipelineType = RenderPipeline;
using SamplerType = Sampler;
using ShaderModuleType = ShaderModule;
@@ -98,10 +96,9 @@
ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override;
DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
InputStateBase* CreateInputState(InputStateBuilder* builder) override;
- FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) override;
PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override;
QueueBase* CreateQueue(QueueBuilder* builder) override;
- RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) override;
+ RenderPassInfoBase* CreateRenderPassInfo(RenderPassInfoBuilder* builder) override;
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
SamplerBase* CreateSampler(SamplerBuilder* builder) override;
ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override;
@@ -143,12 +140,6 @@
BindGroupLayout(BindGroupLayoutBuilder* builder);
};
- class Framebuffer : public FramebufferBase {
- public:
- Framebuffer(FramebufferBuilder* builder);
- ~Framebuffer();
- };
-
class Queue : public QueueBase {
public:
Queue(QueueBuilder* builder);
@@ -163,10 +154,10 @@
id<MTLCommandQueue> mCommandQueue = nil;
};
- class RenderPass : public RenderPassBase {
+ class RenderPassInfo : public RenderPassInfoBase {
public:
- RenderPass(RenderPassBuilder* builder);
- ~RenderPass();
+ RenderPassInfo(RenderPassInfoBuilder* builder);
+ ~RenderPassInfo();
};
}} // namespace backend::metal
diff --git a/src/backend/metal/MetalBackend.mm b/src/backend/metal/MetalBackend.mm
index 68982b4..40d5ce9 100644
--- a/src/backend/metal/MetalBackend.mm
+++ b/src/backend/metal/MetalBackend.mm
@@ -101,9 +101,6 @@
DepthStencilStateBase* Device::CreateDepthStencilState(DepthStencilStateBuilder* builder) {
return new DepthStencilState(builder);
}
- FramebufferBase* Device::CreateFramebuffer(FramebufferBuilder* builder) {
- return new Framebuffer(builder);
- }
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
return new InputState(builder);
}
@@ -113,8 +110,8 @@
QueueBase* Device::CreateQueue(QueueBuilder* builder) {
return new Queue(builder);
}
- RenderPassBase* Device::CreateRenderPass(RenderPassBuilder* builder) {
- return new RenderPass(builder);
+ RenderPassInfoBase* Device::CreateRenderPassInfo(RenderPassInfoBuilder* builder) {
+ return new RenderPassInfo(builder);
}
RenderPipelineBase* Device::CreateRenderPipeline(RenderPipelineBuilder* builder) {
return new RenderPipeline(builder);
@@ -202,14 +199,6 @@
: BindGroupLayoutBase(builder) {
}
- // Framebuffer
-
- Framebuffer::Framebuffer(FramebufferBuilder* builder) : FramebufferBase(builder) {
- }
-
- Framebuffer::~Framebuffer() {
- }
-
// Queue
Queue::Queue(QueueBuilder* builder) : QueueBase(builder) {
@@ -240,10 +229,10 @@
// RenderPass
- RenderPass::RenderPass(RenderPassBuilder* builder) : RenderPassBase(builder) {
+ RenderPassInfo::RenderPassInfo(RenderPassInfoBuilder* builder) : RenderPassInfoBase(builder) {
}
- RenderPass::~RenderPass() {
+ RenderPassInfo::~RenderPassInfo() {
}
}} // namespace backend::metal
diff --git a/src/backend/metal/RenderPipelineMTL.mm b/src/backend/metal/RenderPipelineMTL.mm
index c21accc..af564c8 100644
--- a/src/backend/metal/RenderPipelineMTL.mm
+++ b/src/backend/metal/RenderPipelineMTL.mm
@@ -92,24 +92,17 @@
}
}
- RenderPass* renderPass = ToBackend(GetRenderPass());
- auto& subpassInfo = renderPass->GetSubpassInfo(GetSubPass());
-
- if (subpassInfo.depthStencilAttachmentSet) {
- const auto& attachmentInfo =
- renderPass->GetAttachmentInfo(subpassInfo.depthStencilAttachment);
- descriptor.depthAttachmentPixelFormat = MetalPixelFormat(attachmentInfo.format);
- descriptor.stencilAttachmentPixelFormat = MetalPixelFormat(attachmentInfo.format);
+ if (HasDepthStencilAttachment()) {
+ // TODO(kainino@chromium.org): Handle depth-only and stencil-only formats.
+ nxt::TextureFormat depthStencilFormat = GetDepthStencilFormat();
+ descriptor.depthAttachmentPixelFormat = MetalPixelFormat(depthStencilFormat);
+ descriptor.stencilAttachmentPixelFormat = MetalPixelFormat(depthStencilFormat);
}
- for (unsigned int attachmentSlot : IterateBitSet(subpassInfo.colorAttachmentsSet)) {
- uint32_t attachment = subpassInfo.colorAttachments[attachmentSlot];
- const auto& attachmentInfo = renderPass->GetAttachmentInfo(attachment);
-
- descriptor.colorAttachments[attachmentSlot].pixelFormat =
- MetalPixelFormat(attachmentInfo.format);
- ToBackend(GetBlendState(attachmentSlot))
- ->ApplyBlendState(descriptor.colorAttachments[attachmentSlot]);
+ for (uint32_t i : IterateBitSet(GetColorAttachmentsMask())) {
+ descriptor.colorAttachments[i].pixelFormat =
+ MetalPixelFormat(GetColorAttachmentFormat(i));
+ ToBackend(GetBlendState(i))->ApplyBlendState(descriptor.colorAttachments[i]);
}
descriptor.inputPrimitiveTopology = MTLInputPrimitiveTopology(GetPrimitiveTopology());
diff --git a/src/backend/null/NullBackend.cpp b/src/backend/null/NullBackend.cpp
index 71ac1a8..beefc9e 100644
--- a/src/backend/null/NullBackend.cpp
+++ b/src/backend/null/NullBackend.cpp
@@ -60,9 +60,6 @@
DepthStencilStateBase* Device::CreateDepthStencilState(DepthStencilStateBuilder* builder) {
return new DepthStencilState(builder);
}
- FramebufferBase* Device::CreateFramebuffer(FramebufferBuilder* builder) {
- return new Framebuffer(builder);
- }
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
return new InputState(builder);
}
@@ -72,8 +69,8 @@
QueueBase* Device::CreateQueue(QueueBuilder* builder) {
return new Queue(builder);
}
- RenderPassBase* Device::CreateRenderPass(RenderPassBuilder* builder) {
- return new RenderPass(builder);
+ RenderPassInfoBase* Device::CreateRenderPassInfo(RenderPassInfoBuilder* builder) {
+ return new RenderPassInfo(builder);
}
RenderPipelineBase* Device::CreateRenderPipeline(RenderPipelineBuilder* builder) {
return new RenderPipeline(builder);
diff --git a/src/backend/null/NullBackend.h b/src/backend/null/NullBackend.h
index ec46280..217bb12 100644
--- a/src/backend/null/NullBackend.h
+++ b/src/backend/null/NullBackend.h
@@ -25,11 +25,10 @@
#include "backend/ComputePipeline.h"
#include "backend/DepthStencilState.h"
#include "backend/Device.h"
-#include "backend/Framebuffer.h"
#include "backend/InputState.h"
#include "backend/PipelineLayout.h"
#include "backend/Queue.h"
-#include "backend/RenderPass.h"
+#include "backend/RenderPassInfo.h"
#include "backend/RenderPipeline.h"
#include "backend/Sampler.h"
#include "backend/ShaderModule.h"
@@ -48,11 +47,10 @@
using ComputePipeline = ComputePipelineBase;
using DepthStencilState = DepthStencilStateBase;
class Device;
- using Framebuffer = FramebufferBase;
using InputState = InputStateBase;
using PipelineLayout = PipelineLayoutBase;
class Queue;
- using RenderPass = RenderPassBase;
+ using RenderPassInfo = RenderPassInfoBase;
using RenderPipeline = RenderPipelineBase;
using Sampler = SamplerBase;
using ShaderModule = ShaderModuleBase;
@@ -70,11 +68,10 @@
using ComputePipelineType = ComputePipeline;
using DepthStencilStateType = DepthStencilState;
using DeviceType = Device;
- using FramebufferType = Framebuffer;
using InputStateType = InputState;
using PipelineLayoutType = PipelineLayout;
using QueueType = Queue;
- using RenderPassType = RenderPass;
+ using RenderPassInfoType = RenderPassInfo;
using RenderPipelineType = RenderPipeline;
using SamplerType = Sampler;
using ShaderModuleType = ShaderModule;
@@ -106,11 +103,10 @@
CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) override;
ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override;
DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
- FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) override;
InputStateBase* CreateInputState(InputStateBuilder* builder) override;
PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override;
QueueBase* CreateQueue(QueueBuilder* builder) override;
- RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) override;
+ RenderPassInfoBase* CreateRenderPassInfo(RenderPassInfoBuilder* builder) override;
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
SamplerBase* CreateSampler(SamplerBuilder* builder) override;
ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override;
diff --git a/src/backend/opengl/CommandBufferGL.cpp b/src/backend/opengl/CommandBufferGL.cpp
index f5cbd33..4859c26 100644
--- a/src/backend/opengl/CommandBufferGL.cpp
+++ b/src/backend/opengl/CommandBufferGL.cpp
@@ -254,9 +254,6 @@
PushConstantTracker pushConstants;
InputBufferTracker inputBuffers;
- RenderPass* currentRenderPass = nullptr;
- Framebuffer* currentFramebuffer = nullptr;
- uint32_t currentSubpass = 0;
GLuint currentFBO = 0;
while (mCommands.NextCommandId(&type)) {
@@ -268,13 +265,8 @@
case Command::BeginRenderPass: {
auto* cmd = mCommands.NextCommand<BeginRenderPassCmd>();
- currentRenderPass = ToBackend(cmd->renderPass.Get());
- currentFramebuffer = ToBackend(cmd->framebuffer.Get());
- currentSubpass = 0;
- } break;
+ RenderPassInfo* info = ToBackend(cmd->info.Get());
- case Command::BeginRenderSubpass: {
- mCommands.NextCommand<BeginRenderSubpassCmd>();
pushConstants.OnBeginPass();
inputBuffers.OnBeginPass();
@@ -292,8 +284,6 @@
glGenFramebuffers(1, ¤tFBO);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, currentFBO);
- const auto& subpass = currentRenderPass->GetSubpassInfo(currentSubpass);
-
// Mapping from attachmentSlot to GL framebuffer
// attachment points. Defaults to zero (GL_NONE).
std::array<GLenum, kMaxColorAttachments> drawBuffers = {};
@@ -301,17 +291,15 @@
// Construct GL framebuffer
unsigned int attachmentCount = 0;
- for (unsigned int location : IterateBitSet(subpass.colorAttachmentsSet)) {
- uint32_t attachment = subpass.colorAttachments[location];
-
- auto textureView = currentFramebuffer->GetTextureView(attachment);
+ for (uint32_t i : IterateBitSet(info->GetColorAttachmentMask())) {
+ TextureViewBase* textureView = info->GetColorAttachment(i).view.Get();
GLuint texture = ToBackend(textureView->GetTexture())->GetHandle();
// Attach color buffers.
- glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + location,
+ glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
GL_TEXTURE_2D, texture, 0);
- drawBuffers[location] = GL_COLOR_ATTACHMENT0 + location;
- attachmentCount = location + 1;
+ drawBuffers[i] = GL_COLOR_ATTACHMENT0 + i;
+ attachmentCount = i + 1;
// TODO(kainino@chromium.org): the color clears (later in
// this function) may be undefined for non-normalized integer formats.
@@ -323,10 +311,8 @@
}
glDrawBuffers(attachmentCount, drawBuffers.data());
- if (subpass.depthStencilAttachmentSet) {
- uint32_t attachmentSlot = subpass.depthStencilAttachment;
-
- auto textureView = currentFramebuffer->GetTextureView(attachmentSlot);
+ if (info->HasDepthStencilAttachment()) {
+ TextureViewBase* textureView = info->GetDepthStencilAttachment().view.Get();
GLuint texture = ToBackend(textureView->GetTexture())->GetHandle();
nxt::TextureFormat format = textureView->GetTexture()->GetFormat();
@@ -354,52 +340,39 @@
// Clear framebuffer attachments as needed
- for (unsigned int location : IterateBitSet(subpass.colorAttachmentsSet)) {
- uint32_t attachmentSlot = subpass.colorAttachments[location];
- const auto& attachmentInfo =
- currentRenderPass->GetAttachmentInfo(attachmentSlot);
+ for (uint32_t i : IterateBitSet(info->GetColorAttachmentMask())) {
+ const auto& attachmentInfo = info->GetColorAttachment(i);
- // Only perform load op on first use
- if (attachmentInfo.firstSubpass == currentSubpass) {
- // Load op - color
- if (attachmentInfo.colorLoadOp == nxt::LoadOp::Clear) {
- const auto& clear = currentFramebuffer->GetClearColor(location);
- glClearBufferfv(GL_COLOR, location, clear.color);
- }
+ // Load op - color
+ if (attachmentInfo.loadOp == nxt::LoadOp::Clear) {
+ glClearBufferfv(GL_COLOR, i, attachmentInfo.clearColor.data());
}
}
- if (subpass.depthStencilAttachmentSet) {
- uint32_t attachmentSlot = subpass.depthStencilAttachment;
- const auto& attachmentInfo =
- currentRenderPass->GetAttachmentInfo(attachmentSlot);
+ if (info->HasDepthStencilAttachment()) {
+ const auto& attachmentInfo = info->GetDepthStencilAttachment();
+ nxt::TextureFormat attachmentFormat =
+ attachmentInfo.view->GetTexture()->GetFormat();
- // Only perform load op on first use
- if (attachmentInfo.firstSubpass == currentSubpass) {
- // Load op - depth/stencil
- const auto& clear = currentFramebuffer->GetClearDepthStencil(
- subpass.depthStencilAttachment);
- bool doDepthClear = TextureFormatHasDepth(attachmentInfo.format) &&
- (attachmentInfo.depthLoadOp == nxt::LoadOp::Clear);
- bool doStencilClear =
- TextureFormatHasStencil(attachmentInfo.format) &&
- (attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear);
- if (doDepthClear && doStencilClear) {
- glClearBufferfi(GL_DEPTH_STENCIL, 0, clear.depth, clear.stencil);
- } else if (doDepthClear) {
- glClearBufferfv(GL_DEPTH, 0, &clear.depth);
- } else if (doStencilClear) {
- const GLint clearStencil = clear.stencil;
- glClearBufferiv(GL_STENCIL, 0, &clearStencil);
- }
+ // Load op - depth/stencil
+ bool doDepthClear = TextureFormatHasDepth(attachmentFormat) &&
+ (attachmentInfo.depthLoadOp == nxt::LoadOp::Clear);
+ bool doStencilClear = TextureFormatHasStencil(attachmentFormat) &&
+ (attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear);
+ if (doDepthClear && doStencilClear) {
+ glClearBufferfi(GL_DEPTH_STENCIL, 0, attachmentInfo.clearDepth,
+ attachmentInfo.clearStencil);
+ } else if (doDepthClear) {
+ glClearBufferfv(GL_DEPTH, 0, &attachmentInfo.clearDepth);
+ } else if (doStencilClear) {
+ const GLint clearStencil = attachmentInfo.clearStencil;
+ glClearBufferiv(GL_STENCIL, 0, &clearStencil);
}
}
glBlendColor(0, 0, 0, 0);
- glViewport(0, 0, currentFramebuffer->GetWidth(),
- currentFramebuffer->GetHeight());
- glScissor(0, 0, currentFramebuffer->GetWidth(),
- currentFramebuffer->GetHeight());
+ glViewport(0, 0, info->GetWidth(), info->GetHeight());
+ glScissor(0, 0, info->GetWidth(), info->GetHeight());
} break;
case Command::CopyBufferToBuffer: {
@@ -530,13 +503,8 @@
case Command::EndRenderPass: {
mCommands.NextCommand<EndRenderPassCmd>();
- } break;
-
- case Command::EndRenderSubpass: {
- mCommands.NextCommand<EndRenderSubpassCmd>();
glDeleteFramebuffers(1, ¤tFBO);
currentFBO = 0;
- currentSubpass += 1;
} break;
case Command::SetComputePipeline: {
diff --git a/src/backend/opengl/OpenGLBackend.cpp b/src/backend/opengl/OpenGLBackend.cpp
index d61e8dc..c0456c4 100644
--- a/src/backend/opengl/OpenGLBackend.cpp
+++ b/src/backend/opengl/OpenGLBackend.cpp
@@ -73,17 +73,14 @@
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
return new InputState(builder);
}
- FramebufferBase* Device::CreateFramebuffer(FramebufferBuilder* builder) {
- return new Framebuffer(builder);
- }
PipelineLayoutBase* Device::CreatePipelineLayout(PipelineLayoutBuilder* builder) {
return new PipelineLayout(builder);
}
QueueBase* Device::CreateQueue(QueueBuilder* builder) {
return new Queue(builder);
}
- RenderPassBase* Device::CreateRenderPass(RenderPassBuilder* builder) {
- return new RenderPass(builder);
+ RenderPassInfoBase* Device::CreateRenderPassInfo(RenderPassInfoBuilder* builder) {
+ return new RenderPassInfo(builder);
}
RenderPipelineBase* Device::CreateRenderPipeline(RenderPipelineBuilder* builder) {
return new RenderPipeline(builder);
@@ -118,11 +115,6 @@
: BindGroupLayoutBase(builder) {
}
- // Framebuffer
-
- Framebuffer::Framebuffer(FramebufferBuilder* builder) : FramebufferBase(builder) {
- }
-
// Queue
Queue::Queue(QueueBuilder* builder) : QueueBase(builder) {
@@ -134,9 +126,9 @@
}
}
- // RenderPass
+ // RenderPassInfo
- RenderPass::RenderPass(RenderPassBuilder* builder) : RenderPassBase(builder) {
+ RenderPassInfo::RenderPassInfo(RenderPassInfoBuilder* builder) : RenderPassInfoBase(builder) {
}
}} // namespace backend::opengl
diff --git a/src/backend/opengl/OpenGLBackend.h b/src/backend/opengl/OpenGLBackend.h
index 5a9be0e..2c2299e 100644
--- a/src/backend/opengl/OpenGLBackend.h
+++ b/src/backend/opengl/OpenGLBackend.h
@@ -23,10 +23,9 @@
#include "backend/Buffer.h"
#include "backend/DepthStencilState.h"
#include "backend/Device.h"
-#include "backend/Framebuffer.h"
#include "backend/InputState.h"
#include "backend/Queue.h"
-#include "backend/RenderPass.h"
+#include "backend/RenderPassInfo.h"
#include "backend/ToBackend.h"
#include "glad/glad.h"
@@ -42,12 +41,11 @@
class ComputePipeline;
class DepthStencilState;
class Device;
- class Framebuffer;
class InputState;
class PersistentPipelineState;
class PipelineLayout;
class Queue;
- class RenderPass;
+ class RenderPassInfo;
class RenderPipeline;
class Sampler;
class ShaderModule;
@@ -65,11 +63,10 @@
using ComputePipelineType = ComputePipeline;
using DepthStencilStateType = DepthStencilState;
using DeviceType = Device;
- using FramebufferType = Framebuffer;
using InputStateType = InputState;
using PipelineLayoutType = PipelineLayout;
using QueueType = Queue;
- using RenderPassType = RenderPass;
+ using RenderPassInfoType = RenderPassInfo;
using RenderPipelineType = RenderPipeline;
using SamplerType = Sampler;
using ShaderModuleType = ShaderModule;
@@ -95,10 +92,9 @@
ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override;
DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
InputStateBase* CreateInputState(InputStateBuilder* builder) override;
- FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) override;
PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override;
QueueBase* CreateQueue(QueueBuilder* builder) override;
- RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) override;
+ RenderPassInfoBase* CreateRenderPassInfo(RenderPassInfoBuilder* builder) override;
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
SamplerBase* CreateSampler(SamplerBuilder* builder) override;
ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override;
@@ -119,11 +115,6 @@
BindGroupLayout(BindGroupLayoutBuilder* builder);
};
- class Framebuffer : public FramebufferBase {
- public:
- Framebuffer(FramebufferBuilder* builder);
- };
-
class Queue : public QueueBase {
public:
Queue(QueueBuilder* builder);
@@ -132,9 +123,9 @@
void Submit(uint32_t numCommands, CommandBuffer* const* commands);
};
- class RenderPass : public RenderPassBase {
+ class RenderPassInfo : public RenderPassInfoBase {
public:
- RenderPass(RenderPassBuilder* builder);
+ RenderPassInfo(RenderPassInfoBuilder* builder);
};
}} // namespace backend::opengl
diff --git a/src/backend/opengl/RenderPipelineGL.cpp b/src/backend/opengl/RenderPipelineGL.cpp
index 5804d49..96a5b3c 100644
--- a/src/backend/opengl/RenderPipelineGL.cpp
+++ b/src/backend/opengl/RenderPipelineGL.cpp
@@ -60,10 +60,7 @@
auto depthStencilState = ToBackend(GetDepthStencilState());
depthStencilState->ApplyNow(persistentPipelineState);
- RenderPass* renderPass = ToBackend(GetRenderPass());
- auto& subpassInfo = renderPass->GetSubpassInfo(GetSubPass());
-
- for (uint32_t attachmentSlot : IterateBitSet(subpassInfo.colorAttachmentsSet)) {
+ for (uint32_t attachmentSlot : IterateBitSet(GetColorAttachmentsMask())) {
ToBackend(GetBlendState(attachmentSlot))->ApplyNow(attachmentSlot);
}
}
diff --git a/src/backend/vulkan/CommandBufferVk.cpp b/src/backend/vulkan/CommandBufferVk.cpp
index a1ce476..b85012f 100644
--- a/src/backend/vulkan/CommandBufferVk.cpp
+++ b/src/backend/vulkan/CommandBufferVk.cpp
@@ -18,9 +18,8 @@
#include "backend/vulkan/BindGroupVk.h"
#include "backend/vulkan/BufferVk.h"
#include "backend/vulkan/ComputePipelineVk.h"
-#include "backend/vulkan/FramebufferVk.h"
#include "backend/vulkan/PipelineLayoutVk.h"
-#include "backend/vulkan/RenderPassVk.h"
+#include "backend/vulkan/RenderPassInfoVk.h"
#include "backend/vulkan/RenderPipelineVk.h"
#include "backend/vulkan/TextureVk.h"
#include "backend/vulkan/VulkanBackend.h"
@@ -184,43 +183,32 @@
case Command::BeginRenderPass: {
BeginRenderPassCmd* cmd = mCommands.NextCommand<BeginRenderPassCmd>();
- Framebuffer* framebuffer = ToBackend(cmd->framebuffer.Get());
- RenderPass* renderPass = ToBackend(cmd->renderPass.Get());
+ RenderPassInfo* info = ToBackend(cmd->info.Get());
- // NXT has an implicit transition to color attachment on subpasses. Transition
- // the attachments now before we start the render pass.
- for (uint32_t i = 0; i < renderPass->GetAttachmentCount(); ++i) {
+ // NXT has an implicit transition to color attachment on render passes.
+ // Transition the attachments now before we start the render pass.
+ for (uint32_t i : IterateBitSet(info->GetColorAttachmentMask())) {
Texture* attachment =
- ToBackend(framebuffer->GetTextureView(i)->GetTexture());
+ ToBackend(info->GetColorAttachment(i).view->GetTexture());
- if (attachment->GetUsage() & nxt::TextureUsageBit::OutputAttachment) {
- continue;
+ if (!(attachment->GetUsage() & nxt::TextureUsageBit::OutputAttachment)) {
+ attachment->RecordBarrier(commands, attachment->GetUsage(),
+ nxt::TextureUsageBit::OutputAttachment);
+ attachment->UpdateUsageInternal(nxt::TextureUsageBit::OutputAttachment);
}
+ }
+ if (info->HasDepthStencilAttachment()) {
+ Texture* attachment =
+ ToBackend(info->GetDepthStencilAttachment().view->GetTexture());
- attachment->RecordBarrier(commands, attachment->GetUsage(),
- nxt::TextureUsageBit::OutputAttachment);
- attachment->UpdateUsageInternal(nxt::TextureUsageBit::OutputAttachment);
+ if (!(attachment->GetUsage() & nxt::TextureUsageBit::OutputAttachment)) {
+ attachment->RecordBarrier(commands, attachment->GetUsage(),
+ nxt::TextureUsageBit::OutputAttachment);
+ attachment->UpdateUsageInternal(nxt::TextureUsageBit::OutputAttachment);
+ }
}
- ASSERT(renderPass->GetSubpassCount() == 1);
- ASSERT(renderPass->GetAttachmentCount() <= kMaxColorAttachments + 1);
-
- std::array<VkClearValue, kMaxColorAttachments + 1> clearValues;
- framebuffer->FillClearValues(clearValues.data());
-
- VkRenderPassBeginInfo beginInfo;
- beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
- beginInfo.pNext = nullptr;
- beginInfo.renderPass = renderPass->GetHandle();
- beginInfo.framebuffer = framebuffer->GetHandle();
- beginInfo.renderArea.offset.x = 0;
- beginInfo.renderArea.offset.y = 0;
- beginInfo.renderArea.extent.width = framebuffer->GetWidth();
- beginInfo.renderArea.extent.height = framebuffer->GetHeight();
- beginInfo.clearValueCount = renderPass->GetAttachmentCount();
- beginInfo.pClearValues = clearValues.data();
-
- device->fn.CmdBeginRenderPass(commands, &beginInfo, VK_SUBPASS_CONTENTS_INLINE);
+ info->RecordBeginRenderPass(commands);
// Set all the dynamic state just in case.
device->fn.CmdSetLineWidth(commands, 1.0f);
@@ -228,32 +216,6 @@
device->fn.CmdSetStencilReference(commands, VK_STENCIL_FRONT_AND_BACK, 0);
- // The viewport and scissor default to cover all of the attachments
- VkViewport viewport;
- viewport.x = 0.0f;
- viewport.y = 0.0f;
- viewport.width = static_cast<float>(framebuffer->GetWidth());
- viewport.height = static_cast<float>(framebuffer->GetHeight());
- viewport.minDepth = 0.0f;
- viewport.maxDepth = 1.0f;
- device->fn.CmdSetViewport(commands, 0, 1, &viewport);
-
- VkRect2D scissorRect;
- scissorRect.offset.x = 0;
- scissorRect.offset.y = 0;
- scissorRect.extent.width = framebuffer->GetWidth();
- scissorRect.extent.height = framebuffer->GetHeight();
- device->fn.CmdSetScissor(commands, 0, 1, &scissorRect);
-
- descriptorSets.OnBeginPass();
- } break;
-
- case Command::BeginRenderSubpass: {
- mCommands.NextCommand<BeginRenderSubpassCmd>();
- // Do nothing related to subpasses because the single subpass is started in
- // vkBeginRenderPass
-
- // Set up the default state
float blendConstants[4] = {
0.0f,
0.0f,
@@ -261,6 +223,25 @@
0.0f,
};
device->fn.CmdSetBlendConstants(commands, blendConstants);
+
+ // The viewport and scissor default to cover all of the attachments
+ VkViewport viewport;
+ viewport.x = 0.0f;
+ viewport.y = 0.0f;
+ viewport.width = static_cast<float>(info->GetWidth());
+ viewport.height = static_cast<float>(info->GetHeight());
+ viewport.minDepth = 0.0f;
+ viewport.maxDepth = 1.0f;
+ device->fn.CmdSetViewport(commands, 0, 1, &viewport);
+
+ VkRect2D scissorRect;
+ scissorRect.offset.x = 0;
+ scissorRect.offset.y = 0;
+ scissorRect.extent.width = info->GetWidth();
+ scissorRect.extent.height = info->GetHeight();
+ device->fn.CmdSetScissor(commands, 0, 1, &scissorRect);
+
+ descriptorSets.OnBeginPass();
} break;
case Command::DrawArrays: {
@@ -285,11 +266,6 @@
device->fn.CmdEndRenderPass(commands);
} break;
- case Command::EndRenderSubpass: {
- mCommands.NextCommand<EndRenderSubpassCmd>();
- // Do nothing because the single subpass is ended in vkEndRenderPass
- } break;
-
case Command::BeginComputePass: {
mCommands.NextCommand<BeginComputePassCmd>();
descriptorSets.OnBeginPass();
diff --git a/src/backend/vulkan/FramebufferVk.cpp b/src/backend/vulkan/FramebufferVk.cpp
deleted file mode 100644
index f216dea..0000000
--- a/src/backend/vulkan/FramebufferVk.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2018 The NXT 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 "backend/vulkan/FramebufferVk.h"
-
-#include "backend/vulkan/FencedDeleter.h"
-#include "backend/vulkan/RenderPassVk.h"
-#include "backend/vulkan/TextureVk.h"
-#include "backend/vulkan/VulkanBackend.h"
-
-namespace backend { namespace vulkan {
-
- Framebuffer::Framebuffer(FramebufferBuilder* builder) : FramebufferBase(builder) {
- ASSERT(GetRenderPass()->GetAttachmentCount() <= kMaxColorAttachments + 1);
-
- Device* device = ToBackend(GetDevice());
-
- // Fill in the attachment info that will be chained in the create info.
- std::array<VkImageView, kMaxColorAttachments + 1> attachments;
- for (uint32_t i = 0; i < GetRenderPass()->GetAttachmentCount(); ++i) {
- attachments[i] = ToBackend(GetTextureView(i))->GetHandle();
- }
-
- // Chain attachments and create the framebuffer
- VkFramebufferCreateInfo createInfo;
- createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
- createInfo.pNext = nullptr;
- createInfo.flags = 0;
- createInfo.renderPass = ToBackend(GetRenderPass())->GetHandle();
- createInfo.attachmentCount = GetRenderPass()->GetAttachmentCount();
- createInfo.pAttachments = attachments.data();
- createInfo.width = GetWidth();
- createInfo.height = GetHeight();
- createInfo.layers = 1;
-
- if (device->fn.CreateFramebuffer(device->GetVkDevice(), &createInfo, nullptr, &mHandle) !=
- VK_SUCCESS) {
- ASSERT(false);
- }
- }
-
- Framebuffer::~Framebuffer() {
- Device* device = ToBackend(GetDevice());
-
- if (mHandle != VK_NULL_HANDLE) {
- device->GetFencedDeleter()->DeleteWhenUnused(mHandle);
- mHandle = VK_NULL_HANDLE;
- }
- }
-
- VkFramebuffer Framebuffer::GetHandle() const {
- return mHandle;
- }
-
- void Framebuffer::FillClearValues(VkClearValue* values) {
- const RenderPassBase* renderPass = GetRenderPass();
- for (uint32_t i = 0; i < renderPass->GetAttachmentCount(); ++i) {
- if (TextureFormatHasDepthOrStencil(renderPass->GetAttachmentInfo(i).format)) {
- const auto& clearValues = GetClearDepthStencil(i);
-
- values[i].depthStencil.depth = clearValues.depth;
- values[i].depthStencil.stencil = clearValues.stencil;
- } else {
- const auto& clearValues = GetClearColor(i);
-
- values[i].color.float32[0] = clearValues.color[0];
- values[i].color.float32[1] = clearValues.color[1];
- values[i].color.float32[2] = clearValues.color[2];
- values[i].color.float32[3] = clearValues.color[3];
- }
- }
- }
-
-}} // namespace backend::vulkan
diff --git a/src/backend/vulkan/GeneratedCodeIncludes.h b/src/backend/vulkan/GeneratedCodeIncludes.h
index 23b4489..18e96e7 100644
--- a/src/backend/vulkan/GeneratedCodeIncludes.h
+++ b/src/backend/vulkan/GeneratedCodeIncludes.h
@@ -19,10 +19,9 @@
#include "backend/vulkan/CommandBufferVk.h"
#include "backend/vulkan/ComputePipelineVk.h"
#include "backend/vulkan/DepthStencilStateVk.h"
-#include "backend/vulkan/FramebufferVk.h"
#include "backend/vulkan/InputStateVk.h"
#include "backend/vulkan/PipelineLayoutVk.h"
-#include "backend/vulkan/RenderPassVk.h"
+#include "backend/vulkan/RenderPassInfoVk.h"
#include "backend/vulkan/RenderPipelineVk.h"
#include "backend/vulkan/SamplerVk.h"
#include "backend/vulkan/ShaderModuleVk.h"
diff --git a/src/backend/vulkan/RenderPassCache.cpp b/src/backend/vulkan/RenderPassCache.cpp
new file mode 100644
index 0000000..0d9e63e
--- /dev/null
+++ b/src/backend/vulkan/RenderPassCache.cpp
@@ -0,0 +1,209 @@
+// Copyright 2018 The NXT 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 "backend/vulkan/RenderPassCache.h"
+
+#include "backend/vulkan/TextureVk.h"
+#include "backend/vulkan/VulkanBackend.h"
+#include "common/BitSetIterator.h"
+#include "common/HashUtils.h"
+
+namespace backend { namespace vulkan {
+
+ namespace {
+ VkAttachmentLoadOp VulkanAttachmentLoadOp(nxt::LoadOp op) {
+ switch (op) {
+ case nxt::LoadOp::Load:
+ return VK_ATTACHMENT_LOAD_OP_LOAD;
+ case nxt::LoadOp::Clear:
+ return VK_ATTACHMENT_LOAD_OP_CLEAR;
+ default:
+ UNREACHABLE();
+ }
+ }
+ } // anonymous namespace
+
+ // RenderPassCacheQuery
+
+ void RenderPassCacheQuery::SetColor(uint32_t index,
+ nxt::TextureFormat format,
+ nxt::LoadOp loadOp) {
+ colorMask.set(index);
+ colorFormats[index] = format;
+ colorLoadOp[index] = loadOp;
+ }
+
+ void RenderPassCacheQuery::SetDepthStencil(nxt::TextureFormat format,
+ nxt::LoadOp depthLoadOp,
+ nxt::LoadOp stencilLoadOp) {
+ hasDepthStencil = true;
+ depthStencilFormat = format;
+ this->depthLoadOp = depthLoadOp;
+ this->stencilLoadOp = stencilLoadOp;
+ }
+
+ // RenderPassCache
+
+ RenderPassCache::RenderPassCache(Device* device) : mDevice(device) {
+ }
+
+ RenderPassCache::~RenderPassCache() {
+ for (auto it : mCache) {
+ mDevice->fn.DestroyRenderPass(mDevice->GetVkDevice(), it.second, nullptr);
+ }
+ mCache.clear();
+ }
+
+ VkRenderPass RenderPassCache::GetRenderPass(const RenderPassCacheQuery& query) {
+ auto it = mCache.find(query);
+ if (it != mCache.end()) {
+ return it->second;
+ }
+
+ VkRenderPass renderPass = CreateRenderPassForQuery(query);
+ mCache.emplace(query, renderPass);
+ return renderPass;
+ }
+
+ VkRenderPass RenderPassCache::CreateRenderPassForQuery(
+ const RenderPassCacheQuery& query) const {
+ // The Vulkan subpasses want to know the layout of the attachments with VkAttachmentRef.
+ // Precompute them as they must be pointer-chained in VkSubpassDescription
+ std::array<VkAttachmentReference, kMaxColorAttachments + 1> attachmentRefs;
+
+ // Contains the attachment description that will be chained in the create info
+ std::array<VkAttachmentDescription, kMaxColorAttachments + 1> attachmentDescs = {};
+
+ uint32_t attachmentCount = 0;
+ for (uint32_t i : IterateBitSet(query.colorMask)) {
+ auto& attachmentRef = attachmentRefs[attachmentCount];
+ auto& attachmentDesc = attachmentDescs[attachmentCount];
+
+ attachmentRef.attachment = attachmentCount;
+ attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+ attachmentDesc.flags = 0;
+ attachmentDesc.format = VulkanImageFormat(query.colorFormats[i]);
+ attachmentDesc.samples = VK_SAMPLE_COUNT_1_BIT;
+ attachmentDesc.loadOp = VulkanAttachmentLoadOp(query.colorLoadOp[i]);
+ attachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ attachmentDesc.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+ attachmentCount++;
+ }
+ uint32_t colorAttachmentCount = attachmentCount;
+
+ VkAttachmentReference* depthStencilAttachment = nullptr;
+ if (query.hasDepthStencil) {
+ auto& attachmentRef = attachmentRefs[attachmentCount];
+ auto& attachmentDesc = attachmentDescs[attachmentCount];
+
+ depthStencilAttachment = &attachmentRefs[attachmentCount];
+
+ attachmentRef.attachment = attachmentCount;
+ attachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+
+ attachmentDesc.flags = 0;
+ attachmentDesc.format = VulkanImageFormat(query.depthStencilFormat);
+ attachmentDesc.samples = VK_SAMPLE_COUNT_1_BIT;
+ attachmentDesc.loadOp = VulkanAttachmentLoadOp(query.depthLoadOp);
+ attachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ attachmentDesc.stencilLoadOp = VulkanAttachmentLoadOp(query.stencilLoadOp);
+ attachmentDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
+ attachmentDesc.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+ attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+
+ attachmentCount++;
+ }
+
+ // Create the VkSubpassDescription that will be chained in the VkRenderPassCreateInfo
+ VkSubpassDescription subpassDesc;
+ subpassDesc.flags = 0;
+ subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+ subpassDesc.inputAttachmentCount = 0;
+ subpassDesc.pInputAttachments = nullptr;
+ subpassDesc.colorAttachmentCount = colorAttachmentCount;
+ subpassDesc.pColorAttachments = attachmentRefs.data();
+ subpassDesc.pResolveAttachments = nullptr;
+ subpassDesc.pDepthStencilAttachment = depthStencilAttachment;
+ subpassDesc.preserveAttachmentCount = 0;
+ subpassDesc.pPreserveAttachments = nullptr;
+
+ // Chain everything in VkRenderPassCreateInfo
+ VkRenderPassCreateInfo createInfo;
+ createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+ createInfo.pNext = nullptr;
+ createInfo.flags = 0;
+ createInfo.attachmentCount = attachmentCount;
+ createInfo.pAttachments = attachmentDescs.data();
+ createInfo.subpassCount = 1;
+ createInfo.pSubpasses = &subpassDesc;
+ createInfo.dependencyCount = 0;
+ createInfo.pDependencies = nullptr;
+
+ // Create the render pass from the zillion parameters
+ VkRenderPass renderPass;
+ if (mDevice->fn.CreateRenderPass(mDevice->GetVkDevice(), &createInfo, nullptr,
+ &renderPass) != VK_SUCCESS) {
+ ASSERT(false);
+ }
+
+ return renderPass;
+ }
+
+ // RenderPassCache
+
+ size_t RenderPassCache::CacheFuncs::operator()(const RenderPassCacheQuery& query) const {
+ size_t hash = Hash(query.colorMask);
+
+ for (uint32_t i : IterateBitSet(query.colorMask)) {
+ HashCombine(&hash, query.colorFormats[i], query.colorLoadOp[i]);
+ }
+
+ HashCombine(&hash, query.hasDepthStencil);
+ if (query.hasDepthStencil) {
+ HashCombine(&hash, query.depthStencilFormat, query.depthLoadOp, query.stencilLoadOp);
+ }
+
+ return hash;
+ }
+
+ bool RenderPassCache::CacheFuncs::operator()(const RenderPassCacheQuery& a,
+ const RenderPassCacheQuery& b) const {
+ if (a.colorMask != b.colorMask) {
+ return false;
+ }
+
+ for (uint32_t i : IterateBitSet(a.colorMask)) {
+ if ((a.colorFormats[i] != b.colorFormats[i]) ||
+ (a.colorLoadOp[i] != b.colorLoadOp[i])) {
+ return false;
+ }
+ }
+
+ if (a.hasDepthStencil != b.hasDepthStencil) {
+ return false;
+ }
+
+ if (a.hasDepthStencil) {
+ if ((a.depthStencilFormat != b.depthStencilFormat) ||
+ (a.depthLoadOp != b.depthLoadOp) || (a.stencilLoadOp != b.stencilLoadOp)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}} // namespace backend::vulkan
diff --git a/src/backend/vulkan/RenderPassCache.h b/src/backend/vulkan/RenderPassCache.h
new file mode 100644
index 0000000..1ac12e3
--- /dev/null
+++ b/src/backend/vulkan/RenderPassCache.h
@@ -0,0 +1,81 @@
+// Copyright 2018 The NXT 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 BACKEND_VULKAN_RENDERPASSCACHE_H_
+#define BACKEND_VULKAN_RENDERPASSCACHE_H_
+
+#include "common/vulkan_platform.h"
+
+#include "common/Constants.h"
+#include "nxt/nxtcpp.h"
+
+#include <array>
+#include <bitset>
+#include <unordered_map>
+
+namespace backend { namespace vulkan {
+
+ class Device;
+
+ // This is a key to query the RenderPassCache, it can be sparse meaning that only the
+ // information for bits set in colorMask or hasDepthStencil need to be provided and the rest can
+ // be uninintialized.
+ struct RenderPassCacheQuery {
+ // Use these helpers to build the query, they make sure all relevant data is initialized and
+ // masks set.
+ void SetColor(uint32_t index, nxt::TextureFormat format, nxt::LoadOp loadOp);
+ void SetDepthStencil(nxt::TextureFormat format,
+ nxt::LoadOp depthLoadOp,
+ nxt::LoadOp stencilLoadOp);
+
+ std::bitset<kMaxColorAttachments> colorMask;
+ std::array<nxt::TextureFormat, kMaxColorAttachments> colorFormats;
+ std::array<nxt::LoadOp, kMaxColorAttachments> colorLoadOp;
+
+ bool hasDepthStencil = false;
+ nxt::TextureFormat depthStencilFormat;
+ nxt::LoadOp depthLoadOp;
+ nxt::LoadOp stencilLoadOp;
+ };
+
+ // Caches VkRenderPasses so that we don't create duplicate ones for every RenderPipeline or
+ // render pass.
+ // TODO(cwallez@chromium.org): Make it an LRU cache somehow?
+ class RenderPassCache {
+ public:
+ RenderPassCache(Device* device);
+ ~RenderPassCache();
+
+ VkRenderPass GetRenderPass(const RenderPassCacheQuery& query);
+
+ private:
+ // Does the actual VkRenderPass creation on a cache miss.
+ VkRenderPass CreateRenderPassForQuery(const RenderPassCacheQuery& query) const;
+
+ // Implements the functors necessary for to use RenderPassCacheQueries as unordered_map
+ // keys.
+ struct CacheFuncs {
+ size_t operator()(const RenderPassCacheQuery& query) const;
+ bool operator()(const RenderPassCacheQuery& a, const RenderPassCacheQuery& b) const;
+ };
+ using Cache =
+ std::unordered_map<RenderPassCacheQuery, VkRenderPass, CacheFuncs, CacheFuncs>;
+
+ Device* mDevice = nullptr;
+ Cache mCache;
+ };
+
+}} // namespace backend::vulkan
+
+#endif // BACKEND_VULKAN_RENDERPASSCACHE_H_
diff --git a/src/backend/vulkan/RenderPassInfoVk.cpp b/src/backend/vulkan/RenderPassInfoVk.cpp
new file mode 100644
index 0000000..4f046f5
--- /dev/null
+++ b/src/backend/vulkan/RenderPassInfoVk.cpp
@@ -0,0 +1,122 @@
+// Copyright 2018 The NXT 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 "backend/vulkan/RenderPassInfoVk.h"
+
+#include "backend/vulkan/FencedDeleter.h"
+#include "backend/vulkan/RenderPassCache.h"
+#include "backend/vulkan/TextureVk.h"
+#include "backend/vulkan/VulkanBackend.h"
+#include "common/BitSetIterator.h"
+
+namespace backend { namespace vulkan {
+
+ RenderPassInfo::RenderPassInfo(RenderPassInfoBuilder* builder)
+ : RenderPassInfoBase(builder), mDevice(ToBackend(builder->GetDevice())) {
+ }
+
+ void RenderPassInfo::RecordBeginRenderPass(VkCommandBuffer commands) {
+ // Query a VkRenderPass from the cache
+ VkRenderPass renderPass = VK_NULL_HANDLE;
+ {
+ RenderPassCacheQuery query;
+
+ for (uint32_t i : IterateBitSet(GetColorAttachmentMask())) {
+ const auto& attachmentInfo = GetColorAttachment(i);
+ query.SetColor(i, attachmentInfo.view->GetTexture()->GetFormat(),
+ attachmentInfo.loadOp);
+ }
+
+ if (HasDepthStencilAttachment()) {
+ const auto& attachmentInfo = GetDepthStencilAttachment();
+ query.SetDepthStencil(attachmentInfo.view->GetTexture()->GetFormat(),
+ attachmentInfo.depthLoadOp, attachmentInfo.stencilLoadOp);
+ }
+
+ renderPass = mDevice->GetRenderPassCache()->GetRenderPass(query);
+ }
+
+ // Create a framebuffer that will be used once for the render pass and gather the clear
+ // values for the attachments at the same time.
+ std::array<VkClearValue, kMaxColorAttachments + 1> clearValues;
+ VkFramebuffer framebuffer = VK_NULL_HANDLE;
+ uint32_t attachmentCount = 0;
+ {
+ // Fill in the attachment info that will be chained in the framebuffer create info.
+ std::array<VkImageView, kMaxColorAttachments + 1> attachments;
+
+ for (uint32_t i : IterateBitSet(GetColorAttachmentMask())) {
+ auto& attachmentInfo = GetColorAttachment(i);
+ TextureView* view = ToBackend(attachmentInfo.view.Get());
+
+ attachments[attachmentCount] = view->GetHandle();
+
+ clearValues[attachmentCount].color.float32[0] = attachmentInfo.clearColor[0];
+ clearValues[attachmentCount].color.float32[1] = attachmentInfo.clearColor[1];
+ clearValues[attachmentCount].color.float32[2] = attachmentInfo.clearColor[2];
+ clearValues[attachmentCount].color.float32[3] = attachmentInfo.clearColor[3];
+
+ attachmentCount++;
+ }
+
+ if (HasDepthStencilAttachment()) {
+ auto& attachmentInfo = GetDepthStencilAttachment();
+ TextureView* view = ToBackend(attachmentInfo.view.Get());
+
+ attachments[attachmentCount] = view->GetHandle();
+
+ clearValues[attachmentCount].depthStencil.depth = attachmentInfo.clearDepth;
+ clearValues[attachmentCount].depthStencil.stencil = attachmentInfo.clearStencil;
+
+ attachmentCount++;
+ }
+
+ // Chain attachments and create the framebuffer
+ VkFramebufferCreateInfo createInfo;
+ createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+ createInfo.pNext = nullptr;
+ createInfo.flags = 0;
+ createInfo.renderPass = renderPass;
+ createInfo.attachmentCount = attachmentCount;
+ createInfo.pAttachments = attachments.data();
+ createInfo.width = GetWidth();
+ createInfo.height = GetHeight();
+ createInfo.layers = 1;
+
+ if (mDevice->fn.CreateFramebuffer(mDevice->GetVkDevice(), &createInfo, nullptr,
+ &framebuffer) != VK_SUCCESS) {
+ ASSERT(false);
+ }
+
+ // We don't reuse VkFramebuffers so mark the framebuffer for deletion as soon as the
+ // commands currently being recorded are finished.
+ mDevice->GetFencedDeleter()->DeleteWhenUnused(framebuffer);
+ }
+
+ VkRenderPassBeginInfo beginInfo;
+ beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+ beginInfo.pNext = nullptr;
+ beginInfo.renderPass = renderPass;
+ beginInfo.framebuffer = framebuffer;
+ beginInfo.renderArea.offset.x = 0;
+ beginInfo.renderArea.offset.y = 0;
+ beginInfo.renderArea.extent.width = GetWidth();
+ beginInfo.renderArea.extent.height = GetHeight();
+ beginInfo.clearValueCount = attachmentCount;
+ beginInfo.pClearValues = clearValues.data();
+
+ mDevice->fn.CmdBeginRenderPass(commands, &beginInfo, VK_SUBPASS_CONTENTS_INLINE);
+ }
+
+}} // namespace backend::vulkan
diff --git a/src/backend/vulkan/FramebufferVk.h b/src/backend/vulkan/RenderPassInfoVk.h
similarity index 60%
rename from src/backend/vulkan/FramebufferVk.h
rename to src/backend/vulkan/RenderPassInfoVk.h
index 5a979cf..dcbba41 100644
--- a/src/backend/vulkan/FramebufferVk.h
+++ b/src/backend/vulkan/RenderPassInfoVk.h
@@ -12,27 +12,28 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef BACKEND_VULKAN_FRAMEBUFFERVK_H_
-#define BACKEND_VULKAN_FRAMEBUFFERVK_H_
+#ifndef BACKEND_VULKAN_RENDERPASSINFOVK_H_
+#define BACKEND_VULKAN_RENDERPASSINFOVK_H_
-#include "backend/Framebuffer.h"
+#include "backend/RenderPassInfo.h"
#include "common/vulkan_platform.h"
namespace backend { namespace vulkan {
- class Framebuffer : public FramebufferBase {
- public:
- Framebuffer(FramebufferBuilder* builder);
- ~Framebuffer();
+ class Device;
- VkFramebuffer GetHandle() const;
- void FillClearValues(VkClearValue* values);
+ class RenderPassInfo : public RenderPassInfoBase {
+ public:
+ RenderPassInfo(RenderPassInfoBuilder* builder);
+
+ // Compute all the arguments for, and record the vkCmdBeginRenderPass command.
+ void RecordBeginRenderPass(VkCommandBuffer commands);
private:
- VkFramebuffer mHandle = VK_NULL_HANDLE;
+ Device* mDevice = nullptr;
};
}} // namespace backend::vulkan
-#endif // BACKEND_VULKAN_FRAMEBUFFERVK_H_
+#endif // BACKEND_VULKAN_RENDERPASSINFOVK_H_
diff --git a/src/backend/vulkan/RenderPassVk.cpp b/src/backend/vulkan/RenderPassVk.cpp
deleted file mode 100644
index d1d35b9..0000000
--- a/src/backend/vulkan/RenderPassVk.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright 2018 The NXT 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 "backend/vulkan/RenderPassVk.h"
-
-#include "backend/vulkan/FencedDeleter.h"
-#include "backend/vulkan/TextureVk.h"
-#include "backend/vulkan/VulkanBackend.h"
-#include "common/BitSetIterator.h"
-
-namespace backend { namespace vulkan {
-
- namespace {
- VkAttachmentLoadOp VulkanAttachmentLoadOp(nxt::LoadOp op) {
- switch (op) {
- case nxt::LoadOp::Load:
- return VK_ATTACHMENT_LOAD_OP_LOAD;
- case nxt::LoadOp::Clear:
- return VK_ATTACHMENT_LOAD_OP_CLEAR;
- default:
- UNREACHABLE();
- }
- }
- } // anonymous namespace
-
- RenderPass::RenderPass(RenderPassBuilder* builder)
- : RenderPassBase(builder), mDevice(ToBackend(builder->GetDevice())) {
- // For now we only support single pass render passes.
- ASSERT(GetSubpassCount() == 1);
- ASSERT(GetAttachmentCount() <= kMaxColorAttachments + 1);
-
- const auto& subpass = GetSubpassInfo(0);
-
- // The Vulkan subpasses want to know the layout of the attachments with VkAttachmentRef.
- // Precompute them as they must be pointer-chained in VkSubpassDescription
- std::array<VkAttachmentReference, kMaxColorAttachments + 1> attachmentRefs;
- attachmentRefs.fill(VkAttachmentReference{VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_UNDEFINED});
-
- for (uint32_t i : IterateBitSet(subpass.colorAttachmentsSet)) {
- attachmentRefs[i].attachment = subpass.colorAttachments[i];
- attachmentRefs[i].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
-
- // TODO(cwallez@chromium.org): need validation rule that attachments are packed
- ASSERT(i == 0 || subpass.colorAttachmentsSet[i - 1]);
- }
- if (subpass.depthStencilAttachment) {
- attachmentRefs[kMaxColorAttachments].attachment = subpass.depthStencilAttachment;
- attachmentRefs[kMaxColorAttachments].layout =
- VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
- }
-
- // Create the VkSubpassDescription that will be chained in the VkRenderPassCreateInfo
- VkSubpassDescription subpassDesc;
- subpassDesc.flags = 0;
- subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
- subpassDesc.inputAttachmentCount = 0;
- subpassDesc.pInputAttachments = nullptr;
- subpassDesc.colorAttachmentCount =
- static_cast<uint32_t>(subpass.colorAttachmentsSet.count());
- subpassDesc.pColorAttachments = attachmentRefs.data();
- subpassDesc.pResolveAttachments = nullptr;
- subpassDesc.pDepthStencilAttachment = &attachmentRefs[kMaxColorAttachments];
- subpassDesc.preserveAttachmentCount = 0;
- subpassDesc.pPreserveAttachments = nullptr;
-
- // Create the VkAttachmentDescriptions that will be chained in the VkRenderPassCreateInfo
- std::array<VkAttachmentDescription, kMaxColorAttachments + 1> attachmentDescs = {};
- for (uint32_t i = 0; i < GetAttachmentCount(); ++i) {
- const auto& attachment = GetAttachmentInfo(i);
- auto& attachmentDesc = attachmentDescs[i];
-
- attachmentDesc.flags = 0;
- attachmentDesc.format = VulkanImageFormat(attachment.format);
- attachmentDesc.samples = VK_SAMPLE_COUNT_1_BIT;
- if (TextureFormatHasDepthOrStencil(attachment.format)) {
- attachmentDesc.loadOp = VulkanAttachmentLoadOp(attachment.depthLoadOp);
- attachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
- attachmentDesc.stencilLoadOp = VulkanAttachmentLoadOp(attachment.stencilLoadOp);
- attachmentDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
-
- attachmentDesc.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
- attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
- } else {
- attachmentDesc.loadOp = VulkanAttachmentLoadOp(attachment.colorLoadOp);
- attachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
-
- attachmentDesc.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- }
- }
-
- // Chain everything in VkRenderPassCreateInfo
- VkRenderPassCreateInfo createInfo;
- createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
- createInfo.pNext = nullptr;
- createInfo.flags = 0;
- createInfo.attachmentCount = GetAttachmentCount();
- createInfo.pAttachments = attachmentDescs.data();
- createInfo.subpassCount = 1;
- createInfo.pSubpasses = &subpassDesc;
- createInfo.dependencyCount = 0;
- createInfo.pDependencies = nullptr;
-
- // Create the render pass from the zillion parameters
- if (mDevice->fn.CreateRenderPass(mDevice->GetVkDevice(), &createInfo, nullptr, &mHandle) !=
- VK_SUCCESS) {
- ASSERT(false);
- }
- }
-
- RenderPass::~RenderPass() {
- if (mHandle != VK_NULL_HANDLE) {
- mDevice->GetFencedDeleter()->DeleteWhenUnused(mHandle);
- mHandle = VK_NULL_HANDLE;
- }
- }
-
- VkRenderPass RenderPass::GetHandle() const {
- return mHandle;
- }
-
-}} // namespace backend::vulkan
diff --git a/src/backend/vulkan/RenderPassVk.h b/src/backend/vulkan/RenderPassVk.h
deleted file mode 100644
index fe7889f..0000000
--- a/src/backend/vulkan/RenderPassVk.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2018 The NXT 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 BACKEND_VULKAN_RENDERPASSVK_H_
-#define BACKEND_VULKAN_RENDERPASSVK_H_
-
-#include "backend/RenderPass.h"
-
-#include "common/vulkan_platform.h"
-
-namespace backend { namespace vulkan {
-
- class Device;
-
- class RenderPass : public RenderPassBase {
- public:
- RenderPass(RenderPassBuilder* builder);
- ~RenderPass();
-
- // TODO(cwallez@chromium.org): We need a way to ask for a compatible VkRenderPass with the
- // given load an store operations. Also they should be cached. For now this is hardcoded to
- // have Load = Clear and Store = Write
- VkRenderPass GetHandle() const;
-
- private:
- VkRenderPass mHandle = VK_NULL_HANDLE;
- Device* mDevice = nullptr;
- };
-
-}} // namespace backend::vulkan
-
-#endif // BACKEND_VULKAN_PIPELINELAYOUTVK_H_
diff --git a/src/backend/vulkan/RenderPipelineVk.cpp b/src/backend/vulkan/RenderPipelineVk.cpp
index 7fba8e8..03548a0 100644
--- a/src/backend/vulkan/RenderPipelineVk.cpp
+++ b/src/backend/vulkan/RenderPipelineVk.cpp
@@ -19,7 +19,8 @@
#include "backend/vulkan/FencedDeleter.h"
#include "backend/vulkan/InputStateVk.h"
#include "backend/vulkan/PipelineLayoutVk.h"
-#include "backend/vulkan/RenderPassVk.h"
+#include "backend/vulkan/RenderPassCache.h"
+#include "backend/vulkan/RenderPassInfoVk.h"
#include "backend/vulkan/ShaderModuleVk.h"
#include "backend/vulkan/VulkanBackend.h"
@@ -133,10 +134,8 @@
// Initialize the "blend state info" that will be chained in the "create info" from the data
// pre-computed in the BlendState
- const auto& subpassInfo = GetRenderPass()->GetSubpassInfo(GetSubPass());
-
std::array<VkPipelineColorBlendAttachmentState, kMaxColorAttachments> colorBlendAttachments;
- for (uint32_t i : IterateBitSet(subpassInfo.colorAttachmentsSet)) {
+ for (uint32_t i : IterateBitSet(GetColorAttachmentsMask())) {
colorBlendAttachments[i] = ToBackend(GetBlendState(i))->GetState();
}
VkPipelineColorBlendStateCreateInfo colorBlend;
@@ -147,7 +146,7 @@
colorBlend.logicOpEnable = VK_FALSE;
colorBlend.logicOp = VK_LOGIC_OP_CLEAR;
// TODO(cwallez@chromium.org): Do we allow holes in the color attachments?
- colorBlend.attachmentCount = static_cast<uint32_t>(subpassInfo.colorAttachmentsSet.count());
+ colorBlend.attachmentCount = static_cast<uint32_t>(GetColorAttachmentsMask().count());
colorBlend.pAttachments = colorBlendAttachments.data();
// The blend constant is always dynamic so we fill in a dummy value
colorBlend.blendConstants[0] = 0.0f;
@@ -172,6 +171,24 @@
dynamic.dynamicStateCount = sizeof(dynamicStates) / sizeof(dynamicStates[0]);
dynamic.pDynamicStates = dynamicStates;
+ // Get a VkRenderPass that matches the attachment formats for this pipeline, load ops don't
+ // matter so set them all to LoadOp::Load
+ VkRenderPass renderPass = VK_NULL_HANDLE;
+ {
+ RenderPassCacheQuery query;
+
+ for (uint32_t i : IterateBitSet(GetColorAttachmentsMask())) {
+ query.SetColor(i, GetColorAttachmentFormat(i), nxt::LoadOp::Load);
+ }
+
+ if (HasDepthStencilAttachment()) {
+ query.SetDepthStencil(GetDepthStencilFormat(), nxt::LoadOp::Load,
+ nxt::LoadOp::Load);
+ }
+
+ renderPass = mDevice->GetRenderPassCache()->GetRenderPass(query);
+ }
+
// The create info chains in a bunch of things created on the stack here or inside state
// objects.
VkGraphicsPipelineCreateInfo createInfo;
@@ -190,8 +207,8 @@
createInfo.pColorBlendState = &colorBlend;
createInfo.pDynamicState = &dynamic;
createInfo.layout = ToBackend(GetLayout())->GetHandle();
- createInfo.renderPass = ToBackend(GetRenderPass())->GetHandle();
- createInfo.subpass = GetSubPass();
+ createInfo.renderPass = renderPass;
+ createInfo.subpass = 0;
createInfo.basePipelineHandle = VK_NULL_HANDLE;
createInfo.basePipelineIndex = -1;
diff --git a/src/backend/vulkan/VulkanBackend.cpp b/src/backend/vulkan/VulkanBackend.cpp
index ad2b064..e661f7b 100644
--- a/src/backend/vulkan/VulkanBackend.cpp
+++ b/src/backend/vulkan/VulkanBackend.cpp
@@ -24,11 +24,11 @@
#include "backend/vulkan/ComputePipelineVk.h"
#include "backend/vulkan/DepthStencilStateVk.h"
#include "backend/vulkan/FencedDeleter.h"
-#include "backend/vulkan/FramebufferVk.h"
#include "backend/vulkan/InputStateVk.h"
#include "backend/vulkan/NativeSwapChainImplVk.h"
#include "backend/vulkan/PipelineLayoutVk.h"
-#include "backend/vulkan/RenderPassVk.h"
+#include "backend/vulkan/RenderPassCache.h"
+#include "backend/vulkan/RenderPassInfoVk.h"
#include "backend/vulkan/RenderPipelineVk.h"
#include "backend/vulkan/SamplerVk.h"
#include "backend/vulkan/ShaderModuleVk.h"
@@ -146,6 +146,7 @@
mDeleter = new FencedDeleter(this);
mMapRequestTracker = new MapRequestTracker(this);
mMemoryAllocator = new MemoryAllocator(this);
+ mRenderPassCache = new RenderPassCache(this);
}
Device::~Device() {
@@ -189,6 +190,11 @@
delete mMemoryAllocator;
mMemoryAllocator = nullptr;
+ // The VkRenderPasses in the cache can be destroyed immediately since all commands referring
+ // to them are guaranteed to be finished executing.
+ delete mRenderPassCache;
+ mRenderPassCache = nullptr;
+
// VkQueues are destroyed when the VkDevice is destroyed
if (mVkDevice != VK_NULL_HANDLE) {
fn.DestroyDevice(mVkDevice, nullptr);
@@ -231,9 +237,6 @@
DepthStencilStateBase* Device::CreateDepthStencilState(DepthStencilStateBuilder* builder) {
return new DepthStencilState(builder);
}
- FramebufferBase* Device::CreateFramebuffer(FramebufferBuilder* builder) {
- return new Framebuffer(builder);
- }
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
return new InputState(builder);
}
@@ -243,8 +246,8 @@
QueueBase* Device::CreateQueue(QueueBuilder* builder) {
return new Queue(builder);
}
- RenderPassBase* Device::CreateRenderPass(RenderPassBuilder* builder) {
- return new RenderPass(builder);
+ RenderPassInfoBase* Device::CreateRenderPassInfo(RenderPassInfoBuilder* builder) {
+ return new RenderPassInfo(builder);
}
RenderPipelineBase* Device::CreateRenderPipeline(RenderPipelineBuilder* builder) {
return new RenderPipeline(builder);
@@ -325,6 +328,10 @@
return mDeleter;
}
+ RenderPassCache* Device::GetRenderPassCache() const {
+ return mRenderPassCache;
+ }
+
Serial Device::GetSerial() const {
return mNextSerial;
}
diff --git a/src/backend/vulkan/VulkanBackend.h b/src/backend/vulkan/VulkanBackend.h
index 9612bab..a6844bf 100644
--- a/src/backend/vulkan/VulkanBackend.h
+++ b/src/backend/vulkan/VulkanBackend.h
@@ -39,11 +39,10 @@
class ComputePipeline;
class DepthStencilState;
class Device;
- class Framebuffer;
class InputState;
class PipelineLayout;
class Queue;
- class RenderPass;
+ class RenderPassInfo;
class RenderPipeline;
class Sampler;
class ShaderModule;
@@ -55,6 +54,7 @@
class FencedDeleter;
class MapRequestTracker;
class MemoryAllocator;
+ class RenderPassCache;
struct VulkanBackendTraits {
using BindGroupType = BindGroup;
@@ -66,11 +66,10 @@
using ComputePipelineType = ComputePipeline;
using DepthStencilStateType = DepthStencilState;
using DeviceType = Device;
- using FramebufferType = Framebuffer;
using InputStateType = InputState;
using PipelineLayoutType = PipelineLayout;
using QueueType = Queue;
- using RenderPassType = RenderPass;
+ using RenderPassInfoType = RenderPassInfo;
using RenderPipelineType = RenderPipeline;
using SamplerType = Sampler;
using ShaderModuleType = ShaderModule;
@@ -103,6 +102,7 @@
FencedDeleter* GetFencedDeleter() const;
MapRequestTracker* GetMapRequestTracker() const;
MemoryAllocator* GetMemoryAllocator() const;
+ RenderPassCache* GetRenderPassCache() const;
Serial GetSerial() const;
@@ -119,11 +119,10 @@
CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) override;
ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override;
DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
- FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) override;
InputStateBase* CreateInputState(InputStateBuilder* builder) override;
PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override;
QueueBase* CreateQueue(QueueBuilder* builder) override;
- RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) override;
+ RenderPassInfoBase* CreateRenderPassInfo(RenderPassInfoBuilder* builder) override;
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
SamplerBase* CreateSampler(SamplerBuilder* builder) override;
ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override;
@@ -170,6 +169,7 @@
FencedDeleter* mDeleter = nullptr;
MapRequestTracker* mMapRequestTracker = nullptr;
MemoryAllocator* mMemoryAllocator = nullptr;
+ RenderPassCache* mRenderPassCache = nullptr;
VkFence GetUnusedFence();
void CheckPassedFences();