diff --git a/src/dawn/native/CommandBufferStateTracker.cpp b/src/dawn/native/CommandBufferStateTracker.cpp index 91985f1fdf..245f3a46a4 100644 --- a/src/dawn/native/CommandBufferStateTracker.cpp +++ b/src/dawn/native/CommandBufferStateTracker.cpp @@ -425,6 +425,7 @@ MaybeError CommandBufferStateTracker::CheckMissingAspects(ValidationAspects aspe } if (aspects[VALIDATION_ASPECT_VERTEX_BUFFERS]) { + // Try to be helpful by finding one missing vertex buffer to surface in the error message. const ityp::bitset missingVertexBuffers = GetRenderPipeline()->GetVertexBufferSlotsUsed() & ~mVertexBufferSlotsUsed; ASSERT(missingVertexBuffers.any()); diff --git a/src/dawn/native/RenderPipeline.cpp b/src/dawn/native/RenderPipeline.cpp index ef234d216d..e47a8d7a43 100644 --- a/src/dawn/native/RenderPipeline.cpp +++ b/src/dawn/native/RenderPipeline.cpp @@ -157,9 +157,20 @@ MaybeError ValidateVertexState(DeviceBase* device, // attribute number never exceed kMaxVertexAttributes. ASSERT(totalAttributesNum <= kMaxVertexAttributes); - // TODO(dawn:563): Specify which inputs were not used in error message. - DAWN_INVALID_IF(!IsSubset(vertexMetadata.usedVertexInputs, attributesSetMask), - "Pipeline vertex stage uses vertex buffers not in the vertex state"); + // Validate that attributes used by the VertexState are in the shader using bitmask operations + // but try to be helpful by finding one missing attribute to surface in the error message + if (!IsSubset(vertexMetadata.usedVertexInputs, attributesSetMask)) { + const ityp::bitset missingAttributes = + vertexMetadata.usedVertexInputs & ~attributesSetMask; + ASSERT(missingAttributes.any()); + + VertexAttributeLocation firstMissing = ityp::Sub( + GetHighestBitIndexPlusOne(missingAttributes), VertexAttributeLocation(uint8_t(1))); + return DAWN_VALIDATION_ERROR( + "Vertex attribute slot %u used in (%s, entryPoint: %s) is not present in the " + "VertexState.", + uint8_t(firstMissing), descriptor->module, descriptor->entryPoint); + } return {}; } diff --git a/src/dawn/native/ShaderModule.cpp b/src/dawn/native/ShaderModule.cpp index 48ad17fbb1..4143457cc1 100644 --- a/src/dawn/native/ShaderModule.cpp +++ b/src/dawn/native/ShaderModule.cpp @@ -395,21 +395,18 @@ MaybeError ValidateCompatibilityOfSingleBindingWithLayout(const DeviceBase* devi BindingIndex bindingIndex(bindingIt->second); const BindingInfo& layoutInfo = layout->GetBindingInfo(bindingIndex); - // TODO(dawn:563): Provide info about the binding types. - DAWN_INVALID_IF( - layoutInfo.bindingType != shaderInfo.bindingType, - "Binding type (buffer vs. texture vs. sampler vs. external) doesn't match the type " - "in the layout."); + DAWN_INVALID_IF(layoutInfo.bindingType != shaderInfo.bindingType, + "Binding type in the shader (%s) doesn't match the type in the layout (%s).", + shaderInfo.bindingType, layoutInfo.bindingType); ExternalTextureBindingExpansionMap expansions = layout->GetExternalTextureBindingExpansionMap(); DAWN_INVALID_IF(expansions.find(bindingNumber) != expansions.end(), "Binding type (buffer vs. texture vs. sampler vs. external) doesn't " "match the type in the layout."); - // TODO(dawn:563): Provide info about the visibility. DAWN_INVALID_IF((layoutInfo.visibility & StageBit(entryPointStage)) == 0, - "Entry point's stage is not in the binding visibility in the layout (%s)", - layoutInfo.visibility); + "Entry point's stage (%s) is not in the binding visibility in the layout (%s).", + StageBit(entryPointStage), layoutInfo.visibility); switch (layoutInfo.bindingType) { case BindingInfoType::Texture: {