mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-06-05 14:13:39 +00:00
Implement validation for RenderPipelineDescriptor2
In the service of keeping these changes incremental and easier to review this change only validates the RenderPipelineDescriptor2 before converting it back to a RenderPipelineDescriptor. BUG: dawn:642 Change-Id: Ie24c999756fa74f7d3cd10662a6bc95649602b14 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/46120 Auto-Submit: Brandon Jones <bajones@chromium.org> Commit-Queue: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
parent
864a364742
commit
7f77cfd7cf
@ -29,8 +29,9 @@ namespace dawn_native {
|
|||||||
DAWN_TRY(device->ValidateObject(descriptor->layout));
|
DAWN_TRY(device->ValidateObject(descriptor->layout));
|
||||||
}
|
}
|
||||||
|
|
||||||
DAWN_TRY(ValidateProgrammableStageDescriptor(
|
DAWN_TRY(ValidateProgrammableStage(device, descriptor->computeStage.module,
|
||||||
device, &descriptor->computeStage, descriptor->layout, SingleShaderStage::Compute));
|
descriptor->computeStage.entryPoint, descriptor->layout,
|
||||||
|
SingleShaderStage::Compute));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +41,8 @@ namespace dawn_native {
|
|||||||
const ComputePipelineDescriptor* descriptor)
|
const ComputePipelineDescriptor* descriptor)
|
||||||
: PipelineBase(device,
|
: PipelineBase(device,
|
||||||
descriptor->layout,
|
descriptor->layout,
|
||||||
{{SingleShaderStage::Compute, &descriptor->computeStage}}) {
|
{{SingleShaderStage::Compute, descriptor->computeStage.module,
|
||||||
|
descriptor->computeStage.entryPoint}}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ComputePipelineBase::ComputePipelineBase(DeviceBase* device, ObjectBase::ErrorTag tag)
|
ComputePipelineBase::ComputePipelineBase(DeviceBase* device, ObjectBase::ErrorTag tag)
|
||||||
|
@ -1022,12 +1022,15 @@ namespace dawn_native {
|
|||||||
if (descriptor->layout == nullptr) {
|
if (descriptor->layout == nullptr) {
|
||||||
ComputePipelineDescriptor descriptorWithDefaultLayout = *descriptor;
|
ComputePipelineDescriptor descriptorWithDefaultLayout = *descriptor;
|
||||||
|
|
||||||
DAWN_TRY_ASSIGN(descriptorWithDefaultLayout.layout,
|
|
||||||
PipelineLayoutBase::CreateDefault(
|
|
||||||
this, {{SingleShaderStage::Compute, &descriptor->computeStage}}));
|
|
||||||
// Ref will keep the pipeline layout alive until the end of the function where
|
// Ref will keep the pipeline layout alive until the end of the function where
|
||||||
// the pipeline will take another reference.
|
// the pipeline will take another reference.
|
||||||
Ref<PipelineLayoutBase> layoutRef = AcquireRef(descriptorWithDefaultLayout.layout);
|
Ref<PipelineLayoutBase> layoutRef;
|
||||||
|
DAWN_TRY_ASSIGN(layoutRef,
|
||||||
|
PipelineLayoutBase::CreateDefault(
|
||||||
|
this, {{SingleShaderStage::Compute, descriptor->computeStage.module,
|
||||||
|
descriptor->computeStage.entryPoint}}));
|
||||||
|
|
||||||
|
descriptorWithDefaultLayout.layout = layoutRef.Get();
|
||||||
|
|
||||||
DAWN_TRY_ASSIGN(*result, GetOrCreateComputePipeline(&descriptorWithDefaultLayout));
|
DAWN_TRY_ASSIGN(*result, GetOrCreateComputePipeline(&descriptorWithDefaultLayout));
|
||||||
} else {
|
} else {
|
||||||
@ -1071,6 +1074,11 @@ namespace dawn_native {
|
|||||||
MaybeError DeviceBase::CreateRenderPipelineInternal(
|
MaybeError DeviceBase::CreateRenderPipelineInternal(
|
||||||
RenderPipelineBase** result,
|
RenderPipelineBase** result,
|
||||||
const RenderPipelineDescriptor2* descriptor) {
|
const RenderPipelineDescriptor2* descriptor) {
|
||||||
|
DAWN_TRY(ValidateIsAlive());
|
||||||
|
if (IsValidationEnabled()) {
|
||||||
|
DAWN_TRY(ValidateRenderPipelineDescriptor(this, descriptor));
|
||||||
|
}
|
||||||
|
|
||||||
// Convert descriptor to the older format it before proceeding.
|
// Convert descriptor to the older format it before proceeding.
|
||||||
// TODO: Convert the rest of the code to operate on the newer format.
|
// TODO: Convert the rest of the code to operate on the newer format.
|
||||||
RenderPipelineDescriptor normalizedDescriptor;
|
RenderPipelineDescriptor normalizedDescriptor;
|
||||||
@ -1147,7 +1155,18 @@ namespace dawn_native {
|
|||||||
normalizedDescriptor.colorStates = colorStates.data();
|
normalizedDescriptor.colorStates = colorStates.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
return CreateRenderPipelineInternal(result, &normalizedDescriptor);
|
Ref<PipelineLayoutBase> layoutRef;
|
||||||
|
if (descriptor->layout == nullptr) {
|
||||||
|
// Ref will keep the pipeline layout alive until the end of the function where
|
||||||
|
// the pipeline will take another reference.
|
||||||
|
DAWN_TRY_ASSIGN(layoutRef,
|
||||||
|
PipelineLayoutBase::CreateDefault(this, GetStages(descriptor)));
|
||||||
|
normalizedDescriptor.layout = layoutRef.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
DAWN_TRY_ASSIGN(*result, GetOrCreateRenderPipeline(&normalizedDescriptor));
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeError DeviceBase::CreateRenderPipelineInternal(
|
MaybeError DeviceBase::CreateRenderPipelineInternal(
|
||||||
@ -1162,17 +1181,12 @@ namespace dawn_native {
|
|||||||
if (descriptor->layout == nullptr) {
|
if (descriptor->layout == nullptr) {
|
||||||
RenderPipelineDescriptor descriptorWithDefaultLayout = *descriptor;
|
RenderPipelineDescriptor descriptorWithDefaultLayout = *descriptor;
|
||||||
|
|
||||||
std::vector<StageAndDescriptor> stages;
|
|
||||||
stages.emplace_back(SingleShaderStage::Vertex, &descriptor->vertexStage);
|
|
||||||
if (descriptor->fragmentStage != nullptr) {
|
|
||||||
stages.emplace_back(SingleShaderStage::Fragment, descriptor->fragmentStage);
|
|
||||||
}
|
|
||||||
|
|
||||||
DAWN_TRY_ASSIGN(descriptorWithDefaultLayout.layout,
|
|
||||||
PipelineLayoutBase::CreateDefault(this, std::move(stages)));
|
|
||||||
// Ref will keep the pipeline layout alive until the end of the function where
|
// Ref will keep the pipeline layout alive until the end of the function where
|
||||||
// the pipeline will take another reference.
|
// the pipeline will take another reference.
|
||||||
Ref<PipelineLayoutBase> layoutRef = AcquireRef(descriptorWithDefaultLayout.layout);
|
Ref<PipelineLayoutBase> layoutRef;
|
||||||
|
DAWN_TRY_ASSIGN(layoutRef,
|
||||||
|
PipelineLayoutBase::CreateDefault(this, GetStages(descriptor)));
|
||||||
|
descriptorWithDefaultLayout.layout = layoutRef.Get();
|
||||||
|
|
||||||
DAWN_TRY_ASSIGN(*result, GetOrCreateRenderPipeline(&descriptorWithDefaultLayout));
|
DAWN_TRY_ASSIGN(*result, GetOrCreateRenderPipeline(&descriptorWithDefaultLayout));
|
||||||
} else {
|
} else {
|
||||||
|
@ -22,18 +22,18 @@
|
|||||||
|
|
||||||
namespace dawn_native {
|
namespace dawn_native {
|
||||||
|
|
||||||
MaybeError ValidateProgrammableStageDescriptor(DeviceBase* device,
|
MaybeError ValidateProgrammableStage(DeviceBase* device,
|
||||||
const ProgrammableStageDescriptor* descriptor,
|
const ShaderModuleBase* module,
|
||||||
|
const std::string& entryPoint,
|
||||||
const PipelineLayoutBase* layout,
|
const PipelineLayoutBase* layout,
|
||||||
SingleShaderStage stage) {
|
SingleShaderStage stage) {
|
||||||
const ShaderModuleBase* module = descriptor->module;
|
|
||||||
DAWN_TRY(device->ValidateObject(module));
|
DAWN_TRY(device->ValidateObject(module));
|
||||||
|
|
||||||
if (!module->HasEntryPoint(descriptor->entryPoint)) {
|
if (!module->HasEntryPoint(entryPoint)) {
|
||||||
return DAWN_VALIDATION_ERROR("Entry point doesn't exist in the module");
|
return DAWN_VALIDATION_ERROR("Entry point doesn't exist in the module");
|
||||||
}
|
}
|
||||||
|
|
||||||
const EntryPointMetadata& metadata = module->GetEntryPoint(descriptor->entryPoint);
|
const EntryPointMetadata& metadata = module->GetEntryPoint(entryPoint);
|
||||||
|
|
||||||
if (metadata.stage != stage) {
|
if (metadata.stage != stage) {
|
||||||
return DAWN_VALIDATION_ERROR("Entry point isn't for the correct stage");
|
return DAWN_VALIDATION_ERROR("Entry point isn't for the correct stage");
|
||||||
@ -56,9 +56,9 @@ namespace dawn_native {
|
|||||||
|
|
||||||
for (const StageAndDescriptor& stage : stages) {
|
for (const StageAndDescriptor& stage : stages) {
|
||||||
// Extract argument for this stage.
|
// Extract argument for this stage.
|
||||||
SingleShaderStage shaderStage = stage.first;
|
SingleShaderStage shaderStage = stage.shaderStage;
|
||||||
ShaderModuleBase* module = stage.second->module;
|
ShaderModuleBase* module = stage.module;
|
||||||
const char* entryPointName = stage.second->entryPoint;
|
const char* entryPointName = stage.entryPoint.c_str();
|
||||||
|
|
||||||
const EntryPointMetadata& metadata = module->GetEntryPoint(entryPointName);
|
const EntryPointMetadata& metadata = module->GetEntryPoint(entryPointName);
|
||||||
ASSERT(metadata.stage == shaderStage);
|
ASSERT(metadata.stage == shaderStage);
|
||||||
|
@ -28,8 +28,9 @@
|
|||||||
|
|
||||||
namespace dawn_native {
|
namespace dawn_native {
|
||||||
|
|
||||||
MaybeError ValidateProgrammableStageDescriptor(DeviceBase* device,
|
MaybeError ValidateProgrammableStage(DeviceBase* device,
|
||||||
const ProgrammableStageDescriptor* descriptor,
|
const ShaderModuleBase* module,
|
||||||
|
const std::string& entryPoint,
|
||||||
const PipelineLayoutBase* layout,
|
const PipelineLayoutBase* layout,
|
||||||
SingleShaderStage stage);
|
SingleShaderStage stage);
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ namespace dawn_native {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
ResultOrError<PipelineLayoutBase*> PipelineLayoutBase::CreateDefault(
|
ResultOrError<Ref<PipelineLayoutBase>> PipelineLayoutBase::CreateDefault(
|
||||||
DeviceBase* device,
|
DeviceBase* device,
|
||||||
std::vector<StageAndDescriptor> stages) {
|
std::vector<StageAndDescriptor> stages) {
|
||||||
using EntryMap = std::map<BindingNumber, BindGroupLayoutEntry>;
|
using EntryMap = std::map<BindingNumber, BindGroupLayoutEntry>;
|
||||||
@ -177,7 +177,7 @@ namespace dawn_native {
|
|||||||
// Loops over all the reflected BindGroupLayoutEntries from shaders.
|
// Loops over all the reflected BindGroupLayoutEntries from shaders.
|
||||||
for (const StageAndDescriptor& stage : stages) {
|
for (const StageAndDescriptor& stage : stages) {
|
||||||
const EntryPointMetadata::BindingInfoArray& info =
|
const EntryPointMetadata::BindingInfoArray& info =
|
||||||
stage.second->module->GetEntryPoint(stage.second->entryPoint).bindings;
|
stage.module->GetEntryPoint(stage.entryPoint).bindings;
|
||||||
|
|
||||||
for (BindGroupIndex group(0); group < info.size(); ++group) {
|
for (BindGroupIndex group(0); group < info.size(); ++group) {
|
||||||
for (const auto& bindingIt : info[group]) {
|
for (const auto& bindingIt : info[group]) {
|
||||||
@ -187,7 +187,7 @@ namespace dawn_native {
|
|||||||
// Create the BindGroupLayoutEntry
|
// Create the BindGroupLayoutEntry
|
||||||
BindGroupLayoutEntry entry = ConvertMetadataToEntry(shaderBinding);
|
BindGroupLayoutEntry entry = ConvertMetadataToEntry(shaderBinding);
|
||||||
entry.binding = static_cast<uint32_t>(bindingNumber);
|
entry.binding = static_cast<uint32_t>(bindingNumber);
|
||||||
entry.visibility = StageBit(stage.first);
|
entry.visibility = StageBit(stage.shaderStage);
|
||||||
|
|
||||||
// Add it to our map of all entries, if there is an existing entry, then we
|
// Add it to our map of all entries, if there is an existing entry, then we
|
||||||
// need to merge, if we can.
|
// need to merge, if we can.
|
||||||
@ -213,7 +213,7 @@ namespace dawn_native {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the deduced pipeline layout, validating if it is valid.
|
// Create the deduced pipeline layout, validating if it is valid.
|
||||||
PipelineLayoutBase* pipelineLayout = nullptr;
|
Ref<PipelineLayoutBase> result = nullptr;
|
||||||
{
|
{
|
||||||
ityp::array<BindGroupIndex, BindGroupLayoutBase*, kMaxBindGroups> bgls = {};
|
ityp::array<BindGroupIndex, BindGroupLayoutBase*, kMaxBindGroups> bgls = {};
|
||||||
for (BindGroupIndex group(0); group < pipelineBGLCount; ++group) {
|
for (BindGroupIndex group(0); group < pipelineBGLCount; ++group) {
|
||||||
@ -225,20 +225,24 @@ namespace dawn_native {
|
|||||||
desc.bindGroupLayoutCount = static_cast<uint32_t>(pipelineBGLCount);
|
desc.bindGroupLayoutCount = static_cast<uint32_t>(pipelineBGLCount);
|
||||||
|
|
||||||
DAWN_TRY(ValidatePipelineLayoutDescriptor(device, &desc));
|
DAWN_TRY(ValidatePipelineLayoutDescriptor(device, &desc));
|
||||||
|
|
||||||
|
PipelineLayoutBase* pipelineLayout;
|
||||||
DAWN_TRY_ASSIGN(pipelineLayout, device->GetOrCreatePipelineLayout(&desc));
|
DAWN_TRY_ASSIGN(pipelineLayout, device->GetOrCreatePipelineLayout(&desc));
|
||||||
|
|
||||||
ASSERT(!pipelineLayout->IsError());
|
result = AcquireRef(pipelineLayout);
|
||||||
}
|
|
||||||
|
|
||||||
// Sanity check in debug that the pipeline layout is compatible with the current pipeline.
|
ASSERT(!pipelineLayout->IsError());
|
||||||
|
|
||||||
|
// Sanity check in debug that the pipeline layout is compatible with the current
|
||||||
|
// pipeline.
|
||||||
for (const StageAndDescriptor& stage : stages) {
|
for (const StageAndDescriptor& stage : stages) {
|
||||||
const EntryPointMetadata& metadata =
|
const EntryPointMetadata& metadata = stage.module->GetEntryPoint(stage.entryPoint);
|
||||||
stage.second->module->GetEntryPoint(stage.second->entryPoint);
|
|
||||||
ASSERT(ValidateCompatibilityWithPipelineLayout(device, metadata, pipelineLayout)
|
ASSERT(ValidateCompatibilityWithPipelineLayout(device, metadata, pipelineLayout)
|
||||||
.IsSuccess());
|
.IsSuccess());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return pipelineLayout;
|
return std::move(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
const BindGroupLayoutBase* PipelineLayoutBase::GetBindGroupLayout(BindGroupIndex group) const {
|
const BindGroupLayoutBase* PipelineLayoutBase::GetBindGroupLayout(BindGroupIndex group) const {
|
||||||
|
@ -37,7 +37,11 @@ namespace dawn_native {
|
|||||||
ityp::array<BindGroupIndex, Ref<BindGroupLayoutBase>, kMaxBindGroups>;
|
ityp::array<BindGroupIndex, Ref<BindGroupLayoutBase>, kMaxBindGroups>;
|
||||||
using BindGroupLayoutMask = ityp::bitset<BindGroupIndex, kMaxBindGroups>;
|
using BindGroupLayoutMask = ityp::bitset<BindGroupIndex, kMaxBindGroups>;
|
||||||
|
|
||||||
using StageAndDescriptor = std::pair<SingleShaderStage, const ProgrammableStageDescriptor*>;
|
struct StageAndDescriptor {
|
||||||
|
SingleShaderStage shaderStage;
|
||||||
|
ShaderModuleBase* module;
|
||||||
|
std::string entryPoint;
|
||||||
|
};
|
||||||
|
|
||||||
class PipelineLayoutBase : public CachedObject {
|
class PipelineLayoutBase : public CachedObject {
|
||||||
public:
|
public:
|
||||||
@ -45,7 +49,7 @@ namespace dawn_native {
|
|||||||
~PipelineLayoutBase() override;
|
~PipelineLayoutBase() override;
|
||||||
|
|
||||||
static PipelineLayoutBase* MakeError(DeviceBase* device);
|
static PipelineLayoutBase* MakeError(DeviceBase* device);
|
||||||
static ResultOrError<PipelineLayoutBase*> CreateDefault(
|
static ResultOrError<Ref<PipelineLayoutBase>> CreateDefault(
|
||||||
DeviceBase* device,
|
DeviceBase* device,
|
||||||
std::vector<StageAndDescriptor> stages);
|
std::vector<StageAndDescriptor> stages);
|
||||||
|
|
||||||
|
@ -27,9 +27,8 @@ namespace dawn_native {
|
|||||||
// Helper functions
|
// Helper functions
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
MaybeError ValidateVertexAttributeDescriptor(
|
MaybeError ValidateVertexAttribute(DeviceBase* device,
|
||||||
DeviceBase* device,
|
const VertexAttribute* attribute,
|
||||||
const VertexAttributeDescriptor* attribute,
|
|
||||||
uint64_t vertexBufferStride,
|
uint64_t vertexBufferStride,
|
||||||
std::bitset<kMaxVertexAttributes>* attributesSetMask) {
|
std::bitset<kMaxVertexAttributes>* attributesSetMask) {
|
||||||
DAWN_TRY(ValidateVertexFormat(attribute->format));
|
DAWN_TRY(ValidateVertexFormat(attribute->format));
|
||||||
@ -73,9 +72,9 @@ namespace dawn_native {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeError ValidateVertexBufferLayoutDescriptor(
|
MaybeError ValidateVertexBufferLayout(
|
||||||
DeviceBase* device,
|
DeviceBase* device,
|
||||||
const VertexBufferLayoutDescriptor* buffer,
|
const VertexBufferLayout* buffer,
|
||||||
std::bitset<kMaxVertexAttributes>* attributesSetMask) {
|
std::bitset<kMaxVertexAttributes>* attributesSetMask) {
|
||||||
DAWN_TRY(ValidateInputStepMode(buffer->stepMode));
|
DAWN_TRY(ValidateInputStepMode(buffer->stepMode));
|
||||||
if (buffer->arrayStride > kMaxVertexBufferStride) {
|
if (buffer->arrayStride > kMaxVertexBufferStride) {
|
||||||
@ -88,13 +87,193 @@ namespace dawn_native {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t i = 0; i < buffer->attributeCount; ++i) {
|
for (uint32_t i = 0; i < buffer->attributeCount; ++i) {
|
||||||
DAWN_TRY(ValidateVertexAttributeDescriptor(device, &buffer->attributes[i],
|
DAWN_TRY(ValidateVertexAttribute(device, &buffer->attributes[i],
|
||||||
buffer->arrayStride, attributesSetMask));
|
buffer->arrayStride, attributesSetMask));
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MaybeError ValidateVertexState(DeviceBase* device,
|
||||||
|
const VertexState* descriptor,
|
||||||
|
const PipelineLayoutBase* layout) {
|
||||||
|
if (descriptor->nextInChain != nullptr) {
|
||||||
|
return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (descriptor->bufferCount > kMaxVertexBuffers) {
|
||||||
|
return DAWN_VALIDATION_ERROR("Vertex buffer count exceeds maximum");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::bitset<kMaxVertexAttributes> attributesSetMask;
|
||||||
|
uint32_t totalAttributesNum = 0;
|
||||||
|
for (uint32_t i = 0; i < descriptor->bufferCount; ++i) {
|
||||||
|
DAWN_TRY(ValidateVertexBufferLayout(device, &descriptor->buffers[i],
|
||||||
|
&attributesSetMask));
|
||||||
|
totalAttributesNum += descriptor->buffers[i].attributeCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Every vertex attribute has a member called shaderLocation, and there are some
|
||||||
|
// requirements for shaderLocation: 1) >=0, 2) values are different across different
|
||||||
|
// attributes, 3) can't exceed kMaxVertexAttributes. So it can ensure that total
|
||||||
|
// attribute number never exceed kMaxVertexAttributes.
|
||||||
|
ASSERT(totalAttributesNum <= kMaxVertexAttributes);
|
||||||
|
|
||||||
|
DAWN_TRY(ValidateProgrammableStage(device, descriptor->module, descriptor->entryPoint,
|
||||||
|
layout, SingleShaderStage::Vertex));
|
||||||
|
const EntryPointMetadata& vertexMetadata =
|
||||||
|
descriptor->module->GetEntryPoint(descriptor->entryPoint);
|
||||||
|
if (!IsSubset(vertexMetadata.usedVertexAttributes, attributesSetMask)) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"Pipeline vertex stage uses vertex buffers not in the vertex state");
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
MaybeError ValidatePrimitiveState(const PrimitiveState* descriptor) {
|
||||||
|
if (descriptor->nextInChain != nullptr) {
|
||||||
|
return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
|
||||||
|
}
|
||||||
|
|
||||||
|
DAWN_TRY(ValidatePrimitiveTopology(descriptor->topology));
|
||||||
|
DAWN_TRY(ValidateIndexFormat(descriptor->stripIndexFormat));
|
||||||
|
DAWN_TRY(ValidateFrontFace(descriptor->frontFace));
|
||||||
|
DAWN_TRY(ValidateCullMode(descriptor->cullMode));
|
||||||
|
|
||||||
|
// Pipeline descriptors must have stripIndexFormat != undefined IFF they are using strip
|
||||||
|
// topologies.
|
||||||
|
if (IsStripPrimitiveTopology(descriptor->topology)) {
|
||||||
|
if (descriptor->stripIndexFormat == wgpu::IndexFormat::Undefined) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"stripIndexFormat must not be undefined when using strip primitive "
|
||||||
|
"topologies");
|
||||||
|
}
|
||||||
|
} else if (descriptor->stripIndexFormat != wgpu::IndexFormat::Undefined) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"stripIndexFormat must be undefined when using non-strip primitive topologies");
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
MaybeError ValidateDepthStencilState(const DeviceBase* device,
|
||||||
|
const DepthStencilState* descriptor) {
|
||||||
|
if (descriptor->nextInChain != nullptr) {
|
||||||
|
return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
|
||||||
|
}
|
||||||
|
|
||||||
|
DAWN_TRY(ValidateCompareFunction(descriptor->depthCompare));
|
||||||
|
DAWN_TRY(ValidateCompareFunction(descriptor->stencilFront.compare));
|
||||||
|
DAWN_TRY(ValidateStencilOperation(descriptor->stencilFront.failOp));
|
||||||
|
DAWN_TRY(ValidateStencilOperation(descriptor->stencilFront.depthFailOp));
|
||||||
|
DAWN_TRY(ValidateStencilOperation(descriptor->stencilFront.passOp));
|
||||||
|
DAWN_TRY(ValidateCompareFunction(descriptor->stencilBack.compare));
|
||||||
|
DAWN_TRY(ValidateStencilOperation(descriptor->stencilBack.failOp));
|
||||||
|
DAWN_TRY(ValidateStencilOperation(descriptor->stencilBack.depthFailOp));
|
||||||
|
DAWN_TRY(ValidateStencilOperation(descriptor->stencilBack.passOp));
|
||||||
|
|
||||||
|
const Format* format;
|
||||||
|
DAWN_TRY_ASSIGN(format, device->GetInternalFormat(descriptor->format));
|
||||||
|
if (!format->HasDepthOrStencil() || !format->isRenderable) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"Depth stencil format must be depth-stencil renderable");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::isnan(descriptor->depthBiasSlopeScale) ||
|
||||||
|
std::isnan(descriptor->depthBiasClamp)) {
|
||||||
|
return DAWN_VALIDATION_ERROR("Depth bias parameters must not be NaN.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
MaybeError ValidateMultisampleState(const MultisampleState* descriptor) {
|
||||||
|
if (descriptor->nextInChain != nullptr) {
|
||||||
|
return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsValidSampleCount(descriptor->count)) {
|
||||||
|
return DAWN_VALIDATION_ERROR("Multisample count is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (descriptor->alphaToCoverageEnabled && descriptor->count <= 1) {
|
||||||
|
return DAWN_VALIDATION_ERROR("Enabling alphaToCoverage requires sample count > 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
MaybeError ValidateBlendState(const BlendState* descriptor) {
|
||||||
|
DAWN_TRY(ValidateBlendOperation(descriptor->alpha.operation));
|
||||||
|
DAWN_TRY(ValidateBlendFactor(descriptor->alpha.srcFactor));
|
||||||
|
DAWN_TRY(ValidateBlendFactor(descriptor->alpha.dstFactor));
|
||||||
|
DAWN_TRY(ValidateBlendOperation(descriptor->color.operation));
|
||||||
|
DAWN_TRY(ValidateBlendFactor(descriptor->color.srcFactor));
|
||||||
|
DAWN_TRY(ValidateBlendFactor(descriptor->color.dstFactor));
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
MaybeError ValidateColorTargetState(const DeviceBase* device,
|
||||||
|
const ColorTargetState* descriptor,
|
||||||
|
bool fragmentWritten,
|
||||||
|
wgpu::TextureComponentType fragmentOutputBaseType) {
|
||||||
|
if (descriptor->nextInChain != nullptr) {
|
||||||
|
return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (descriptor->blend) {
|
||||||
|
DAWN_TRY(ValidateBlendState(descriptor->blend));
|
||||||
|
}
|
||||||
|
|
||||||
|
DAWN_TRY(ValidateColorWriteMask(descriptor->writeMask));
|
||||||
|
|
||||||
|
const Format* format;
|
||||||
|
DAWN_TRY_ASSIGN(format, device->GetInternalFormat(descriptor->format));
|
||||||
|
if (!format->IsColor() || !format->isRenderable) {
|
||||||
|
return DAWN_VALIDATION_ERROR("Color format must be color renderable");
|
||||||
|
}
|
||||||
|
if (fragmentWritten &&
|
||||||
|
fragmentOutputBaseType != format->GetAspectInfo(Aspect::Color).baseType) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"Color format must match the fragment stage output type");
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
MaybeError ValidateFragmentState(DeviceBase* device,
|
||||||
|
const FragmentState* descriptor,
|
||||||
|
const PipelineLayoutBase* layout) {
|
||||||
|
if (descriptor->nextInChain != nullptr) {
|
||||||
|
return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
|
||||||
|
}
|
||||||
|
|
||||||
|
DAWN_TRY(ValidateProgrammableStage(device, descriptor->module, descriptor->entryPoint,
|
||||||
|
layout, SingleShaderStage::Fragment));
|
||||||
|
|
||||||
|
if (descriptor->targetCount > kMaxColorAttachments) {
|
||||||
|
return DAWN_VALIDATION_ERROR("Number of color targets exceeds maximum");
|
||||||
|
}
|
||||||
|
|
||||||
|
const EntryPointMetadata& fragmentMetadata =
|
||||||
|
descriptor->module->GetEntryPoint(descriptor->entryPoint);
|
||||||
|
for (ColorAttachmentIndex i(uint8_t(0));
|
||||||
|
i < ColorAttachmentIndex(static_cast<uint8_t>(descriptor->targetCount)); ++i) {
|
||||||
|
DAWN_TRY(
|
||||||
|
ValidateColorTargetState(device, &descriptor->targets[static_cast<uint8_t>(i)],
|
||||||
|
fragmentMetadata.fragmentOutputsWritten[i],
|
||||||
|
fragmentMetadata.fragmentOutputFormatBaseTypes[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(dawn:642): Validation methods below here are for the deprecated
|
||||||
|
// RenderPipelineDescriptor format and should be removed once it is no longer necessary to
|
||||||
|
// validate that format.
|
||||||
|
|
||||||
MaybeError ValidateVertexStateDescriptor(
|
MaybeError ValidateVertexStateDescriptor(
|
||||||
DeviceBase* device,
|
DeviceBase* device,
|
||||||
const VertexStateDescriptor* descriptor,
|
const VertexStateDescriptor* descriptor,
|
||||||
@ -123,7 +302,7 @@ namespace dawn_native {
|
|||||||
|
|
||||||
uint32_t totalAttributesNum = 0;
|
uint32_t totalAttributesNum = 0;
|
||||||
for (uint32_t i = 0; i < descriptor->vertexBufferCount; ++i) {
|
for (uint32_t i = 0; i < descriptor->vertexBufferCount; ++i) {
|
||||||
DAWN_TRY(ValidateVertexBufferLayoutDescriptor(device, &descriptor->vertexBuffers[i],
|
DAWN_TRY(ValidateVertexBufferLayout(device, &descriptor->vertexBuffers[i],
|
||||||
attributesSetMask));
|
attributesSetMask));
|
||||||
totalAttributesNum += descriptor->vertexBuffers[i].attributeCount;
|
totalAttributesNum += descriptor->vertexBuffers[i].attributeCount;
|
||||||
}
|
}
|
||||||
@ -251,10 +430,12 @@ namespace dawn_native {
|
|||||||
descriptor->vertexState, descriptor->primitiveTopology, &attributesSetMask));
|
descriptor->vertexState, descriptor->primitiveTopology, &attributesSetMask));
|
||||||
}
|
}
|
||||||
|
|
||||||
DAWN_TRY(ValidateProgrammableStageDescriptor(
|
DAWN_TRY(ValidateProgrammableStage(device, descriptor->vertexStage.module,
|
||||||
device, &descriptor->vertexStage, descriptor->layout, SingleShaderStage::Vertex));
|
descriptor->vertexStage.entryPoint, descriptor->layout,
|
||||||
DAWN_TRY(ValidateProgrammableStageDescriptor(
|
SingleShaderStage::Vertex));
|
||||||
device, descriptor->fragmentStage, descriptor->layout, SingleShaderStage::Fragment));
|
DAWN_TRY(ValidateProgrammableStage(device, descriptor->fragmentStage->module,
|
||||||
|
descriptor->fragmentStage->entryPoint,
|
||||||
|
descriptor->layout, SingleShaderStage::Fragment));
|
||||||
|
|
||||||
if (descriptor->rasterizationState) {
|
if (descriptor->rasterizationState) {
|
||||||
DAWN_TRY(ValidateRasterizationStateDescriptor(descriptor->rasterizationState));
|
DAWN_TRY(ValidateRasterizationStateDescriptor(descriptor->rasterizationState));
|
||||||
@ -302,6 +483,63 @@ namespace dawn_native {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MaybeError ValidateRenderPipelineDescriptor(DeviceBase* device,
|
||||||
|
const RenderPipelineDescriptor2* descriptor) {
|
||||||
|
if (descriptor->nextInChain != nullptr) {
|
||||||
|
return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (descriptor->layout != nullptr) {
|
||||||
|
DAWN_TRY(device->ValidateObject(descriptor->layout));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(crbug.com/dawn/136): Support vertex-only pipelines.
|
||||||
|
if (descriptor->fragment == nullptr) {
|
||||||
|
return DAWN_VALIDATION_ERROR("Null fragment stage is not supported (yet)");
|
||||||
|
}
|
||||||
|
|
||||||
|
DAWN_TRY(ValidateVertexState(device, &descriptor->vertex, descriptor->layout));
|
||||||
|
|
||||||
|
DAWN_TRY(ValidatePrimitiveState(&descriptor->primitive));
|
||||||
|
|
||||||
|
if (descriptor->depthStencil) {
|
||||||
|
DAWN_TRY(ValidateDepthStencilState(device, descriptor->depthStencil));
|
||||||
|
}
|
||||||
|
|
||||||
|
DAWN_TRY(ValidateMultisampleState(&descriptor->multisample));
|
||||||
|
|
||||||
|
ASSERT(descriptor->fragment != nullptr);
|
||||||
|
DAWN_TRY(ValidateFragmentState(device, descriptor->fragment, descriptor->layout));
|
||||||
|
|
||||||
|
if (descriptor->fragment->targetCount == 0 && !descriptor->depthStencil) {
|
||||||
|
return DAWN_VALIDATION_ERROR("Should have at least one color target or a depthStencil");
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<StageAndDescriptor> GetStages(const RenderPipelineDescriptor* descriptor) {
|
||||||
|
std::vector<StageAndDescriptor> stages;
|
||||||
|
stages.push_back({SingleShaderStage::Vertex, descriptor->vertexStage.module,
|
||||||
|
descriptor->vertexStage.entryPoint});
|
||||||
|
if (descriptor->fragmentStage != nullptr) {
|
||||||
|
stages.push_back({SingleShaderStage::Fragment, descriptor->fragmentStage->module,
|
||||||
|
descriptor->fragmentStage->entryPoint});
|
||||||
|
}
|
||||||
|
return stages;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<StageAndDescriptor> GetStages(const RenderPipelineDescriptor2* descriptor) {
|
||||||
|
std::vector<StageAndDescriptor> stages;
|
||||||
|
stages.push_back(
|
||||||
|
{SingleShaderStage::Vertex, descriptor->vertex.module, descriptor->vertex.entryPoint});
|
||||||
|
if (descriptor->fragment != nullptr) {
|
||||||
|
stages.push_back({SingleShaderStage::Fragment, descriptor->fragment->module,
|
||||||
|
descriptor->fragment->entryPoint});
|
||||||
|
}
|
||||||
|
return stages;
|
||||||
|
}
|
||||||
|
|
||||||
bool StencilTestEnabled(const DepthStencilState* mDepthStencil) {
|
bool StencilTestEnabled(const DepthStencilState* mDepthStencil) {
|
||||||
return mDepthStencil->stencilBack.compare != wgpu::CompareFunction::Always ||
|
return mDepthStencil->stencilBack.compare != wgpu::CompareFunction::Always ||
|
||||||
mDepthStencil->stencilBack.failOp != wgpu::StencilOperation::Keep ||
|
mDepthStencil->stencilBack.failOp != wgpu::StencilOperation::Keep ||
|
||||||
@ -328,8 +566,10 @@ namespace dawn_native {
|
|||||||
const RenderPipelineDescriptor* descriptor)
|
const RenderPipelineDescriptor* descriptor)
|
||||||
: PipelineBase(device,
|
: PipelineBase(device,
|
||||||
descriptor->layout,
|
descriptor->layout,
|
||||||
{{SingleShaderStage::Vertex, &descriptor->vertexStage},
|
{{SingleShaderStage::Vertex, descriptor->vertexStage.module,
|
||||||
{SingleShaderStage::Fragment, descriptor->fragmentStage}}),
|
descriptor->vertexStage.entryPoint},
|
||||||
|
{SingleShaderStage::Fragment, descriptor->fragmentStage->module,
|
||||||
|
descriptor->fragmentStage->entryPoint}}),
|
||||||
mAttachmentState(device->GetOrCreateAttachmentState(descriptor)) {
|
mAttachmentState(device->GetOrCreateAttachmentState(descriptor)) {
|
||||||
mPrimitive.topology = descriptor->primitiveTopology;
|
mPrimitive.topology = descriptor->primitiveTopology;
|
||||||
|
|
||||||
|
@ -31,6 +31,12 @@ namespace dawn_native {
|
|||||||
|
|
||||||
MaybeError ValidateRenderPipelineDescriptor(DeviceBase* device,
|
MaybeError ValidateRenderPipelineDescriptor(DeviceBase* device,
|
||||||
const RenderPipelineDescriptor* descriptor);
|
const RenderPipelineDescriptor* descriptor);
|
||||||
|
MaybeError ValidateRenderPipelineDescriptor(DeviceBase* device,
|
||||||
|
const RenderPipelineDescriptor2* descriptor);
|
||||||
|
|
||||||
|
std::vector<StageAndDescriptor> GetStages(const RenderPipelineDescriptor* descriptor);
|
||||||
|
std::vector<StageAndDescriptor> GetStages(const RenderPipelineDescriptor2* descriptor);
|
||||||
|
|
||||||
size_t IndexFormatSize(wgpu::IndexFormat format);
|
size_t IndexFormatSize(wgpu::IndexFormat format);
|
||||||
|
|
||||||
bool IsStripPrimitiveTopology(wgpu::PrimitiveTopology primitiveTopology);
|
bool IsStripPrimitiveTopology(wgpu::PrimitiveTopology primitiveTopology);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user