Make autogenerated validation produce device or builder errors

This commit is contained in:
Corentin Wallez 2017-05-10 15:30:05 +02:00 committed by Corentin Wallez
parent f79df0c62d
commit 36cf2dd54b
13 changed files with 69 additions and 29 deletions

View File

@ -17,8 +17,6 @@
#include "{{namespace}}/GeneratedCodeIncludes.h" #include "{{namespace}}/GeneratedCodeIncludes.h"
#include <iostream>
namespace backend { namespace backend {
namespace {{namespace}} { namespace {{namespace}} {
@ -91,18 +89,30 @@ namespace {{namespace}} {
{%- endfor -%} {%- endfor -%}
) { ) {
{% if type.is_builder and method.name.canonical_case() not in ("release", "reference") %} {% if type.is_builder and method.name.canonical_case() not in ("release", "reference") %}
if (!self->CanBeUsed()) return false; if (!self->CanBeUsed()) {
self->GetDevice()->HandleError("Builder cannot be used after GetResult");
return false;
}
{% else %} {% else %}
(void) self; (void) self;
{% endif %} {% endif %}
bool error = false;
{% for arg in method.arguments %} {% for arg in method.arguments %}
{% if arg.type.category == "enum" %} {% if arg.type.category == "enum" %}
if (!CheckEnum{{as_cType(arg.type.name)}}({{as_varName(arg.name)}})) return false; if (!CheckEnum{{as_cType(arg.type.name)}}({{as_varName(arg.name)}})) error = true;;
{% elif arg.type.category == "bitmask" %} {% elif arg.type.category == "bitmask" %}
if (!CheckBitmask{{as_cType(arg.type.name)}}({{as_varName(arg.name)}})) return false; if (!CheckBitmask{{as_cType(arg.type.name)}}({{as_varName(arg.name)}})) error = true;
{% else %} {% else %}
(void) {{as_varName(arg.name)}}; (void) {{as_varName(arg.name)}};
{% endif %} {% endif %}
if (error) {
{% if type.is_builder %}
self->HandleError("Bad value in {{suffix}}");
{% else %}
self->GetDevice()->HandleError("Bad value in {{suffix}}");
{% endif %}
return false;
}
{% endfor %} {% endfor %}
return true; return true;
} }
@ -133,25 +143,16 @@ namespace {{namespace}} {
} }
{% endif %} {% endif %}
//* If there is an error we forward it appropriately. //* HACK(cwallez@chromium.org): special casing GetResult so that the error callback
if (!valid) { //* is called if needed. Without this, no call to HandleResult would happen, and the
//* An error in a builder methods is always handled by the builder //* error callback would always get called with an Unknown status
{% if type.is_builder %} {% if type.is_builder and method.name.canonical_case() == "get result" %}
//* HACK(cwallez@chromium.org): special casing GetResult so that the error callback if (!valid) {
//* is called if needed. Without this, no call to HandleResult would happen, and the {{as_backendType(method.return_type)}} fakeResult = nullptr;
//* error callback would always get called with an Unknown status bool shouldBeFalse = self->HandleResult(fakeResult);
{% if method.name.canonical_case() == "get result" %} assert(shouldBeFalse == false);
{{as_backendType(method.return_type)}} fakeResult = nullptr; }
bool shouldBeFalse = self->HandleResult(fakeResult); {% endif %}
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 method.return_type.name.canonical_case() == "void" %}
if (!valid) return; if (!valid) return;

View File

@ -34,6 +34,10 @@ namespace backend {
return new BufferViewBuilder(device, this); return new BufferViewBuilder(device, this);
} }
DeviceBase* BufferBase::GetDevice() {
return device;
}
uint32_t BufferBase::GetSize() const { uint32_t BufferBase::GetSize() const {
return size; return size;
} }

View File

@ -36,6 +36,8 @@ namespace backend {
bool HasFrozenUsage(nxt::BufferUsageBit usage) const; bool HasFrozenUsage(nxt::BufferUsageBit usage) const;
void TransitionUsageImpl(nxt::BufferUsageBit usage); void TransitionUsageImpl(nxt::BufferUsageBit usage);
DeviceBase* GetDevice();
// NXT API // NXT API
BufferViewBuilder* CreateBufferViewBuilder(); BufferViewBuilder* CreateBufferViewBuilder();
void SetSubData(uint32_t start, uint32_t count, const uint32_t* data); void SetSubData(uint32_t start, uint32_t count, const uint32_t* data);

View File

@ -22,6 +22,10 @@ namespace backend {
return !consumed && !gotStatus; return !consumed && !gotStatus;
} }
DeviceBase* BuilderBase::GetDevice() {
return device;
}
void BuilderBase::HandleError(const char* message) { void BuilderBase::HandleError(const char* message) {
SetStatus(nxt::BuilderErrorStatus::Error, message); SetStatus(nxt::BuilderErrorStatus::Error, message);
} }

View File

