Use a descriptor for PipelineLayout (#206)
Adds support for structures inside descriptors.
diff --git a/src/backend/CommandBufferStateTracker.cpp b/src/backend/CommandBufferStateTracker.cpp
index 81971f9..7503b05 100644
--- a/src/backend/CommandBufferStateTracker.cpp
+++ b/src/backend/CommandBufferStateTracker.cpp
@@ -395,7 +395,8 @@
for (size_t i = 0; i < mBindgroups.size(); ++i) {
if (auto* bindgroup = mBindgroups[i]) {
// TODO(kainino@chromium.org): bind group compatibility
- if (bindgroup->GetLayout() != mLastPipeline->GetLayout()->GetBindGroupLayout(i)) {
+ auto* pipelineBGL = mLastPipeline->GetLayout()->GetBindGroupLayout(i);
+ if (pipelineBGL && bindgroup->GetLayout() != pipelineBGL) {
return false;
}
}
diff --git a/src/backend/Device.cpp b/src/backend/Device.cpp
index 8b08a40..360ae99 100644
--- a/src/backend/Device.cpp
+++ b/src/backend/Device.cpp
@@ -119,8 +119,23 @@
InputStateBuilder* DeviceBase::CreateInputStateBuilder() {
return new InputStateBuilder(this);
}
- PipelineLayoutBuilder* DeviceBase::CreatePipelineLayoutBuilder() {
- return new PipelineLayoutBuilder(this);
+ PipelineLayoutBase* DeviceBase::CreatePipelineLayout(
+ const nxt::PipelineLayoutDescriptor* descriptor) {
+ MaybeError validation = ValidatePipelineLayoutDescriptor(this, descriptor);
+ if (validation.IsError()) {
+ // TODO(cwallez@chromium.org): Implement the WebGPU error handling mechanism.
+ delete validation.AcquireError();
+ return nullptr;
+ }
+
+ ResultOrError<PipelineLayoutBase*> maybePipelineLayout =
+ CreatePipelineLayoutImpl(descriptor);
+ if (maybePipelineLayout.IsError()) {
+ // TODO(cwallez@chromium.org): Implement the WebGPU error handling mechanism.
+ delete maybePipelineLayout.AcquireError();
+ return nullptr;
+ }
+ return maybePipelineLayout.AcquireSuccess();
}
QueueBase* DeviceBase::CreateQueue() {
ResultOrError<QueueBase*> maybeQueue = CreateQueueImpl();
diff --git a/src/backend/Device.h b/src/backend/Device.h
index 93dee15..204eaf9 100644
--- a/src/backend/Device.h
+++ b/src/backend/Device.h
@@ -45,7 +45,6 @@
virtual DepthStencilStateBase* CreateDepthStencilState(
DepthStencilStateBuilder* builder) = 0;
virtual InputStateBase* CreateInputState(InputStateBuilder* builder) = 0;
- virtual PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) = 0;
virtual RenderPassDescriptorBase* CreateRenderPassDescriptor(
RenderPassDescriptorBuilder* builder) = 0;
virtual RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) = 0;
@@ -83,7 +82,7 @@
ComputePipelineBuilder* CreateComputePipelineBuilder();
DepthStencilStateBuilder* CreateDepthStencilStateBuilder();
InputStateBuilder* CreateInputStateBuilder();
- PipelineLayoutBuilder* CreatePipelineLayoutBuilder();
+ PipelineLayoutBase* CreatePipelineLayout(const nxt::PipelineLayoutDescriptor* descriptor);
QueueBase* CreateQueue();
RenderPassDescriptorBuilder* CreateRenderPassDescriptorBuilder();
RenderPipelineBuilder* CreateRenderPipelineBuilder();
@@ -98,6 +97,8 @@
void Release();
private:
+ virtual ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl(
+ const nxt::PipelineLayoutDescriptor* descriptor) = 0;
virtual ResultOrError<QueueBase*> CreateQueueImpl() = 0;
virtual ResultOrError<SamplerBase*> CreateSamplerImpl(
const nxt::SamplerDescriptor* descriptor) = 0;
diff --git a/src/backend/Error.h b/src/backend/Error.h
index 9db8358..8f0200c 100644
--- a/src/backend/Error.h
+++ b/src/backend/Error.h
@@ -36,7 +36,15 @@
//
// Returning an error is done via:
// NXT_RETURN_ERROR("My error message");
-#define NXT_RETURN_ERROR(EXPR) return MakeError(EXPR, __FILE__, __func__, __LINE__)
+#define NXT_RETURN_ERROR(MESSAGE) return MakeError(MESSAGE, __FILE__, __func__, __LINE__)
+#define NXT_TRY_ASSERT(EXPR, MESSAGE) \
+ { \
+ if (!(EXPR)) { \
+ NXT_RETURN_ERROR(MESSAGE); \
+ } \
+ } \
+ for (;;) \
+ break
#define NXT_CONCAT1(x, y) x##y
#define NXT_CONCAT2(x, y) NXT_CONCAT1(x, y)
diff --git a/src/backend/Pipeline.cpp b/src/backend/Pipeline.cpp
index 67275e3..13c320e 100644
--- a/src/backend/Pipeline.cpp
+++ b/src/backend/Pipeline.cpp
@@ -27,10 +27,10 @@
PipelineBase::PipelineBase(PipelineBuilder* builder)
: mStageMask(builder->mStageMask), mLayout(std::move(builder->mLayout)) {
if (!mLayout) {
- mLayout = builder->GetParentBuilder()
- ->GetDevice()
- ->CreatePipelineLayoutBuilder()
- ->GetResult();
+ nxt::PipelineLayoutDescriptor descriptor;
+ descriptor.numBindGroupLayouts = 0;
+ descriptor.bindGroupLayouts = nullptr;
+ mLayout = builder->GetParentBuilder()->GetDevice()->CreatePipelineLayout(&descriptor);
// Remove the external ref objects are created with
mLayout->Release();
}
diff --git a/src/backend/PipelineLayout.cpp b/src/backend/PipelineLayout.cpp
index d8040e2..d25c2ac 100644
--- a/src/backend/PipelineLayout.cpp
+++ b/src/backend/PipelineLayout.cpp
@@ -20,10 +20,37 @@
namespace backend {
+ MaybeError ValidatePipelineLayoutDescriptor(DeviceBase*,
+ const nxt::PipelineLayoutDescriptor* descriptor) {
+ NXT_TRY_ASSERT(descriptor->nextInChain == nullptr, "nextInChain must be nullptr");
+ NXT_TRY_ASSERT(descriptor->numBindGroupLayouts <= kMaxBindGroups,
+ "too many bind group layouts");
+ for (uint32_t i = 0; i < descriptor->numBindGroupLayouts; ++i) {
+ NXT_TRY_ASSERT(descriptor->bindGroupLayouts[i].Get() != nullptr,
+ "bind group layouts may not be null");
+ }
+ return {};
+ }
+
// PipelineLayoutBase
- PipelineLayoutBase::PipelineLayoutBase(PipelineLayoutBuilder* builder)
- : mBindGroupLayouts(std::move(builder->mBindGroupLayouts)), mMask(builder->mMask) {
+ PipelineLayoutBase::PipelineLayoutBase(DeviceBase* device,
+ const nxt::PipelineLayoutDescriptor* descriptor) {
+ ASSERT(descriptor->numBindGroupLayouts <= kMaxBindGroups);
+ for (uint32_t group = 0; group < descriptor->numBindGroupLayouts; ++group) {
+ mBindGroupLayouts[group] =
+ reinterpret_cast<BindGroupLayoutBase*>(descriptor->bindGroupLayouts[group].Get());
+ mMask.set(group);
+ }
+ // TODO(kainino@chromium.org): It shouldn't be necessary to construct default bind
+ // group layouts here. Remove these and fix things so that they are not needed.
+ for (uint32_t group = descriptor->numBindGroupLayouts; group < kMaxBindGroups; ++group) {
+ auto builder = device->CreateBindGroupLayoutBuilder();
+ mBindGroupLayouts[group] = builder->GetResult();
+ // Remove the external ref objects are created with
+ mBindGroupLayouts[group]->Release();
+ builder->Release();
+ }
}
const BindGroupLayoutBase* PipelineLayoutBase::GetBindGroupLayout(size_t group) const {
@@ -49,40 +76,4 @@
return kMaxBindGroups + 1;
}
- // PipelineLayoutBuilder
-
- PipelineLayoutBuilder::PipelineLayoutBuilder(DeviceBase* device) : Builder(device) {
- }
-
- PipelineLayoutBase* PipelineLayoutBuilder::GetResultImpl() {
- // TODO(cwallez@chromium.org): this is a hack, have the null bind group layout somewhere in
- // the device once we have a cache of BGL
- for (size_t group = 0; group < kMaxBindGroups; ++group) {
- if (!mBindGroupLayouts[group]) {
- auto builder = mDevice->CreateBindGroupLayoutBuilder();
- mBindGroupLayouts[group] = builder->GetResult();
- // Remove the external ref objects are created with
- mBindGroupLayouts[group]->Release();
- builder->Release();
- }
- }
-
- return mDevice->CreatePipelineLayout(this);
- }
-
- void PipelineLayoutBuilder::SetBindGroupLayout(uint32_t groupIndex,
- BindGroupLayoutBase* layout) {
- if (groupIndex >= kMaxBindGroups) {
- HandleError("groupIndex is over the maximum allowed");
- return;
- }
- if (mMask[groupIndex]) {
- HandleError("Bind group layout already specified");
- return;
- }
-
- mBindGroupLayouts[groupIndex] = layout;
- mMask.set(groupIndex);
- }
-
} // namespace backend
diff --git a/src/backend/PipelineLayout.h b/src/backend/PipelineLayout.h
index 19062e9..262dafb 100644
--- a/src/backend/PipelineLayout.h
+++ b/src/backend/PipelineLayout.h
@@ -15,7 +15,7 @@
#ifndef BACKEND_PIPELINELAYOUT_H_
#define BACKEND_PIPELINELAYOUT_H_
-#include "backend/Builder.h"
+#include "backend/Error.h"
#include "backend/Forward.h"
#include "backend/RefCounted.h"
#include "common/Constants.h"
@@ -27,11 +27,14 @@
namespace backend {
+ MaybeError ValidatePipelineLayoutDescriptor(DeviceBase*,
+ const nxt::PipelineLayoutDescriptor* descriptor);
+
using BindGroupLayoutArray = std::array<Ref<BindGroupLayoutBase>, kMaxBindGroups>;
class PipelineLayoutBase : public RefCounted {
public:
- PipelineLayoutBase(PipelineLayoutBuilder* builder);
+ PipelineLayoutBase(DeviceBase* device, const nxt::PipelineLayoutDescriptor* descriptor);
const BindGroupLayoutBase* GetBindGroupLayout(size_t group) const;
const std::bitset<kMaxBindGroups> GetBindGroupsLayoutMask() const;
@@ -49,22 +52,6 @@
std::bitset<kMaxBindGroups> mMask;
};
- class PipelineLayoutBuilder : public Builder<PipelineLayoutBase> {
- public:
- PipelineLayoutBuilder(DeviceBase* device);
-
- // NXT API
- void SetBindGroupLayout(uint32_t groupIndex, BindGroupLayoutBase* layout);
-
- private:
- friend class PipelineLayoutBase;
-
- PipelineLayoutBase* GetResultImpl() override;
-
- BindGroupLayoutArray mBindGroupLayouts;
- std::bitset<kMaxBindGroups> mMask;
- };
-
} // namespace backend
#endif // BACKEND_PIPELINELAYOUT_H_
diff --git a/src/backend/Sampler.cpp b/src/backend/Sampler.cpp
index 7b00a5c..6798241 100644
--- a/src/backend/Sampler.cpp
+++ b/src/backend/Sampler.cpp
@@ -20,16 +20,13 @@
namespace backend {
MaybeError ValidateSamplerDescriptor(DeviceBase*, const nxt::SamplerDescriptor* descriptor) {
+ NXT_TRY_ASSERT(descriptor->nextInChain == nullptr, "nextInChain must be nullptr");
NXT_TRY(ValidateFilterMode(descriptor->minFilter));
NXT_TRY(ValidateFilterMode(descriptor->magFilter));
NXT_TRY(ValidateFilterMode(descriptor->mipmapFilter));
NXT_TRY(ValidateAddressMode(descriptor->addressModeU));
NXT_TRY(ValidateAddressMode(descriptor->addressModeV));
NXT_TRY(ValidateAddressMode(descriptor->addressModeW));
-
- if (descriptor->nextInChain != nullptr) {
- NXT_RETURN_ERROR("nextInChain must be nullptr");
- }
return {};
}
diff --git a/src/backend/d3d12/DeviceD3D12.cpp b/src/backend/d3d12/DeviceD3D12.cpp
index 8346213..7575c39 100644
--- a/src/backend/d3d12/DeviceD3D12.cpp
+++ b/src/backend/d3d12/DeviceD3D12.cpp
@@ -285,8 +285,9 @@
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
return new InputState(this, builder);
}
- PipelineLayoutBase* Device::CreatePipelineLayout(PipelineLayoutBuilder* builder) {
- return new PipelineLayout(this, builder);
+ ResultOrError<PipelineLayoutBase*> Device::CreatePipelineLayoutImpl(
+ const nxt::PipelineLayoutDescriptor* descriptor) {
+ return new PipelineLayout(this, descriptor);
}
ResultOrError<QueueBase*> Device::CreateQueueImpl() {
return new Queue(this);
diff --git a/src/backend/d3d12/DeviceD3D12.h b/src/backend/d3d12/DeviceD3D12.h
index 6a22536..126f463 100644
--- a/src/backend/d3d12/DeviceD3D12.h
+++ b/src/backend/d3d12/DeviceD3D12.h
@@ -47,7 +47,6 @@
ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override;
DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
InputStateBase* CreateInputState(InputStateBuilder* builder) override;
- PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override;
RenderPassDescriptorBase* CreateRenderPassDescriptor(
RenderPassDescriptorBuilder* builder) override;
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
@@ -79,6 +78,8 @@
void ExecuteCommandLists(std::initializer_list<ID3D12CommandList*> commandLists);
private:
+ ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl(
+ const nxt::PipelineLayoutDescriptor* descriptor) override;
ResultOrError<QueueBase*> CreateQueueImpl() override;
ResultOrError<SamplerBase*> CreateSamplerImpl(
const nxt::SamplerDescriptor* descriptor) override;
diff --git a/src/backend/d3d12/PipelineLayoutD3D12.cpp b/src/backend/d3d12/PipelineLayoutD3D12.cpp
index c4e1d65..2b6674f 100644
--- a/src/backend/d3d12/PipelineLayoutD3D12.cpp
+++ b/src/backend/d3d12/PipelineLayoutD3D12.cpp
@@ -22,8 +22,8 @@
namespace backend { namespace d3d12 {
- PipelineLayout::PipelineLayout(Device* device, PipelineLayoutBuilder* builder)
- : PipelineLayoutBase(builder), mDevice(device) {
+ PipelineLayout::PipelineLayout(Device* device, const nxt::PipelineLayoutDescriptor* descriptor)
+ : PipelineLayoutBase(device, descriptor) {
D3D12_ROOT_PARAMETER rootParameters[kMaxBindGroups * 2];
// A root parameter is one of these types
diff --git a/src/backend/d3d12/PipelineLayoutD3D12.h b/src/backend/d3d12/PipelineLayoutD3D12.h
index a7af1f7..141456d 100644
--- a/src/backend/d3d12/PipelineLayoutD3D12.h
+++ b/src/backend/d3d12/PipelineLayoutD3D12.h
@@ -25,7 +25,7 @@
class PipelineLayout : public PipelineLayoutBase {
public:
- PipelineLayout(Device* device, PipelineLayoutBuilder* builder);
+ PipelineLayout(Device* device, const nxt::PipelineLayoutDescriptor* descriptor);
uint32_t GetCbvUavSrvRootParameterIndex(uint32_t group) const;
uint32_t GetSamplerRootParameterIndex(uint32_t group) const;
@@ -33,8 +33,6 @@
ComPtr<ID3D12RootSignature> GetRootSignature();
private:
- Device* mDevice;
-
std::array<uint32_t, kMaxBindGroups> mCbvUavSrvRootParameterInfo;
std::array<uint32_t, kMaxBindGroups> mSamplerRootParameterInfo;
diff --git a/src/backend/metal/DeviceMTL.h b/src/backend/metal/DeviceMTL.h
index d4e83a9..456b2ca 100644
--- a/src/backend/metal/DeviceMTL.h
+++ b/src/backend/metal/DeviceMTL.h
@@ -44,7 +44,6 @@
ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override;
DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
InputStateBase* CreateInputState(InputStateBuilder* builder) override;
- PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override;
RenderPassDescriptorBase* CreateRenderPassDescriptor(
RenderPassDescriptorBuilder* builder) override;
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
@@ -65,6 +64,8 @@
ResourceUploader* GetResourceUploader() const;
private:
+ ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl(
+ const nxt::PipelineLayoutDescriptor* descriptor) override;
ResultOrError<QueueBase*> CreateQueueImpl() override;
ResultOrError<SamplerBase*> CreateSamplerImpl(
const nxt::SamplerDescriptor* descriptor) override;
diff --git a/src/backend/metal/DeviceMTL.mm b/src/backend/metal/DeviceMTL.mm
index 4d61245..368615c 100644
--- a/src/backend/metal/DeviceMTL.mm
+++ b/src/backend/metal/DeviceMTL.mm
@@ -108,8 +108,9 @@
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
return new InputState(builder);
}
- PipelineLayoutBase* Device::CreatePipelineLayout(PipelineLayoutBuilder* builder) {
- return new PipelineLayout(builder);
+ ResultOrError<PipelineLayoutBase*> Device::CreatePipelineLayoutImpl(
+ const nxt::PipelineLayoutDescriptor* descriptor) {
+ return new PipelineLayout(this, descriptor);
}
RenderPassDescriptorBase* Device::CreateRenderPassDescriptor(
RenderPassDescriptorBuilder* builder) {
diff --git a/src/backend/metal/PipelineLayoutMTL.h b/src/backend/metal/PipelineLayoutMTL.h
index 16f42f9..ebea453 100644
--- a/src/backend/metal/PipelineLayoutMTL.h
+++ b/src/backend/metal/PipelineLayoutMTL.h
@@ -27,9 +27,11 @@
namespace backend { namespace metal {
+ class Device;
+
class PipelineLayout : public PipelineLayoutBase {
public:
- PipelineLayout(PipelineLayoutBuilder* builder);
+ PipelineLayout(Device* device, const nxt::PipelineLayoutDescriptor* descriptor);
using BindingIndexInfo =
std::array<std::array<uint32_t, kMaxBindingsPerGroup>, kMaxBindGroups>;
diff --git a/src/backend/metal/PipelineLayoutMTL.mm b/src/backend/metal/PipelineLayoutMTL.mm
index f0bedbc..0a85d4f 100644
--- a/src/backend/metal/PipelineLayoutMTL.mm
+++ b/src/backend/metal/PipelineLayoutMTL.mm
@@ -15,10 +15,12 @@
#include "backend/metal/PipelineLayoutMTL.h"
#include "backend/BindGroupLayout.h"
+#include "backend/metal/DeviceMTL.h"
namespace backend { namespace metal {
- PipelineLayout::PipelineLayout(PipelineLayoutBuilder* builder) : PipelineLayoutBase(builder) {
+ PipelineLayout::PipelineLayout(Device* device, const nxt::PipelineLayoutDescriptor* descriptor)
+ : PipelineLayoutBase(device, descriptor) {
// Each stage has its own numbering namespace in CompilerMSL.
for (auto stage : IterateStages(kAllStages)) {
// Buffer number 0 is reserved for push constants
diff --git a/src/backend/null/NullBackend.cpp b/src/backend/null/NullBackend.cpp
index 26da79a..b879da4 100644
--- a/src/backend/null/NullBackend.cpp
+++ b/src/backend/null/NullBackend.cpp
@@ -63,8 +63,9 @@
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
return new InputState(builder);
}
- PipelineLayoutBase* Device::CreatePipelineLayout(PipelineLayoutBuilder* builder) {
- return new PipelineLayout(builder);
+ ResultOrError<PipelineLayoutBase*> Device::CreatePipelineLayoutImpl(
+ const nxt::PipelineLayoutDescriptor* descriptor) {
+ return new PipelineLayout(this, descriptor);
}
ResultOrError<QueueBase*> Device::CreateQueueImpl() {
return new Queue(this);
diff --git a/src/backend/null/NullBackend.h b/src/backend/null/NullBackend.h
index 9af570b..6f2330f 100644
--- a/src/backend/null/NullBackend.h
+++ b/src/backend/null/NullBackend.h
@@ -104,7 +104,6 @@
ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override;
DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
InputStateBase* CreateInputState(InputStateBuilder* builder) override;
- PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override;
RenderPassDescriptorBase* CreateRenderPassDescriptor(
RenderPassDescriptorBuilder* builder) override;
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
@@ -119,6 +118,8 @@
std::vector<std::unique_ptr<PendingOperation>> AcquirePendingOperations();
private:
+ ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl(
+ const nxt::PipelineLayoutDescriptor* descriptor) override;
ResultOrError<QueueBase*> CreateQueueImpl() override;
ResultOrError<SamplerBase*> CreateSamplerImpl(
const nxt::SamplerDescriptor* descriptor) override;
diff --git a/src/backend/opengl/DeviceGL.cpp b/src/backend/opengl/DeviceGL.cpp
index 1eb66dd..008f8ec 100644
--- a/src/backend/opengl/DeviceGL.cpp
+++ b/src/backend/opengl/DeviceGL.cpp
@@ -77,8 +77,9 @@
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
return new InputState(builder);
}
- PipelineLayoutBase* Device::CreatePipelineLayout(PipelineLayoutBuilder* builder) {
- return new PipelineLayout(builder);
+ ResultOrError<PipelineLayoutBase*> Device::CreatePipelineLayoutImpl(
+ const nxt::PipelineLayoutDescriptor* descriptor) {
+ return new PipelineLayout(this, descriptor);
}
ResultOrError<QueueBase*> Device::CreateQueueImpl() {
return new Queue(this);
diff --git a/src/backend/opengl/DeviceGL.h b/src/backend/opengl/DeviceGL.h
index fed98b8..9789267 100644
--- a/src/backend/opengl/DeviceGL.h
+++ b/src/backend/opengl/DeviceGL.h
@@ -35,7 +35,6 @@
ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override;
DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
InputStateBase* CreateInputState(InputStateBuilder* builder) override;
- PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override;
RenderPassDescriptorBase* CreateRenderPassDescriptor(
RenderPassDescriptorBuilder* builder) override;
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
@@ -47,6 +46,8 @@
void TickImpl() override;
private:
+ ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl(
+ const nxt::PipelineLayoutDescriptor* descriptor) override;
ResultOrError<QueueBase*> CreateQueueImpl() override;
ResultOrError<SamplerBase*> CreateSamplerImpl(
const nxt::SamplerDescriptor* descriptor) override;
diff --git a/src/backend/opengl/PipelineLayoutGL.cpp b/src/backend/opengl/PipelineLayoutGL.cpp
index 444246d..44a08d8 100644
--- a/src/backend/opengl/PipelineLayoutGL.cpp
+++ b/src/backend/opengl/PipelineLayoutGL.cpp
@@ -15,10 +15,12 @@
#include "backend/opengl/PipelineLayoutGL.h"
#include "backend/BindGroupLayout.h"
+#include "backend/opengl/DeviceGL.h"
namespace backend { namespace opengl {
- PipelineLayout::PipelineLayout(PipelineLayoutBuilder* builder) : PipelineLayoutBase(builder) {
+ PipelineLayout::PipelineLayout(Device* device, const nxt::PipelineLayoutDescriptor* descriptor)
+ : PipelineLayoutBase(device, descriptor) {
GLuint uboIndex = 0;
GLuint samplerIndex = 0;
GLuint sampledTextureIndex = 0;
diff --git a/src/backend/opengl/PipelineLayoutGL.h b/src/backend/opengl/PipelineLayoutGL.h
index 3c60787..c084590 100644
--- a/src/backend/opengl/PipelineLayoutGL.h
+++ b/src/backend/opengl/PipelineLayoutGL.h
@@ -25,7 +25,7 @@
class PipelineLayout : public PipelineLayoutBase {
public:
- PipelineLayout(PipelineLayoutBuilder* builder);
+ PipelineLayout(Device* device, const nxt::PipelineLayoutDescriptor* descriptor);
using BindingIndexInfo =
std::array<std::array<GLuint, kMaxBindingsPerGroup>, kMaxBindGroups>;
diff --git a/src/backend/opengl/TextureGL.h b/src/backend/opengl/TextureGL.h
index a6583e8..50756f4 100644
--- a/src/backend/opengl/TextureGL.h
+++ b/src/backend/opengl/TextureGL.h
@@ -21,8 +21,6 @@
namespace backend { namespace opengl {
- class Device;
-
struct TextureFormatInfo {
GLenum internalFormat;
GLenum format;
diff --git a/src/backend/vulkan/DeviceVk.cpp b/src/backend/vulkan/DeviceVk.cpp
index 632c29b..b31bf1b 100644
--- a/src/backend/vulkan/DeviceVk.cpp
+++ b/src/backend/vulkan/DeviceVk.cpp
@@ -241,8 +241,9 @@
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
return new InputState(builder);
}
- PipelineLayoutBase* Device::CreatePipelineLayout(PipelineLayoutBuilder* builder) {
- return new PipelineLayout(builder);
+ ResultOrError<PipelineLayoutBase*> Device::CreatePipelineLayoutImpl(
+ const nxt::PipelineLayoutDescriptor* descriptor) {
+ return new PipelineLayout(this, descriptor);
}
ResultOrError<QueueBase*> Device::CreateQueueImpl() {
return new Queue(this);
diff --git a/src/backend/vulkan/DeviceVk.h b/src/backend/vulkan/DeviceVk.h
index 14cbcf3..4b79cff 100644
--- a/src/backend/vulkan/DeviceVk.h
+++ b/src/backend/vulkan/DeviceVk.h
@@ -72,7 +72,6 @@
ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override;
DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
InputStateBase* CreateInputState(InputStateBuilder* builder) override;
- PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override;
RenderPassDescriptorBase* CreateRenderPassDescriptor(
RenderPassDescriptorBuilder* builder) override;
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
@@ -84,6 +83,8 @@
void TickImpl() override;
private:
+ ResultOrError<PipelineLayoutBase*> CreatePipelineLayoutImpl(
+ const nxt::PipelineLayoutDescriptor* descriptor) override;
ResultOrError<QueueBase*> CreateQueueImpl() override;
ResultOrError<SamplerBase*> CreateSamplerImpl(
const nxt::SamplerDescriptor* descriptor) override;
diff --git a/src/backend/vulkan/PipelineLayoutVk.cpp b/src/backend/vulkan/PipelineLayoutVk.cpp
index 21fb38f..8ef1091 100644
--- a/src/backend/vulkan/PipelineLayoutVk.cpp
+++ b/src/backend/vulkan/PipelineLayoutVk.cpp
@@ -22,8 +22,8 @@
namespace backend { namespace vulkan {
- PipelineLayout::PipelineLayout(PipelineLayoutBuilder* builder)
- : PipelineLayoutBase(builder), mDevice(ToBackend(builder->GetDevice())) {
+ PipelineLayout::PipelineLayout(Device* device, const nxt::PipelineLayoutDescriptor* descriptor)
+ : PipelineLayoutBase(device, descriptor), mDevice(device) {
// Compute the array of VkDescriptorSetLayouts that will be chained in the create info.
// TODO(cwallez@chromium.org) Vulkan doesn't allow holes in this array, should we expose
// this constraints at the NXT level?
diff --git a/src/backend/vulkan/PipelineLayoutVk.h b/src/backend/vulkan/PipelineLayoutVk.h
index e26d314..a6ab0c4 100644
--- a/src/backend/vulkan/PipelineLayoutVk.h
+++ b/src/backend/vulkan/PipelineLayoutVk.h
@@ -25,7 +25,7 @@
class PipelineLayout : public PipelineLayoutBase {
public:
- PipelineLayout(PipelineLayoutBuilder* builder);
+ PipelineLayout(Device* device, const nxt::PipelineLayoutDescriptor* descriptor);
~PipelineLayout();
VkPipelineLayout GetHandle() const;
diff --git a/src/tests/end2end/BlendStateTests.cpp b/src/tests/end2end/BlendStateTests.cpp
index 1a7be71..c2b26b4 100644
--- a/src/tests/end2end/BlendStateTests.cpp
+++ b/src/tests/end2end/BlendStateTests.cpp
@@ -41,9 +41,7 @@
.SetBindingsType(nxt::ShaderStageBit::Fragment, nxt::BindingType::UniformBuffer, 0, 1)
.GetResult();
- pipelineLayout = device.CreatePipelineLayoutBuilder()
- .SetBindGroupLayout(0, bindGroupLayout)
- .GetResult();
+ pipelineLayout = utils::MakeBasicPipelineLayout(device, &bindGroupLayout);
renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
}
diff --git a/src/tests/end2end/DepthStencilStateTests.cpp b/src/tests/end2end/DepthStencilStateTests.cpp
index f236aed..bb3a300 100644
--- a/src/tests/end2end/DepthStencilStateTests.cpp
+++ b/src/tests/end2end/DepthStencilStateTests.cpp
@@ -82,9 +82,7 @@
.SetBindingsType(nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment, nxt::BindingType::UniformBuffer, 0, 1)
.GetResult();
- pipelineLayout = device.CreatePipelineLayoutBuilder()
- .SetBindGroupLayout(0, bindGroupLayout)
- .GetResult();
+ pipelineLayout = utils::MakeBasicPipelineLayout(device, &bindGroupLayout);
}
struct TestSpec {
diff --git a/src/tests/end2end/PushConstantTests.cpp b/src/tests/end2end/PushConstantTests.cpp
index 1ecd417..6a3d072 100644
--- a/src/tests/end2end/PushConstantTests.cpp
+++ b/src/tests/end2end/PushConstantTests.cpp
@@ -49,9 +49,7 @@
.SetBindingsType(kAllStages, nxt::BindingType::StorageBuffer, 0, extraBuffer ? 2 : 1)
.GetResult();
- nxt::PipelineLayout pl = device.CreatePipelineLayoutBuilder()
- .SetBindGroupLayout(0, bgl)
- .GetResult();
+ nxt::PipelineLayout pl = utils::MakeBasicPipelineLayout(device, &bgl);
nxt::BufferView views[2] = {
buf1.CreateBufferViewBuilder().SetExtent(0, 4).GetResult(),
@@ -155,7 +153,7 @@
}
nxt::PipelineLayout MakeEmptyLayout() {
- return device.CreatePipelineLayoutBuilder().GetResult();
+ return utils::MakeBasicPipelineLayout(device, nullptr);
}
// The render pipeline adds one to the red channel for successful vertex push constant test
diff --git a/src/tests/end2end/RenderPassLoadOpTests.cpp b/src/tests/end2end/RenderPassLoadOpTests.cpp
index 59c9ae5..9d2983e 100644
--- a/src/tests/end2end/RenderPassLoadOpTests.cpp
+++ b/src/tests/end2end/RenderPassLoadOpTests.cpp
@@ -28,8 +28,7 @@
vsModule = utils::CreateShaderModule(*device, nxt::ShaderStage::Vertex, vsSource);
fsModule = utils::CreateShaderModule(*device, nxt::ShaderStage::Fragment, fsSource);
- pipelineLayout = device->CreatePipelineLayoutBuilder()
- .GetResult();
+ pipelineLayout = utils::MakeBasicPipelineLayout(*device, nullptr);
}
void Draw(nxt::CommandBufferBuilder* builder) {
diff --git a/src/tests/end2end/SamplerTests.cpp b/src/tests/end2end/SamplerTests.cpp
index a35dd05..366a653 100644
--- a/src/tests/end2end/SamplerTests.cpp
+++ b/src/tests/end2end/SamplerTests.cpp
@@ -48,9 +48,7 @@
.SetBindingsType(nxt::ShaderStageBit::Fragment, nxt::BindingType::SampledTexture, 1, 1)
.GetResult();
- auto pipelineLayout = device.CreatePipelineLayoutBuilder()
- .SetBindGroupLayout(0, mBindGroupLayout)
- .GetResult();
+ auto pipelineLayout = utils::MakeBasicPipelineLayout(device, &mBindGroupLayout);
auto vsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Vertex, R"(
#version 450
diff --git a/src/tests/unittests/WireTests.cpp b/src/tests/unittests/WireTests.cpp
index 8c0381a..5676330 100644
--- a/src/tests/unittests/WireTests.cpp
+++ b/src/tests/unittests/WireTests.cpp
@@ -408,6 +408,34 @@
FlushClient();
}
+// Test that the wire is able to send structures that contain objects
+TEST_F(WireTests, StructureOfObjectArrayArgument) {
+ nxtBindGroupLayoutBuilder bglBuilder = nxtDeviceCreateBindGroupLayoutBuilder(device);
+ nxtBindGroupLayout bgl = nxtBindGroupLayoutBuilderGetResult(bglBuilder);
+
+ nxtBindGroupLayoutBuilder apiBglBuilder = api.GetNewBindGroupLayoutBuilder();
+ EXPECT_CALL(api, DeviceCreateBindGroupLayoutBuilder(apiDevice))
+ .WillOnce(Return(apiBglBuilder));
+ nxtBindGroupLayout apiBgl = api.GetNewBindGroupLayout();
+ EXPECT_CALL(api, BindGroupLayoutBuilderGetResult(apiBglBuilder))
+ .WillOnce(Return(apiBgl));
+
+ nxtPipelineLayoutDescriptor descriptor;
+ descriptor.nextInChain = nullptr;
+ descriptor.numBindGroupLayouts = 1;
+ descriptor.bindGroupLayouts = &bgl;
+
+ nxtDeviceCreatePipelineLayout(device, &descriptor);
+ EXPECT_CALL(api, DeviceCreatePipelineLayout(apiDevice, MatchesLambda([apiBgl](const nxtPipelineLayoutDescriptor* desc) -> bool {
+ return desc->nextInChain == nullptr &&
+ desc->numBindGroupLayouts == 1 &&
+ desc->bindGroupLayouts[0] == apiBgl;
+ })))
+ .WillOnce(Return(nullptr));
+
+ 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) {
diff --git a/src/tests/unittests/validation/RenderPipelineValidationTests.cpp b/src/tests/unittests/validation/RenderPipelineValidationTests.cpp
index 5c14e09..8a4ec41 100644
--- a/src/tests/unittests/validation/RenderPipelineValidationTests.cpp
+++ b/src/tests/unittests/validation/RenderPipelineValidationTests.cpp
@@ -24,7 +24,7 @@
renderpass = CreateSimpleRenderPass();
- pipelineLayout = device.CreatePipelineLayoutBuilder().GetResult();
+ nxt::PipelineLayout pl = utils::MakeBasicPipelineLayout(device, nullptr);
inputState = device.CreateInputStateBuilder().GetResult();
diff --git a/src/utils/NXTHelpers.cpp b/src/utils/NXTHelpers.cpp
index e2de02b..6581b9b 100644
--- a/src/utils/NXTHelpers.cpp
+++ b/src/utils/NXTHelpers.cpp
@@ -149,5 +149,17 @@
return desc;
}
+ nxt::PipelineLayout MakeBasicPipelineLayout(const nxt::Device& device,
+ const nxt::BindGroupLayout* bindGroupLayout) {
+ nxt::PipelineLayoutDescriptor descriptor;
+ if (bindGroupLayout) {
+ descriptor.numBindGroupLayouts = 1;
+ descriptor.bindGroupLayouts = bindGroupLayout;
+ } else {
+ descriptor.numBindGroupLayouts = 0;
+ descriptor.bindGroupLayouts = nullptr;
+ }
+ return device.CreatePipelineLayout(&descriptor);
+ }
} // namespace utils
diff --git a/src/utils/NXTHelpers.h b/src/utils/NXTHelpers.h
index 67959c0..c86cc83 100644
--- a/src/utils/NXTHelpers.h
+++ b/src/utils/NXTHelpers.h
@@ -49,5 +49,7 @@
uint32_t height);
nxt::SamplerDescriptor GetDefaultSamplerDescriptor();
+ nxt::PipelineLayout MakeBasicPipelineLayout(const nxt::Device& device,
+ const nxt::BindGroupLayout* bindGroupLayout);
} // namespace utils