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()
.SetBindingsType(nxt::ShaderStageBit::Compute, nxt::BindingType::UniformBuffer, 0, 1)
.SetBindingsType(nxt::ShaderStageBit::Compute, nxt::BindingType::StorageBuffer, 1, 2)
.GetResult();
auto bgl = utils::MakeBindGroupLayout(
device, {
{0, nxt::ShaderStageBit::Compute, nxt::BindingType::UniformBuffer},
{1, nxt::ShaderStageBit::Compute, nxt::BindingType::StorageBuffer},
{2, nxt::ShaderStageBit::Compute, nxt::BindingType::StorageBuffer},
});
nxt::PipelineLayout pl = utils::MakeBasicPipelineLayout(device, &bgl);

View File

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

View File

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

View File

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

View File

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

View File

@ -15,6 +15,7 @@
#include "backend/BindGroupLayout.h"
#include "backend/Device.h"
#include "backend/ValidationUtils_autogen.h"
#include "common/BitSetIterator.h"
#include "common/HashUtils.h"
@ -22,6 +23,24 @@
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 {
size_t HashBindingInfo(const BindGroupLayoutBase::LayoutBindingInfo& info) {
size_t hash = Hash(info.mask);
@ -52,8 +71,20 @@ namespace backend {
// BindGroupLayoutBase
BindGroupLayoutBase::BindGroupLayoutBase(BindGroupLayoutBuilder* builder, bool blueprint)
: mDevice(builder->mDevice), mBindingInfo(builder->mBindingInfo), mIsBlueprint(blueprint) {
BindGroupLayoutBase::BindGroupLayoutBase(DeviceBase* device,
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() {
@ -71,44 +102,6 @@ namespace backend {
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
size_t BindGroupLayoutCacheFuncs::operator()(const BindGroupLayoutBase* bgl) const {

View File

@ -15,7 +15,7 @@
#ifndef BACKEND_BINDGROUPLAYOUT_H_
#define BACKEND_BINDGROUPLAYOUT_H_
#include "backend/Builder.h"
#include "backend/Error.h"
#include "backend/Forward.h"
#include "backend/RefCounted.h"
#include "common/Constants.h"
@ -27,9 +27,14 @@
namespace backend {
MaybeError ValidateBindGroupLayoutDescriptor(DeviceBase*,
const nxt::BindGroupLayoutDescriptor* descriptor);
class BindGroupLayoutBase : public RefCounted {
public:
BindGroupLayoutBase(BindGroupLayoutBuilder* builder, bool blueprint = false);
BindGroupLayoutBase(DeviceBase* device,
const nxt::BindGroupLayoutDescriptor* descriptor,
bool blueprint = false);
~BindGroupLayoutBase() override;
struct LayoutBindingInfo {
@ -47,26 +52,6 @@ namespace backend {
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.
struct BindGroupLayoutCacheFuncs {
// The hash function

View File

@ -73,20 +73,18 @@ namespace backend {
return this;
}
BindGroupLayoutBase* DeviceBase::GetOrCreateBindGroupLayout(
const BindGroupLayoutBase* blueprint,
BindGroupLayoutBuilder* builder) {
// 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
// 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));
ResultOrError<BindGroupLayoutBase*> DeviceBase::GetOrCreateBindGroupLayout(
const nxt::BindGroupLayoutDescriptor* descriptor) {
BindGroupLayoutBase blueprint(this, descriptor, true);
auto iter = mCaches->bindGroupLayouts.find(&blueprint);
if (iter != mCaches->bindGroupLayouts.end()) {
(*iter)->Reference();
return *iter;
}
BindGroupLayoutBase* backendObj = CreateBindGroupLayout(builder);
BindGroupLayoutBase* backendObj;
NXT_TRY_ASSIGN(backendObj, CreateBindGroupLayoutImpl(descriptor));
mCaches->bindGroupLayouts.insert(backendObj);
return backendObj;
}
@ -98,8 +96,22 @@ namespace backend {
BindGroupBuilder* DeviceBase::CreateBindGroupBuilder() {
return new BindGroupBuilder(this);
}
BindGroupLayoutBuilder* DeviceBase::CreateBindGroupLayoutBuilder() {
return new BindGroupLayoutBuilder(this);
BindGroupLayoutBase* DeviceBase::CreateBindGroupLayout(
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() {
return new BlendStateBuilder(this);

View File

@ -36,7 +36,6 @@ namespace backend {
DeviceBase* GetDevice();
virtual BindGroupBase* CreateBindGroup(BindGroupBuilder* builder) = 0;
virtual BindGroupLayoutBase* CreateBindGroupLayout(BindGroupLayoutBuilder* builder) = 0;
virtual BlendStateBase* CreateBlendState(BlendStateBuilder* builder) = 0;
virtual BufferBase* CreateBuffer(BufferBuilder* 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
// 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.
BindGroupLayoutBase* GetOrCreateBindGroupLayout(const BindGroupLayoutBase* blueprint,
BindGroupLayoutBuilder* builder);
ResultOrError<BindGroupLayoutBase*> GetOrCreateBindGroupLayout(
const nxt::BindGroupLayoutDescriptor* descriptor);
void UncacheBindGroupLayout(BindGroupLayoutBase* obj);
// NXT API
BindGroupBuilder* CreateBindGroupBuilder();
BindGroupLayoutBuilder* CreateBindGroupLayoutBuilder();
BindGroupLayoutBase* CreateBindGroupLayout(
const nxt::BindGroupLayoutDescriptor* descriptor);
BlendStateBuilder* CreateBlendStateBuilder();
BufferBuilder* CreateBufferBuilder();
CommandBufferBuilder* CreateCommandBufferBuilder();
@ -97,6 +97,8 @@ namespace backend {
void Release();
private:
virtual ResultOrError<BindGroupLayoutBase*> CreateBindGroupLayoutImpl(
const nxt::BindGroupLayoutDescriptor* descriptor) = 0;
virtual ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl(
const nxt::PipelineLayoutDescriptor* descriptor) = 0;
virtual ResultOrError<QueueBase*> CreateQueueImpl() = 0;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -54,8 +54,9 @@ namespace backend { namespace vulkan {
}
}
BindGroupLayout::BindGroupLayout(BindGroupLayoutBuilder* builder)
: BindGroupLayoutBase(builder) {
BindGroupLayout::BindGroupLayout(Device* device,
const nxt::BindGroupLayoutDescriptor* descriptor)
: BindGroupLayoutBase(device, descriptor) {
const auto& info = GetBindingInfo();
// 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.pBindings = bindings.data();
Device* device = ToBackend(GetDevice());
if (device->fn.CreateDescriptorSetLayout(device->GetVkDevice(), &createInfo, nullptr,
&mHandle) != VK_SUCCESS) {
ASSERT(false);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -45,9 +45,14 @@ class PushConstantTest: public NXTTest {
buf2.FreezeUsage(nxt::BufferUsageBit::Storage);
nxt::ShaderStageBit kAllStages = nxt::ShaderStageBit::Compute | nxt::ShaderStageBit::Fragment | nxt::ShaderStageBit::Vertex;
nxt::BindGroupLayout bgl = device.CreateBindGroupLayoutBuilder()
.SetBindingsType(kAllStages, nxt::BindingType::StorageBuffer, 0, extraBuffer ? 2 : 1)
.GetResult();
constexpr nxt::ShaderStageBit kNoStages{};
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);

View File

@ -43,10 +43,11 @@ protected:
mRenderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
mRenderPass.color.TransitionUsage(nxt::TextureUsageBit::OutputAttachment);
mBindGroupLayout = device.CreateBindGroupLayoutBuilder()
.SetBindingsType(nxt::ShaderStageBit::Fragment, nxt::BindingType::Sampler, 0, 1)
.SetBindingsType(nxt::ShaderStageBit::Fragment, nxt::BindingType::SampledTexture, 1, 1)
.GetResult();
mBindGroupLayout = utils::MakeBindGroupLayout(
device, {
{0, nxt::ShaderStageBit::Fragment, nxt::BindingType::Sampler},
{1, nxt::ShaderStageBit::Fragment, nxt::BindingType::SampledTexture},
});
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 {
if (!mLambda(value)) {
*listener << "which doesn't satisfy the custom predicate";
return false;
}
return true;
}
@ -410,15 +411,13 @@ TEST_F(WireTests, StructureOfValuesArgument) {
// Test that the wire is able to send structures that contain objects
TEST_F(WireTests, StructureOfObjectArrayArgument) {
nxtBindGroupLayoutBuilder bglBuilder = nxtDeviceCreateBindGroupLayoutBuilder(device);
nxtBindGroupLayout bgl = nxtBindGroupLayoutBuilderGetResult(bglBuilder);
nxtBindGroupLayoutDescriptor bglDescriptor;
bglDescriptor.numBindings = 0;
bglDescriptor.bindings = nullptr;
nxtBindGroupLayoutBuilder apiBglBuilder = api.GetNewBindGroupLayoutBuilder();
EXPECT_CALL(api, DeviceCreateBindGroupLayoutBuilder(apiDevice))
.WillOnce(Return(apiBglBuilder));
nxtBindGroupLayout bgl = nxtDeviceCreateBindGroupLayout(device, &bglDescriptor);
nxtBindGroupLayout apiBgl = api.GetNewBindGroupLayout();
EXPECT_CALL(api, BindGroupLayoutBuilderGetResult(apiBglBuilder))
.WillOnce(Return(apiBgl));
EXPECT_CALL(api, DeviceCreateBindGroupLayout(apiDevice, _)).WillOnce(Return(apiBgl));
nxtPipelineLayoutDescriptor descriptor;
descriptor.nextInChain = nullptr;
@ -436,6 +435,42 @@ TEST_F(WireTests, StructureOfObjectArrayArgument) {
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
// Also test that when GetResult is called on an error builder, the error callback is fired
TEST_F(WireTests, CallsSkippedAfterBuilderError) {

View File

@ -13,21 +13,23 @@
// limitations under the License.
#include "tests/unittests/validation/ValidationTest.h"
#include "utils/NXTHelpers.h"
class BindGroupValidationTest : public ValidationTest {
};
TEST_F(BindGroupValidationTest, BufferViewOffset) {
auto layout = device.CreateBindGroupLayoutBuilder()
.SetBindingsType(nxt::ShaderStageBit::Vertex, nxt::BindingType::UniformBuffer, 0, 1)
.GetResult();
auto layout = utils::MakeBindGroupLayout(
device, {
{0, nxt::ShaderStageBit::Vertex, nxt::BindingType::UniformBuffer},
});
auto buffer = device.CreateBufferBuilder()
.SetAllowedUsage(nxt::BufferUsageBit::Uniform)
.SetInitialUsage(nxt::BufferUsageBit::Uniform)
.SetSize(512)
.GetResult();
// Check that offset 0 is valid
{
auto bufferView = buffer.CreateBufferViewBuilder()
@ -103,3 +105,21 @@ TEST_F(BindGroupValidationTest, BufferViewOffset) {
.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;
}
nxt::PipelineLayout MakeBasicPipelineLayout(const nxt::Device& device,
const nxt::BindGroupLayout* bindGroupLayout) {
nxt::PipelineLayoutDescriptor descriptor;
@ -162,4 +163,21 @@ namespace utils {
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

View File

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

View File

@ -27,6 +27,10 @@ namespace nxt { namespace wire {
}
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)) {
return nullptr;
}