Use a descriptor for BindGroupLayout (#211)

* Use a descriptor for BindGroupLayout
* Fix MatchesLambda
* Add WireTests.StructureOfStructureArrayArgument
* Add BindGroupValidationTests.BindGroupLayoutCache
This commit is contained in:
Kai Ninomiya 2018-07-10 12:23:50 -07:00 committed by GitHub
parent 7883e7e59c
commit 234becf175
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 259 additions and 163 deletions

View File

@ -223,10 +223,12 @@ void initSim() {
} }
)"); )");
nxt::BindGroupLayout bgl = device.CreateBindGroupLayoutBuilder() auto bgl = utils::MakeBindGroupLayout(
.SetBindingsType(nxt::ShaderStageBit::Compute, nxt::BindingType::UniformBuffer, 0, 1) device, {
.SetBindingsType(nxt::ShaderStageBit::Compute, nxt::BindingType::StorageBuffer, 1, 2) {0, nxt::ShaderStageBit::Compute, nxt::BindingType::UniformBuffer},
.GetResult(); {1, nxt::ShaderStageBit::Compute, nxt::BindingType::StorageBuffer},
{2, nxt::ShaderStageBit::Compute, nxt::BindingType::StorageBuffer},
});
nxt::PipelineLayout pl = utils::MakeBasicPipelineLayout(device, &bgl); nxt::PipelineLayout pl = utils::MakeBasicPipelineLayout(device, &bgl);

View File

