Implement the builder error callback in the backends
This makes the Builder base class retain the error status, if any, and call the callback on GetResult (or ~Builder, whichever comes first).
This commit is contained in:
parent
5dc7915d38
commit
7f96177289
|
@ -309,15 +309,24 @@ def as_backendType(typ):
|
|||
else:
|
||||
return as_cType(typ.name)
|
||||
|
||||
def cpp_native_methods(types, typ):
|
||||
methods = typ.methods + typ.native_methods
|
||||
|
||||
if typ.is_builder:
|
||||
methods.append(Method(Name('set error callback'), types['void'], [
|
||||
MethodArgument(Name('callback'), types['builder error callback'], 'value'),
|
||||
MethodArgument(Name('userdata1'), types['callback userdata'], 'value'),
|
||||
MethodArgument(Name('userdata2'), types['callback userdata'], 'value'),
|
||||
]))
|
||||
|
||||
return methods
|
||||
|
||||
def c_native_methods(types, typ):
|
||||
return cpp_native_methods(typ) + [
|
||||
return cpp_native_methods(types, typ) + [
|
||||
Method(Name('reference'), types['void'], []),
|
||||
Method(Name('release'), types['void'], []),
|
||||
]
|
||||
|
||||
def cpp_native_methods(typ):
|
||||
return typ.methods + typ.native_methods
|
||||
|
||||
def debug(text):
|
||||
print(text)
|
||||
|
||||
|
@ -376,7 +385,7 @@ def main():
|
|||
renders.append(FileRender('api.c', 'nxt/nxt.c', [base_params, api_params, c_params]))
|
||||
|
||||
if 'nxtcpp' in targets:
|
||||
additional_params = {'native_methods': cpp_native_methods}
|
||||
additional_params = {'native_methods': lambda typ: cpp_native_methods(api_params['types'], typ)}
|
||||
renders.append(FileRender('apicpp.h', 'nxt/nxtcpp.h', [base_params, api_params, additional_params]))
|
||||
renders.append(FileRender('apicpp.cpp', 'nxt/nxtcpp.cpp', [base_params, api_params, additional_params]))
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ namespace {{namespace}} {
|
|||
{%- endfor -%}
|
||||
) {
|
||||
{% if type.is_builder and method.name.canonical_case() not in ("release", "reference") %}
|
||||
if (self->WasConsumed()) return false;
|
||||
if (!self->CanBeUsed()) return false;
|
||||
{% else %}
|
||||
(void) self;
|
||||
{% endif %}
|
||||
|
@ -121,6 +121,8 @@ namespace {{namespace}} {
|
|||
{%- endfor -%}
|
||||
);
|
||||
|
||||
//* Some function have very heavy checks in a seperate method, so that they
|
||||
//* can be skipped in the NonValidatingEntryPoints.
|
||||
{% if suffix in methodsWithExtraValidation %}
|
||||
if (valid) {
|
||||
valid = self->Validate{{method.name.CamelCase()}}(
|
||||
|
@ -130,12 +132,27 @@ namespace {{namespace}} {
|
|||
);
|
||||
}
|
||||
{% endif %}
|
||||
//* TODO Do the hand-written checks if necessary
|
||||
//* On success, forward the arguments to the method, else error out without calling it
|
||||
|
||||
//* If there is an error we forward it appropriately.
|
||||
if (!valid) {
|
||||
// TODO get the device and give it the error?
|
||||
std::cout << "Error in {{suffix}}" << std::endl;
|
||||
//* An error in a builder methods is always handled by the builder
|
||||
{% if type.is_builder %}
|
||||
//* HACK(cwallez@chromium.org): special casing GetResult so that the error callback
|
||||
//* is called if needed. Without this, no call to HandleResult would happen, and the
|
||||
//* error callback would always get called with an Unknown status
|
||||
{% if method.name.canonical_case() == "get result" %}
|
||||
{{as_backendType(method.return_type)}} fakeResult = nullptr;
|
||||
bool shouldBeFalse = self->HandleResult(fakeResult);
|
||||
assert(shouldBeFalse == false);
|
||||
{% else %}
|
||||
self->HandleError("Error in {{suffix}}");
|
||||
{% endif %}
|
||||
{% else %}
|
||||
// TODO get the device or builder and give it the error?
|
||||
std::cout << "Error in {{suffix}}" << std::endl;
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
{% if method.return_type.name.canonical_case() == "void" %}
|
||||
if (!valid) return;
|
||||
{% else %}
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
// Custom types depending on the target language
|
||||
typedef uint64_t nxtCallbackUserdata;
|
||||
typedef void (*nxtDeviceErrorCallback)(const char* message, nxtCallbackUserdata userdata);
|
||||
typedef void (*nxtBuilderErrorCallback)(nxtBuilderErrorStatus status, const char* message, nxtCallbackUserdata userdata1, nxtCallbackUserdata userdata2);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
|
@ -172,6 +172,14 @@ namespace wire {
|
|||
}
|
||||
{% endfor %}
|
||||
|
||||
{% if type.is_builder %}
|
||||
void Client{{as_MethodSuffix(type.name, Name("set error callback"))}}(nxtBuilderErrorCallback callback,
|
||||
nxtCallbackUserdata userdata1,
|
||||
nxtCallbackUserdata userdata2) {
|
||||
//TODO(cwallez@chromium.org): will be implemented in a follow-up commit.
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if not type.name.canonical_case() == "device" %}
|
||||
//* When an object's refcount reaches 0, notify the server side of it and delete it.
|
||||
void Client{{as_MethodSuffix(type.name, Name("release"))}}({{Type}}* obj) {
|
||||
|
|
12
next.json
12
next.json
|
@ -102,6 +102,18 @@
|
|||
{"value": 3, "name": "storage buffer"}
|
||||
]
|
||||
},
|
||||
"builder error status": {
|
||||
"category": "enum",
|
||||
"values": [
|
||||
{"value": 0, "name": "success"},
|
||||
{"value": 1, "name": "error", "TODO": "cwallez@chromium.org: recoverable errors like GPU OOM"},
|
||||
{"value": 2, "name": "unknown"},
|
||||
{"value": 3, "name": "context lost"}
|
||||
]
|
||||
},
|
||||
"builder error callback": {
|
||||
"category": "natively defined"
|
||||
},
|
||||
"buffer": {
|
||||
"category": "object",
|
||||
"methods": [
|
||||
|
|
|
@ -64,11 +64,10 @@ namespace backend {
|
|||
BINDGROUP_PROPERTY_LAYOUT = 0x2,
|
||||
};
|
||||
|
||||
BindGroupBuilder::BindGroupBuilder(DeviceBase* device)
|
||||
: Builder(device) {
|
||||
BindGroupBuilder::BindGroupBuilder(DeviceBase* device) : Builder(device) {
|
||||
}
|
||||
|
||||
BindGroupBase* BindGroupBuilder::GetResult() {
|
||||
BindGroupBase* BindGroupBuilder::GetResultImpl() {
|
||||
constexpr int allProperties = BINDGROUP_PROPERTY_USAGE | BINDGROUP_PROPERTY_LAYOUT;
|
||||
if ((propertiesSet & allProperties) != allProperties) {
|
||||
HandleError("Bindgroup missing properties");
|
||||
|
@ -80,7 +79,6 @@ namespace backend {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
MarkConsumed();
|
||||
return device->CreateBindGroup(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -43,12 +43,11 @@ namespace backend {
|
|||
std::array<Ref<RefCounted>, kMaxBindingsPerGroup> bindings;
|
||||
};
|
||||
|
||||
class BindGroupBuilder : public Builder {
|
||||
class BindGroupBuilder : public Builder<BindGroupBase> {
|
||||
public:
|
||||
BindGroupBuilder(DeviceBase* device);
|
||||
|
||||
// NXT API
|
||||
BindGroupBase* GetResult();
|
||||
void SetLayout(BindGroupLayoutBase* layout);
|
||||
void SetUsage(nxt::BindGroupUsage usage);
|
||||
|
||||
|
@ -76,6 +75,7 @@ namespace backend {
|
|||
private:
|
||||
friend class BindGroupBase;
|
||||
|
||||
BindGroupBase* GetResultImpl() override;
|
||||
void SetBindingsBase(uint32_t start, uint32_t count, RefCounted* const * objects);
|
||||
bool SetBindingsValidationBase(uint32_t start, uint32_t count);
|
||||
|
||||
|
|
|
@ -101,8 +101,7 @@ namespace backend {
|
|||
return bindingInfo;
|
||||
}
|
||||
|
||||
BindGroupLayoutBase* BindGroupLayoutBuilder::GetResult() {
|
||||
MarkConsumed();
|
||||
BindGroupLayoutBase* BindGroupLayoutBuilder::GetResultImpl() {
|
||||
BindGroupLayoutBase blueprint(this, true);
|
||||
|
||||
auto* result = device->GetOrCreateBindGroupLayout(&blueprint, this);
|
||||
|
|
|
@ -44,19 +44,20 @@ namespace backend {
|
|||
bool blueprint = false;
|
||||
};
|
||||
|
||||
class BindGroupLayoutBuilder : public Builder {
|
||||
class BindGroupLayoutBuilder : public Builder<BindGroupLayoutBase> {
|
||||
public:
|
||||
BindGroupLayoutBuilder(DeviceBase* device);
|
||||
|
||||
const BindGroupLayoutBase::LayoutBindingInfo& GetBindingInfo() const;
|
||||
|
||||
// NXT API
|
||||
BindGroupLayoutBase* GetResult();
|
||||
void SetBindingsType(nxt::ShaderStageBit visibility, nxt::BindingType bindingType, uint32_t start, uint32_t count);
|
||||
|
||||
private:
|
||||
friend class BindGroupLayoutBase;
|
||||
|
||||
BindGroupLayoutBase* GetResultImpl() override;
|
||||
|
||||
BindGroupLayoutBase::LayoutBindingInfo bindingInfo;
|
||||
};
|
||||
|
||||
|
|
|
@ -121,7 +121,7 @@ namespace backend {
|
|||
BufferBuilder::BufferBuilder(DeviceBase* device) : Builder(device) {
|
||||
}
|
||||
|
||||
BufferBase* BufferBuilder::GetResult() {
|
||||
BufferBase* BufferBuilder::GetResultImpl() {
|
||||
constexpr int allProperties = BUFFER_PROPERTY_ALLOWED_USAGE | BUFFER_PROPERTY_SIZE;
|
||||
if ((propertiesSet & allProperties) != allProperties) {
|
||||
HandleError("Buffer missing properties");
|
||||
|
@ -133,7 +133,6 @@ namespace backend {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
MarkConsumed();
|
||||
return device->CreateBuffer(this);
|
||||
}
|
||||
|
||||
|
@ -195,14 +194,13 @@ namespace backend {
|
|||
: Builder(device), buffer(buffer) {
|
||||
}
|
||||
|
||||
BufferViewBase* BufferViewBuilder::GetResult() {
|
||||
BufferViewBase* BufferViewBuilder::GetResultImpl() {
|
||||
constexpr int allProperties = BUFFER_VIEW_PROPERTY_EXTENT;
|
||||
if ((propertiesSet & allProperties) != allProperties) {
|
||||
HandleError("Buffer view missing properties");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MarkConsumed();
|
||||
return device->CreateBufferView(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -52,12 +52,11 @@ namespace backend {
|
|||
bool frozen = false;
|
||||
};
|
||||
|
||||
class BufferBuilder : public Builder {
|
||||
class BufferBuilder : public Builder<BufferBase> {
|
||||
public:
|
||||
BufferBuilder(DeviceBase* device);
|
||||
|
||||
// NXT API
|
||||
BufferBase* GetResult();
|
||||
void SetAllowedUsage(nxt::BufferUsageBit usage);
|
||||
void SetInitialUsage(nxt::BufferUsageBit usage);
|
||||
void SetSize(uint32_t size);
|
||||
|
@ -65,6 +64,8 @@ namespace backend {
|
|||
private:
|
||||
friend class BufferBase;
|
||||
|
||||
BufferBase* GetResultImpl() override;
|
||||
|
||||
uint32_t size;
|
||||
nxt::BufferUsageBit allowedUsage = nxt::BufferUsageBit::None;
|
||||
nxt::BufferUsageBit currentUsage = nxt::BufferUsageBit::None;
|
||||
|
@ -85,17 +86,18 @@ namespace backend {
|
|||
uint32_t offset;
|
||||
};
|
||||
|
||||
class BufferViewBuilder : public Builder {
|
||||
class BufferViewBuilder : public Builder<BufferViewBase> {
|
||||
public:
|
||||
BufferViewBuilder(DeviceBase* device, BufferBase* buffer);
|
||||
|
||||
// NXT API
|
||||
BufferViewBase* GetResult();
|
||||
void SetExtent(uint32_t offset, uint32_t size);
|
||||
|
||||
private:
|
||||
friend class BufferViewBase;
|
||||
|
||||
BufferViewBase* GetResultImpl() override;
|
||||
|
||||
Ref<BufferBase> buffer;
|
||||
uint32_t offset = 0;
|
||||
uint32_t size = 0;
|
||||
|
|
|
@ -18,20 +18,69 @@
|
|||
|
||||
namespace backend {
|
||||
|
||||
bool Builder::WasConsumed() const {
|
||||
return consumed;
|
||||
bool BuilderBase::CanBeUsed() const {
|
||||
return !consumed && !gotStatus;
|
||||
}
|
||||
|
||||
Builder::Builder(DeviceBase* device) : device(device) {
|
||||
void BuilderBase::HandleError(const char* message) {
|
||||
SetStatus(nxt::BuilderErrorStatus::Error, message);
|
||||
}
|
||||
|
||||
void Builder::MarkConsumed() {
|
||||
void BuilderBase::SetErrorCallback(nxt::BuilderErrorCallback callback,
|
||||
nxt::CallbackUserdata userdata1,
|
||||
nxt::CallbackUserdata userdata2) {
|
||||
this->callback = callback;
|
||||
this->userdata1 = userdata1;
|
||||
this->userdata2 = userdata2;
|
||||
}
|
||||
|
||||
BuilderBase::BuilderBase(DeviceBase* device) : device(device) {
|
||||
}
|
||||
|
||||
BuilderBase::~BuilderBase() {
|
||||
if (!consumed && callback != nullptr) {
|
||||
callback(NXT_BUILDER_ERROR_STATUS_UNKNOWN, "Builder destroyed before GetResult", userdata1, userdata2);
|
||||
}
|
||||
}
|
||||
|
||||
void BuilderBase::SetStatus(nxt::BuilderErrorStatus status, const char* message) {
|
||||
ASSERT(status != nxt::BuilderErrorStatus::Success);
|
||||
ASSERT(status != nxt::BuilderErrorStatus::Unknown);
|
||||
ASSERT(!gotStatus); // This is not strictly necessary but something to strive for.
|
||||
gotStatus = true;
|
||||
|
||||
storedStatus = status;
|
||||
storedMessage = std::move(message);
|
||||
}
|
||||
|
||||
bool BuilderBase::HandleResult(RefCounted* result) {
|
||||
// GetResult can only be called once.
|
||||
ASSERT(!consumed);
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
void Builder::HandleError(const char* message) {
|
||||
device->HandleError(message);
|
||||
// result == nullptr implies there was an error which implies we should have a status set.
|
||||
ASSERT(result != nullptr || gotStatus);
|
||||
|
||||
// If we have any error, then we have to return nullptr
|
||||
if (gotStatus) {
|
||||
ASSERT(storedStatus != nxt::BuilderErrorStatus::Success);
|
||||
|
||||
// The application will never see "result" so we need to remove the
|
||||
// external ref here.
|
||||
if (result != nullptr) {
|
||||
result->Release();
|
||||
result = nullptr;
|
||||
}
|
||||
} else {
|
||||
ASSERT(storedStatus == nxt::BuilderErrorStatus::Success);
|
||||
ASSERT(storedMessage.empty());
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
callback(static_cast<nxtBuilderErrorStatus>(storedStatus), storedMessage.c_str(), userdata1, userdata2);
|
||||
}
|
||||
|
||||
return result != nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,24 +18,92 @@
|
|||
#include "Forward.h"
|
||||
#include "RefCounted.h"
|
||||
|
||||
#include "nxt/nxtcpp.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace backend {
|
||||
|
||||
class Builder : public RefCounted {
|
||||
// This class implements behavior shared by all builders:
|
||||
// - Tracking whether GetResult has been called already, needed by the
|
||||
// autogenerated code to prevent operations on "consumed" builders.
|
||||
// - The error status callback of the API. The callback is guaranteed to be
|
||||
// called exactly once with an error, a success, or "unknown" if the
|
||||
// builder is destroyed; also the builder callback cannot be called before
|
||||
// either the object is destroyed or GetResult is called.
|
||||
//
|
||||
// It is possible for error to be generated before the error callback is
|
||||
// registered when a builder "set" function performance validation inline.
|
||||
// Because of this we have to store the status in the builder and defer
|
||||
// calling the callback to GetResult.
|
||||
|
||||
class BuilderBase : public RefCounted {
|
||||
public:
|
||||
bool WasConsumed() const;
|
||||
// Used by the auto-generated validation to prevent usage of the builder
|
||||
// after GetResult or an error.
|
||||
bool CanBeUsed() const;
|
||||
|
||||
// Set the status of the builder to an error.
|
||||
void HandleError(const char* message);
|
||||
|
||||
protected:
|
||||
Builder(DeviceBase* device);
|
||||
// Internal API, to be used by builder and BackendProcTable only.
|
||||
// rReturns true for success cases, and calls the callback with appropriate status.
|
||||
bool HandleResult(RefCounted* result);
|
||||
|
||||
void MarkConsumed();
|
||||
// NXT API
|
||||
void SetErrorCallback(nxt::BuilderErrorCallback callback,
|
||||
nxt::CallbackUserdata userdata1,
|
||||
nxt::CallbackUserdata userdata2);
|
||||
|
||||
protected:
|
||||
BuilderBase(DeviceBase* device);
|
||||
~BuilderBase();
|
||||
|
||||
DeviceBase* const device;
|
||||
bool gotStatus = false;
|
||||
|
||||
private:
|
||||
void SetStatus(nxt::BuilderErrorStatus status, const char* message);
|
||||
|
||||
nxt::BuilderErrorCallback callback = nullptr;
|
||||
nxt::CallbackUserdata userdata1 = 0;
|
||||
nxt::CallbackUserdata userdata2 = 0;
|
||||
|
||||
nxt::BuilderErrorStatus storedStatus = nxt::BuilderErrorStatus::Success;
|
||||
std::string storedMessage;
|
||||
|
||||
bool consumed = false;
|
||||
};
|
||||
|
||||
// This builder base class is used to capture the calls to GetResult and make sure
|
||||
// that either:
|
||||
// - There was an error, callback is called with an error and nullptr is returned.
|
||||
// - There was no error, callback is called with success and a non-null T* is returned.
|
||||
template<typename T>
|
||||
class Builder : public BuilderBase {
|
||||
public:
|
||||
// NXT API
|
||||
T* GetResult();
|
||||
|
||||
protected:
|
||||
using BuilderBase::BuilderBase;
|
||||
|
||||
private:
|
||||
virtual T* GetResultImpl() = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
T* Builder<T>::GetResult() {
|
||||
T* result = GetResultImpl();
|
||||
// An object can have been returned but failed its initialization, so if an error
|
||||
// happened, return nullptr instead of result.
|
||||
if (HandleResult(result)) {
|
||||
return result;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // BACKEND_COMMON_BUILDER_H_
|
||||
|
|
|
@ -136,7 +136,7 @@ namespace backend {
|
|||
}
|
||||
|
||||
CommandBufferBuilder::~CommandBufferBuilder() {
|
||||
if (!WasConsumed()) {
|
||||
if (!commandsAcquired) {
|
||||
MoveToIterator();
|
||||
FreeCommands(&iterator);
|
||||
}
|
||||
|
@ -484,12 +484,13 @@ namespace backend {
|
|||
}
|
||||
|
||||
CommandIterator CommandBufferBuilder::AcquireCommands() {
|
||||
ASSERT(!commandsAcquired);
|
||||
commandsAcquired = true;
|
||||
return std::move(iterator);
|
||||
}
|
||||
|
||||
CommandBufferBase* CommandBufferBuilder::GetResult() {
|
||||
CommandBufferBase* CommandBufferBuilder::GetResultImpl() {
|
||||
MoveToIterator();
|
||||
MarkConsumed();
|
||||
return device->CreateCommandBuffer(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace backend {
|
|||
std::set<TextureBase*> texturesTransitioned;
|
||||
};
|
||||
|
||||
class CommandBufferBuilder : public Builder {
|
||||
class CommandBufferBuilder : public Builder<CommandBufferBase> {
|
||||
public:
|
||||
CommandBufferBuilder(DeviceBase* device);
|
||||
~CommandBufferBuilder();
|
||||
|
@ -55,8 +55,6 @@ namespace backend {
|
|||
CommandIterator AcquireCommands();
|
||||
|
||||
// NXT API
|
||||
CommandBufferBase* GetResult();
|
||||
|
||||
void CopyBufferToTexture(BufferBase* buffer, uint32_t bufferOffset,
|
||||
TextureBase* texture, uint32_t x, uint32_t y, uint32_t z,
|
||||
uint32_t width, uint32_t height, uint32_t depth, uint32_t level);
|
||||
|
@ -81,11 +79,13 @@ namespace backend {
|
|||
private:
|
||||
friend class CommandBufferBase;
|
||||
|
||||
CommandBufferBase* GetResultImpl() override;
|
||||
void MoveToIterator();
|
||||
|
||||
CommandAllocator allocator;
|
||||
CommandIterator iterator;
|
||||
bool movedToIterator = false;
|
||||
bool commandsAcquired = false;
|
||||
// These pointers will remain valid since they are referenced by
|
||||
// the bind groups which are referenced by this command buffer.
|
||||
std::set<BufferBase*> buffersTransitioned;
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace backend {
|
|||
~DeviceBase();
|
||||
|
||||
void HandleError(const char* message);
|
||||
void SetErrorCallback(nxt::DeviceErrorCallback, nxt::CallbackUserdata userdata);
|
||||
void SetErrorCallback(nxt::DeviceErrorCallback callback, nxt::CallbackUserdata userdata);
|
||||
|
||||
virtual BindGroupBase* CreateBindGroup(BindGroupBuilder* builder) = 0;
|
||||
virtual BindGroupLayoutBase* CreateBindGroupLayout(BindGroupLayoutBuilder* builder) = 0;
|
||||
|
@ -86,7 +86,7 @@ namespace backend {
|
|||
Caches* caches = nullptr;
|
||||
|
||||
nxt::DeviceErrorCallback errorCallback = nullptr;
|
||||
nxt::CallbackUserdata errorUserdata;
|
||||
nxt::CallbackUserdata errorUserdata = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ namespace backend {
|
|||
InputStateBuilder::InputStateBuilder(DeviceBase* device) : Builder(device) {
|
||||
}
|
||||
|
||||
InputStateBase* InputStateBuilder::GetResult() {
|
||||
InputStateBase* InputStateBuilder::GetResultImpl() {
|
||||
for (uint32_t location = 0; location < kMaxVertexAttributes; ++location) {
|
||||
if (attributesSetMask[location] &&
|
||||
!inputsSetMask[attributeInfos[location].bindingSlot]) {
|
||||
|
@ -90,7 +90,6 @@ namespace backend {
|
|||
}
|
||||
}
|
||||
|
||||
MarkConsumed();
|
||||
return device->CreateInputState(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -57,12 +57,11 @@ namespace backend {
|
|||
std::array<InputInfo, kMaxVertexInputs> inputInfos;
|
||||
};
|
||||
|
||||
class InputStateBuilder : public Builder {
|
||||
class InputStateBuilder : public Builder<InputStateBase> {
|
||||
public:
|
||||
InputStateBuilder(DeviceBase* device);
|
||||
|
||||
// NXT API
|
||||
InputStateBase* GetResult();
|
||||
void SetAttribute(uint32_t shaderLocation, uint32_t bindingSlot,
|
||||
nxt::VertexFormat format, uint32_t offset);
|
||||
void SetInput(uint32_t bindingSlot, uint32_t stride,
|
||||
|
@ -71,6 +70,8 @@ namespace backend {
|
|||
private:
|
||||
friend class InputStateBase;
|
||||
|
||||
InputStateBase* GetResultImpl() override;
|
||||
|
||||
std::bitset<kMaxVertexAttributes> attributesSetMask;
|
||||
std::array<InputStateBase::AttributeInfo, kMaxVertexAttributes> attributeInfos;
|
||||
std::bitset<kMaxVertexInputs> inputsSetMask;
|
||||
|
|
|
@ -98,7 +98,7 @@ namespace backend {
|
|||
return stages[stage];
|
||||
}
|
||||
|
||||
PipelineBase* PipelineBuilder::GetResult() {
|
||||
PipelineBase* PipelineBuilder::GetResultImpl() {
|
||||
// TODO(cwallez@chromium.org): the layout should be required, and put the default objects in the device
|
||||
if (!layout) {
|
||||
layout = device->CreatePipelineLayoutBuilder()->GetResult();
|
||||
|
@ -107,7 +107,6 @@ namespace backend {
|
|||
inputState = device->CreateInputStateBuilder()->GetResult();
|
||||
}
|
||||
|
||||
MarkConsumed();
|
||||
return device->CreatePipeline(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace backend {
|
|||
Ref<InputStateBase> inputState;
|
||||
};
|
||||
|
||||
class PipelineBuilder : public Builder {
|
||||
class PipelineBuilder : public Builder<PipelineBase> {
|
||||
public:
|
||||
PipelineBuilder(DeviceBase* device);
|
||||
|
||||
|
@ -70,7 +70,6 @@ namespace backend {
|
|||
const StageInfo& GetStageInfo(nxt::ShaderStage stage) const;
|
||||
|
||||
// NXT API
|
||||
PipelineBase* GetResult();
|
||||
void SetLayout(PipelineLayoutBase* layout);
|
||||
void SetStage(nxt::ShaderStage stage, ShaderModuleBase* module, const char* entryPoint);
|
||||
void SetInputState(InputStateBase* inputState);
|
||||
|
@ -78,6 +77,8 @@ namespace backend {
|
|||
private:
|
||||
friend class PipelineBase;
|
||||
|
||||
PipelineBase* GetResultImpl() override;
|
||||
|
||||
Ref<PipelineLayoutBase> layout;
|
||||
nxt::ShaderStageBit stageMask;
|
||||
PerStage<StageInfo> stages;
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace backend {
|
|||
PipelineLayoutBuilder::PipelineLayoutBuilder(DeviceBase* device) : Builder(device) {
|
||||
}
|
||||
|
||||
PipelineLayoutBase* PipelineLayoutBuilder::GetResult() {
|
||||
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) {
|
||||
|
@ -48,7 +48,6 @@ namespace backend {
|
|||
}
|
||||
}
|
||||
|
||||
MarkConsumed();
|
||||
return device->CreatePipelineLayout(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -40,17 +40,18 @@ namespace backend {
|
|||
std::bitset<kMaxBindGroups> mask;
|
||||
};
|
||||
|
||||
class PipelineLayoutBuilder : public Builder {
|
||||
class PipelineLayoutBuilder : public Builder<PipelineLayoutBase> {
|
||||
public:
|
||||
PipelineLayoutBuilder(DeviceBase* device);
|
||||
|
||||
// NXT API
|
||||
PipelineLayoutBase* GetResult();
|
||||
void SetBindGroupLayout(uint32_t groupIndex, BindGroupLayoutBase* layout);
|
||||
|
||||
private:
|
||||
friend class PipelineLayoutBase;
|
||||
|
||||
PipelineLayoutBase* GetResultImpl() override;
|
||||
|
||||
BindGroupLayoutArray bindGroupLayouts;
|
||||
std::bitset<kMaxBindGroups> mask;
|
||||
};
|
||||
|
|
|
@ -30,8 +30,7 @@ namespace backend {
|
|||
QueueBuilder::QueueBuilder(DeviceBase* device) : Builder(device) {
|
||||
}
|
||||
|
||||
QueueBase* QueueBuilder::GetResult() {
|
||||
MarkConsumed();
|
||||
QueueBase* QueueBuilder::GetResultImpl() {
|
||||
return device->CreateQueue(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -41,12 +41,12 @@ namespace backend {
|
|||
}
|
||||
};
|
||||
|
||||
class QueueBuilder : public Builder {
|
||||
class QueueBuilder : public Builder<QueueBase> {
|
||||
public:
|
||||
QueueBuilder(DeviceBase* device);
|
||||
|
||||
// NXT API
|
||||
QueueBase* GetResult();
|
||||
private:
|
||||
QueueBase* GetResultImpl() override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -43,11 +43,6 @@ namespace backend {
|
|||
return mipMapFilter;
|
||||
}
|
||||
|
||||
SamplerBase* SamplerBuilder::GetResult() {
|
||||
MarkConsumed();
|
||||
return device->CreateSampler(this);
|
||||
}
|
||||
|
||||
void SamplerBuilder::SetFilterMode(nxt::FilterMode magFilter, nxt::FilterMode minFilter, nxt::FilterMode mipMapFilter) {
|
||||
if ((propertiesSet & SAMPLER_PROPERTY_FILTER) != 0) {
|
||||
HandleError("Sampler filter property set multiple times");
|
||||
|
@ -59,4 +54,9 @@ namespace backend {
|
|||
this->mipMapFilter = mipMapFilter;
|
||||
propertiesSet |= SAMPLER_PROPERTY_FILTER;
|
||||
}
|
||||
|
||||
SamplerBase* SamplerBuilder::GetResultImpl() {
|
||||
return device->CreateSampler(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace backend {
|
|||
SamplerBase(SamplerBuilder* builder);
|
||||
};
|
||||
|
||||
class SamplerBuilder : public Builder {
|
||||
class SamplerBuilder : public Builder<SamplerBase> {
|
||||
public:
|
||||
SamplerBuilder(DeviceBase* device);
|
||||
|
||||
|
@ -37,12 +37,13 @@ namespace backend {
|
|||
nxt::FilterMode GetMipMapFilter() const;
|
||||
|
||||
// NXT API
|
||||
SamplerBase* GetResult();
|
||||
void SetFilterMode(nxt::FilterMode magFilter, nxt::FilterMode minFilter, nxt::FilterMode mipMapFilter);
|
||||
|
||||
private:
|
||||
friend class SamplerBase;
|
||||
|
||||
SamplerBase* GetResultImpl() override;
|
||||
|
||||
int propertiesSet = 0;
|
||||
|
||||
nxt::FilterMode magFilter = nxt::FilterMode::Nearest;
|
||||
|
|
|
@ -198,13 +198,12 @@ namespace backend {
|
|||
return std::move(spirv);
|
||||
}
|
||||
|
||||
ShaderModuleBase* ShaderModuleBuilder::GetResult() {
|
||||
ShaderModuleBase* ShaderModuleBuilder::GetResultImpl() {
|
||||
if (spirv.size() == 0) {
|
||||
HandleError("Shader module needs to have the source set");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MarkConsumed();
|
||||
return device->CreateShaderModule(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -71,19 +71,20 @@ namespace backend {
|
|||
nxt::ShaderStage executionModel;
|
||||
};
|
||||
|
||||
class ShaderModuleBuilder : public Builder {
|
||||
class ShaderModuleBuilder : public Builder<ShaderModuleBase> {
|
||||
public:
|
||||
ShaderModuleBuilder(DeviceBase* device);
|
||||
|
||||
std::vector<uint32_t> AcquireSpirv();
|
||||
|
||||
// NXT API
|
||||
ShaderModuleBase* GetResult();
|
||||
void SetSource(uint32_t codeSize, const uint32_t* code);
|
||||
|
||||
private:
|
||||
friend class ShaderModuleBase;
|
||||
|
||||
ShaderModuleBase* GetResultImpl() override;
|
||||
|
||||
std::vector<uint32_t> spirv;
|
||||
};
|
||||
|
||||
|
|
|
@ -121,7 +121,7 @@ namespace backend {
|
|||
: Builder(device) {
|
||||
}
|
||||
|
||||
TextureBase* TextureBuilder::GetResult() {
|
||||
TextureBase* TextureBuilder::GetResultImpl() {
|
||||
constexpr int allProperties = TEXTURE_PROPERTY_DIMENSION | TEXTURE_PROPERTY_EXTENT |
|
||||
TEXTURE_PROPERTY_FORMAT | TEXTURE_PROPERTY_MIP_LEVELS | TEXTURE_PROPERTY_ALLOWED_USAGE;
|
||||
if ((propertiesSet & allProperties) != allProperties) {
|
||||
|
@ -136,7 +136,6 @@ namespace backend {
|
|||
|
||||
// TODO(cwallez@chromium.org): check stuff based on the dimension
|
||||
|
||||
MarkConsumed();
|
||||
return device->CreateTexture(this);
|
||||
}
|
||||
|
||||
|
@ -223,8 +222,7 @@ namespace backend {
|
|||
: Builder(device), texture(texture) {
|
||||
}
|
||||
|
||||
TextureViewBase* TextureViewBuilder::GetResult() {
|
||||
MarkConsumed();
|
||||
TextureViewBase* TextureViewBuilder::GetResultImpl() {
|
||||
return device->CreateTextureView(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -60,12 +60,11 @@ namespace backend {
|
|||
bool frozen = false;
|
||||
};
|
||||
|
||||
class TextureBuilder : public Builder {
|
||||
class TextureBuilder : public Builder<TextureBase> {
|
||||
public:
|
||||
TextureBuilder(DeviceBase* device);
|
||||
|
||||
// NXT API
|
||||
TextureBase* GetResult();
|
||||
void SetDimension(nxt::TextureDimension dimension);
|
||||
void SetExtent(uint32_t width, uint32_t height, uint32_t depth);
|
||||
void SetFormat(nxt::TextureFormat format);
|
||||
|
@ -76,6 +75,8 @@ namespace backend {
|
|||
private:
|
||||
friend class TextureBase;
|
||||
|
||||
TextureBase* GetResultImpl() override;
|
||||
|
||||
int propertiesSet = 0;
|
||||
|
||||
nxt::TextureDimension dimension;
|
||||
|
@ -96,16 +97,15 @@ namespace backend {
|
|||
Ref<TextureBase> texture;
|
||||
};
|
||||
|
||||
class TextureViewBuilder : public Builder {
|
||||
class TextureViewBuilder : public Builder<TextureViewBase> {
|
||||
public:
|
||||
TextureViewBuilder(DeviceBase* device, TextureBase* texture);
|
||||
|
||||
// NXT API
|
||||
TextureViewBase* GetResult();
|
||||
|
||||
private:
|
||||
friend class TextureViewBase;
|
||||
|
||||
TextureViewBase* GetResultImpl() override;
|
||||
|
||||
Ref<TextureBase> texture;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue