Split Pipeline in Render and Compute, common part

This commit is contained in:
Corentin Wallez 2017-07-14 10:58:07 -04:00 committed by Corentin Wallez
parent 00349e6e36
commit 29ced285d4
20 changed files with 496 additions and 245 deletions

137
next.json
View File

@ -387,12 +387,15 @@
]
},
{
"name": "set pipeline",
"name": "set compute pipeline",
"args": [
{"name": "pipeline", "type": "pipeline"}
],
"notes": [
"Not specifying graphics or compute because we know from render pass"
{"name": "pipeline", "type": "compute pipeline"}
]
},
{
"name": "set render pipeline",
"args": [
{"name": "pipeline", "type": "render pipeline"}
]
},
{
@ -433,6 +436,32 @@
{"value": 7, "name": "always"}
]
},
"compute pipeline": {
"category": "object"
},
"compute pipeline builder": {
"category": "object",
"methods": [
{
"name": "get result",
"returns": "compute pipeline"
},
{
"name": "set layout",
"args": [
{"name": "layout", "type": "pipeline layout"}
]
},
{
"name": "set stage",
"args": [
{"name": "stage", "type": "shader stage"},
{"name": "module", "type": "shader module"},
{"name": "entry point", "type": "char", "annotation": "const*", "length": "strlen"}
]
}
]
},
"device": {
"category": "object",
"methods": [
@ -465,8 +494,12 @@
"returns": "input state builder"
},
{
"name": "create pipeline builder",
"returns": "pipeline builder"
"name": "create compute pipeline builder",
"returns": "compute pipeline builder"
},
{
"name": "create render pipeline builder",
"returns": "render pipeline builder"
},
{
"name": "create pipeline layout builder",
@ -639,51 +672,6 @@
{"value": 1, "name": "instance"}
]
},
"pipeline": {
"category": "object"
},
"pipeline builder": {
"category": "object",
"methods": [
{
"name": "get result",
"returns": "pipeline"
},
{
"name": "set layout",
"args": [
{"name": "layout", "type": "pipeline layout"}
]
},
{
"name": "set subpass",
"args": [
{"name": "render pass", "type": "render pass"},
{"name": "subpass", "type": "uint32_t"}
]
},
{
"name": "set stage",
"args": [
{"name": "stage", "type": "shader stage"},
{"name": "module", "type": "shader module"},
{"name": "entry point", "type": "char", "annotation": "const*", "length": "strlen"}
]
},
{
"name": "set input state",
"args": [
{"name": "input", "type": "input state"}
]
},
{
"name": "set depth stencil state",
"args": [
{"name": "depth stencil state", "type": "depth stencil state"}
]
}
]
},
"pipeline layout": {
"category": "object"
},
@ -775,6 +763,51 @@
"render pass": {
"category": "object"
},
"render pipeline": {
"category": "object"
},
"render pipeline builder": {
"category": "object",
"methods": [
{
"name": "get result",
"returns": "render pipeline"
},
{
"name": "set layout",
"args": [
{"name": "layout", "type": "pipeline layout"}
]
},
{
"name": "set subpass",
"args": [
{"name": "render pass", "type": "render pass"},
{"name": "subpass", "type": "uint32_t"}
]
},
{
"name": "set stage",
"args": [
{"name": "stage", "type": "shader stage"},
{"name": "module", "type": "shader module"},
{"name": "entry point", "type": "char", "annotation": "const*", "length": "strlen"}
]
},
{
"name": "set input state",
"args": [
{"name": "input", "type": "input state"}
]
},
{
"name": "set depth stencil state",
"args": [
{"name": "depth stencil state", "type": "depth stencil state"}
]
}
]
},
"sampler": {
"category": "object"
},

View File

