Introduce a base class for Builder objects.

All builder objects will depend from this "Builder" base class. This
will allow having the builder callback logic in only one place.
This commit is contained in:
Corentin Wallez 2017-05-08 10:52:11 +02:00 committed by Corentin Wallez
parent 4b410a33ca
commit 5dc7915d38
26 changed files with 202 additions and 212 deletions

View File

@ -23,6 +23,8 @@ list(APPEND BACKEND_SOURCES
${COMMON_DIR}/BindGroupLayout.cpp
${COMMON_DIR}/BindGroupLayout.h
${COMMON_DIR}/BitSetIterator.h
${COMMON_DIR}/Builder.cpp
${COMMON_DIR}/Builder.h
${COMMON_DIR}/Buffer.cpp
${COMMON_DIR}/Buffer.h
${COMMON_DIR}/CommandAllocator.cpp

View File

@ -65,32 +65,28 @@ namespace backend {
};
BindGroupBuilder::BindGroupBuilder(DeviceBase* device)
: device(device) {
}
bool BindGroupBuilder::WasConsumed() const {
return consumed;
: Builder(device) {
}
BindGroupBase* BindGroupBuilder::GetResult() {
constexpr int allProperties = BINDGROUP_PROPERTY_USAGE | BINDGROUP_PROPERTY_LAYOUT;
if ((propertiesSet & allProperties) != allProperties) {
device->HandleError("Bindgroup missing properties");
HandleError("Bindgroup missing properties");
return nullptr;
}
if (setMask != layout->GetBindingInfo().mask) {
device->HandleError("Bindgroup missing bindings");
HandleError("Bindgroup missing bindings");
return nullptr;
}
consumed = true;
MarkConsumed();
return device->CreateBindGroup(this);
}
void BindGroupBuilder::SetLayout(BindGroupLayoutBase* layout) {
if ((propertiesSet & BINDGROUP_PROPERTY_LAYOUT) != 0) {
device->HandleError("Bindgroup layout property set multiple times");
HandleError("Bindgroup layout property set multiple times");
return;
}
@ -100,7 +96,7 @@ namespace backend {
void BindGroupBuilder::SetUsage(nxt::BindGroupUsage usage) {
if ((propertiesSet & BINDGROUP_PROPERTY_USAGE) != 0) {
device->HandleError("Bindgroup usage property set multiple times");
HandleError("Bindgroup usage property set multiple times");
return;
}
@ -127,12 +123,12 @@ namespace backend {
case nxt::BindingType::Sampler:
case nxt::BindingType::SampledTexture:
device->HandleError("Setting buffer for a wrong binding type");
HandleError("Setting buffer for a wrong binding type");
return;
}
if (!(bufferViews[j]->GetBuffer()->GetAllowedUsage() & requiredBit)) {
device->HandleError("Buffer needs to allow the correct usage bit");
HandleError("Buffer needs to allow the correct usage bit");
return;
}
}
@ -148,7 +144,7 @@ namespace backend {
const auto& layoutInfo = layout->GetBindingInfo();
for (size_t i = start, j = 0; i < start + count; ++i, ++j) {
if (layoutInfo.types[i] != nxt::BindingType::Sampler) {
device->HandleError("Setting binding for a wrong layout binding type");
HandleError("Setting binding for a wrong layout binding type");
return;
}
}
@ -164,12 +160,12 @@ namespace backend {
const auto& layoutInfo = layout->GetBindingInfo();
for (size_t i = start, j = 0; i < start + count; ++i, ++j) {
if (layoutInfo.types[i] != nxt::BindingType::SampledTexture) {
device->HandleError("Setting binding for a wrong layout binding type");
HandleError("Setting binding for a wrong layout binding type");
return;
}
if (!(textureViews[j]->GetTexture()->GetAllowedUsage() & nxt::TextureUsageBit::Sampled)) {
device->HandleError("Texture needs to allow the sampled usage bit");
HandleError("Texture needs to allow the sampled usage bit");
return;
}
}
@ -186,24 +182,24 @@ namespace backend {
bool BindGroupBuilder::SetBindingsValidationBase(uint32_t start, uint32_t count) {
if (start + count > kMaxBindingsPerGroup) {
device->HandleError("Setting bindings type over maximum number of bindings");
HandleError("Setting bindings type over maximum number of bindings");
return false;
}
if ((propertiesSet & BINDGROUP_PROPERTY_LAYOUT) == 0) {
device->HandleError("Bindgroup layout must be set before views");
HandleError("Bindgroup layout must be set before views");
return false;
}
const auto& layoutInfo = layout->GetBindingInfo();
for (size_t i = start, j = 0; i < start + count; ++i, ++j) {
if (setMask[i]) {
device->HandleError("Setting already set binding");
HandleError("Setting already set binding");
return false;
}
if (!layoutInfo.mask[i]) {
device->HandleError("Setting binding that isn't present in the layout");
HandleError("Setting binding that isn't present in the layout");
return false;
}
}

View File

@ -16,6 +16,7 @@
#define BACKEND_COMMON_BINDGROUP_H_
#include "Forward.h"
#include "Builder.h"
#include "RefCounted.h"
#include "nxt/nxtcpp.h"
@ -42,12 +43,10 @@ namespace backend {
std::array<Ref<RefCounted>, kMaxBindingsPerGroup> bindings;
};
class BindGroupBuilder : public RefCounted {
class BindGroupBuilder : public Builder {
public:
BindGroupBuilder(DeviceBase* device);
bool WasConsumed() const;
// NXT API
BindGroupBase* GetResult();
void SetLayout(BindGroupLayoutBase* layout);
@ -80,10 +79,8 @@ namespace backend {
void SetBindingsBase(uint32_t start, uint32_t count, RefCounted* const * objects);
bool SetBindingsValidationBase(uint32_t start, uint32_t count);
DeviceBase* device;
std::bitset<kMaxBindingsPerGroup> setMask;
int propertiesSet = 0;
bool consumed = false;
Ref<BindGroupLayoutBase> layout;
nxt::BindGroupUsage usage;

View File

@ -94,11 +94,7 @@ namespace backend {
// BindGroupLayoutBuilder
BindGroupLayoutBuilder::BindGroupLayoutBuilder(DeviceBase* device) : device(device) {
}
bool BindGroupLayoutBuilder::WasConsumed() const {
return consumed;
BindGroupLayoutBuilder::BindGroupLayoutBuilder(DeviceBase* device) : Builder(device) {
}
const BindGroupLayoutBase::LayoutBindingInfo& BindGroupLayoutBuilder::GetBindingInfo() const {
@ -106,7 +102,7 @@ namespace backend {
}
BindGroupLayoutBase* BindGroupLayoutBuilder::GetResult() {
consumed = true;
MarkConsumed();
BindGroupLayoutBase blueprint(this, true);
auto* result = device->GetOrCreateBindGroupLayout(&blueprint, this);
@ -116,13 +112,13 @@ namespace backend {
void BindGroupLayoutBuilder::SetBindingsType(nxt::ShaderStageBit visibility, nxt::BindingType bindingType, uint32_t start, uint32_t count) {
if (start + count > kMaxBindingsPerGroup) {
device->HandleError("Setting bindings type over maximum number of bindings");
HandleError("Setting bindings type over maximum number of bindings");
return;
}
for (size_t i = start; i < start + count; i++) {
if (bindingInfo.mask[i]) {
device->HandleError("Setting already set binding type");
HandleError("Setting already set binding type");
return;
}
bindingInfo.mask.set(i);

View File

@ -16,6 +16,7 @@
#define BACKEND_COMMON_BINDGROUPLAYOUT_H_
#include "Forward.h"
#include "Builder.h"
#include "RefCounted.h"
#include "nxt/nxtcpp.h"
@ -43,11 +44,10 @@ namespace backend {
bool blueprint = false;
};
class BindGroupLayoutBuilder : public RefCounted {
class BindGroupLayoutBuilder : public Builder {
public:
BindGroupLayoutBuilder(DeviceBase* device);
bool WasConsumed() const;
const BindGroupLayoutBase::LayoutBindingInfo& GetBindingInfo() const;
// NXT API
@ -57,9 +57,7 @@ namespace backend {
private:
friend class BindGroupLayoutBase;
DeviceBase* device;
BindGroupLayoutBase::LayoutBindingInfo bindingInfo;
bool consumed = false;
};
// Implements the functors necessary for the unordered_set<BGL*>-based cache.

View File

@ -118,32 +118,28 @@ namespace backend {
BUFFER_PROPERTY_SIZE = 0x4,
};
BufferBuilder::BufferBuilder(DeviceBase* device) : device(device) {
}
bool BufferBuilder::WasConsumed() const {
return consumed;
BufferBuilder::BufferBuilder(DeviceBase* device) : Builder(device) {
}
BufferBase* BufferBuilder::GetResult() {
constexpr int allProperties = BUFFER_PROPERTY_ALLOWED_USAGE | BUFFER_PROPERTY_SIZE;
if ((propertiesSet & allProperties) != allProperties) {
device->HandleError("Buffer missing properties");
HandleError("Buffer missing properties");
return nullptr;
}
if (!BufferBase::IsUsagePossible(allowedUsage, currentUsage)) {
device->HandleError("Initial buffer usage is not allowed");
HandleError("Initial buffer usage is not allowed");
return nullptr;
}
consumed = true;
MarkConsumed();
return device->CreateBuffer(this);
}
void BufferBuilder::SetAllowedUsage(nxt::BufferUsageBit usage) {
if ((propertiesSet & BUFFER_PROPERTY_ALLOWED_USAGE) != 0) {
device->HandleError("Buffer allowedUsage property set multiple times");
HandleError("Buffer allowedUsage property set multiple times");
return;
}
@ -153,7 +149,7 @@ namespace backend {
void BufferBuilder::SetInitialUsage(nxt::BufferUsageBit usage) {
if ((propertiesSet & BUFFER_PROPERTY_INITIAL_USAGE) != 0) {
device->HandleError("Buffer initialUsage property set multiple times");
HandleError("Buffer initialUsage property set multiple times");
return;
}
@ -163,7 +159,7 @@ namespace backend {
void BufferBuilder::SetSize(uint32_t size) {
if ((propertiesSet & BUFFER_PROPERTY_SIZE) != 0) {
device->HandleError("Buffer size property set multiple times");
HandleError("Buffer size property set multiple times");
return;
}
@ -196,32 +192,29 @@ namespace backend {
};
BufferViewBuilder::BufferViewBuilder(DeviceBase* device, BufferBase* buffer)
: device(device), buffer(buffer) {
}
bool BufferViewBuilder::WasConsumed() const {
return consumed;
: Builder(device), buffer(buffer) {
}
BufferViewBase* BufferViewBuilder::GetResult() {
constexpr int allProperties = BUFFER_VIEW_PROPERTY_EXTENT;
if ((propertiesSet & allProperties) != allProperties) {
device->HandleError("Buffer view missing properties");
HandleError("Buffer view missing properties");
return nullptr;
}
MarkConsumed();
return device->CreateBufferView(this);
}
void BufferViewBuilder::SetExtent(uint32_t offset, uint32_t size) {
if ((propertiesSet & BUFFER_VIEW_PROPERTY_EXTENT) != 0) {
device->HandleError("Buffer view extent property set multiple times");
HandleError("Buffer view extent property set multiple times");
return;
}
uint64_t viewEnd = static_cast<uint64_t>(offset) + static_cast<uint64_t>(size);
if (viewEnd > static_cast<uint64_t>(buffer->GetSize())) {
device->HandleError("Buffer view end is OOB");
HandleError("Buffer view end is OOB");
return;
}

View File

@ -16,6 +16,7 @@
#define BACKEND_COMMON_BUFFER_H_
#include "Forward.h"
#include "Builder.h"
#include "RefCounted.h"
#include "nxt/nxtcpp.h"
@ -51,12 +52,10 @@ namespace backend {
bool frozen = false;
};
class BufferBuilder : public RefCounted {
class BufferBuilder : public Builder {
public:
BufferBuilder(DeviceBase* device);
bool WasConsumed() const;
// NXT API
BufferBase* GetResult();
void SetAllowedUsage(nxt::BufferUsageBit usage);
@ -66,12 +65,10 @@ namespace backend {
private:
friend class BufferBase;
DeviceBase* device;
uint32_t size;
nxt::BufferUsageBit allowedUsage = nxt::BufferUsageBit::None;
nxt::BufferUsageBit currentUsage = nxt::BufferUsageBit::None;
int propertiesSet = 0;
bool consumed = false;
};
class BufferViewBase : public RefCounted {
@ -88,12 +85,10 @@ namespace backend {
uint32_t offset;
};
class BufferViewBuilder : public RefCounted {
class BufferViewBuilder : public Builder {
public:
BufferViewBuilder(DeviceBase* device, BufferBase* buffer);
bool WasConsumed() const;
// NXT API
BufferViewBase* GetResult();
void SetExtent(uint32_t offset, uint32_t size);
@ -101,12 +96,10 @@ namespace backend {
private:
friend class BufferViewBase;
DeviceBase* device;
Ref<BufferBase> buffer;
uint32_t offset = 0;
uint32_t size = 0;
int propertiesSet = 0;
bool consumed = false;
};
}

View File

@ -0,0 +1,37 @@
// 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 "Builder.h"
#include "Device.h"
namespace backend {
bool Builder::WasConsumed() const {
return consumed;
}
Builder::Builder(DeviceBase* device) : device(device) {
}
void Builder::MarkConsumed() {
ASSERT(!consumed);
consumed = true;
}
void Builder::HandleError(const char* message) {
device->HandleError(message);
}
}

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.
#ifndef BACKEND_COMMON_BUILDER_H_
#define BACKEND_COMMON_BUILDER_H_
#include "Forward.h"
#include "RefCounted.h"
namespace backend {
class Builder : public RefCounted {
public:
bool WasConsumed() const;
void HandleError(const char* message);
protected:
Builder(DeviceBase* device);
void MarkConsumed();
DeviceBase* const device;
private:
bool consumed = false;
};
}
#endif // BACKEND_COMMON_BUILDER_H_

View File

@ -132,20 +132,16 @@ namespace backend {
commands->DataWasDestroyed();
}
CommandBufferBuilder::CommandBufferBuilder(DeviceBase* device) : device(device) {
CommandBufferBuilder::CommandBufferBuilder(DeviceBase* device) : Builder(device) {
}
CommandBufferBuilder::~CommandBufferBuilder() {
if (!consumed) {
if (!WasConsumed()) {
MoveToIterator();
FreeCommands(&iterator);
}
}
bool CommandBufferBuilder::WasConsumed() const {
return consumed;
}
enum ValidationAspect {
VALIDATION_ASPECT_RENDER_PIPELINE,
VALIDATION_ASPECT_COMPUTE_PIPELINE,
@ -215,7 +211,7 @@ namespace backend {
auto buffer = group->GetBindingAsBufferView(i)->GetBuffer();
if (!bufferHasGuaranteedUsageBit(buffer, requiredUsage)) {
device->HandleError("Can't guarantee buffer usage needed by bind group");
HandleError("Can't guarantee buffer usage needed by bind group");
return false;
}
}
@ -226,7 +222,7 @@ namespace backend {
auto texture = group->GetBindingAsTextureView(i)->GetTexture();
if (!textureHasGuaranteedUsageBit(texture, requiredUsage)) {
device->HandleError("Can't guarantee texture usage needed by bind group");
HandleError("Can't guarantee texture usage needed by bind group");
return false;
}
}
@ -256,17 +252,17 @@ namespace backend {
uint32_t level = copy->level;
if (!bufferHasGuaranteedUsageBit(buffer, nxt::BufferUsageBit::TransferSrc)) {
device->HandleError("Buffer needs the transfer source usage bit");
HandleError("Buffer needs the transfer source usage bit");
return false;
}
if (!textureHasGuaranteedUsageBit(texture, nxt::TextureUsageBit::TransferDst)) {
device->HandleError("Texture needs the transfer destination usage bit");
HandleError("Texture needs the transfer destination usage bit");
return false;
}
if (width == 0 || height == 0 || depth == 0) {
device->HandleError("Empty copy");
HandleError("Empty copy");
return false;
}
@ -275,7 +271,7 @@ namespace backend {
uint64_t dataSize = width * height * depth * pixelSize;
if (dataSize + static_cast<uint64_t>(bufferOffset) > static_cast<uint64_t>(buffer->GetSize())) {
device->HandleError("Copy would read after end of the buffer");
HandleError("Copy would read after end of the buffer");
return false;
}
@ -283,7 +279,7 @@ namespace backend {
y + height > static_cast<uint64_t>(texture->GetHeight()) ||
z + depth > static_cast<uint64_t>(texture->GetDepth()) ||
level > texture->GetNumMipLevels()) {
device->HandleError("Copy would write outside of the texture");
HandleError("Copy would write outside of the texture");
return false;
}
}
@ -311,7 +307,7 @@ namespace backend {
// Check again if anything is missing
if ((requiredDispatchAspects & ~aspects).any()) {
device->HandleError("Some dispatch state is missing");
HandleError("Some dispatch state is missing");
return false;
}
}
@ -339,7 +335,7 @@ namespace backend {
// Check again if anything is missing
if ((requiredDrawAspects & ~aspects).any()) {
device->HandleError("Some draw state is missing");
HandleError("Some draw state is missing");
return false;
}
}
@ -351,7 +347,7 @@ namespace backend {
DrawElementsCmd* draw = iterator.NextCommand<DrawElementsCmd>();
if (!aspects[VALIDATION_ASPECT_INDEX_BUFFER]) {
device->HandleError("Draw elements requires an index buffer");
HandleError("Draw elements requires an index buffer");
return false;
}
}
@ -394,7 +390,7 @@ namespace backend {
SetPushConstantsCmd* cmd = iterator.NextCommand<SetPushConstantsCmd>();
iterator.NextData<uint32_t>(cmd->count);
if (cmd->count + cmd->offset > kMaxPushConstants) {
device->HandleError("Setting pushconstants past the limit");
HandleError("Setting pushconstants past the limit");
return false;
}
}
@ -406,7 +402,7 @@ namespace backend {
uint32_t index = cmd->index;
if (cmd->group->GetLayout() != lastPipeline->GetLayout()->GetBindGroupLayout(index)) {
device->HandleError("Bind group layout mismatch");
HandleError("Bind group layout mismatch");
return false;
}
if (!validateBindGroupUsages(cmd->group.Get())) {
@ -422,7 +418,7 @@ namespace backend {
auto buffer = cmd->buffer;
auto usage = nxt::BufferUsageBit::Index;
if (!bufferHasGuaranteedUsageBit(buffer.Get(), usage)) {
device->HandleError("Buffer needs the index usage bit to be guaranteed");
HandleError("Buffer needs the index usage bit to be guaranteed");
return false;
}
@ -440,7 +436,7 @@ namespace backend {
auto buffer = buffers[i];
auto usage = nxt::BufferUsageBit::Vertex;
if (!bufferHasGuaranteedUsageBit(buffer.Get(), usage)) {
device->HandleError("Buffer needs vertex usage bit to be guaranteed");
HandleError("Buffer needs vertex usage bit to be guaranteed");
return false;
}
inputsSet.set(cmd->startSlot + i);
@ -455,7 +451,7 @@ namespace backend {
auto usage = cmd->usage;
if (!cmd->buffer->IsTransitionPossible(cmd->usage)) {
device->HandleError("Buffer frozen or usage not allowed");
HandleError("Buffer frozen or usage not allowed");
return false;
}
@ -472,7 +468,7 @@ namespace backend {
auto usage = cmd->usage;
if (!cmd->texture->IsTransitionPossible(cmd->usage)) {
device->HandleError("Texture frozen or usage not allowed");
HandleError("Texture frozen or usage not allowed");
return false;
}
@ -493,7 +489,7 @@ namespace backend {
CommandBufferBase* CommandBufferBuilder::GetResult() {
MoveToIterator();
consumed = true;
MarkConsumed();
return device->CreateCommandBuffer(this);
}
@ -548,7 +544,7 @@ namespace backend {
void CommandBufferBuilder::SetPushConstants(nxt::ShaderStageBit stage, uint32_t offset, uint32_t count, const void* data) {
if (offset + count > kMaxPushConstants) {
device->HandleError("Setting too many push constants");
HandleError("Setting too many push constants");
return;
}
@ -564,7 +560,7 @@ namespace backend {
void CommandBufferBuilder::SetBindGroup(uint32_t groupIndex, BindGroupBase* group) {
if (groupIndex >= kMaxBindGroups) {
device->HandleError("Setting bind group over the max");
HandleError("Setting bind group over the max");
return;
}

View File

@ -18,6 +18,7 @@
#include "nxt/nxtcpp.h"
#include "CommandAllocator.h"
#include "Builder.h"
#include "RefCounted.h"
#include <set>
@ -44,12 +45,11 @@ namespace backend {
std::set<TextureBase*> texturesTransitioned;
};
class CommandBufferBuilder : public RefCounted {
class CommandBufferBuilder : public Builder {
public:
CommandBufferBuilder(DeviceBase* device);
~CommandBufferBuilder();
bool WasConsumed() const;
bool ValidateGetResult();
CommandIterator AcquireCommands();
@ -83,10 +83,8 @@ namespace backend {
void MoveToIterator();
DeviceBase* device;
CommandAllocator allocator;
CommandIterator iterator;
bool consumed = false;
bool movedToIterator = false;
// These pointers will remain valid since they are referenced by
// the bind groups which are referenced by this command buffer.

View File

@ -78,37 +78,34 @@ namespace backend {
// InputStateBuilder
InputStateBuilder::InputStateBuilder(DeviceBase* device) : device(device) {
}
bool InputStateBuilder::WasConsumed() const {
return consumed;
InputStateBuilder::InputStateBuilder(DeviceBase* device) : Builder(device) {
}
InputStateBase* InputStateBuilder::GetResult() {
for (uint32_t location = 0; location < kMaxVertexAttributes; ++location) {
if (attributesSetMask[location] &&
!inputsSetMask[attributeInfos[location].bindingSlot]) {
device->HandleError("Attribute uses unset input");
HandleError("Attribute uses unset input");
return nullptr;
}
}
consumed = true;
MarkConsumed();
return device->CreateInputState(this);
}
void InputStateBuilder::SetAttribute(uint32_t shaderLocation,
uint32_t bindingSlot, nxt::VertexFormat format, uint32_t offset) {
if (shaderLocation >= kMaxVertexAttributes) {
device->HandleError("Setting attribute out of bounds");
HandleError("Setting attribute out of bounds");
return;
}
if (bindingSlot >= kMaxVertexInputs) {
device->HandleError("Binding slot out of bounds");
HandleError("Binding slot out of bounds");
return;
}
if (attributesSetMask[shaderLocation]) {
device->HandleError("Setting already set attribute");
HandleError("Setting already set attribute");
return;
}
@ -122,11 +119,11 @@ namespace backend {
void InputStateBuilder::SetInput(uint32_t bindingSlot, uint32_t stride,
nxt::InputStepMode stepMode) {
if (bindingSlot >= kMaxVertexInputs) {
device->HandleError("Setting input out of bounds");
HandleError("Setting input out of bounds");
return;
}
if (inputsSetMask[bindingSlot]) {
device->HandleError("Setting already set input");
HandleError("Setting already set input");
return;
}

View File

@ -16,6 +16,7 @@
#define BACKEND_COMMON_INPUTSTATE_H_
#include "Forward.h"
#include "Builder.h"
#include "RefCounted.h"
#include "nxt/nxtcpp.h"
@ -56,12 +57,10 @@ namespace backend {
std::array<InputInfo, kMaxVertexInputs> inputInfos;
};
class InputStateBuilder : public RefCounted {
class InputStateBuilder : public Builder {
public:
InputStateBuilder(DeviceBase* device);
bool WasConsumed() const;
// NXT API
InputStateBase* GetResult();
void SetAttribute(uint32_t shaderLocation, uint32_t bindingSlot,
@ -72,12 +71,10 @@ namespace backend {
private:
friend class InputStateBase;
DeviceBase* device;
std::bitset<kMaxVertexAttributes> attributesSetMask;
std::array<InputStateBase::AttributeInfo, kMaxVertexAttributes> attributeInfos;
std::bitset<kMaxVertexInputs> inputsSetMask;
std::array<InputStateBase::InputInfo, kMaxVertexInputs> inputInfos;
bool consumed = false;
};
}

View File

@ -29,7 +29,7 @@ namespace backend {
if (stageMask != (nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment) &&
stageMask != nxt::ShaderStageBit::Compute) {
device->HandleError("Wrong combination of stage for pipeline");
builder->HandleError("Wrong combination of stage for pipeline");
return;
}
@ -52,7 +52,7 @@ namespace backend {
for (auto stageBit : IterateStages(builder->stageMask)) {
if (!builder->stages[stageBit].module->IsCompatibleWithPipelineLayout(layout.Get())) {
device->HandleError("Stage not compatible with layout");
builder->HandleError("Stage not compatible with layout");
return;
}
@ -61,7 +61,7 @@ namespace backend {
if (!IsCompute()) {
if ((builder->stages[nxt::ShaderStage::Vertex].module->GetUsedVertexAttributes() & ~inputState->GetAttributesSetMask()).any()) {
device->HandleError("Pipeline vertex stage uses inputs not in the input state");
builder->HandleError("Pipeline vertex stage uses inputs not in the input state");
return;
}
}
@ -90,11 +90,7 @@ namespace backend {
// PipelineBuilder
PipelineBuilder::PipelineBuilder(DeviceBase* device)
: device(device), stageMask(static_cast<nxt::ShaderStageBit>(0)) {
}
bool PipelineBuilder::WasConsumed() const {
return consumed;
: Builder(device), stageMask(static_cast<nxt::ShaderStageBit>(0)) {
}
const PipelineBuilder::StageInfo& PipelineBuilder::GetStageInfo(nxt::ShaderStage stage) const {
@ -111,7 +107,7 @@ namespace backend {
inputState = device->CreateInputStateBuilder()->GetResult();
}
consumed = true;
MarkConsumed();
return device->CreatePipeline(this);
}
@ -121,18 +117,18 @@ namespace backend {
void PipelineBuilder::SetStage(nxt::ShaderStage stage, ShaderModuleBase* module, const char* entryPoint) {
if (entryPoint != std::string("main")) {
device->HandleError("Currently the entry point has to be main()");
HandleError("Currently the entry point has to be main()");
return;
}
if (stage != module->GetExecutionModel()) {
device->HandleError("Setting module with wrong execution model");
HandleError("Setting module with wrong execution model");
return;
}
nxt::ShaderStageBit bit = StageBit(stage);
if (stageMask & bit) {
device->HandleError("Setting already set stage");
HandleError("Setting already set stage");
return;
}
stageMask |= bit;

View File

@ -16,6 +16,7 @@
#define BACKEND_COMMON_PIPELINE_H_
#include "Forward.h"
#include "Builder.h"
#include "PerStage.h"
#include "RefCounted.h"
@ -58,12 +59,10 @@ namespace backend {
Ref<InputStateBase> inputState;
};
class PipelineBuilder : public RefCounted {
class PipelineBuilder : public Builder {
public:
PipelineBuilder(DeviceBase* device);
bool WasConsumed() const;
struct StageInfo {
std::string entryPoint;
Ref<ShaderModuleBase> module;
@ -79,12 +78,10 @@ namespace backend {
private:
friend class PipelineBase;
DeviceBase* device;
Ref<PipelineLayoutBase> layout;
nxt::ShaderStageBit stageMask;
PerStage<StageInfo> stages;
Ref<InputStateBase> inputState;
bool consumed = false;
};
}

View File

@ -36,11 +36,7 @@ namespace backend {
// PipelineLayoutBuilder
PipelineLayoutBuilder::PipelineLayoutBuilder(DeviceBase* device) : device(device) {
}
bool PipelineLayoutBuilder::WasConsumed() const {
return consumed;
PipelineLayoutBuilder::PipelineLayoutBuilder(DeviceBase* device) : Builder(device) {
}
PipelineLayoutBase* PipelineLayoutBuilder::GetResult() {
@ -52,17 +48,17 @@ namespace backend {
}
}
consumed = true;
MarkConsumed();
return device->CreatePipelineLayout(this);
}
void PipelineLayoutBuilder::SetBindGroupLayout(uint32_t groupIndex, BindGroupLayoutBase* layout) {
if (groupIndex >= kMaxBindGroups) {
device->HandleError("groupIndex is over the maximum allowed");
HandleError("groupIndex is over the maximum allowed");
return;
}
if (mask[groupIndex]) {
device->HandleError("Bind group layout already specified");
HandleError("Bind group layout already specified");
return;
}

View File

@ -16,6 +16,7 @@
#define BACKEND_COMMON_PIPELINELAYOUT_H_
#include "Forward.h"
#include "Builder.h"
#include "RefCounted.h"
#include "nxt/nxtcpp.h"
@ -39,12 +40,10 @@ namespace backend {
std::bitset<kMaxBindGroups> mask;
};
class PipelineLayoutBuilder : public RefCounted {
class PipelineLayoutBuilder : public Builder {
public:
PipelineLayoutBuilder(DeviceBase* device);
bool WasConsumed() const;
// NXT API
PipelineLayoutBase* GetResult();
void SetBindGroupLayout(uint32_t groupIndex, BindGroupLayoutBase* layout);
@ -52,10 +51,8 @@ namespace backend {
private:
friend class PipelineLayoutBase;
DeviceBase* device;
BindGroupLayoutArray bindGroupLayouts;
std::bitset<kMaxBindGroups> mask;
bool consumed = false;
};
}

View File

@ -27,15 +27,11 @@ namespace backend {
// QueueBuilder
QueueBuilder::QueueBuilder(DeviceBase* device) : device(device) {
}
bool QueueBuilder::WasConsumed() const {
return consumed;
QueueBuilder::QueueBuilder(DeviceBase* device) : Builder(device) {
}
QueueBase* QueueBuilder::GetResult() {
consumed = true;
MarkConsumed();
return device->CreateQueue(this);
}

View File

@ -16,6 +16,7 @@
#define BACKEND_COMMON_QUEUE_H_
#include "Forward.h"
#include "Builder.h"
#include "RefCounted.h"
#include "nxt/nxtcpp.h"
@ -40,18 +41,12 @@ namespace backend {
}
};
class QueueBuilder : public RefCounted {
class QueueBuilder : public Builder {
public:
QueueBuilder(DeviceBase* device);
bool WasConsumed() const;
// NXT API
QueueBase* GetResult();
private:
DeviceBase* device;
bool consumed = false;
};
}

View File

@ -28,8 +28,7 @@ namespace backend {
enum SamplerSetProperties {
SAMPLER_PROPERTY_FILTER = 0x1,
};
SamplerBuilder::SamplerBuilder(DeviceBase* device)
:device(device) {
SamplerBuilder::SamplerBuilder(DeviceBase* device) : Builder(device) {
}
nxt::FilterMode SamplerBuilder::GetMagFilter() const {
@ -44,18 +43,14 @@ namespace backend {
return mipMapFilter;
}
bool SamplerBuilder::WasConsumed() const {
return consumed;
}
SamplerBase* SamplerBuilder::GetResult() {
consumed = true;
MarkConsumed();
return device->CreateSampler(this);
}
void SamplerBuilder::SetFilterMode(nxt::FilterMode magFilter, nxt::FilterMode minFilter, nxt::FilterMode mipMapFilter) {
if ((propertiesSet & SAMPLER_PROPERTY_FILTER) != 0) {
device->HandleError("Sampler filter property set multiple times");
HandleError("Sampler filter property set multiple times");
return;
}

View File

@ -16,6 +16,7 @@
#define BACKEND_COMMON_SAMPLER_H_
#include "Forward.h"
#include "Buffer.h"
#include "RefCounted.h"
#include "nxt/nxtcpp.h"
@ -27,7 +28,7 @@ namespace backend {
SamplerBase(SamplerBuilder* builder);
};
class SamplerBuilder : public RefCounted {
class SamplerBuilder : public Builder {
public:
SamplerBuilder(DeviceBase* device);
@ -35,8 +36,6 @@ namespace backend {
nxt::FilterMode GetMinFilter() const;
nxt::FilterMode GetMipMapFilter() const;
bool WasConsumed() const;
// NXT API
SamplerBase* GetResult();
void SetFilterMode(nxt::FilterMode magFilter, nxt::FilterMode minFilter, nxt::FilterMode mipMapFilter);
@ -44,9 +43,7 @@ namespace backend {
private:
friend class SamplerBase;
DeviceBase* device;
int propertiesSet = 0;
bool consumed = false;
nxt::FilterMode magFilter = nxt::FilterMode::Nearest;
nxt::FilterMode minFilter = nxt::FilterMode::Nearest;

View File

@ -28,6 +28,7 @@ namespace backend {
}
void ShaderModuleBase::ExtractSpirvInfo(const spirv_cross::Compiler& compiler) {
// TODO(cwallez@chromium.org): make errors here builder-level
const auto& resources = compiler.get_shader_resources();
switch (compiler.get_execution_model()) {
@ -190,10 +191,7 @@ namespace backend {
return true;
}
ShaderModuleBuilder::ShaderModuleBuilder(DeviceBase* device) : device(device) {}
bool ShaderModuleBuilder::WasConsumed() const {
return consumed;
ShaderModuleBuilder::ShaderModuleBuilder(DeviceBase* device) : Builder(device) {
}
std::vector<uint32_t> ShaderModuleBuilder::AcquireSpirv() {
@ -202,11 +200,11 @@ namespace backend {
ShaderModuleBase* ShaderModuleBuilder::GetResult() {
if (spirv.size() == 0) {
device->HandleError("Shader module needs to have the source set");
HandleError("Shader module needs to have the source set");
return nullptr;
}
consumed = true;
MarkConsumed();
return device->CreateShaderModule(this);
}

View File

@ -16,6 +16,7 @@
#define BACKEND_COMMON_SHADERMODULE_H_
#include "Forward.h"
#include "Builder.h"
#include "RefCounted.h"
#include "nxt/nxtcpp.h"
@ -70,12 +71,10 @@ namespace backend {
nxt::ShaderStage executionModel;
};
class ShaderModuleBuilder : public RefCounted {
class ShaderModuleBuilder : public Builder {
public:
ShaderModuleBuilder(DeviceBase* device);
bool WasConsumed() const;
std::vector<uint32_t> AcquireSpirv();
// NXT API
@ -85,9 +84,7 @@ namespace backend {
private:
friend class ShaderModuleBase;
DeviceBase* device;
std::vector<uint32_t> spirv;
bool consumed = false;
};
}

View File

@ -118,35 +118,31 @@ namespace backend {
};
TextureBuilder::TextureBuilder(DeviceBase* device)
: device(device) {
}
bool TextureBuilder::WasConsumed() const {
return consumed;
: Builder(device) {
}
TextureBase* TextureBuilder::GetResult() {
constexpr int allProperties = TEXTURE_PROPERTY_DIMENSION | TEXTURE_PROPERTY_EXTENT |
TEXTURE_PROPERTY_FORMAT | TEXTURE_PROPERTY_MIP_LEVELS | TEXTURE_PROPERTY_ALLOWED_USAGE;
if ((propertiesSet & allProperties) != allProperties) {
device->HandleError("Texture missing properties");
HandleError("Texture missing properties");
return nullptr;
}
if (!TextureBase::IsUsagePossible(allowedUsage, currentUsage)) {
device->HandleError("Initial texture usage is not allowed");
HandleError("Initial texture usage is not allowed");
return nullptr;
}
// TODO(cwallez@chromium.org): check stuff based on the dimension
consumed = true;
MarkConsumed();
return device->CreateTexture(this);
}
void TextureBuilder::SetDimension(nxt::TextureDimension dimension) {
if ((propertiesSet & TEXTURE_PROPERTY_DIMENSION) != 0) {
device->HandleError("Texture dimension property set multiple times");
HandleError("Texture dimension property set multiple times");
return;
}
@ -156,12 +152,12 @@ namespace backend {
void TextureBuilder::SetExtent(uint32_t width, uint32_t height, uint32_t depth) {
if ((propertiesSet & TEXTURE_PROPERTY_EXTENT) != 0) {
device->HandleError("Texture extent property set multiple times");
HandleError("Texture extent property set multiple times");
return;
}
if (width == 0 || height == 0 || depth == 0) {
device->HandleError("Cannot create an empty texture");
HandleError("Cannot create an empty texture");
return;
}
@ -173,7 +169,7 @@ namespace backend {
void TextureBuilder::SetFormat(nxt::TextureFormat format) {
if ((propertiesSet & TEXTURE_PROPERTY_FORMAT) != 0) {
device->HandleError("Texture format property set multiple times");
HandleError("Texture format property set multiple times");
return;
}
@ -183,7 +179,7 @@ namespace backend {
void TextureBuilder::SetMipLevels(uint32_t numMipLevels) {
if ((propertiesSet & TEXTURE_PROPERTY_MIP_LEVELS) != 0) {
device->HandleError("Texture mip levels property set multiple times");
HandleError("Texture mip levels property set multiple times");
return;
}
@ -193,7 +189,7 @@ namespace backend {
void TextureBuilder::SetAllowedUsage(nxt::TextureUsageBit usage) {
if ((propertiesSet & TEXTURE_PROPERTY_ALLOWED_USAGE) != 0) {
device->HandleError("Texture allowed usage property set multiple times");
HandleError("Texture allowed usage property set multiple times");
return;
}
@ -203,7 +199,7 @@ namespace backend {
void TextureBuilder::SetInitialUsage(nxt::TextureUsageBit usage) {
if ((propertiesSet & TEXTURE_PROPERTY_INITIAL_USAGE) != 0) {
device->HandleError("Texture initial usage property set multiple times");
HandleError("Texture initial usage property set multiple times");
return;
}
@ -224,15 +220,11 @@ namespace backend {
// TextureViewBuilder
TextureViewBuilder::TextureViewBuilder(DeviceBase* device, TextureBase* texture)
: device(device), texture(texture) {
}
bool TextureViewBuilder::WasConsumed() const {
return false;
: Builder(device), texture(texture) {
}
TextureViewBase* TextureViewBuilder::GetResult() {
consumed = true;
MarkConsumed();
return device->CreateTextureView(this);
}

View File

@ -16,6 +16,7 @@
#define BACKEND_COMMON_TEXTURE_H_
#include "Forward.h"
#include "Builder.h"
#include "RefCounted.h"
#include "nxt/nxtcpp.h"
@ -59,12 +60,10 @@ namespace backend {
bool frozen = false;
};
class TextureBuilder : public RefCounted {
class TextureBuilder : public Builder {
public:
TextureBuilder(DeviceBase* device);
bool WasConsumed() const;
// NXT API
TextureBase* GetResult();
void SetDimension(nxt::TextureDimension dimension);
@ -77,9 +76,7 @@ namespace backend {
private:
friend class TextureBase;
DeviceBase* device;
int propertiesSet = 0;
bool consumed = false;
nxt::TextureDimension dimension;
uint32_t width, height, depth;
@ -99,20 +96,16 @@ namespace backend {
Ref<TextureBase> texture;
};
class TextureViewBuilder : public RefCounted {
class TextureViewBuilder : public Builder {
public:
TextureViewBuilder(DeviceBase* device, TextureBase* texture);
bool WasConsumed() const;
// NXT API
TextureViewBase* GetResult();
private:
friend class TextureViewBase;
DeviceBase* device;
bool consumed = false;
Ref<TextureBase> texture;
};

View File

@ -678,7 +678,7 @@ namespace metal {
newComputePipelineStateWithFunction:function error:&error];
if (error != nil) {
NSLog(@" error => %@", error);
device->HandleError("Error creating pipeline state");
builder->HandleError("Error creating pipeline state");
return;
}
@ -720,7 +720,7 @@ namespace metal {
newRenderPipelineStateWithDescriptor:descriptor error:&error];
if (error != nil) {
NSLog(@" error => %@", error);
device->HandleError("Error creating pipeline state");
builder->HandleError("Error creating pipeline state");
return;
}
@ -898,7 +898,7 @@ namespace metal {
mtlLibrary = [device->GetMTLDevice() newLibraryWithSource:mslSource options:nil error:&error];
if (error != nil) {
NSLog(@"MTLDevice newLibraryWithSource => %@", error);
device->HandleError("Error creating MTLLibrary from MSL source");
builder->HandleError("Error creating MTLLibrary from MSL source");
}
}