@ -110,10 +110,11 @@ void init() {
.SetInput(0, 4 * sizeof(float), nxt::InputStepMode::Vertex) .SetInput(0, 4 * sizeof(float), nxt::InputStepMode::Vertex)
.GetResult(); .GetResult();
nxt::BindGroupLayout bgl = device.CreateBindGroupLayoutBuilder() auto bgl = utils::MakeBindGroupLayout(
.SetBindingsType(nxt::ShaderStageBit::Fragment, nxt::BindingType::Sampler, 0, 1) device, {
.SetBindingsType(nxt::ShaderStageBit::Fragment, nxt::BindingType::SampledTexture, 1, 1) {0, nxt::ShaderStageBit::Fragment, nxt::BindingType::Sampler},
.GetResult(); {1, nxt::ShaderStageBit::Fragment, nxt::BindingType::SampledTexture},
});
nxt::PipelineLayout pl = utils::MakeBasicPipelineLayout(device, &bgl); nxt::PipelineLayout pl = utils::MakeBasicPipelineLayout(device, &bgl);

View File

@ -161,9 +161,11 @@ void init() {
.SetInput(0, 6 * sizeof(float), nxt::InputStepMode::Vertex) .SetInput(0, 6 * sizeof(float), nxt::InputStepMode::Vertex)
.GetResult(); .GetResult();
nxt::BindGroupLayout bgl = device.CreateBindGroupLayoutBuilder() auto bgl = utils::MakeBindGroupLayout(
.SetBindingsType(nxt::ShaderStageBit::Vertex, nxt::BindingType::UniformBuffer, 0, 2) device, {
.GetResult(); {0, nxt::ShaderStageBit::Vertex, nxt::BindingType::UniformBuffer},
{1, nxt::ShaderStageBit::Vertex, nxt::BindingType::UniformBuffer},
});
nxt::PipelineLayout pl = utils::MakeBasicPipelineLayout(device, &bgl); nxt::PipelineLayout pl = utils::MakeBasicPipelineLayout(device, &bgl);

View File

@ -271,15 +271,14 @@ namespace {
} }
auto inputState = builder.GetResult(); auto inputState = builder.GetResult();
auto bindGroupLayoutBuilder = device.CreateBindGroupLayoutBuilder() constexpr nxt::ShaderStageBit kNoStages{};
.SetBindingsType(nxt::ShaderStageBit::Vertex, nxt::BindingType::UniformBuffer, 0, 1) nxt::BindGroupLayout bindGroupLayout = utils::MakeBindGroupLayout(
.Clone(); device, {
if (hasTexture) { {0, nxt::ShaderStageBit::Vertex, nxt::BindingType::UniformBuffer},
bindGroupLayoutBuilder {1, nxt::ShaderStageBit::Fragment, nxt::BindingType::Sampler},
.SetBindingsType(nxt::ShaderStageBit::Fragment, nxt::BindingType::Sampler, 1, 1) {2, hasTexture ? nxt::ShaderStageBit::Fragment : kNoStages,
.SetBindingsType(nxt::ShaderStageBit::Fragment, nxt::BindingType::SampledTexture, 2, 1); nxt::BindingType::SampledTexture},
} });
auto bindGroupLayout = bindGroupLayoutBuilder.GetResult();
auto depthStencilState = device.CreateDepthStencilStateBuilder() auto depthStencilState = device.CreateDepthStencilStateBuilder()
.SetDepthCompareFunction(nxt::CompareFunction::Less) .SetDepthCompareFunction(nxt::CompareFunction::Less)

View File

@ -78,22 +78,21 @@
"bind group layout": { "bind group layout": {
"category": "object" "category": "object"
}, },
"bind group layout builder": { "bind group binding": {
"category": "object", "category": "structure",
"methods": [ "extensible": false,
{ "members": [
"name": "get result", {"name": "binding", "type": "uint32_t"},
"returns": "bind group layout" {"name": "visibility", "type": "shader stage bit"},
}, {"name": "type", "type": "binding type"}
{ ]
"name": "set bindings type", },
"args": [ "bind group layout descriptor": {
{"name": "visibility", "type": "shader stage bit"}, "category": "structure",
{"name": "binding type", "type": "binding type"}, "extensible": true,
{"name": "start", "type": "uint32_t"}, "members": [
{"name": "count", "type": "uint32_t"} {"name": "num bindings", "type": "uint32_t"},
] {"name": "bindings", "type": "bind group binding", "annotation": "const*", "length": "num bindings"}
}
] ]
}, },
"binding type": { "binding type": {
@ -572,8 +571,11 @@
"returns": "bind group builder" "returns": "bind group builder"
}, },
{ {
"name": "create bind group layout builder", "name": "create bind group layout",
"returns": "bind group layout builder" "returns": "bind group layout",
"args": [
{"name": "descriptor", "type": "bind group layout descriptor", "annotation": "const*"}
]
}, },
{ {
"name": "create blend state builder", "name": "create blend state builder",

View File

@ -15,6 +15,7 @@
#include "backend/BindGroupLayout.h" #include "backend/BindGroupLayout.h"
#include "backend/Device.h" #include "backend/Device.h"
#include "backend/ValidationUtils_autogen.h"
#include "common/BitSetIterator.h" #include "common/BitSetIterator.h"
#include "common/HashUtils.h" #include "common/HashUtils.h"
@ -22,6 +23,24 @@
namespace backend { namespace backend {
MaybeError ValidateBindGroupLayoutDescriptor(DeviceBase*,
const nxt::BindGroupLayoutDescriptor* descriptor) {
NXT_TRY_ASSERT(descriptor->nextInChain == nullptr, "nextInChain must be nullptr");
std::bitset<kMaxBindingsPerGroup> bindingsSet;
for (uint32_t i = 0; i < descriptor->numBindings; ++i) {
auto& binding = descriptor->bindings[i];
NXT_TRY_ASSERT(binding.binding <= kMaxBindingsPerGroup,
"some binding index exceeds the maximum value");
NXT_TRY(ValidateShaderStageBit(binding.visibility));
NXT_TRY(ValidateBindingType(binding.type));
NXT_TRY_ASSERT(!bindingsSet[i], "some binding index was specified more than once");
bindingsSet.set(binding.binding);
}
return {};
}
namespace { namespace {
size_t HashBindingInfo(const BindGroupLayoutBase::LayoutBindingInfo& info) { size_t HashBindingInfo(const BindGroupLayoutBase::LayoutBindingInfo& info) {
size_t hash = Hash(info.mask); size_t hash = Hash(info.mask);
@ -52,8 +71,20 @@ namespace backend {
// BindGroupLayoutBase // BindGroupLayoutBase
BindGroupLayoutBase::BindGroupLayoutBase(BindGroupLayoutBuilder* builder, bool blueprint) BindGroupLayoutBase::BindGroupLayoutBase(DeviceBase* device,
: mDevice(builder->mDevice), mBindingInfo(builder->mBindingInfo), mIsBlueprint(blueprint) { const nxt::BindGroupLayoutDescriptor* descriptor,
bool blueprint)
: mDevice(device), mIsBlueprint(blueprint) {
for (uint32_t i = 0; i < descriptor->numBindings; ++i) {
auto& binding = descriptor->bindings[i];
uint32_t index = binding.binding;
mBindingInfo.visibilities[index] = binding.visibility;
mBindingInfo.types[index] = binding.type;
ASSERT(!mBindingInfo.mask[index]);
mBindingInfo.mask.set(index);
}
} }
BindGroupLayoutBase::~BindGroupLayoutBase() { BindGroupLayoutBase::~BindGroupLayoutBase() {
@ -71,44 +102,6 @@ namespace backend {
return mDevice; return mDevice;
} }
// BindGroupLayoutBuilder
BindGroupLayoutBuilder::BindGroupLayoutBuilder(DeviceBase* device) : Builder(device) {
}
const BindGroupLayoutBase::LayoutBindingInfo& BindGroupLayoutBuilder::GetBindingInfo() const {
return mBindingInfo;
}
BindGroupLayoutBase* BindGroupLayoutBuilder::GetResultImpl() {
BindGroupLayoutBase blueprint(this, true);
auto* result = mDevice->GetOrCreateBindGroupLayout(&blueprint, this);
return result;
}
void BindGroupLayoutBuilder::SetBindingsType(nxt::ShaderStageBit visibility,
nxt::BindingType bindingType,
uint32_t start,
uint32_t count) {
if (start + count > kMaxBindingsPerGroup) {
HandleError("Setting bindings type over maximum number of bindings");
return;
}
for (size_t i = start; i < start + count; i++) {
if (mBindingInfo.mask[i]) {
HandleError("Setting already set binding type");
return;
}
}
for (size_t i = start; i < start + count; i++) {
mBindingInfo.mask.set(i);
mBindingInfo.visibilities[i] = visibility;
mBindingInfo.types[i] = bindingType;
}
}
// BindGroupLayoutCacheFuncs // BindGroupLayoutCacheFuncs
size_t BindGroupLayoutCacheFuncs::operator()(const BindGroupLayoutBase* bgl) const { size_t BindGroupLayoutCacheFuncs::operator()(const BindGroupLayoutBase* bgl) const {

View File

@ -15,7 +15,7 @@
#ifndef BACKEND_BINDGROUPLAYOUT_H_ #ifndef BACKEND_BINDGROUPLAYOUT_H_
#define BACKEND_BINDGROUPLAYOUT_H_ #define BACKEND_BINDGROUPLAYOUT_H_
#include "backend/Builder.h" #include "backend/Error.h"
#include "backend/Forward.h" #include "backend/Forward.h"
#include "backend/RefCounted.h" #include "backend/RefCounted.h"
#include "common/Constants.h" #include "common/Constants.h"
@ -27,9 +27,14 @@
namespace backend { namespace backend {
MaybeError ValidateBindGroupLayoutDescriptor(DeviceBase*,
const nxt::BindGroupLayoutDescriptor* descriptor);
class BindGroupLayoutBase : public RefCounted { class BindGroupLayoutBase : public RefCounted {
public: public:
BindGroupLayoutBase(BindGroupLayoutBuilder* builder, bool blueprint = false); BindGroupLayoutBase(DeviceBase* device,
const nxt::BindGroupLayoutDescriptor* descriptor,
bool blueprint = false);
~BindGroupLayoutBase() override; ~BindGroupLayoutBase() override;
struct LayoutBindingInfo { struct LayoutBindingInfo {
@ -47,26 +52,6 @@ namespace backend {
bool mIsBlueprint = false; bool mIsBlueprint = false;
}; };
class BindGroupLayoutBuilder : public Builder<BindGroupLayoutBase> {
public:
BindGroupLayoutBuilder(DeviceBase* device);
const BindGroupLayoutBase::LayoutBindingInfo& GetBindingInfo() const;
// NXT API
void SetBindingsType(nxt::ShaderStageBit visibility,
nxt::BindingType bindingType,
uint32_t start,
uint32_t count);
private:
friend class BindGroupLayoutBase;
BindGroupLayoutBase* GetResultImpl() override;
BindGroupLayoutBase::LayoutBindingInfo mBindingInfo;
};
// Implements the functors necessary for the unordered_set<BGL*>-based cache. // Implements the functors necessary for the unordered_set<BGL*>-based cache.
struct BindGroupLayoutCacheFuncs { struct BindGroupLayoutCacheFuncs {
// The hash function // The hash function

View File

@ -73,20 +73,18 @@ namespace backend {
return this; return this;
} }
BindGroupLayoutBase* DeviceBase::GetOrCreateBindGroupLayout( ResultOrError<BindGroupLayoutBase*> DeviceBase::GetOrCreateBindGroupLayout(
const BindGroupLayoutBase* blueprint, const nxt::BindGroupLayoutDescriptor* descriptor) {
BindGroupLayoutBuilder* builder) { BindGroupLayoutBase blueprint(this, descriptor, true);
// The blueprint is only used to search in the cache and is not modified. However cached
// objects can be modified, and unordered_set cannot search for a const pointer in a non auto iter = mCaches->bindGroupLayouts.find(&blueprint);
// const pointer set. That's why we do a const_cast here, but the blueprint won't be
// modified.
auto iter = mCaches->bindGroupLayouts.find(const_cast<BindGroupLayoutBase*>(blueprint));
if (iter != mCaches->bindGroupLayouts.end()) { if (iter != mCaches->bindGroupLayouts.end()) {
(*iter)->Reference(); (*iter)->Reference();
return *iter; return *iter;
} }
BindGroupLayoutBase* backendObj = CreateBindGroupLayout(builder); BindGroupLayoutBase* backendObj;
NXT_TRY_ASSIGN(backendObj, CreateBindGroupLayoutImpl(descriptor));
mCaches->bindGroupLayouts.insert(backendObj); mCaches->bindGroupLayouts.insert(backendObj);
return backendObj; return backendObj;
} }
@ -98,8 +96,22 @@ namespace backend {
BindGroupBuilder* DeviceBase::CreateBindGroupBuilder() { BindGroupBuilder* DeviceBase::CreateBindGroupBuilder() {
return new BindGroupBuilder(this); return new BindGroupBuilder(this);
} }
BindGroupLayoutBuilder* DeviceBase::CreateBindGroupLayoutBuilder() { BindGroupLayoutBase* DeviceBase::CreateBindGroupLayout(
return new BindGroupLayoutBuilder(this); const nxt::BindGroupLayoutDescriptor* descriptor) {
MaybeError validation = ValidateBindGroupLayoutDescriptor(this, descriptor);
if (validation.IsError()) {
// TODO(cwallez@chromium.org): Implement the WebGPU error handling mechanism.
delete validation.AcquireError();
return nullptr;
}
auto maybeBindGroupLayout = GetOrCreateBindGroupLayout(descriptor);
if (maybeBindGroupLayout.IsError()) {
// TODO(cwallez@chromium.org): Implement the WebGPU error handling mechanism.
delete maybeBindGroupLayout.AcquireError();
return nullptr;
}
return maybeBindGroupLayout.AcquireSuccess();
} }
BlendStateBuilder* DeviceBase::CreateBlendStateBuilder() { BlendStateBuilder* DeviceBase::CreateBlendStateBuilder() {
return new BlendStateBuilder(this); return new BlendStateBuilder(this);

View File

@ -36,7 +36,6 @@ namespace backend {
DeviceBase* GetDevice(); DeviceBase* GetDevice();
virtual BindGroupBase* CreateBindGroup(BindGroupBuilder* builder) = 0; virtual BindGroupBase* CreateBindGroup(BindGroupBuilder* builder) = 0;
virtual BindGroupLayoutBase* CreateBindGroupLayout(BindGroupLayoutBuilder* builder) = 0;
virtual BlendStateBase* CreateBlendState(BlendStateBuilder* builder) = 0; virtual BlendStateBase* CreateBlendState(BlendStateBuilder* builder) = 0;
virtual BufferBase* CreateBuffer(BufferBuilder* builder) = 0; virtual BufferBase* CreateBuffer(BufferBuilder* builder) = 0;
virtual BufferViewBase* CreateBufferView(BufferViewBuilder* builder) = 0; virtual BufferViewBase* CreateBufferView(BufferViewBuilder* builder) = 0;
@ -69,13 +68,14 @@ namespace backend {
// the built object will be, the "blueprint". The blueprint is just a FooBase object // the built object will be, the "blueprint". The blueprint is just a FooBase object
// instead of a backend Foo object. If the blueprint doesn't match an object in the // instead of a backend Foo object. If the blueprint doesn't match an object in the
// cache, then the builder is used to make a new object. // cache, then the builder is used to make a new object.
BindGroupLayoutBase* GetOrCreateBindGroupLayout(const BindGroupLayoutBase* blueprint, ResultOrError<BindGroupLayoutBase*> GetOrCreateBindGroupLayout(
BindGroupLayoutBuilder* builder); const nxt::BindGroupLayoutDescriptor* descriptor);
void UncacheBindGroupLayout(BindGroupLayoutBase* obj); void UncacheBindGroupLayout(BindGroupLayoutBase* obj);
// NXT API // NXT API
BindGroupBuilder* CreateBindGroupBuilder(); BindGroupBuilder* CreateBindGroupBuilder();
BindGroupLayoutBuilder* CreateBindGroupLayoutBuilder(); BindGroupLayoutBase* CreateBindGroupLayout(
const nxt::BindGroupLayoutDescriptor* descriptor);
BlendStateBuilder* CreateBlendStateBuilder(); BlendStateBuilder* CreateBlendStateBuilder();
BufferBuilder* CreateBufferBuilder(); BufferBuilder* CreateBufferBuilder();
CommandBufferBuilder* CreateCommandBufferBuilder(); CommandBufferBuilder* CreateCommandBufferBuilder();
@ -97,6 +97,8 @@ namespace backend {
void Release(); void Release();
private: private:
virtual ResultOrError<BindGroupLayoutBase*> CreateBindGroupLayoutImpl(
const nxt::BindGroupLayoutDescriptor* descriptor) = 0;
virtual ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl( virtual ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl(
const nxt::PipelineLayoutDescriptor* descriptor) = 0; const nxt::PipelineLayoutDescriptor* descriptor) = 0;
virtual ResultOrError<QueueBase*> CreateQueueImpl() = 0; virtual ResultOrError<QueueBase*> CreateQueueImpl() = 0;

View File

@ -19,8 +19,9 @@
namespace backend { namespace d3d12 { namespace backend { namespace d3d12 {
BindGroupLayout::BindGroupLayout(Device* device, BindGroupLayoutBuilder* builder) BindGroupLayout::BindGroupLayout(Device* device,
: BindGroupLayoutBase(builder), mDevice(device), mDescriptorCounts{} { const nxt::BindGroupLayoutDescriptor* descriptor)
: BindGroupLayoutBase(device, descriptor), mDescriptorCounts{} {
const auto& groupInfo = GetBindingInfo(); const auto& groupInfo = GetBindingInfo();
for (uint32_t binding : IterateBitSet(groupInfo.mask)) { for (uint32_t binding : IterateBitSet(groupInfo.mask)) {

View File

@ -25,7 +25,7 @@ namespace backend { namespace d3d12 {
class BindGroupLayout : public BindGroupLayoutBase { class BindGroupLayout : public BindGroupLayoutBase {
public: public:
BindGroupLayout(Device* device, BindGroupLayoutBuilder* builder); BindGroupLayout(Device* device, const nxt::BindGroupLayoutDescriptor* descriptor);
enum DescriptorType { enum DescriptorType {
CBV, CBV,
@ -44,7 +44,6 @@ namespace backend { namespace d3d12 {
const D3D12_DESCRIPTOR_RANGE* GetSamplerDescriptorRanges() const; const D3D12_DESCRIPTOR_RANGE* GetSamplerDescriptorRanges() const;
private: private:
Device* mDevice;
std::array<uint32_t, kMaxBindingsPerGroup> mBindingOffsets; std::array<uint32_t, kMaxBindingsPerGroup> mBindingOffsets;
std::array<uint32_t, DescriptorType::Count> mDescriptorCounts; std::array<uint32_t, DescriptorType::Count> mDescriptorCounts;
D3D12_DESCRIPTOR_RANGE mRanges[DescriptorType::Count]; D3D12_DESCRIPTOR_RANGE mRanges[DescriptorType::Count];

View File

@ -261,8 +261,9 @@ namespace backend { namespace d3d12 {
BindGroupBase* Device::CreateBindGroup(BindGroupBuilder* builder) { BindGroupBase* Device::CreateBindGroup(BindGroupBuilder* builder) {
return new BindGroup(this, builder); return new BindGroup(this, builder);
} }
BindGroupLayoutBase* Device::CreateBindGroupLayout(BindGroupLayoutBuilder* builder) { ResultOrError<BindGroupLayoutBase*> Device::CreateBindGroupLayoutImpl(
return new BindGroupLayout(this, builder); const nxt::BindGroupLayoutDescriptor* descriptor) {
return new BindGroupLayout(this, descriptor);
} }
BlendStateBase* Device::CreateBlendState(BlendStateBuilder* builder) { BlendStateBase* Device::CreateBlendState(BlendStateBuilder* builder) {
return new BlendState(builder); return new BlendState(builder);

View File

@ -39,7 +39,6 @@ namespace backend { namespace d3d12 {
~Device(); ~Device();
BindGroupBase* CreateBindGroup(BindGroupBuilder* builder) override; BindGroupBase* CreateBindGroup(BindGroupBuilder* builder) override;
BindGroupLayoutBase* CreateBindGroupLayout(BindGroupLayoutBuilder* builder) override;
BlendStateBase* CreateBlendState(BlendStateBuilder* builder) override; BlendStateBase* CreateBlendState(BlendStateBuilder* builder) override;
BufferBase* CreateBuffer(BufferBuilder* builder) override; BufferBase* CreateBuffer(BufferBuilder* builder) override;
BufferViewBase* CreateBufferView(BufferViewBuilder* builder) override; BufferViewBase* CreateBufferView(BufferViewBuilder* builder) override;
@ -78,6 +77,8 @@ namespace backend { namespace d3d12 {
void ExecuteCommandLists(std::initializer_list<ID3D12CommandList*> commandLists); void ExecuteCommandLists(std::initializer_list<ID3D12CommandList*> commandLists);
private: private:
ResultOrError<BindGroupLayoutBase*> CreateBindGroupLayoutImpl(
const nxt::BindGroupLayoutDescriptor* descriptor) override;
ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl( ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl(
const nxt::PipelineLayoutDescriptor* descriptor) override; const nxt::PipelineLayoutDescriptor* descriptor) override;
ResultOrError<QueueBase*> CreateQueueImpl() override; ResultOrError<QueueBase*> CreateQueueImpl() override;

View File

@ -36,7 +36,6 @@ namespace backend { namespace metal {
~Device(); ~Device();
BindGroupBase* CreateBindGroup(BindGroupBuilder* builder) override; BindGroupBase* CreateBindGroup(BindGroupBuilder* builder) override;
BindGroupLayoutBase* CreateBindGroupLayout(BindGroupLayoutBuilder* builder) override;
BlendStateBase* CreateBlendState(BlendStateBuilder* builder) override; BlendStateBase* CreateBlendState(BlendStateBuilder* builder) override;
BufferBase* CreateBuffer(BufferBuilder* builder) override; BufferBase* CreateBuffer(BufferBuilder* builder) override;
BufferViewBase* CreateBufferView(BufferViewBuilder* builder) override; BufferViewBase* CreateBufferView(BufferViewBuilder* builder) override;
@ -64,6 +63,8 @@ namespace backend { namespace metal {
ResourceUploader* GetResourceUploader() const; ResourceUploader* GetResourceUploader() const;
private: private:
ResultOrError<BindGroupLayoutBase*> CreateBindGroupLayoutImpl(
const nxt::BindGroupLayoutDescriptor* descriptor) override;
ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl( ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl(
const nxt::PipelineLayoutDescriptor* descriptor) override; const nxt::PipelineLayoutDescriptor* descriptor) override;
ResultOrError<QueueBase*> CreateQueueImpl() override; ResultOrError<QueueBase*> CreateQueueImpl() override;

View File

@ -85,8 +85,9 @@ namespace backend { namespace metal {
BindGroupBase* Device::CreateBindGroup(BindGroupBuilder* builder) { BindGroupBase* Device::CreateBindGroup(BindGroupBuilder* builder) {
return new BindGroup(builder); return new BindGroup(builder);
} }
BindGroupLayoutBase* Device::CreateBindGroupLayout(BindGroupLayoutBuilder* builder) { ResultOrError<BindGroupLayoutBase*> Device::CreateBindGroupLayoutImpl(
return new BindGroupLayout(builder); const nxt::BindGroupLayoutDescriptor* descriptor) {
return new BindGroupLayout(this, descriptor);
} }
BlendStateBase* Device::CreateBlendState(BlendStateBuilder* builder) { BlendStateBase* Device::CreateBlendState(BlendStateBuilder* builder) {
return new BlendState(builder); return new BlendState(builder);

View File

@ -39,8 +39,9 @@ namespace backend { namespace null {
BindGroupBase* Device::CreateBindGroup(BindGroupBuilder* builder) { BindGroupBase* Device::CreateBindGroup(BindGroupBuilder* builder) {
return new BindGroup(builder); return new BindGroup(builder);
} }
BindGroupLayoutBase* Device::CreateBindGroupLayout(BindGroupLayoutBuilder* builder) { ResultOrError<BindGroupLayoutBase*> Device::CreateBindGroupLayoutImpl(
return new BindGroupLayout(builder); const nxt::BindGroupLayoutDescriptor* descriptor) {
return new BindGroupLayout(this, descriptor);
} }
BlendStateBase* Device::CreateBlendState(BlendStateBuilder* builder) { BlendStateBase* Device::CreateBlendState(BlendStateBuilder* builder) {
return new BlendState(builder); return new BlendState(builder);

View File

@ -96,7 +96,6 @@ namespace backend { namespace null {
~Device(); ~Device();
BindGroupBase* CreateBindGroup(BindGroupBuilder* builder) override; BindGroupBase* CreateBindGroup(BindGroupBuilder* builder) override;
BindGroupLayoutBase* CreateBindGroupLayout(BindGroupLayoutBuilder* builder) override;
BlendStateBase* CreateBlendState(BlendStateBuilder* builder) override; BlendStateBase* CreateBlendState(BlendStateBuilder* builder) override;
BufferBase* CreateBuffer(BufferBuilder* builder) override; BufferBase* CreateBuffer(BufferBuilder* builder) override;
BufferViewBase* CreateBufferView(BufferViewBuilder* builder) override; BufferViewBase* CreateBufferView(BufferViewBuilder* builder) override;
@ -118,6 +117,8 @@ namespace backend { namespace null {
std::vector<std::unique_ptr<PendingOperation>> AcquirePendingOperations(); std::vector<std::unique_ptr<PendingOperation>> AcquirePendingOperations();
private: private:
ResultOrError<BindGroupLayoutBase*> CreateBindGroupLayoutImpl(
const nxt::BindGroupLayoutDescriptor* descriptor) override;
ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl( ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl(
const nxt::PipelineLayoutDescriptor* descriptor) override; const nxt::PipelineLayoutDescriptor* descriptor) override;
ResultOrError<QueueBase*> CreateQueueImpl() override; ResultOrError<QueueBase*> CreateQueueImpl() override;

View File

@ -53,8 +53,9 @@ namespace backend { namespace opengl {
BindGroupBase* Device::CreateBindGroup(BindGroupBuilder* builder) { BindGroupBase* Device::CreateBindGroup(BindGroupBuilder* builder) {
return new BindGroup(builder); return new BindGroup(builder);
} }
BindGroupLayoutBase* Device::CreateBindGroupLayout(BindGroupLayoutBuilder* builder) { ResultOrError<BindGroupLayoutBase*> Device::CreateBindGroupLayoutImpl(
return new BindGroupLayout(builder); const nxt::BindGroupLayoutDescriptor* descriptor) {
return new BindGroupLayout(this, descriptor);
} }
BlendStateBase* Device::CreateBlendState(BlendStateBuilder* builder) { BlendStateBase* Device::CreateBlendState(BlendStateBuilder* builder) {
return new BlendState(builder); return new BlendState(builder);

View File

@ -27,7 +27,6 @@ namespace backend { namespace opengl {
class Device : public DeviceBase { class Device : public DeviceBase {
public: public:
BindGroupBase* CreateBindGroup(BindGroupBuilder* builder) override; BindGroupBase* CreateBindGroup(BindGroupBuilder* builder) override;
BindGroupLayoutBase* CreateBindGroupLayout(BindGroupLayoutBuilder* builder) override;
BlendStateBase* CreateBlendState(BlendStateBuilder* builder) override; BlendStateBase* CreateBlendState(BlendStateBuilder* builder) override;
BufferBase* CreateBuffer(BufferBuilder* builder) override; BufferBase* CreateBuffer(BufferBuilder* builder) override;
BufferViewBase* CreateBufferView(BufferViewBuilder* builder) override; BufferViewBase* CreateBufferView(BufferViewBuilder* builder) override;
@ -46,6 +45,8 @@ namespace backend { namespace opengl {
void TickImpl() override; void TickImpl() override;
private: private:
ResultOrError<BindGroupLayoutBase*> CreateBindGroupLayoutImpl(
const nxt::BindGroupLayoutDescriptor* descriptor) override;
ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl( ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl(
const nxt::PipelineLayoutDescriptor* descriptor) override; const nxt::PipelineLayoutDescriptor* descriptor) override;
ResultOrError<QueueBase*> CreateQueueImpl() override; ResultOrError<QueueBase*> CreateQueueImpl() override;

View File

@ -54,8 +54,9 @@ namespace backend { namespace vulkan {
} }
} }
BindGroupLayout::BindGroupLayout(BindGroupLayoutBuilder* builder) BindGroupLayout::BindGroupLayout(Device* device,
: BindGroupLayoutBase(builder) { const nxt::BindGroupLayoutDescriptor* descriptor)
: BindGroupLayoutBase(device, descriptor) {
const auto& info = GetBindingInfo(); const auto& info = GetBindingInfo();
// Compute the bindings that will be chained in the DescriptorSetLayout create info. We add // Compute the bindings that will be chained in the DescriptorSetLayout create info. We add
@ -81,7 +82,6 @@ namespace backend { namespace vulkan {
createInfo.bindingCount = numBindings; createInfo.bindingCount = numBindings;
createInfo.pBindings = bindings.data(); createInfo.pBindings = bindings.data();
Device* device = ToBackend(GetDevice());
if (device->fn.CreateDescriptorSetLayout(device->GetVkDevice(), &createInfo, nullptr, if (device->fn.CreateDescriptorSetLayout(device->GetVkDevice(), &createInfo, nullptr,
&mHandle) != VK_SUCCESS) { &mHandle) != VK_SUCCESS) {
ASSERT(false); ASSERT(false);

View File

@ -27,7 +27,7 @@ namespace backend { namespace vulkan {
class BindGroupLayout : public BindGroupLayoutBase { class BindGroupLayout : public BindGroupLayoutBase {
public: public:
BindGroupLayout(BindGroupLayoutBuilder* builder); BindGroupLayout(Device* device, const nxt::BindGroupLayoutDescriptor* descriptor);
~BindGroupLayout(); ~BindGroupLayout();
VkDescriptorSetLayout GetHandle() const; VkDescriptorSetLayout GetHandle() const;

View File

@ -217,8 +217,9 @@ namespace backend { namespace vulkan {
BindGroupBase* Device::CreateBindGroup(BindGroupBuilder* builder) { BindGroupBase* Device::CreateBindGroup(BindGroupBuilder* builder) {
return new BindGroup(builder); return new BindGroup(builder);
} }
BindGroupLayoutBase* Device::CreateBindGroupLayout(BindGroupLayoutBuilder* builder) { ResultOrError<BindGroupLayoutBase*> Device::CreateBindGroupLayoutImpl(
return new BindGroupLayout(builder); const nxt::BindGroupLayoutDescriptor* descriptor) {
return new BindGroupLayout(this, descriptor);
} }
BlendStateBase* Device::CreateBlendState(BlendStateBuilder* builder) { BlendStateBase* Device::CreateBlendState(BlendStateBuilder* builder) {
return new BlendState(builder); return new BlendState(builder);

View File

@ -64,7 +64,6 @@ namespace backend { namespace vulkan {
// NXT API // NXT API
BindGroupBase* CreateBindGroup(BindGroupBuilder* builder) override; BindGroupBase* CreateBindGroup(BindGroupBuilder* builder) override;
BindGroupLayoutBase* CreateBindGroupLayout(BindGroupLayoutBuilder* builder) override;
BlendStateBase* CreateBlendState(BlendStateBuilder* builder) override; BlendStateBase* CreateBlendState(BlendStateBuilder* builder) override;
BufferBase* CreateBuffer(BufferBuilder* builder) override; BufferBase* CreateBuffer(BufferBuilder* builder) override;
BufferViewBase* CreateBufferView(BufferViewBuilder* builder) override; BufferViewBase* CreateBufferView(BufferViewBuilder* builder) override;
@ -83,6 +82,8 @@ namespace backend { namespace vulkan {
void TickImpl() override; void TickImpl() override;
private: private:
ResultOrError<BindGroupLayoutBase*> CreateBindGroupLayoutImpl(
const nxt::BindGroupLayoutDescriptor* descriptor) override;
ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl( ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl(
const nxt::PipelineLayoutDescriptor* descriptor) override; const nxt::PipelineLayoutDescriptor* descriptor) override;
ResultOrError<QueueBase*> CreateQueueImpl() override; ResultOrError<QueueBase*> CreateQueueImpl() override;

View File

@ -36,10 +36,10 @@ class BlendStateTest : public NXTTest {
} }
)"); )");
bindGroupLayout = utils::MakeBindGroupLayout(
bindGroupLayout = device.CreateBindGroupLayoutBuilder() device, {
.SetBindingsType(nxt::ShaderStageBit::Fragment, nxt::BindingType::UniformBuffer, 0, 1) {0, nxt::ShaderStageBit::Fragment, nxt::BindingType::UniformBuffer},
.GetResult(); });
pipelineLayout = utils::MakeBasicPipelineLayout(device, &bindGroupLayout); pipelineLayout = utils::MakeBasicPipelineLayout(device, &bindGroupLayout);

View File

@ -78,9 +78,11 @@ class DepthStencilStateTest : public NXTTest {
} }
)"); )");
bindGroupLayout = device.CreateBindGroupLayoutBuilder() bindGroupLayout = utils::MakeBindGroupLayout(
.SetBindingsType(nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment, nxt::BindingType::UniformBuffer, 0, 1) device, {
.GetResult(); {0, nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment,
nxt::BindingType::UniformBuffer},
});
pipelineLayout = utils::MakeBasicPipelineLayout(device, &bindGroupLayout); pipelineLayout = utils::MakeBasicPipelineLayout(device, &bindGroupLayout);
} }

View File

@ -45,9 +45,14 @@ class PushConstantTest: public NXTTest {
buf2.FreezeUsage(nxt::BufferUsageBit::Storage); buf2.FreezeUsage(nxt::BufferUsageBit::Storage);
nxt::ShaderStageBit kAllStages = nxt::ShaderStageBit::Compute | nxt::ShaderStageBit::Fragment | nxt::ShaderStageBit::Vertex; nxt::ShaderStageBit kAllStages = nxt::ShaderStageBit::Compute | nxt::ShaderStageBit::Fragment | nxt::ShaderStageBit::Vertex;
nxt::BindGroupLayout bgl = device.CreateBindGroupLayoutBuilder() constexpr nxt::ShaderStageBit kNoStages{};
.SetBindingsType(kAllStages, nxt::BindingType::StorageBuffer, 0, extraBuffer ? 2 : 1)
.GetResult(); nxt::BindGroupLayout bgl = utils::MakeBindGroupLayout(
device,
{
{0, kAllStages, nxt::BindingType::StorageBuffer},
{1, extraBuffer ? kAllStages : kNoStages, nxt::BindingType::StorageBuffer},
});
nxt::PipelineLayout pl = utils::MakeBasicPipelineLayout(device, &bgl); nxt::PipelineLayout pl = utils::MakeBasicPipelineLayout(device, &bgl);

View File

@ -43,10 +43,11 @@ protected:
mRenderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize); mRenderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
mRenderPass.color.TransitionUsage(nxt::TextureUsageBit::OutputAttachment); mRenderPass.color.TransitionUsage(nxt::TextureUsageBit::OutputAttachment);
mBindGroupLayout = device.CreateBindGroupLayoutBuilder() mBindGroupLayout = utils::MakeBindGroupLayout(
.SetBindingsType(nxt::ShaderStageBit::Fragment, nxt::BindingType::Sampler, 0, 1) device, {
.SetBindingsType(nxt::ShaderStageBit::Fragment, nxt::BindingType::SampledTexture, 1, 1) {0, nxt::ShaderStageBit::Fragment, nxt::BindingType::Sampler},
.GetResult(); {1, nxt::ShaderStageBit::Fragment, nxt::BindingType::SampledTexture},
});
auto pipelineLayout = utils::MakeBasicPipelineLayout(device, &mBindGroupLayout); auto pipelineLayout = utils::MakeBasicPipelineLayout(device, &mBindGroupLayout);

View File

@ -50,6 +50,7 @@ class LambdaMatcherImpl : public MatcherInterface<Arg> {
bool MatchAndExplain(Arg value, MatchResultListener* listener) const override { bool MatchAndExplain(Arg value, MatchResultListener* listener) const override {
if (!mLambda(value)) { if (!mLambda(value)) {
*listener << "which doesn't satisfy the custom predicate"; *listener << "which doesn't satisfy the custom predicate";
return false;
} }
return true; return true;
} }
@ -410,15 +411,13 @@ TEST_F(WireTests, StructureOfValuesArgument) {
// Test that the wire is able to send structures that contain objects // Test that the wire is able to send structures that contain objects
TEST_F(WireTests, StructureOfObjectArrayArgument) { TEST_F(WireTests, StructureOfObjectArrayArgument) {
nxtBindGroupLayoutBuilder bglBuilder = nxtDeviceCreateBindGroupLayoutBuilder(device); nxtBindGroupLayoutDescriptor bglDescriptor;
nxtBindGroupLayout bgl = nxtBindGroupLayoutBuilderGetResult(bglBuilder); bglDescriptor.numBindings = 0;
bglDescriptor.bindings = nullptr;
nxtBindGroupLayoutBuilder apiBglBuilder = api.GetNewBindGroupLayoutBuilder(); nxtBindGroupLayout bgl = nxtDeviceCreateBindGroupLayout(device, &bglDescriptor);
EXPECT_CALL(api, DeviceCreateBindGroupLayoutBuilder(apiDevice))
.WillOnce(Return(apiBglBuilder));
nxtBindGroupLayout apiBgl = api.GetNewBindGroupLayout(); nxtBindGroupLayout apiBgl = api.GetNewBindGroupLayout();
EXPECT_CALL(api, BindGroupLayoutBuilderGetResult(apiBglBuilder)) EXPECT_CALL(api, DeviceCreateBindGroupLayout(apiDevice, _)).WillOnce(Return(apiBgl));
.WillOnce(Return(apiBgl));
nxtPipelineLayoutDescriptor descriptor; nxtPipelineLayoutDescriptor descriptor;
descriptor.nextInChain = nullptr; descriptor.nextInChain = nullptr;
@ -436,6 +435,42 @@ TEST_F(WireTests, StructureOfObjectArrayArgument) {
FlushClient(); FlushClient();
} }
// Test that the wire is able to send structures that contain objects
TEST_F(WireTests, StructureOfStructureArrayArgument) {
static constexpr int NUM_BINDINGS = 3;
nxtBindGroupBinding bindings[NUM_BINDINGS]{
{0, NXT_SHADER_STAGE_BIT_VERTEX, NXT_BINDING_TYPE_SAMPLER},
{1, NXT_SHADER_STAGE_BIT_VERTEX, NXT_BINDING_TYPE_SAMPLED_TEXTURE},
{2,
static_cast<nxtShaderStageBit>(NXT_SHADER_STAGE_BIT_VERTEX |
NXT_SHADER_STAGE_BIT_FRAGMENT),
NXT_BINDING_TYPE_UNIFORM_BUFFER},
};
nxtBindGroupLayoutDescriptor bglDescriptor;
bglDescriptor.numBindings = NUM_BINDINGS;
bglDescriptor.bindings = bindings;
nxtDeviceCreateBindGroupLayout(device, &bglDescriptor);
nxtBindGroupLayout apiBgl = api.GetNewBindGroupLayout();
EXPECT_CALL(
api,
DeviceCreateBindGroupLayout(
apiDevice, MatchesLambda([bindings](const nxtBindGroupLayoutDescriptor* desc) -> bool {
for (int i = 0; i < NUM_BINDINGS; ++i) {
const auto& a = desc->bindings[i];
const auto& b = bindings[i];
if (a.binding != b.binding || a.visibility != b.visibility ||
a.type != b.type) {
return false;
}
}
return desc->nextInChain == nullptr && desc->numBindings == 3;
})))
.WillOnce(Return(apiBgl));
FlushClient();
}
// Test that the server doesn't forward calls to error objects or with error objects // Test that the server doesn't forward calls to error objects or with error objects
// Also test that when GetResult is called on an error builder, the error callback is fired // Also test that when GetResult is called on an error builder, the error callback is fired
TEST_F(WireTests, CallsSkippedAfterBuilderError) { TEST_F(WireTests, CallsSkippedAfterBuilderError) {

View File

@ -13,21 +13,23 @@
// limitations under the License. // limitations under the License.
#include "tests/unittests/validation/ValidationTest.h" #include "tests/unittests/validation/ValidationTest.h"
#include "utils/NXTHelpers.h"
class BindGroupValidationTest : public ValidationTest { class BindGroupValidationTest : public ValidationTest {
}; };
TEST_F(BindGroupValidationTest, BufferViewOffset) { TEST_F(BindGroupValidationTest, BufferViewOffset) {
auto layout = device.CreateBindGroupLayoutBuilder() auto layout = utils::MakeBindGroupLayout(
.SetBindingsType(nxt::ShaderStageBit::Vertex, nxt::BindingType::UniformBuffer, 0, 1) device, {
.GetResult(); {0, nxt::ShaderStageBit::Vertex, nxt::BindingType::UniformBuffer},
});
auto buffer = device.CreateBufferBuilder() auto buffer = device.CreateBufferBuilder()
.SetAllowedUsage(nxt::BufferUsageBit::Uniform) .SetAllowedUsage(nxt::BufferUsageBit::Uniform)
.SetInitialUsage(nxt::BufferUsageBit::Uniform) .SetInitialUsage(nxt::BufferUsageBit::Uniform)
.SetSize(512) .SetSize(512)
.GetResult(); .GetResult();
// Check that offset 0 is valid // Check that offset 0 is valid
{ {
auto bufferView = buffer.CreateBufferViewBuilder() auto bufferView = buffer.CreateBufferViewBuilder()
@ -103,3 +105,21 @@ TEST_F(BindGroupValidationTest, BufferViewOffset) {
.GetResult(); .GetResult();
} }
} }
// This test verifies that the BindGroupLayout cache is successfully caching/deduplicating objects.
//
// NOTE: This test only works currently because unittests are run without the wire - so the returned
// BindGroupLayout pointers are actually visibly equivalent. With the wire, this would not be true.
TEST_F(BindGroupValidationTest, BindGroupLayoutCache) {
auto layout1 = utils::MakeBindGroupLayout(
device, {
{0, nxt::ShaderStageBit::Vertex, nxt::BindingType::UniformBuffer},
});
auto layout2 = utils::MakeBindGroupLayout(
device, {
{0, nxt::ShaderStageBit::Vertex, nxt::BindingType::UniformBuffer},
});
// Caching should cause these to be the same.
ASSERT_EQ(layout1.Get(), layout2.Get());
}

View File

@ -149,6 +149,7 @@ namespace utils {
return desc; return desc;
} }
nxt::PipelineLayout MakeBasicPipelineLayout(const nxt::Device& device, nxt::PipelineLayout MakeBasicPipelineLayout(const nxt::Device& device,
const nxt::BindGroupLayout* bindGroupLayout) { const nxt::BindGroupLayout* bindGroupLayout) {
nxt::PipelineLayoutDescriptor descriptor; nxt::PipelineLayoutDescriptor descriptor;
@ -162,4 +163,21 @@ namespace utils {
return device.CreatePipelineLayout(&descriptor); return device.CreatePipelineLayout(&descriptor);
} }
nxt::BindGroupLayout MakeBindGroupLayout(
const nxt::Device& device,
std::initializer_list<nxt::BindGroupBinding> bindingsInitializer) {
std::vector<nxt::BindGroupBinding> bindings;
nxt::ShaderStageBit kNoStages{};
for (const nxt::BindGroupBinding& binding : bindingsInitializer) {
if (binding.visibility != kNoStages) {
bindings.push_back(binding);
}
}
nxt::BindGroupLayoutDescriptor descriptor;
descriptor.numBindings = static_cast<uint32_t>(bindings.size());
descriptor.bindings = bindings.data();
return device.CreateBindGroupLayout(&descriptor);
}
} // namespace utils } // namespace utils

View File

@ -51,5 +51,8 @@ namespace utils {
nxt::SamplerDescriptor GetDefaultSamplerDescriptor(); nxt::SamplerDescriptor GetDefaultSamplerDescriptor();
nxt::PipelineLayout MakeBasicPipelineLayout(const nxt::Device& device, nxt::PipelineLayout MakeBasicPipelineLayout(const nxt::Device& device,
const nxt::BindGroupLayout* bindGroupLayout); const nxt::BindGroupLayout* bindGroupLayout);
nxt::BindGroupLayout MakeBindGroupLayout(
const nxt::Device& device,
std::initializer_list<nxt::BindGroupBinding> bindingsInitializer);
} // namespace utils } // namespace utils

View File

@ -27,6 +27,10 @@ namespace nxt { namespace wire {
} }
void* TerribleCommandBuffer::GetCmdSpace(size_t size) { void* TerribleCommandBuffer::GetCmdSpace(size_t size) {
// TODO(kainino@chromium.org): Should we early-out if size is 0?
// (Here and/or in the caller?) It might be good to make the wire receiver get a nullptr
// instead of pointer to zero-sized allocation in mBuffer.
if (size > sizeof(mBuffer)) { if (size > sizeof(mBuffer)) {
return nullptr; return nullptr;
} }