Add validation for fragment output and attachment interface matching

Validation rules discussed at
https://github.com/gpuweb/gpuweb/issues/2013

Bug: dawn:1063
Change-Id: I264eecb7c548f29975e5459a7ad020105acab634
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/61383
Commit-Queue: Shrek Shao <shrekshao@google.com>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
This commit is contained in:
shrekshao 2021-08-11 21:12:36 +00:00 committed by Dawn LUCI CQ
parent 6ef39372f8
commit 4f2edf576e
10 changed files with 319 additions and 108 deletions

View File

@ -158,7 +158,7 @@ namespace dawn_native {
auto AddColorFormat = [&AddFormat](wgpu::TextureFormat format, bool renderable, auto AddColorFormat = [&AddFormat](wgpu::TextureFormat format, bool renderable,
bool supportsStorageUsage, uint32_t byteSize, bool supportsStorageUsage, uint32_t byteSize,
SampleTypeBit sampleTypes) { SampleTypeBit sampleTypes, uint8_t componentCount) {
Format internalFormat; Format internalFormat;
internalFormat.format = format; internalFormat.format = format;
internalFormat.isRenderable = renderable; internalFormat.isRenderable = renderable;
@ -166,6 +166,7 @@ namespace dawn_native {
internalFormat.isSupported = true; internalFormat.isSupported = true;
internalFormat.supportsStorageUsage = supportsStorageUsage; internalFormat.supportsStorageUsage = supportsStorageUsage;
internalFormat.aspects = Aspect::Color; internalFormat.aspects = Aspect::Color;
internalFormat.componentCount = componentCount;
AspectInfo* firstAspect = internalFormat.aspectInfo.data(); AspectInfo* firstAspect = internalFormat.aspectInfo.data();
firstAspect->block.byteSize = byteSize; firstAspect->block.byteSize = byteSize;
firstAspect->block.width = 1; firstAspect->block.width = 1;
@ -202,6 +203,7 @@ namespace dawn_native {
internalFormat.isSupported = true; internalFormat.isSupported = true;
internalFormat.supportsStorageUsage = false; internalFormat.supportsStorageUsage = false;
internalFormat.aspects = Aspect::Depth; internalFormat.aspects = Aspect::Depth;
internalFormat.componentCount = 1;
AspectInfo* firstAspect = internalFormat.aspectInfo.data(); AspectInfo* firstAspect = internalFormat.aspectInfo.data();
firstAspect->block.byteSize = byteSize; firstAspect->block.byteSize = byteSize;
firstAspect->block.width = 1; firstAspect->block.width = 1;
@ -220,6 +222,7 @@ namespace dawn_native {
internalFormat.isSupported = false; internalFormat.isSupported = false;
internalFormat.supportsStorageUsage = false; internalFormat.supportsStorageUsage = false;
internalFormat.aspects = Aspect::Stencil; internalFormat.aspects = Aspect::Stencil;
internalFormat.componentCount = 1;
AspectInfo* firstAspect = internalFormat.aspectInfo.data(); AspectInfo* firstAspect = internalFormat.aspectInfo.data();
firstAspect->block.byteSize = 1; firstAspect->block.byteSize = 1;
firstAspect->block.width = 1; firstAspect->block.width = 1;
@ -231,7 +234,8 @@ namespace dawn_native {
}; };
auto AddCompressedFormat = [&AddFormat](wgpu::TextureFormat format, uint32_t byteSize, auto AddCompressedFormat = [&AddFormat](wgpu::TextureFormat format, uint32_t byteSize,
uint32_t width, uint32_t height, bool isSupported) { uint32_t width, uint32_t height, bool isSupported,
uint8_t componentCount) {
Format internalFormat; Format internalFormat;
internalFormat.format = format; internalFormat.format = format;
internalFormat.isRenderable = false; internalFormat.isRenderable = false;
@ -239,6 +243,7 @@ namespace dawn_native {
internalFormat.isSupported = isSupported; internalFormat.isSupported = isSupported;
internalFormat.supportsStorageUsage = false; internalFormat.supportsStorageUsage = false;
internalFormat.aspects = Aspect::Color; internalFormat.aspects = Aspect::Color;
internalFormat.componentCount = componentCount;
AspectInfo* firstAspect = internalFormat.aspectInfo.data(); AspectInfo* firstAspect = internalFormat.aspectInfo.data();
firstAspect->block.byteSize = byteSize; firstAspect->block.byteSize = byteSize;
firstAspect->block.width = width; firstAspect->block.width = width;
@ -249,10 +254,10 @@ namespace dawn_native {
AddFormat(internalFormat); AddFormat(internalFormat);
}; };
auto AddMultiAspectFormat = [&AddFormat, &table](wgpu::TextureFormat format, Aspect aspects, auto AddMultiAspectFormat =
wgpu::TextureFormat firstFormat, [&AddFormat, &table](wgpu::TextureFormat format, Aspect aspects,
wgpu::TextureFormat secondFormat, wgpu::TextureFormat firstFormat, wgpu::TextureFormat secondFormat,
bool isRenderable, bool isSupported) { bool isRenderable, bool isSupported, uint8_t componentCount) {
Format internalFormat; Format internalFormat;
internalFormat.format = format; internalFormat.format = format;
internalFormat.isRenderable = isRenderable; internalFormat.isRenderable = isRenderable;
@ -260,7 +265,7 @@ namespace dawn_native {
internalFormat.isSupported = isSupported; internalFormat.isSupported = isSupported;
internalFormat.supportsStorageUsage = false; internalFormat.supportsStorageUsage = false;
internalFormat.aspects = aspects; internalFormat.aspects = aspects;
internalFormat.componentCount = componentCount;
const size_t firstFormatIndex = ComputeFormatIndex(firstFormat); const size_t firstFormatIndex = ComputeFormatIndex(firstFormat);
const size_t secondFormatIndex = ComputeFormatIndex(secondFormat); const size_t secondFormatIndex = ComputeFormatIndex(secondFormat);
@ -272,51 +277,51 @@ namespace dawn_native {
// clang-format off // clang-format off
// 1 byte color formats // 1 byte color formats
AddColorFormat(wgpu::TextureFormat::R8Unorm, true, false, 1, kAnyFloat); AddColorFormat(wgpu::TextureFormat::R8Unorm, true, false, 1, kAnyFloat, 1);
AddColorFormat(wgpu::TextureFormat::R8Snorm, false, false, 1, kAnyFloat); AddColorFormat(wgpu::TextureFormat::R8Snorm, false, false, 1, kAnyFloat, 1);
AddColorFormat(wgpu::TextureFormat::R8Uint, true, false, 1, SampleTypeBit::Uint); AddColorFormat(wgpu::TextureFormat::R8Uint, true, false, 1, SampleTypeBit::Uint, 1);
AddColorFormat(wgpu::TextureFormat::R8Sint, true, false, 1, SampleTypeBit::Sint); AddColorFormat(wgpu::TextureFormat::R8Sint, true, false, 1, SampleTypeBit::Sint, 1);
// 2 bytes color formats // 2 bytes color formats
AddColorFormat(wgpu::TextureFormat::R16Uint, true, false, 2, SampleTypeBit::Uint); AddColorFormat(wgpu::TextureFormat::R16Uint, true, false, 2, SampleTypeBit::Uint, 1);
AddColorFormat(wgpu::TextureFormat::R16Sint, true, false, 2, SampleTypeBit::Sint); AddColorFormat(wgpu::TextureFormat::R16Sint, true, false, 2, SampleTypeBit::Sint, 1);
AddColorFormat(wgpu::TextureFormat::R16Float, true, false, 2, kAnyFloat); AddColorFormat(wgpu::TextureFormat::R16Float, true, false, 2, kAnyFloat, 1);
AddColorFormat(wgpu::TextureFormat::RG8Unorm, true, false, 2, kAnyFloat); AddColorFormat(wgpu::TextureFormat::RG8Unorm, true, false, 2, kAnyFloat, 2);
AddColorFormat(wgpu::TextureFormat::RG8Snorm, false, false, 2, kAnyFloat); AddColorFormat(wgpu::TextureFormat::RG8Snorm, false, false, 2, kAnyFloat, 2);
AddColorFormat(wgpu::TextureFormat::RG8Uint, true, false, 2, SampleTypeBit::Uint); AddColorFormat(wgpu::TextureFormat::RG8Uint, true, false, 2, SampleTypeBit::Uint, 2);
AddColorFormat(wgpu::TextureFormat::RG8Sint, true, false, 2, SampleTypeBit::Sint); AddColorFormat(wgpu::TextureFormat::RG8Sint, true, false, 2, SampleTypeBit::Sint, 2);
// 4 bytes color formats // 4 bytes color formats
AddColorFormat(wgpu::TextureFormat::R32Uint, true, true, 4, SampleTypeBit::Uint); AddColorFormat(wgpu::TextureFormat::R32Uint, true, true, 4, SampleTypeBit::Uint, 1);
AddColorFormat(wgpu::TextureFormat::R32Sint, true, true, 4, SampleTypeBit::Sint); AddColorFormat(wgpu::TextureFormat::R32Sint, true, true, 4, SampleTypeBit::Sint, 1);
AddColorFormat(wgpu::TextureFormat::R32Float, true, true, 4, SampleTypeBit::UnfilterableFloat); AddColorFormat(wgpu::TextureFormat::R32Float, true, true, 4, SampleTypeBit::UnfilterableFloat, 1);
AddColorFormat(wgpu::TextureFormat::RG16Uint, true, false, 4, SampleTypeBit::Uint); AddColorFormat(wgpu::TextureFormat::RG16Uint, true, false, 4, SampleTypeBit::Uint, 2);
AddColorFormat(wgpu::TextureFormat::RG16Sint, true, false, 4, SampleTypeBit::Sint); AddColorFormat(wgpu::TextureFormat::RG16Sint, true, false, 4, SampleTypeBit::Sint, 2);
AddColorFormat(wgpu::TextureFormat::RG16Float, true, false, 4, kAnyFloat); AddColorFormat(wgpu::TextureFormat::RG16Float, true, false, 4, kAnyFloat, 2);
AddColorFormat(wgpu::TextureFormat::RGBA8Unorm, true, true, 4, kAnyFloat); AddColorFormat(wgpu::TextureFormat::RGBA8Unorm, true, true, 4, kAnyFloat, 4);
AddColorFormat(wgpu::TextureFormat::RGBA8UnormSrgb, true, false, 4, kAnyFloat); AddColorFormat(wgpu::TextureFormat::RGBA8UnormSrgb, true, false, 4, kAnyFloat, 4);
AddColorFormat(wgpu::TextureFormat::RGBA8Snorm, false, true, 4, kAnyFloat); AddColorFormat(wgpu::TextureFormat::RGBA8Snorm, false, true, 4, kAnyFloat, 4);
AddColorFormat(wgpu::TextureFormat::RGBA8Uint, true, true, 4, SampleTypeBit::Uint); AddColorFormat(wgpu::TextureFormat::RGBA8Uint, true, true, 4, SampleTypeBit::Uint, 4);
AddColorFormat(wgpu::TextureFormat::RGBA8Sint, true, true, 4, SampleTypeBit::Sint); AddColorFormat(wgpu::TextureFormat::RGBA8Sint, true, true, 4, SampleTypeBit::Sint, 4);
AddColorFormat(wgpu::TextureFormat::BGRA8Unorm, true, false, 4, kAnyFloat); AddColorFormat(wgpu::TextureFormat::BGRA8Unorm, true, false, 4, kAnyFloat, 4);
AddColorFormat(wgpu::TextureFormat::BGRA8UnormSrgb, true, false, 4, kAnyFloat); AddColorFormat(wgpu::TextureFormat::BGRA8UnormSrgb, true, false, 4, kAnyFloat, 4);
AddColorFormat(wgpu::TextureFormat::RGB10A2Unorm, true, false, 4, kAnyFloat); AddColorFormat(wgpu::TextureFormat::RGB10A2Unorm, true, false, 4, kAnyFloat, 4);
AddColorFormat(wgpu::TextureFormat::RG11B10Ufloat, false, false, 4, kAnyFloat); AddColorFormat(wgpu::TextureFormat::RG11B10Ufloat, false, false, 4, kAnyFloat, 3);
AddColorFormat(wgpu::TextureFormat::RGB9E5Ufloat, false, false, 4, kAnyFloat); AddColorFormat(wgpu::TextureFormat::RGB9E5Ufloat, false, false, 4, kAnyFloat, 3);
// 8 bytes color formats // 8 bytes color formats
AddColorFormat(wgpu::TextureFormat::RG32Uint, true, true, 8, SampleTypeBit::Uint); AddColorFormat(wgpu::TextureFormat::RG32Uint, true, true, 8, SampleTypeBit::Uint, 2);
AddColorFormat(wgpu::TextureFormat::RG32Sint, true, true, 8, SampleTypeBit::Sint); AddColorFormat(wgpu::TextureFormat::RG32Sint, true, true, 8, SampleTypeBit::Sint, 2);
AddColorFormat(wgpu::TextureFormat::RG32Float, true, true, 8, SampleTypeBit::UnfilterableFloat); AddColorFormat(wgpu::TextureFormat::RG32Float, true, true, 8, SampleTypeBit::UnfilterableFloat, 2);
AddColorFormat(wgpu::TextureFormat::RGBA16Uint, true, true, 8, SampleTypeBit::Uint); AddColorFormat(wgpu::TextureFormat::RGBA16Uint, true, true, 8, SampleTypeBit::Uint, 4);
AddColorFormat(wgpu::TextureFormat::RGBA16Sint, true, true, 8, SampleTypeBit::Sint); AddColorFormat(wgpu::TextureFormat::RGBA16Sint, true, true, 8, SampleTypeBit::Sint, 4);
AddColorFormat(wgpu::TextureFormat::RGBA16Float, true, true, 8, kAnyFloat); AddColorFormat(wgpu::TextureFormat::RGBA16Float, true, true, 8, kAnyFloat, 4);
// 16 bytes color formats // 16 bytes color formats
AddColorFormat(wgpu::TextureFormat::RGBA32Uint, true, true, 16, SampleTypeBit::Uint); AddColorFormat(wgpu::TextureFormat::RGBA32Uint, true, true, 16, SampleTypeBit::Uint, 4);
AddColorFormat(wgpu::TextureFormat::RGBA32Sint, true, true, 16, SampleTypeBit::Sint); AddColorFormat(wgpu::TextureFormat::RGBA32Sint, true, true, 16, SampleTypeBit::Sint, 4);
AddColorFormat(wgpu::TextureFormat::RGBA32Float, true, true, 16, SampleTypeBit::UnfilterableFloat); AddColorFormat(wgpu::TextureFormat::RGBA32Float, true, true, 16, SampleTypeBit::UnfilterableFloat, 4);
// Depth-stencil formats // Depth-stencil formats
AddDepthFormat(wgpu::TextureFormat::Depth32Float, 4); AddDepthFormat(wgpu::TextureFormat::Depth32Float, 4);
@ -327,30 +332,30 @@ namespace dawn_native {
// TODO(dawn:666): Implement the stencil8 format // TODO(dawn:666): Implement the stencil8 format
AddStencilFormat(wgpu::TextureFormat::Stencil8); AddStencilFormat(wgpu::TextureFormat::Stencil8);
AddMultiAspectFormat(wgpu::TextureFormat::Depth24PlusStencil8, AddMultiAspectFormat(wgpu::TextureFormat::Depth24PlusStencil8,
Aspect::Depth | Aspect::Stencil, wgpu::TextureFormat::Depth24Plus, wgpu::TextureFormat::Stencil8, true, true); Aspect::Depth | Aspect::Stencil, wgpu::TextureFormat::Depth24Plus, wgpu::TextureFormat::Stencil8, true, true, 2);
// TODO(dawn:690): Implement Depth16Unorm, Depth24UnormStencil8, Depth32FloatStencil8. // TODO(dawn:690): Implement Depth16Unorm, Depth24UnormStencil8, Depth32FloatStencil8.
// BC compressed formats // BC compressed formats
bool isBCFormatSupported = device->IsExtensionEnabled(Extension::TextureCompressionBC); bool isBCFormatSupported = device->IsExtensionEnabled(Extension::TextureCompressionBC);
AddCompressedFormat(wgpu::TextureFormat::BC1RGBAUnorm, 8, 4, 4, isBCFormatSupported); AddCompressedFormat(wgpu::TextureFormat::BC1RGBAUnorm, 8, 4, 4, isBCFormatSupported, 4);
AddCompressedFormat(wgpu::TextureFormat::BC1RGBAUnormSrgb, 8, 4, 4, isBCFormatSupported); AddCompressedFormat(wgpu::TextureFormat::BC1RGBAUnormSrgb, 8, 4, 4, isBCFormatSupported, 4);
AddCompressedFormat(wgpu::TextureFormat::BC4RSnorm, 8, 4, 4, isBCFormatSupported); AddCompressedFormat(wgpu::TextureFormat::BC4RSnorm, 8, 4, 4, isBCFormatSupported, 1);
AddCompressedFormat(wgpu::TextureFormat::BC4RUnorm, 8, 4, 4, isBCFormatSupported); AddCompressedFormat(wgpu::TextureFormat::BC4RUnorm, 8, 4, 4, isBCFormatSupported, 1);
AddCompressedFormat(wgpu::TextureFormat::BC2RGBAUnorm, 16, 4, 4, isBCFormatSupported); AddCompressedFormat(wgpu::TextureFormat::BC2RGBAUnorm, 16, 4, 4, isBCFormatSupported, 4);
AddCompressedFormat(wgpu::TextureFormat::BC2RGBAUnormSrgb, 16, 4, 4, isBCFormatSupported); AddCompressedFormat(wgpu::TextureFormat::BC2RGBAUnormSrgb, 16, 4, 4, isBCFormatSupported, 4);
AddCompressedFormat(wgpu::TextureFormat::BC3RGBAUnorm, 16, 4, 4, isBCFormatSupported); AddCompressedFormat(wgpu::TextureFormat::BC3RGBAUnorm, 16, 4, 4, isBCFormatSupported, 4);
AddCompressedFormat(wgpu::TextureFormat::BC3RGBAUnormSrgb, 16, 4, 4, isBCFormatSupported); AddCompressedFormat(wgpu::TextureFormat::BC3RGBAUnormSrgb, 16, 4, 4, isBCFormatSupported, 4);
AddCompressedFormat(wgpu::TextureFormat::BC5RGSnorm, 16, 4, 4, isBCFormatSupported); AddCompressedFormat(wgpu::TextureFormat::BC5RGSnorm, 16, 4, 4, isBCFormatSupported, 2);
AddCompressedFormat(wgpu::TextureFormat::BC5RGUnorm, 16, 4, 4, isBCFormatSupported); AddCompressedFormat(wgpu::TextureFormat::BC5RGUnorm, 16, 4, 4, isBCFormatSupported, 2);
AddCompressedFormat(wgpu::TextureFormat::BC6HRGBFloat, 16, 4, 4, isBCFormatSupported); AddCompressedFormat(wgpu::TextureFormat::BC6HRGBFloat, 16, 4, 4, isBCFormatSupported, 3);
AddCompressedFormat(wgpu::TextureFormat::BC6HRGBUfloat, 16, 4, 4, isBCFormatSupported); AddCompressedFormat(wgpu::TextureFormat::BC6HRGBUfloat, 16, 4, 4, isBCFormatSupported, 3);
AddCompressedFormat(wgpu::TextureFormat::BC7RGBAUnorm, 16, 4, 4, isBCFormatSupported); AddCompressedFormat(wgpu::TextureFormat::BC7RGBAUnorm, 16, 4, 4, isBCFormatSupported, 4);
AddCompressedFormat(wgpu::TextureFormat::BC7RGBAUnormSrgb, 16, 4, 4, isBCFormatSupported); AddCompressedFormat(wgpu::TextureFormat::BC7RGBAUnormSrgb, 16, 4, 4, isBCFormatSupported, 4);
// multi-planar formats // multi-planar formats
const bool isMultiPlanarFormatSupported = device->IsExtensionEnabled(Extension::MultiPlanarFormats); const bool isMultiPlanarFormatSupported = device->IsExtensionEnabled(Extension::MultiPlanarFormats);
AddMultiAspectFormat(wgpu::TextureFormat::R8BG8Biplanar420Unorm, Aspect::Plane0 | Aspect::Plane1, AddMultiAspectFormat(wgpu::TextureFormat::R8BG8Biplanar420Unorm, Aspect::Plane0 | Aspect::Plane1,
wgpu::TextureFormat::R8Unorm, wgpu::TextureFormat::RG8Unorm, false, isMultiPlanarFormatSupported); wgpu::TextureFormat::R8Unorm, wgpu::TextureFormat::RG8Unorm, false, isMultiPlanarFormatSupported, 3);
// clang-format on // clang-format on

View File

@ -91,6 +91,8 @@ namespace dawn_native {
bool isSupported; bool isSupported;
bool supportsStorageUsage; bool supportsStorageUsage;
Aspect aspects; Aspect aspects;
// Only used for renderable color formats, number of color channels.
uint8_t componentCount;
bool IsColor() const; bool IsColor() const;
bool HasDepth() const; bool HasDepth() const;

View File

@ -253,10 +253,22 @@ namespace dawn_native {
return {}; return {};
} }
MaybeError ValidateColorTargetState(DeviceBase* device, bool BlendFactorContainsSrcAlpha(const wgpu::BlendFactor& blendFactor) {
return blendFactor == wgpu::BlendFactor::SrcAlpha ||
blendFactor == wgpu::BlendFactor::OneMinusSrcAlpha ||
blendFactor == wgpu::BlendFactor::SrcAlphaSaturated;
}
bool BlendFactorContainsSrc(const wgpu::BlendFactor& blendFactor) {
return blendFactor == wgpu::BlendFactor::Src ||
blendFactor == wgpu::BlendFactor::OneMinusSrc;
}
MaybeError ValidateColorTargetState(
DeviceBase* device,
const ColorTargetState* descriptor, const ColorTargetState* descriptor,
bool fragmentWritten, bool fragmentWritten,
wgpu::TextureComponentType fragmentOutputBaseType) { const EntryPointMetadata::FragmentOutputVariableInfo& fragmentOutputVariable) {
if (descriptor->nextInChain != nullptr) { if (descriptor->nextInChain != nullptr) {
return DAWN_VALIDATION_ERROR("nextInChain must be nullptr"); return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
} }
@ -278,10 +290,37 @@ namespace dawn_native {
"Color format must be blendable when blending is enabled"); "Color format must be blendable when blending is enabled");
} }
if (fragmentWritten) { if (fragmentWritten) {
if (fragmentOutputBaseType != format->GetAspectInfo(Aspect::Color).baseType) { if (fragmentOutputVariable.baseType !=
format->GetAspectInfo(Aspect::Color).baseType) {
return DAWN_VALIDATION_ERROR( return DAWN_VALIDATION_ERROR(
"Color format must match the fragment stage output type"); "Color format must match the fragment stage output type");
} }
if (fragmentOutputVariable.componentCount < format->componentCount) {
return DAWN_VALIDATION_ERROR(
"The fragment stage output components count must be no fewer than the "
"color format channel count");
}
if (descriptor->blend) {
if (fragmentOutputVariable.componentCount < 4u) {
// No alpha channel output
// Make sure there's no alpha involved in the blending operation
if (BlendFactorContainsSrcAlpha(descriptor->blend->color.srcFactor) ||
BlendFactorContainsSrcAlpha(descriptor->blend->color.dstFactor)) {
return DAWN_VALIDATION_ERROR(
"Color blending factor is reading alpha but it is missing from "
"fragment output");
}
if (descriptor->blend->alpha.srcFactor != wgpu::BlendFactor::Zero ||
BlendFactorContainsSrc(descriptor->blend->alpha.dstFactor) ||
BlendFactorContainsSrcAlpha(descriptor->blend->alpha.dstFactor)) {
return DAWN_VALIDATION_ERROR(
"Alpha blending factor is reading alpha but it is missing from "
"fragment output");
}
}
}
} else { } else {
if (descriptor->writeMask != wgpu::ColorWriteMask::None) { if (descriptor->writeMask != wgpu::ColorWriteMask::None) {
return DAWN_VALIDATION_ERROR( return DAWN_VALIDATION_ERROR(
@ -311,10 +350,10 @@ namespace dawn_native {
descriptor->module->GetEntryPoint(descriptor->entryPoint); descriptor->module->GetEntryPoint(descriptor->entryPoint);
for (ColorAttachmentIndex i(uint8_t(0)); for (ColorAttachmentIndex i(uint8_t(0));
i < ColorAttachmentIndex(static_cast<uint8_t>(descriptor->targetCount)); ++i) { i < ColorAttachmentIndex(static_cast<uint8_t>(descriptor->targetCount)); ++i) {
DAWN_TRY( DAWN_TRY(ValidateColorTargetState(device,
ValidateColorTargetState(device, &descriptor->targets[static_cast<uint8_t>(i)], &descriptor->targets[static_cast<uint8_t>(i)],
fragmentMetadata.fragmentOutputsWritten[i], fragmentMetadata.fragmentOutputsWritten[i],
fragmentMetadata.fragmentOutputFormatBaseTypes[i])); fragmentMetadata.fragmentOutputVariables[i]));
} }
return {}; return {};

View File

@ -875,8 +875,16 @@ namespace dawn_native {
ColorAttachmentIndex attachment( ColorAttachmentIndex attachment(
static_cast<uint8_t>(unsanitizedAttachment)); static_cast<uint8_t>(unsanitizedAttachment));
DAWN_TRY_ASSIGN( DAWN_TRY_ASSIGN(
metadata->fragmentOutputFormatBaseTypes[attachment], metadata->fragmentOutputVariables[attachment].baseType,
TintComponentTypeToTextureComponentType(output_var.component_type)); TintComponentTypeToTextureComponentType(output_var.component_type));
uint32_t componentCount;
DAWN_TRY_ASSIGN(componentCount,
TintCompositionTypeToInterStageComponentCount(
output_var.composition_type));
// componentCount should be no larger than 4u
ASSERT(componentCount <= 4u);
metadata->fragmentOutputVariables[attachment].componentCount =
componentCount;
metadata->fragmentOutputsWritten.set(attachment); metadata->fragmentOutputsWritten.set(attachment);
} }
} }

View File

@ -173,8 +173,12 @@ namespace dawn_native {
ityp::bitset<VertexAttributeLocation, kMaxVertexAttributes> usedVertexInputs; ityp::bitset<VertexAttributeLocation, kMaxVertexAttributes> usedVertexInputs;
// An array to record the basic types (float, int and uint) of the fragment shader outputs. // An array to record the basic types (float, int and uint) of the fragment shader outputs.
ityp::array<ColorAttachmentIndex, wgpu::TextureComponentType, kMaxColorAttachments> struct FragmentOutputVariableInfo {
fragmentOutputFormatBaseTypes; wgpu::TextureComponentType baseType;
uint8_t componentCount;
};
ityp::array<ColorAttachmentIndex, FragmentOutputVariableInfo, kMaxColorAttachments>
fragmentOutputVariables;
ityp::bitset<ColorAttachmentIndex, kMaxColorAttachments> fragmentOutputsWritten; ityp::bitset<ColorAttachmentIndex, kMaxColorAttachments> fragmentOutputsWritten;
struct InterStageVariableInfo { struct InterStageVariableInfo {

View File

@ -288,8 +288,9 @@ namespace dawn_native { namespace opengl {
spirv_cross::SPIRType::BaseType shaderFragmentOutputBaseType = spirv_cross::SPIRType::BaseType shaderFragmentOutputBaseType =
compiler.get_type(fragmentOutput.base_type_id).basetype; compiler.get_type(fragmentOutput.base_type_id).basetype;
metadata->fragmentOutputFormatBaseTypes[attachment] = // spriv path so temporarily always set to 4u to always pass validation
SpirvBaseTypeToTextureComponentType(shaderFragmentOutputBaseType); metadata->fragmentOutputVariables[attachment] = {
SpirvBaseTypeToTextureComponentType(shaderFragmentOutputBaseType), 4u};
metadata->fragmentOutputsWritten.set(attachment); metadata->fragmentOutputsWritten.set(attachment);
} }
} }

View File

@ -47,6 +47,14 @@ class RenderPipelineValidationTest : public ValidationTest {
wgpu::ShaderModule fsModuleUint; wgpu::ShaderModule fsModuleUint;
}; };
namespace {
bool BlendFactorContainsSrcAlpha(const wgpu::BlendFactor& blendFactor) {
return blendFactor == wgpu::BlendFactor::SrcAlpha ||
blendFactor == wgpu::BlendFactor::OneMinusSrcAlpha ||
blendFactor == wgpu::BlendFactor::SrcAlphaSaturated;
}
} // namespace
// Test cases where creation should succeed // Test cases where creation should succeed
TEST_F(RenderPipelineValidationTest, CreationSuccess) { TEST_F(RenderPipelineValidationTest, CreationSuccess) {
{ {
@ -216,18 +224,14 @@ TEST_F(RenderPipelineValidationTest, NonBlendableFormat) {
// Tests that the format of the color state descriptor must match the output of the fragment shader. // Tests that the format of the color state descriptor must match the output of the fragment shader.
TEST_F(RenderPipelineValidationTest, FragmentOutputFormatCompatibility) { TEST_F(RenderPipelineValidationTest, FragmentOutputFormatCompatibility) {
constexpr uint32_t kNumTextureFormatBaseType = 3u; std::array<const char*, 3> kScalarTypes = {{"f32", "i32", "u32"}};
std::array<const char*, kNumTextureFormatBaseType> kScalarTypes = {{"f32", "i32", "u32"}}; std::array<wgpu::TextureFormat, 3> kColorFormats = {{wgpu::TextureFormat::RGBA8Unorm,
std::array<wgpu::TextureFormat, kNumTextureFormatBaseType> kColorFormats = { wgpu::TextureFormat::RGBA8Sint,
{wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureFormat::RGBA8Sint,
wgpu::TextureFormat::RGBA8Uint}}; wgpu::TextureFormat::RGBA8Uint}};
for (size_t i = 0; i < kNumTextureFormatBaseType; ++i) { for (size_t i = 0; i < kScalarTypes.size(); ++i) {
for (size_t j = 0; j < kNumTextureFormatBaseType; ++j) {
utils::ComboRenderPipelineDescriptor descriptor; utils::ComboRenderPipelineDescriptor descriptor;
descriptor.vertex.module = vsModule; descriptor.vertex.module = vsModule;
descriptor.cTargets[0].format = kColorFormats[j];
std::ostringstream stream; std::ostringstream stream;
stream << R"( stream << R"(
[[stage(fragment)]] fn main() -> [[location(0)]] vec4<)" [[stage(fragment)]] fn main() -> [[location(0)]] vec4<)"
@ -238,6 +242,8 @@ TEST_F(RenderPipelineValidationTest, FragmentOutputFormatCompatibility) {
})"; })";
descriptor.cFragment.module = utils::CreateShaderModule(device, stream.str().c_str()); descriptor.cFragment.module = utils::CreateShaderModule(device, stream.str().c_str());
for (size_t j = 0; j < kColorFormats.size(); ++j) {
descriptor.cTargets[0].format = kColorFormats[j];
if (i == j) { if (i == j) {
device.CreateRenderPipeline(&descriptor); device.CreateRenderPipeline(&descriptor);
} else { } else {
@ -247,6 +253,110 @@ TEST_F(RenderPipelineValidationTest, FragmentOutputFormatCompatibility) {
} }
} }
// Tests that the component count of the color state target format must be fewer than that of the
// fragment shader output.
TEST_F(RenderPipelineValidationTest, FragmentOutputComponentCountCompatibility) {
std::array<wgpu::TextureFormat, 3> kColorFormats = {wgpu::TextureFormat::R8Unorm,
wgpu::TextureFormat::RG8Unorm,
wgpu::TextureFormat::RGBA8Unorm};
std::array<wgpu::BlendFactor, 8> kBlendFactors = {wgpu::BlendFactor::Zero,
wgpu::BlendFactor::One,
wgpu::BlendFactor::SrcAlpha,
wgpu::BlendFactor::OneMinusSrcAlpha,
wgpu::BlendFactor::Src,
wgpu::BlendFactor::DstAlpha,
wgpu::BlendFactor::OneMinusDstAlpha,
wgpu::BlendFactor::Dst};
for (size_t componentCount = 1; componentCount <= 4; ++componentCount) {
utils::ComboRenderPipelineDescriptor descriptor;
descriptor.vertex.module = vsModule;
std::ostringstream stream;
stream << R"(
[[stage(fragment)]] fn main() -> [[location(0)]] )";
switch (componentCount) {
case 1:
stream << R"(f32 {
return 1.0;
})";
break;
case 2:
stream << R"(vec2<f32> {
return vec2<f32>(1.0, 1.0);
})";
break;
case 3:
stream << R"(vec3<f32> {
return vec3<f32>(1.0, 1.0, 1.0);
})";
break;
case 4:
stream << R"(vec4<f32> {
return vec4<f32>(1.0, 1.0, 1.0, 1.0);
})";
break;
default:
UNREACHABLE();
}
descriptor.cFragment.module = utils::CreateShaderModule(device, stream.str().c_str());
for (auto colorFormat : kColorFormats) {
descriptor.cTargets[0].format = colorFormat;
descriptor.cTargets[0].blend = nullptr;
if (componentCount >= utils::GetWGSLRenderableColorTextureComponentCount(colorFormat)) {
device.CreateRenderPipeline(&descriptor);
} else {
ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
}
descriptor.cTargets[0].blend = &descriptor.cBlends[0];
for (auto colorSrcFactor : kBlendFactors) {
descriptor.cBlends[0].color.srcFactor = colorSrcFactor;
for (auto colorDstFactor : kBlendFactors) {
descriptor.cBlends[0].color.dstFactor = colorDstFactor;
for (auto alphaSrcFactor : kBlendFactors) {
descriptor.cBlends[0].alpha.srcFactor = alphaSrcFactor;
for (auto alphaDstFactor : kBlendFactors) {
descriptor.cBlends[0].alpha.dstFactor = alphaDstFactor;
bool valid = true;
if (componentCount >=
utils::GetWGSLRenderableColorTextureComponentCount(colorFormat)) {
if (BlendFactorContainsSrcAlpha(
descriptor.cTargets[0].blend->color.srcFactor) ||
BlendFactorContainsSrcAlpha(
descriptor.cTargets[0].blend->color.dstFactor) ||
descriptor.cTargets[0].blend->alpha.srcFactor !=
wgpu::BlendFactor::Zero ||
descriptor.cTargets[0].blend->alpha.dstFactor ==
wgpu::BlendFactor::Src ||
descriptor.cTargets[0].blend->alpha.dstFactor ==
wgpu::BlendFactor::OneMinusSrc ||
BlendFactorContainsSrcAlpha(
descriptor.cTargets[0].blend->alpha.dstFactor)) {
valid = componentCount == 4;
}
} else {
valid = false;
}
if (valid) {
device.CreateRenderPipeline(&descriptor);
} else {
ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
}
}
}
}
}
}
}
}
/// Tests that the sample count of the render pipeline must be valid. /// Tests that the sample count of the render pipeline must be valid.
TEST_F(RenderPipelineValidationTest, SampleCount) { TEST_F(RenderPipelineValidationTest, SampleCount) {
{ {

View File

@ -449,8 +449,8 @@ TEST_P(D3D12DescriptorHeapTests, EncodeManyUBO) {
}; };
[[group(0), binding(0)]] var<uniform> buffer0 : U; [[group(0), binding(0)]] var<uniform> buffer0 : U;
[[stage(fragment)]] fn main() -> [[location(0)]] f32 { [[stage(fragment)]] fn main() -> [[location(0)]] vec4<f32> {
return buffer0.heapSize; return vec4<f32>(buffer0.heapSize, 0.0, 0.0, 1.0);
})"); })");
wgpu::BlendState blend; wgpu::BlendState blend;

View File

@ -304,6 +304,47 @@ namespace utils {
} }
} }
uint32_t GetWGSLRenderableColorTextureComponentCount(wgpu::TextureFormat textureFormat) {
switch (textureFormat) {
case wgpu::TextureFormat::R8Unorm:
case wgpu::TextureFormat::R8Uint:
case wgpu::TextureFormat::R8Sint:
case wgpu::TextureFormat::R16Uint:
case wgpu::TextureFormat::R16Sint:
case wgpu::TextureFormat::R16Float:
case wgpu::TextureFormat::R32Float:
case wgpu::TextureFormat::R32Uint:
case wgpu::TextureFormat::R32Sint:
return 1u;
case wgpu::TextureFormat::RG8Unorm:
case wgpu::TextureFormat::RG8Uint:
case wgpu::TextureFormat::RG8Sint:
case wgpu::TextureFormat::RG16Uint:
case wgpu::TextureFormat::RG16Sint:
case wgpu::TextureFormat::RG16Float:
case wgpu::TextureFormat::RG32Float:
case wgpu::TextureFormat::RG32Uint:
case wgpu::TextureFormat::RG32Sint:
return 2u;
case wgpu::TextureFormat::RGBA8Unorm:
case wgpu::TextureFormat::RGBA8UnormSrgb:
case wgpu::TextureFormat::RGBA8Uint:
case wgpu::TextureFormat::RGBA8Sint:
case wgpu::TextureFormat::BGRA8Unorm:
case wgpu::TextureFormat::BGRA8UnormSrgb:
case wgpu::TextureFormat::RGB10A2Unorm:
case wgpu::TextureFormat::RGBA16Uint:
case wgpu::TextureFormat::RGBA16Sint:
case wgpu::TextureFormat::RGBA16Float:
case wgpu::TextureFormat::RGBA32Float:
case wgpu::TextureFormat::RGBA32Uint:
case wgpu::TextureFormat::RGBA32Sint:
return 4u;
default:
UNREACHABLE();
}
}
const char* GetWGSLImageFormatQualifier(wgpu::TextureFormat textureFormat) { const char* GetWGSLImageFormatQualifier(wgpu::TextureFormat textureFormat) {
switch (textureFormat) { switch (textureFormat) {
case wgpu::TextureFormat::RGBA8Unorm: case wgpu::TextureFormat::RGBA8Unorm:

View File

@ -95,6 +95,7 @@ namespace utils {
const char* GetWGSLColorTextureComponentType(wgpu::TextureFormat textureFormat); const char* GetWGSLColorTextureComponentType(wgpu::TextureFormat textureFormat);
const char* GetWGSLImageFormatQualifier(wgpu::TextureFormat textureFormat); const char* GetWGSLImageFormatQualifier(wgpu::TextureFormat textureFormat);
uint32_t GetWGSLRenderableColorTextureComponentCount(wgpu::TextureFormat textureFormat);
wgpu::TextureDimension ViewDimensionToTextureDimension( wgpu::TextureDimension ViewDimensionToTextureDimension(
const wgpu::TextureViewDimension dimension); const wgpu::TextureViewDimension dimension);