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.
This commit is contained in:
Corentin Wallez
2018-05-02 18:10:13 -04:00
committed by Corentin Wallez
parent 87ec361cc2
commit 6f7749cce9
92 changed files with 1869 additions and 3168 deletions

View File

@@ -40,7 +40,8 @@ namespace backend {
}
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;
}
}

View File

@@ -241,8 +241,6 @@ if (NXT_ENABLE_D3D12)
${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 @@ if (NXT_ENABLE_D3D12)
${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 @@ if (NXT_ENABLE_VULKAN)
${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 @@ if (NXT_ENABLE_VULKAN)
${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 @@ list(APPEND BACKEND_SOURCES
${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 @@ list(APPEND BACKEND_SOURCES
${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

View File

@@ -162,10 +162,6 @@ namespace backend {
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 @@ namespace backend {
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 @@ namespace backend {
commands->NextCommand<BeginRenderPassCmd>();
break;
case Command::BeginRenderSubpass:
commands->NextCommand<BeginRenderSubpassCmd>();
break;
case Command::CopyBufferToBuffer:
commands->NextCommand<CopyBufferToBufferCmd>();
break;
@@ -305,10 +293,6 @@ namespace backend {
commands->NextCommand<EndRenderPassCmd>();
break;
case Command::EndRenderSubpass:
commands->NextCommand<EndRenderSubpassCmd>();
break;
case Command::SetComputePipeline:
commands->NextCommand<SetComputePipelineCmd>();
break;
@@ -384,25 +368,8 @@ namespace backend {
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 @@ namespace backend {
}
} 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 @@ namespace backend {
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 @@ namespace backend {
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 @@ namespace backend {
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);

View File

@@ -62,8 +62,7 @@ namespace backend {
// 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 @@ namespace backend {
uint32_t firstInstance);
void EndComputePass();
void EndRenderPass();
void EndRenderSubpass();
void SetPushConstants(nxt::ShaderStageBit stages,
uint32_t offset,
uint32_t count,

View File

@@ -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 @@ namespace backend {
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 @@ namespace backend {
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 @@ namespace backend {
"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 @@ namespace backend {
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 @@ namespace backend {
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 @@ namespace backend {
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 @@ namespace backend {
}
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;
}

View File

@@ -30,7 +30,6 @@ namespace backend {
// 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 @@ namespace backend {
// 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 @@ namespace backend {
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 @@ namespace backend {
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

View File

@@ -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 @@ namespace backend {
enum class Command {
BeginComputePass,
BeginRenderPass,
BeginRenderSubpass,
CopyBufferToBuffer,
CopyBufferToTexture,
CopyTextureToBuffer,
@@ -39,7 +37,6 @@ namespace backend {
DrawElements,
EndComputePass,
EndRenderPass,
EndRenderSubpass,
SetComputePipeline,
SetRenderPipeline,
SetPushConstants,
@@ -56,12 +53,9 @@ namespace backend {
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 @@ namespace backend {
struct EndRenderPassCmd {};
struct EndRenderSubpassCmd {};
struct SetComputePipelineCmd {
Ref<ComputePipelineBase> pipeline;
};

View File

@@ -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 @@ namespace backend {
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 @@ namespace backend {
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);

View File

@@ -43,11 +43,10 @@ namespace backend {
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 @@ namespace backend {
CommandBufferBuilder* CreateCommandBufferBuilder();
ComputePipelineBuilder* CreateComputePipelineBuilder();
DepthStencilStateBuilder* CreateDepthStencilStateBuilder();
FramebufferBuilder* CreateFramebufferBuilder();
InputStateBuilder* CreateInputStateBuilder();
PipelineLayoutBuilder* CreatePipelineLayoutBuilder();
QueueBuilder* CreateQueueBuilder();
RenderPassBuilder* CreateRenderPassBuilder();
RenderPassInfoBuilder* CreateRenderPassInfoBuilder();
RenderPipelineBuilder* CreateRenderPipelineBuilder();
SamplerBuilder* CreateSamplerBuilder();
ShaderModuleBuilder* CreateShaderModuleBuilder();

View File

@@ -35,16 +35,14 @@ namespace backend {
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;

View File

@@ -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

View File

@@ -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_

View File

@@ -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 {

View File

@@ -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

View File

@@ -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_

View File

@@ -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

View File

@@ -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_

View File

@@ -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 @@ namespace backend {
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 @@ namespace backend {
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 @@ namespace backend {
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 @@ namespace backend {
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 @@ namespace backend {
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 @@ namespace backend {
mDepthStencilState = depthStencilState;
}
void RenderPipelineBuilder::SetDepthStencilAttachmentFormat(nxt::TextureFormat format) {
mDepthStencilFormatSet = true;
mDepthStencilFormat = format;
}
void RenderPipelineBuilder::SetIndexFormat(nxt::IndexFormat format) {
mIndexFormat = format;
}
@@ -155,9 +218,4 @@ namespace backend {
mPrimitiveTopology = primitiveTopology;
}
void RenderPipelineBuilder::SetSubpass(RenderPassBase* renderPass, uint32_t subpass) {
mRenderPass = renderPass;
mSubpass = subpass;
}
} // namespace backend

View File

@@ -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 @@ namespace backend {
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 @@ namespace backend {
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 @@ namespace backend {
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 @@ namespace backend {
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

View File

@@ -267,6 +267,10 @@ namespace backend {
TextureViewBase::TextureViewBase(TextureViewBuilder* builder) : mTexture(builder->mTexture) {
}
const TextureBase* TextureViewBase::GetTexture() const {
return mTexture.Get();
}
TextureBase* TextureViewBase::GetTexture() {
return mTexture.Get();
}

View File

@@ -99,6 +99,7 @@ namespace backend {
public:
TextureViewBase(TextureViewBuilder* builder);
const TextureBase* GetTexture() const;
TextureBase* GetTexture();
private:

View File

@@ -68,11 +68,6 @@ namespace backend {
using BackendType = typename BackendTraits::DeviceType;
};
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 @@ namespace backend {
};
template <typename BackendTraits>
struct ToBackendTraits<RenderPassBase, BackendTraits> {
using BackendType = typename BackendTraits::RenderPassType;
struct ToBackendTraits<RenderPassInfoBase, BackendTraits> {
using BackendType = typename BackendTraits::RenderPassInfoType;
};
template <typename BackendTraits>

View File

@@ -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 @@ namespace backend { namespace d3d12 {
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 @@ namespace backend { namespace d3d12 {
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 @@ namespace backend { namespace d3d12 {
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 @@ namespace backend { namespace d3d12 {
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();

View File

@@ -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 @@ namespace backend { namespace d3d12 {
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 @@ namespace backend { namespace d3d12 {
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 @@ namespace backend { namespace d3d12 {
return new TextureView(builder);
}
// RenderPass
RenderPass::RenderPass(Device* device, RenderPassBuilder* builder)
: RenderPassBase(builder), mDevice(device) {
}
}} // namespace backend::d3d12

View File

@@ -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 @@ namespace backend { namespace d3d12 {
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 @@ namespace backend { namespace d3d12 {
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 @@ namespace backend { namespace d3d12 {
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 @@ namespace backend { namespace d3d12 {
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_

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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 @@ namespace backend { namespace d3d12 {
class Device;
class Framebuffer : public FramebufferBase {
class RenderPassInfo : public RenderPassInfoBase {
public:
struct OMSetRenderTargetArgs {
unsigned int numRTVs = 0;
@@ -36,20 +36,17 @@ namespace backend { namespace d3d12 {
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_

View File

@@ -136,26 +136,16 @@ namespace backend { namespace d3d12 {
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;

View File

@@ -35,9 +35,6 @@ namespace backend { namespace metal {
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 @@ namespace backend { namespace metal {
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 @@ namespace backend { namespace metal {
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 @@ namespace backend { namespace metal {
// 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 @@ namespace backend { namespace metal {
PerStage<std::array<uint32_t, kMaxPushConstants>> pushConstants;
uint32_t currentSubpass = 0;
while (mCommands.NextCommandId(&type)) {
switch (type) {
case Command::BeginComputePass: {
@@ -190,15 +171,11 @@ namespace backend { namespace metal {
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 @@ namespace backend { namespace metal {
case Command::EndRenderPass: {
mCommands.NextCommand<EndRenderPassCmd>();
} break;
case Command::EndRenderSubpass: {
mCommands.NextCommand<EndRenderSubpassCmd>();
encoders.EndSubpass();
currentSubpass += 1;
encoders.EndRenderPass();
} break;
case Command::SetComputePipeline: {

View File

@@ -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 @@ namespace backend { namespace metal {
class InputState;
class PipelineLayout;
class Queue;
class RenderPass;
class RenderPassInfo;
class RenderPipeline;
class Sampler;
class ShaderModule;
@@ -63,11 +62,10 @@ namespace backend { namespace metal {
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 @@ namespace backend { namespace metal {
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 @@ namespace backend { namespace metal {
BindGroupLayout(BindGroupLayoutBuilder* builder);
};
class Framebuffer : public FramebufferBase {
public:
Framebuffer(FramebufferBuilder* builder);
~Framebuffer();
};
class Queue : public QueueBase {
public:
Queue(QueueBuilder* builder);
@@ -163,10 +154,10 @@ namespace backend { namespace metal {
id<MTLCommandQueue> mCommandQueue = nil;
};
class RenderPass : public RenderPassBase {
class RenderPassInfo : public RenderPassInfoBase {
public:
RenderPass(RenderPassBuilder* builder);
~RenderPass();
RenderPassInfo(RenderPassInfoBuilder* builder);
~RenderPassInfo();
};
}} // namespace backend::metal

View File

@@ -101,9 +101,6 @@ namespace backend { namespace metal {
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 @@ namespace backend { namespace metal {
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 @@ namespace backend { namespace metal {
: BindGroupLayoutBase(builder) {
}
// Framebuffer
Framebuffer::Framebuffer(FramebufferBuilder* builder) : FramebufferBase(builder) {
}
Framebuffer::~Framebuffer() {
}
// Queue
Queue::Queue(QueueBuilder* builder) : QueueBase(builder) {
@@ -240,10 +229,10 @@ namespace backend { namespace metal {
// RenderPass
RenderPass::RenderPass(RenderPassBuilder* builder) : RenderPassBase(builder) {
RenderPassInfo::RenderPassInfo(RenderPassInfoBuilder* builder) : RenderPassInfoBase(builder) {
}
RenderPass::~RenderPass() {
RenderPassInfo::~RenderPassInfo() {
}
}} // namespace backend::metal

View File

@@ -92,24 +92,17 @@ namespace backend { namespace metal {
}
}
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());

View File

@@ -60,9 +60,6 @@ namespace backend { namespace null {
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 @@ namespace backend { namespace null {
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);

View File

@@ -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 @@ namespace backend { namespace null {
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 @@ namespace backend { namespace null {
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 @@ namespace backend { namespace null {
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;

View File

@@ -254,9 +254,6 @@ namespace backend { namespace opengl {
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 @@ namespace backend { namespace opengl {
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 @@ namespace backend { namespace opengl {
glGenFramebuffers(1, &currentFBO);
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 @@ namespace backend { namespace opengl {
// 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 @@ namespace backend { namespace opengl {
}
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 @@ namespace backend { namespace opengl {
// 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 @@ namespace backend { namespace opengl {
case Command::EndRenderPass: {
mCommands.NextCommand<EndRenderPassCmd>();
} break;
case Command::EndRenderSubpass: {
mCommands.NextCommand<EndRenderSubpassCmd>();
glDeleteFramebuffers(1, &currentFBO);
currentFBO = 0;
currentSubpass += 1;
} break;
case Command::SetComputePipeline: {

View File

@@ -73,17 +73,14 @@ namespace backend { namespace opengl {
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 @@ namespace backend { namespace opengl {
: BindGroupLayoutBase(builder) {
}
// Framebuffer
Framebuffer::Framebuffer(FramebufferBuilder* builder) : FramebufferBase(builder) {
}
// Queue
Queue::Queue(QueueBuilder* builder) : QueueBase(builder) {
@@ -134,9 +126,9 @@ namespace backend { namespace opengl {
}
}
// RenderPass
// RenderPassInfo
RenderPass::RenderPass(RenderPassBuilder* builder) : RenderPassBase(builder) {
RenderPassInfo::RenderPassInfo(RenderPassInfoBuilder* builder) : RenderPassInfoBase(builder) {
}
}} // namespace backend::opengl

View File

@@ -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 @@ namespace backend { namespace opengl {
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 @@ namespace backend { namespace opengl {
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 @@ namespace backend { namespace opengl {
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 @@ namespace backend { namespace opengl {
BindGroupLayout(BindGroupLayoutBuilder* builder);
};
class Framebuffer : public FramebufferBase {
public:
Framebuffer(FramebufferBuilder* builder);
};
class Queue : public QueueBase {
public:
Queue(QueueBuilder* builder);
@@ -132,9 +123,9 @@ namespace backend { namespace opengl {
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

View File

@@ -60,10 +60,7 @@ namespace backend { namespace opengl {
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);
}
}

View File

@@ -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 @@ namespace backend { namespace vulkan {
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 @@ namespace backend { namespace vulkan {
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 @@ namespace backend { namespace vulkan {
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 @@ namespace backend { namespace vulkan {
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();

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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_

View File

@@ -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

View File

@@ -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_

View File

@@ -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

View File

@@ -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_

View File

@@ -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 @@ namespace backend { namespace vulkan {
// 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 @@ namespace backend { namespace vulkan {
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 @@ namespace backend { namespace vulkan {
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 @@ namespace backend { namespace vulkan {
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;

View File

@@ -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 @@ namespace backend { namespace vulkan {
mDeleter = new FencedDeleter(this);
mMapRequestTracker = new MapRequestTracker(this);
mMemoryAllocator = new MemoryAllocator(this);
mRenderPassCache = new RenderPassCache(this);
}
Device::~Device() {
@@ -189,6 +190,11 @@ namespace backend { namespace vulkan {
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 @@ namespace backend { namespace vulkan {
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 @@ namespace backend { namespace vulkan {
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 @@ namespace backend { namespace vulkan {
return mDeleter;
}
RenderPassCache* Device::GetRenderPassCache() const {
return mRenderPassCache;
}
Serial Device::GetSerial() const {
return mNextSerial;
}

View File

@@ -39,11 +39,10 @@ namespace backend { namespace vulkan {
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 @@ namespace backend { namespace vulkan {
class FencedDeleter;
class MapRequestTracker;
class MemoryAllocator;
class RenderPassCache;
struct VulkanBackendTraits {
using BindGroupType = BindGroup;
@@ -66,11 +66,10 @@ namespace backend { namespace vulkan {
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 @@ namespace backend { namespace vulkan {
FencedDeleter* GetFencedDeleter() const;
MapRequestTracker* GetMapRequestTracker() const;
MemoryAllocator* GetMemoryAllocator() const;
RenderPassCache* GetRenderPassCache() const;
Serial GetSerial() const;
@@ -119,11 +119,10 @@ namespace backend { namespace vulkan {
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 @@ namespace backend { namespace vulkan {
FencedDeleter* mDeleter = nullptr;
MapRequestTracker* mMapRequestTracker = nullptr;
MemoryAllocator* mMemoryAllocator = nullptr;
RenderPassCache* mRenderPassCache = nullptr;
VkFence GetUnusedFence();
void CheckPassedFences();