@ -42,6 +42,7 @@ namespace backend {
// Used by the auto-generated validation to prevent usage of the builder // Used by the auto-generated validation to prevent usage of the builder
// after GetResult or an error. // after GetResult or an error.
bool CanBeUsed() const; bool CanBeUsed() const;
DeviceBase* GetDevice();
// Set the status of the builder to an error. // Set the status of the builder to an error.
void HandleError(const char* message); void HandleError(const char* message);

View File

@ -61,6 +61,10 @@ namespace backend {
this->errorUserdata = userdata; this->errorUserdata = userdata;
} }
DeviceBase* DeviceBase::GetDevice() {
return this;
}
BindGroupLayoutBase* DeviceBase::GetOrCreateBindGroupLayout(const BindGroupLayoutBase* blueprint, BindGroupLayoutBuilder* builder) { BindGroupLayoutBase* DeviceBase::GetOrCreateBindGroupLayout(const BindGroupLayoutBase* blueprint, BindGroupLayoutBuilder* builder) {
// The blueprint is only used to search in the cache and is not modified. However cached // 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 // objects can be modified, and unordered_set cannot search for a const pointer in a non

View File

@ -32,6 +32,9 @@ namespace backend {
void HandleError(const char* message); void HandleError(const char* message);
void SetErrorCallback(nxt::DeviceErrorCallback callback, nxt::CallbackUserdata userdata); void SetErrorCallback(nxt::DeviceErrorCallback callback, nxt::CallbackUserdata userdata);
// Used by autogenerated code, returns itself
DeviceBase* GetDevice();
virtual BindGroupBase* CreateBindGroup(BindGroupBuilder* builder) = 0; virtual BindGroupBase* CreateBindGroup(BindGroupBuilder* builder) = 0;
virtual BindGroupLayoutBase* CreateBindGroupLayout(BindGroupLayoutBuilder* builder) = 0; virtual BindGroupLayoutBase* CreateBindGroupLayout(BindGroupLayoutBuilder* builder) = 0;
virtual BufferBase* CreateBuffer(BufferBuilder* builder) = 0; virtual BufferBase* CreateBuffer(BufferBuilder* builder) = 0;

View File

@ -21,6 +21,13 @@ namespace backend {
// QueueBase // QueueBase
QueueBase::QueueBase(QueueBuilder* builder) : device(builder->device) {
}
DeviceBase* QueueBase::GetDevice() {
return device;
}
bool QueueBase::ValidateSubmitCommand(CommandBufferBase* command) { bool QueueBase::ValidateSubmitCommand(CommandBufferBase* command) {
return command->ValidateResourceUsagesImmediate(); return command->ValidateResourceUsagesImmediate();
} }

View File

@ -24,10 +24,11 @@
namespace backend { namespace backend {
class QueueBase : public RefCounted { class QueueBase : public RefCounted {
private:
bool ValidateSubmitCommand(CommandBufferBase* command);
public: public:
QueueBase(QueueBuilder* builder);
DeviceBase* GetDevice();
template<typename T> template<typename T>
bool ValidateSubmit(uint32_t numCommands, T* const * commands) { bool ValidateSubmit(uint32_t numCommands, T* const * commands) {
static_assert(std::is_base_of<CommandBufferBase, T>::value, "invalid command buffer type"); static_assert(std::is_base_of<CommandBufferBase, T>::value, "invalid command buffer type");
@ -39,6 +40,11 @@ namespace backend {
} }
return true; return true;
} }
private:
bool ValidateSubmitCommand(CommandBufferBase* command);
DeviceBase* device;
}; };
class QueueBuilder : public Builder<QueueBase> { class QueueBuilder : public Builder<QueueBase> {
@ -46,6 +52,7 @@ namespace backend {
QueueBuilder(DeviceBase* device); QueueBuilder(DeviceBase* device);
private: private:
friend class QueueBase;
QueueBase* GetResultImpl() override; QueueBase* GetResultImpl() override;
}; };

View File

@ -33,6 +33,10 @@ namespace backend {
allowedUsage(builder->allowedUsage), currentUsage(builder->currentUsage) { allowedUsage(builder->allowedUsage), currentUsage(builder->currentUsage) {
} }
DeviceBase* TextureBase::GetDevice() {
return device;
}
nxt::TextureDimension TextureBase::GetDimension() const { nxt::TextureDimension TextureBase::GetDimension() const {
return dimension; return dimension;
} }

View File

@ -43,6 +43,8 @@ namespace backend {
bool IsTransitionPossible(nxt::TextureUsageBit usage) const; bool IsTransitionPossible(nxt::TextureUsageBit usage) const;
void TransitionUsageImpl(nxt::TextureUsageBit usage); void TransitionUsageImpl(nxt::TextureUsageBit usage);
DeviceBase* GetDevice();
// NXT API // NXT API
TextureViewBuilder* CreateTextureViewBuilder(); TextureViewBuilder* CreateTextureViewBuilder();
void TransitionUsage(nxt::TextureUsageBit usage); void TransitionUsage(nxt::TextureUsageBit usage);

View File

@ -803,7 +803,7 @@ namespace metal {
// Queue // Queue
Queue::Queue(Device* device, QueueBuilder* builder) Queue::Queue(Device* device, QueueBuilder* builder)
: device(device) { : QueueBase(builder), device(device) {
commandQueue = [device->GetMTLDevice() newCommandQueue]; commandQueue = [device->GetMTLDevice() newCommandQueue];
} }

View File

@ -167,7 +167,8 @@ namespace opengl {
// Queue // Queue
Queue::Queue(Device* device, QueueBuilder* builder) : device(device) { Queue::Queue(Device* device, QueueBuilder* builder)
: QueueBase(builder), device(device) {
} }
void Queue::Submit(uint32_t numCommands, CommandBuffer* const * commands) { void Queue::Submit(uint32_t numCommands, CommandBuffer* const * commands) {