@ -253,6 +253,8 @@ list(APPEND BACKEND_SOURCES
${BACKEND_DIR}/CommandAllocator.h
${BACKEND_DIR}/CommandBuffer.cpp
${BACKEND_DIR}/CommandBuffer.h
${BACKEND_DIR}/ComputePipeline.cpp
${BACKEND_DIR}/ComputePipeline.h
${BACKEND_DIR}/DepthStencilState.cpp
${BACKEND_DIR}/DepthStencilState.h
${BACKEND_DIR}/CommandBufferStateTracker.cpp
@ -264,6 +266,8 @@ list(APPEND BACKEND_SOURCES
${BACKEND_DIR}/Framebuffer.h
${BACKEND_DIR}/InputState.cpp
${BACKEND_DIR}/InputState.h
${BACKEND_DIR}/RenderPipeline.cpp
${BACKEND_DIR}/RenderPipeline.h
${BACKEND_DIR}/PerStage.cpp
${BACKEND_DIR}/PerStage.h
${BACKEND_DIR}/Pipeline.cpp

View File

@ -18,10 +18,11 @@
#include "backend/Buffer.h"
#include "backend/Commands.h"
#include "backend/CommandBufferStateTracker.h"
#include "backend/ComputePipeline.h"
#include "backend/Device.h"
#include "backend/InputState.h"
#include "backend/Pipeline.h"
#include "backend/PipelineLayout.h"
#include "backend/RenderPipeline.h"
#include "backend/Texture.h"
#include <cstring>
@ -181,10 +182,16 @@ namespace backend {
cmd->~EndRenderSubpassCmd();
}
break;
case Command::SetPipeline:
case Command::SetComputePipeline:
{
SetPipelineCmd* cmd = commands->NextCommand<SetPipelineCmd>();
cmd->~SetPipelineCmd();
SetComputePipelineCmd* cmd = commands->NextCommand<SetComputePipelineCmd>();
cmd->~SetComputePipelineCmd();
}
break;
case Command::SetRenderPipeline:
{
SetRenderPipelineCmd* cmd = commands->NextCommand<SetRenderPipelineCmd>();
cmd->~SetRenderPipelineCmd();
}
break;
case Command::SetPushConstants:
@ -290,8 +297,12 @@ namespace backend {
commands->NextCommand<EndRenderSubpassCmd>();
break;
case Command::SetPipeline:
commands->NextCommand<SetPipelineCmd>();
case Command::SetComputePipeline:
commands->NextCommand<SetComputePipelineCmd>();
break;
case Command::SetRenderPipeline:
commands->NextCommand<SetRenderPipelineCmd>();
break;
case Command::SetPushConstants:
@ -484,11 +495,21 @@ namespace backend {
}
break;
case Command::SetPipeline:
case Command::SetComputePipeline:
{
SetPipelineCmd* cmd = iterator.NextCommand<SetPipelineCmd>();
PipelineBase* pipeline = cmd->pipeline.Get();
if (!state->SetPipeline(pipeline)) {
SetComputePipelineCmd* cmd = iterator.NextCommand<SetComputePipelineCmd>();
ComputePipelineBase* pipeline = cmd->pipeline.Get();
if (!state->SetComputePipeline(pipeline)) {
return false;
}
}
break;
case Command::SetRenderPipeline:
{
SetRenderPipelineCmd* cmd = iterator.NextCommand<SetRenderPipelineCmd>();
RenderPipelineBase* pipeline = cmd->pipeline.Get();
if (!state->SetRenderPipeline(pipeline)) {
return false;
}
}
@ -681,9 +702,15 @@ namespace backend {
allocator.Allocate<EndRenderSubpassCmd>(Command::EndRenderSubpass);
}
void CommandBufferBuilder::SetPipeline(PipelineBase* pipeline) {
SetPipelineCmd* cmd = allocator.Allocate<SetPipelineCmd>(Command::SetPipeline);
new(cmd) SetPipelineCmd;
void CommandBufferBuilder::SetComputePipeline(ComputePipelineBase* pipeline) {
SetComputePipelineCmd* cmd = allocator.Allocate<SetComputePipelineCmd>(Command::SetComputePipeline);
new(cmd) SetComputePipelineCmd;
cmd->pipeline = pipeline;
}
void CommandBufferBuilder::SetRenderPipeline(RenderPipelineBase* pipeline) {
SetRenderPipelineCmd* cmd = allocator.Allocate<SetRenderPipelineCmd>(Command::SetRenderPipeline);
new(cmd) SetRenderPipelineCmd;
cmd->pipeline = pipeline;
}

View File

@ -78,7 +78,8 @@ namespace backend {
void EndRenderPass();
void EndRenderSubpass();
void SetPushConstants(nxt::ShaderStageBit stage, uint32_t offset, uint32_t count, const void* data);
void SetPipeline(PipelineBase* pipeline);
void SetComputePipeline(ComputePipelineBase* pipeline);
void SetRenderPipeline(RenderPipelineBase* pipeline);
void SetStencilReference(uint32_t reference);
void SetBindGroup(uint32_t groupIndex, BindGroupBase* group);
void SetIndexBuffer(BufferBase* buffer, uint32_t offset, nxt::IndexFormat format);

View File

@ -18,11 +18,12 @@
#include "backend/BindGroup.h"
#include "backend/BindGroupLayout.h"
#include "backend/Buffer.h"
#include "backend/ComputePipeline.h"
#include "backend/Framebuffer.h"
#include "backend/InputState.h"
#include "backend/Pipeline.h"
#include "backend/PipelineLayout.h"
#include "backend/RenderPass.h"
#include "backend/RenderPipeline.h"
#include "backend/Texture.h"
#include "common/Assert.h"
#include "common/BitSetIterator.h"
@ -257,47 +258,33 @@ namespace backend {
return true;
}
bool CommandBufferStateTracker::SetPipeline(PipelineBase* pipeline) {
PipelineLayoutBase* layout = pipeline->GetLayout();
if (pipeline->IsCompute()) {
if (!aspects[VALIDATION_ASPECT_COMPUTE_PASS]) {
builder->HandleError("A compute pass must be active when a compute pipeline is set");
return false;
}
if (currentRenderPass) {
builder->HandleError("Can't use a compute pipeline while a render pass is active");
return false;
}
aspects.set(VALIDATION_ASPECT_COMPUTE_PIPELINE);
} else {
if (!aspects[VALIDATION_ASPECT_RENDER_SUBPASS]) {
builder->HandleError("A render subpass must be active when a render pipeline is set");
return false;
}
if (!pipeline->GetRenderPass()->IsCompatibleWith(currentRenderPass)) {
builder->HandleError("Pipeline is incompatible with this render pass");
return false;
}
aspects.set(VALIDATION_ASPECT_RENDER_PIPELINE);
bool CommandBufferStateTracker::SetComputePipeline(ComputePipelineBase* pipeline) {
if (!aspects[VALIDATION_ASPECT_COMPUTE_PASS]) {
builder->HandleError("A compute pass must be active when a compute pipeline is set");
return false;
}
aspects.reset(VALIDATION_ASPECT_BIND_GROUPS);
bindgroupsSet = ~layout->GetBindGroupsLayoutMask();
// Only bindgroups that were not the same layout in the last pipeline need to be set again.
if (lastPipeline) {
PipelineLayoutBase* lastLayout = lastPipeline->GetLayout();
for (uint32_t i = 0; i < kMaxBindGroups; ++i) {
if (lastLayout->GetBindGroupLayout(i) == layout->GetBindGroupLayout(i)) {
bindgroupsSet |= uint64_t(1) << i;
} else {
break;
}
}
if (currentRenderPass) {
builder->HandleError("Can't use a compute pipeline while a render pass is active");
return false;
}
aspects.set(VALIDATION_ASPECT_COMPUTE_PIPELINE);
lastPipeline = pipeline;
return true;
return SetPipelineCommon(pipeline);
}
bool CommandBufferStateTracker::SetRenderPipeline(RenderPipelineBase* pipeline) {
if (!aspects[VALIDATION_ASPECT_RENDER_SUBPASS]) {
builder->HandleError("A render subpass must be active when a render pipeline is set");
return false;
}
if (!pipeline->GetRenderPass()->IsCompatibleWith(currentRenderPass)) {
builder->HandleError("Pipeline is incompatible with this render pass");
return false;
}
aspects.set(VALIDATION_ASPECT_RENDER_PIPELINE);
lastRenderPipeline = pipeline;
return SetPipelineCommon(pipeline);
}
bool CommandBufferStateTracker::SetBindGroup(uint32_t index, BindGroupBase* bindgroup) {
@ -450,7 +437,7 @@ namespace backend {
return true;
}
// Assumes we have a pipeline already
auto requiredInputs = lastPipeline->GetInputState()->GetInputsSetMask();
auto requiredInputs = lastRenderPipeline->GetInputState()->GetInputsSetMask();
if ((inputsSet & ~requiredInputs).none()) {
aspects.set(VALIDATION_ASPECT_VERTEX_BUFFERS);
return true;
@ -533,6 +520,29 @@ namespace backend {
return true;
}
bool CommandBufferStateTracker::SetPipelineCommon(PipelineBase* pipeline) {
PipelineLayoutBase* layout = pipeline->GetLayout();
aspects.reset(VALIDATION_ASPECT_BIND_GROUPS);
bindgroupsSet = ~layout->GetBindGroupsLayoutMask();
// Only bindgroups that were not the same layout in the last pipeline need to be set again.
if (lastPipeline) {
PipelineLayoutBase* lastLayout = lastPipeline->GetLayout();
for (uint32_t i = 0; i < kMaxBindGroups; ++i) {
if (lastLayout->GetBindGroupLayout(i) == layout->GetBindGroupLayout(i)) {
bindgroupsSet |= uint64_t(1) << i;
} else {
break;
}
}
}
lastPipeline = pipeline;
return true;
}
void CommandBufferStateTracker::UnsetPipeline() {
constexpr ValidationAspects pipelineDependentAspects =
1 << VALIDATION_ASPECT_RENDER_PIPELINE |

View File

@ -45,7 +45,8 @@ namespace backend {
bool EndSubpass();
bool BeginRenderPass(RenderPassBase* renderPass, FramebufferBase* framebuffer);
bool EndRenderPass();
bool SetPipeline(PipelineBase* pipeline);
bool SetComputePipeline(ComputePipelineBase* pipeline);
bool SetRenderPipeline(RenderPipelineBase* pipeline);
bool SetBindGroup(uint32_t index, BindGroupBase* bindgroup);
bool SetIndexBuffer(BufferBase* buffer);
bool SetVertexBuffer(uint32_t index, BufferBase* buffer);
@ -88,6 +89,7 @@ namespace backend {
bool ValidateBindGroupUsages(BindGroupBase* group) const;
bool RevalidateCanDraw();
bool SetPipelineCommon(PipelineBase* pipeline);
void UnsetPipeline();
CommandBufferBuilder* builder;
@ -98,6 +100,7 @@ namespace backend {
std::array<BindGroupBase*, kMaxBindGroups> bindgroups = {};
std::bitset<kMaxVertexInputs> inputsSet;
PipelineBase* lastPipeline = nullptr;
RenderPipelineBase* lastRenderPipeline = nullptr;
std::map<BufferBase*, nxt::BufferUsageBit> mostRecentBufferUsages;
std::map<TextureBase*, nxt::TextureUsageBit> mostRecentTextureUsages;

View File

@ -40,7 +40,8 @@ namespace backend {
EndComputePass,
EndRenderPass,
EndRenderSubpass,
SetPipeline,
SetComputePipeline,
SetRenderPipeline,
SetPushConstants,
SetStencilReference,
SetBindGroup,
@ -118,8 +119,12 @@ namespace backend {
struct EndRenderSubpassCmd {
};
struct SetPipelineCmd {
Ref<PipelineBase> pipeline;
struct SetComputePipelineCmd {
Ref<ComputePipelineBase> pipeline;
};
struct SetRenderPipelineCmd {
Ref<RenderPipelineBase> pipeline;
};
struct SetPushConstantsCmd {

View File

@ -0,0 +1,41 @@
// 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/ComputePipeline.h"
#include "backend/Device.h"
namespace backend {
// ComputePipelineBase
ComputePipelineBase::ComputePipelineBase(ComputePipelineBuilder* builder)
: PipelineBase(builder) {
if (GetStageMask() != nxt::ShaderStageBit::Compute) {
builder->HandleError("Compute pipeline should have exactly a compute stage");
return;
}
}
// ComputePipelineBuilder
ComputePipelineBuilder::ComputePipelineBuilder(DeviceBase* device)
: Builder(device), PipelineBuilder(this) {
}
ComputePipelineBase* ComputePipelineBuilder::GetResultImpl() {
return device->CreateComputePipeline(this);
}
}

View File

@ -0,0 +1,38 @@
// 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_COMPUTEPIPELINE_H_
#define BACKEND_COMPUTEPIPELINE_H_
#include "backend/Pipeline.h"
namespace backend {
class ComputePipelineBase : public RefCounted, public PipelineBase {
public:
ComputePipelineBase(ComputePipelineBuilder* builder);
};
class ComputePipelineBuilder : public Builder<ComputePipelineBase>, public PipelineBuilder {
public:
ComputePipelineBuilder(DeviceBase* device);
private:
ComputePipelineBase* GetResultImpl() override;
};
}
#endif // BACKEND_COMPUTEPIPELINE_H_

View File

@ -18,13 +18,14 @@
#include "backend/BindGroupLayout.h"
#include "backend/Buffer.h"
#include "backend/CommandBuffer.h"
#include "backend/ComputePipeline.h"
#include "backend/DepthStencilState.h"
#include "backend/Framebuffer.h"
#include "backend/InputState.h"
#include "backend/Pipeline.h"
#include "backend/PipelineLayout.h"
#include "backend/Queue.h"
#include "backend/RenderPass.h"
#include "backend/RenderPipeline.h"
#include "backend/Sampler.h"
#include "backend/ShaderModule.h"
#include "backend/Texture.h"
@ -99,6 +100,9 @@ namespace backend {
CommandBufferBuilder* DeviceBase::CreateCommandBufferBuilder() {
return new CommandBufferBuilder(this);
}
ComputePipelineBuilder* DeviceBase::CreateComputePipelineBuilder() {
return new ComputePipelineBuilder(this);
}
DepthStencilStateBuilder* DeviceBase::CreateDepthStencilStateBuilder() {
return new DepthStencilStateBuilder(this);
}
@ -108,9 +112,6 @@ namespace backend {
InputStateBuilder* DeviceBase::CreateInputStateBuilder() {
return new InputStateBuilder(this);
}
PipelineBuilder* DeviceBase::CreatePipelineBuilder() {
return new PipelineBuilder(this);
}
PipelineLayoutBuilder* DeviceBase::CreatePipelineLayoutBuilder() {
return new PipelineLayoutBuilder(this);
}
@ -120,6 +121,9 @@ namespace backend {
RenderPassBuilder* DeviceBase::CreateRenderPassBuilder() {
return new RenderPassBuilder(this);
}
RenderPipelineBuilder* DeviceBase::CreateRenderPipelineBuilder() {
return new RenderPipelineBuilder(this);
}
SamplerBuilder* DeviceBase::CreateSamplerBuilder() {
return new SamplerBuilder(this);
}

View File

@ -39,13 +39,14 @@ namespace backend {
virtual BufferBase* CreateBuffer(BufferBuilder* builder) = 0;
virtual BufferViewBase* CreateBufferView(BufferViewBuilder* builder) = 0;
virtual CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) = 0;
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 PipelineBase* CreatePipeline(PipelineBuilder* builder) = 0;
virtual PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) = 0;
virtual QueueBase* CreateQueue(QueueBuilder* builder) = 0;
virtual RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) = 0;
virtual RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) = 0;
virtual SamplerBase* CreateSampler(SamplerBuilder* builder) = 0;
virtual ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) = 0;
virtual TextureBase* CreateTexture(TextureBuilder* builder) = 0;
@ -76,13 +77,14 @@ namespace backend {
BufferBuilder* CreateBufferBuilder();
BufferViewBuilder* CreateBufferViewBuilder();
CommandBufferBuilder* CreateCommandBufferBuilder();
ComputePipelineBuilder* CreateComputePipelineBuilder();
DepthStencilStateBuilder* CreateDepthStencilStateBuilder();
FramebufferBuilder* CreateFramebufferBuilder();
InputStateBuilder* CreateInputStateBuilder();
PipelineBuilder* CreatePipelineBuilder();
PipelineLayoutBuilder* CreatePipelineLayoutBuilder();
QueueBuilder* CreateQueueBuilder();
RenderPassBuilder* CreateRenderPassBuilder();
RenderPipelineBuilder* CreateRenderPipelineBuilder();
SamplerBuilder* CreateSamplerBuilder();
ShaderModuleBuilder* CreateShaderModuleBuilder();
TextureBuilder* CreateTextureBuilder();

View File

@ -27,6 +27,8 @@ namespace backend {
class BufferBuilder;
class BufferViewBase;
class BufferViewBuilder;
class ComputePipelineBase;
class ComputePipelineBuilder;
class CommandBufferBase;
class CommandBufferBuilder;
class DepthStencilStateBase;
@ -35,14 +37,14 @@ namespace backend {
class FramebufferBuilder;
class InputStateBase;
class InputStateBuilder;
class PipelineBase;
class PipelineBuilder;
class PipelineLayoutBase;
class PipelineLayoutBuilder;
class QueueBase;
class QueueBuilder;
class RenderPassBase;
class RenderPassBuilder;
class RenderPipelineBase;
class RenderPipelineBuilder;
class SamplerBase;
class SamplerBuilder;
class ShaderModuleBase;

View File

@ -0,0 +1,95 @@
// 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/RenderPipeline.h"
#include "backend/Device.h"
#include "backend/DepthStencilState.h"
#include "backend/InputState.h"
#include "backend/RenderPass.h"
namespace backend {
// RenderPipelineBase
RenderPipelineBase::RenderPipelineBase(RenderPipelineBuilder* builder)
: PipelineBase(builder), renderPass(std::move(builder->renderPass)), subpass(builder->subpass),
inputState(std::move(builder->inputState)), depthStencilState(std::move(builder->depthStencilState)) {
if (GetStageMask() != (nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment)) {
builder->HandleError("Render pipeline should have exactly a vertex and fragment stage");
return;
}
if (!renderPass) {
builder->HandleError("Pipeline render pass not set");
return;
}
// TODO(kainino@chromium.org): Need to verify the pipeline against its render subpass.
if ((builder->GetStageInfo(nxt::ShaderStage::Vertex).module->GetUsedVertexAttributes() & ~inputState->GetAttributesSetMask()).any()) {
builder->HandleError("Pipeline vertex stage uses inputs not in the input state");
return;
}
}
RenderPassBase* RenderPipelineBase::GetRenderPass() {
return renderPass.Get();
}
uint32_t RenderPipelineBase::GetSubPass() {
return subpass;
}
InputStateBase* RenderPipelineBase::GetInputState() {
return inputState.Get();
}
DepthStencilStateBase* RenderPipelineBase::GetDepthStencilState() {
return depthStencilState.Get();
}
// RenderPipelineBuilder
RenderPipelineBuilder::RenderPipelineBuilder(DeviceBase* device)
: Builder(device), PipelineBuilder(this) {
}
RenderPipelineBase* RenderPipelineBuilder::GetResultImpl() {
// TODO(cwallez@chromium.org): the layout should be required, and put the default objects in the device
if (!inputState) {
inputState = device->CreateInputStateBuilder()->GetResult();
}
if (!depthStencilState) {
depthStencilState = device->CreateDepthStencilStateBuilder()->GetResult();
}
return device->CreateRenderPipeline(this);
}
void RenderPipelineBuilder::SetSubpass(RenderPassBase* renderPass, uint32_t subpass) {
this->renderPass = renderPass;
this->subpass = subpass;
}
void RenderPipelineBuilder::SetInputState(InputStateBase* inputState) {
this->inputState = inputState;
}
void RenderPipelineBuilder::SetDepthStencilState(DepthStencilStateBase* depthStencilState) {
this->depthStencilState = depthStencilState;
}
}

View File

@ -0,0 +1,62 @@
// 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_RENDERPIPELINE_H_
#define BACKEND_RENDERPIPELINE_H_
#include "backend/Pipeline.h"
#include "nxt/nxtcpp.h"
namespace backend {
class RenderPipelineBase : public RefCounted, public PipelineBase {
public:
RenderPipelineBase(RenderPipelineBuilder* builder);
RenderPassBase* GetRenderPass();
uint32_t GetSubPass();
InputStateBase* GetInputState();
DepthStencilStateBase* GetDepthStencilState();
private:
Ref<RenderPassBase> renderPass;
uint32_t subpass;
Ref<InputStateBase> inputState;
Ref<DepthStencilStateBase> depthStencilState;
};
class RenderPipelineBuilder : public Builder<RenderPipelineBase>, public PipelineBuilder {
public:
RenderPipelineBuilder(DeviceBase* device);
// NXT API
void SetSubpass(RenderPassBase* renderPass, uint32_t subpass);
void SetInputState(InputStateBase* inputState);
void SetDepthStencilState(DepthStencilStateBase* depthStencilState);
private:
friend class RenderPipelineBase;
RenderPipelineBase* GetResultImpl() override;
Ref<RenderPassBase> renderPass;
uint32_t subpass;
Ref<InputStateBase> inputState;
Ref<DepthStencilStateBase> depthStencilState;
};
}
#endif // BACKEND_RENDERPIPELINE_H_

View File

@ -26,27 +26,11 @@ namespace backend {
// PipelineBase
PipelineBase::PipelineBase(PipelineBuilder* builder)
: stageMask(builder->stageMask), layout(std::move(builder->layout)),
renderPass(std::move(builder->renderPass)), subpass(builder->subpass),
inputState(std::move(builder->inputState)), depthStencilState(std::move(builder->depthStencilState)) {
if (stageMask != (nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment) &&
stageMask != nxt::ShaderStageBit::Compute) {
builder->HandleError("Wrong combination of stage for pipeline");
return;
: stageMask(builder->stageMask), layout(std::move(builder->layout)) {
if (!layout) {
layout = builder->GetParentBuilder()->GetDevice()->CreatePipelineLayoutBuilder()->GetResult();
}
if (IsCompute() && depthStencilState) {
builder->HandleError("Compute pipeline cannot have depth stencil state");
return;
}
if (!IsCompute() && !renderPass) {
builder->HandleError("Pipeline render pass not set");
return;
}
// TODO(kainino@chromium.org): Need to verify the pipeline against its render subpass.
auto FillPushConstants = [](const ShaderModuleBase* module, PushConstantInfo* info) {
const auto& moduleInfo = module->GetPushConstants();
info->mask = moduleInfo.mask;
@ -66,19 +50,12 @@ namespace backend {
for (auto stageBit : IterateStages(builder->stageMask)) {
if (!builder->stages[stageBit].module->IsCompatibleWithPipelineLayout(layout.Get())) {
builder->HandleError("Stage not compatible with layout");
builder->GetParentBuilder()->HandleError("Stage not compatible with layout");
return;
}
FillPushConstants(builder->stages[stageBit].module.Get(), &pushConstants[stageBit]);
}
if (!IsCompute()) {
if ((builder->stages[nxt::ShaderStage::Vertex].module->GetUsedVertexAttributes() & ~inputState->GetAttributesSetMask()).any()) {
builder->HandleError("Pipeline vertex stage uses inputs not in the input state");
return;
}
}
}
const PipelineBase::PushConstantInfo& PipelineBase::GetPushConstants(nxt::ShaderStage stage) const {
@ -93,30 +70,10 @@ namespace backend {
return layout.Get();
}
RenderPassBase* PipelineBase::GetRenderPass() {
return renderPass.Get();
}
uint32_t PipelineBase::GetSubPass() {
return subpass;
}
InputStateBase* PipelineBase::GetInputState() {
return inputState.Get();
}
DepthStencilStateBase* PipelineBase::GetDepthStencilState() {
return depthStencilState.Get();
}
bool PipelineBase::IsCompute() const {
return stageMask == nxt::ShaderStageBit::Compute;
}
// PipelineBuilder
PipelineBuilder::PipelineBuilder(DeviceBase* device)
: Builder(device), stageMask(static_cast<nxt::ShaderStageBit>(0)) {
PipelineBuilder::PipelineBuilder(BuilderBase* parentBuilder)
: parentBuilder(parentBuilder), stageMask(static_cast<nxt::ShaderStageBit>(0)) {
}
const PipelineBuilder::StageInfo& PipelineBuilder::GetStageInfo(nxt::ShaderStage stage) const {
@ -124,48 +81,28 @@ namespace backend {
return stages[stage];
}
PipelineBase* PipelineBuilder::GetResultImpl() {
// TODO(cwallez@chromium.org): the layout should be required, and put the default objects in the device
if (!layout) {
layout = device->CreatePipelineLayoutBuilder()->GetResult();
}
if (!inputState && !IsCompute()) {
inputState = device->CreateInputStateBuilder()->GetResult();
}
if (!depthStencilState && !IsCompute()) {
depthStencilState = device->CreateDepthStencilStateBuilder()->GetResult();
}
return device->CreatePipeline(this);
}
bool PipelineBuilder::IsCompute() const {
return stageMask == nxt::ShaderStageBit::Compute;
BuilderBase* PipelineBuilder::GetParentBuilder() const {
return parentBuilder;
}
void PipelineBuilder::SetLayout(PipelineLayoutBase* layout) {
this->layout = layout;
}
void PipelineBuilder::SetSubpass(RenderPassBase* renderPass, uint32_t subpass) {
this->renderPass = renderPass;
this->subpass = subpass;
}
void PipelineBuilder::SetStage(nxt::ShaderStage stage, ShaderModuleBase* module, const char* entryPoint) {
if (entryPoint != std::string("main")) {
HandleError("Currently the entry point has to be main()");
parentBuilder->HandleError("Currently the entry point has to be main()");
return;
}
if (stage != module->GetExecutionModel()) {
HandleError("Setting module with wrong execution model");
parentBuilder->HandleError("Setting module with wrong execution model");
return;
}
nxt::ShaderStageBit bit = StageBit(stage);
if (stageMask & bit) {
HandleError("Setting already set stage");
parentBuilder->HandleError("Setting already set stage");
return;
}
stageMask |= bit;
@ -174,13 +111,4 @@ namespace backend {
stages[stage].entryPoint = entryPoint;
}
void PipelineBuilder::SetInputState(InputStateBase* inputState) {
this->inputState = inputState;
}
void PipelineBuilder::SetDepthStencilState(DepthStencilStateBase* depthStencilState) {
this->depthStencilState = depthStencilState;
}
}

View File

@ -18,7 +18,9 @@
#include "backend/Forward.h"
#include "backend/Builder.h"
#include "backend/PerStage.h"
#include "backend/PipelineLayout.h"
#include "backend/RefCounted.h"
#include "backend/ShaderModule.h"
#include "nxt/nxtcpp.h"
@ -33,7 +35,9 @@ namespace backend {
Float,
};
class PipelineBase : public RefCounted {
class PipelineBuilder;
class PipelineBase {
public:
PipelineBase(PipelineBuilder* builder);
@ -45,55 +49,35 @@ namespace backend {
nxt::ShaderStageBit GetStageMask() const;
PipelineLayoutBase* GetLayout();
RenderPassBase* GetRenderPass();
uint32_t GetSubPass();
InputStateBase* GetInputState();
DepthStencilStateBase* GetDepthStencilState();
// TODO(cwallez@chromium.org): split compute and render pipelines
bool IsCompute() const;
private:
nxt::ShaderStageBit stageMask;
Ref<PipelineLayoutBase> layout;
Ref<RenderPassBase> renderPass;
uint32_t subpass;
PerStage<PushConstantInfo> pushConstants;
Ref<InputStateBase> inputState;
Ref<DepthStencilStateBase> depthStencilState;
};
class PipelineBuilder : public Builder<PipelineBase> {
class PipelineBuilder {
public:
PipelineBuilder(DeviceBase* device);
PipelineBuilder(BuilderBase* parentBuilder);
struct StageInfo {
std::string entryPoint;
Ref<ShaderModuleBase> module;
};
const StageInfo& GetStageInfo(nxt::ShaderStage stage) const;
BuilderBase* GetParentBuilder() const;
// NXT API
void SetLayout(PipelineLayoutBase* layout);
void SetSubpass(RenderPassBase* renderPass, uint32_t subpass);
void SetStage(nxt::ShaderStage stage, ShaderModuleBase* module, const char* entryPoint);
void SetInputState(InputStateBase* inputState);
void SetDepthStencilState(DepthStencilStateBase* depthStencilState);
private:
friend class PipelineBase;
PipelineBase* GetResultImpl() override;
bool IsCompute() const;
BuilderBase* parentBuilder;
Ref<PipelineLayoutBase> layout;
Ref<RenderPassBase> renderPass;
uint32_t subpass;
nxt::ShaderStageBit stageMask;
PerStage<StageInfo> stages;
Ref<InputStateBase> inputState;
Ref<DepthStencilStateBase> depthStencilState;
};
}

View File

@ -48,6 +48,11 @@ namespace backend {
using BackendType = typename BackendTraits::CommandBufferType;
};
template<typename BackendTraits>
struct ToBackendTraits<ComputePipelineBase, BackendTraits> {
using BackendType = typename BackendTraits::ComputePipelineType;
};
template<typename BackendTraits>
struct ToBackendTraits<DepthStencilStateBase, BackendTraits> {
using BackendType = typename BackendTraits::DepthStencilStateType;
@ -68,11 +73,6 @@ namespace backend {
using BackendType = typename BackendTraits::InputStateType;
};
template<typename BackendTraits>
struct ToBackendTraits<PipelineBase, BackendTraits> {
using BackendType = typename BackendTraits::PipelineType;
};
template<typename BackendTraits>
struct ToBackendTraits<PipelineLayoutBase, BackendTraits> {
using BackendType = typename BackendTraits::PipelineLayoutType;
@ -88,6 +88,11 @@ namespace backend {
using BackendType = typename BackendTraits::RenderPassType;
};
template<typename BackendTraits>
struct ToBackendTraits<RenderPipelineBase, BackendTraits> {
using BackendType = typename BackendTraits::RenderPipelineType;
};
template<typename BackendTraits>
struct ToBackendTraits<SamplerBase, BackendTraits> {
using BackendType = typename BackendTraits::SamplerType;

View File

@ -162,7 +162,7 @@ namespace d3d12 {
descriptor.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
descriptor.SampleDesc.Count = 1;
ASSERT_SUCCESS(device->GetD3D12Device()->CreateGraphicsPipelineState(&descriptor, IID_PPV_ARGS(&renderPipelineState)));
ASSERT_SUCCESS(device->GetD3D12Device()->CreateRenderPipelineState(&descriptor, IID_PPV_ARGS(&renderPipelineState)));
}
}

View File

@ -52,17 +52,17 @@ namespace null {
CommandBufferBase* Device::CreateCommandBuffer(CommandBufferBuilder* builder) {
return new CommandBuffer(builder);
}
ComputePipelineBase* Device::CreateComputePipeline(ComputePipelineBuilder* builder) {
return new ComputePipeline(builder);
}
DepthStencilStateBase* Device::CreateDepthStencilState(DepthStencilStateBuilder* builder) {
return new DepthStencilState(builder);
}
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
return new InputState(builder);
}
FramebufferBase* Device::CreateFramebuffer(FramebufferBuilder* builder) {
return new Framebuffer(builder);
}
PipelineBase* Device::CreatePipeline(PipelineBuilder* builder) {
return new Pipeline(builder);
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
return new InputState(builder);
}
PipelineLayoutBase* Device::CreatePipelineLayout(PipelineLayoutBuilder* builder) {
return new PipelineLayout(builder);
@ -73,6 +73,9 @@ namespace null {
RenderPassBase* Device::CreateRenderPass(RenderPassBuilder* builder) {
return new RenderPass(builder);
}
RenderPipelineBase* Device::CreateRenderPipeline(RenderPipelineBuilder* builder) {
return new RenderPipeline(builder);
}
SamplerBase* Device::CreateSampler(SamplerBuilder* builder) {
return new Sampler(builder);
}

View File

@ -22,13 +22,14 @@
#include "backend/BindGroupLayout.h"
#include "backend/Device.h"
#include "backend/CommandBuffer.h"
#include "backend/ComputePipeline.h"
#include "backend/DepthStencilState.h"
#include "backend/InputState.h"
#include "backend/Framebuffer.h"
#include "backend/Pipeline.h"
#include "backend/InputState.h"
#include "backend/PipelineLayout.h"
#include "backend/Queue.h"
#include "backend/RenderPass.h"
#include "backend/RenderPipeline.h"
#include "backend/Sampler.h"
#include "backend/ShaderModule.h"
#include "backend/Texture.h"
@ -42,14 +43,15 @@ namespace null {
class Buffer;
using BufferView = BufferViewBase;
class CommandBuffer;
using ComputePipeline = ComputePipelineBase;
using DepthStencilState = DepthStencilStateBase;
class Device;
using InputState = InputStateBase;
using Framebuffer = FramebufferBase;
using Pipeline = PipelineBase;
using InputState = InputStateBase;
using PipelineLayout = PipelineLayoutBase;
class Queue;
using RenderPass = RenderPassBase;
using RenderPipeline = RenderPipelineBase;
using Sampler = SamplerBase;
using ShaderModule = ShaderModuleBase;
class Texture;
@ -61,14 +63,15 @@ namespace null {
using BufferType = Buffer;
using BufferViewType = BufferView;
using CommandBufferType = CommandBuffer;
using ComputePipelineType = ComputePipeline;
using DepthStencilStateType = DepthStencilState;
using DeviceType = Device;
using InputStateType = InputState;
using FramebufferType = Framebuffer;
using PipelineType = Pipeline;
using InputStateType = InputState;
using PipelineLayoutType = PipelineLayout;
using QueueType = Queue;
using RenderPassType = RenderPass;
using RenderPipelineType = RenderPipeline;
using SamplerType = Sampler;
using ShaderModuleType = ShaderModule;
using TextureType = Texture;
@ -95,13 +98,14 @@ namespace null {
BufferBase* CreateBuffer(BufferBuilder* builder) override;
BufferViewBase* CreateBufferView(BufferViewBuilder* builder) override;
CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) override;
ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override;
DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
InputStateBase* CreateInputState(InputStateBuilder* builder) override;
FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) override;
PipelineBase* CreatePipeline(PipelineBuilder* builder) override;
InputStateBase* CreateInputState(InputStateBuilder* builder) override;
PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override;
QueueBase* CreateQueue(QueueBuilder* builder) override;
RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) override;
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
SamplerBase* CreateSampler(SamplerBuilder* builder) override;
ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override;
TextureBase* CreateTexture(TextureBuilder* builder) override;