diff --git a/dawn.json b/dawn.json index bccd3b59ca..81fb547009 100644 --- a/dawn.json +++ b/dawn.json @@ -205,7 +205,7 @@ {"value": 9, "name": "writeonly storage texture"} ] }, - "blend descriptor": { + "blend component": { "category": "structure", "extensible": false, "members": [ @@ -214,6 +214,10 @@ {"name": "dst factor", "type": "blend factor", "default": "zero"} ] }, + "blend descriptor": { + "category": "typedef", + "type": "blend component" + }, "blend factor": { "category": "enum", "values": [ @@ -247,8 +251,8 @@ "extensible": true, "members": [ {"name": "format", "type": "texture format"}, - {"name": "alpha blend", "type": "blend descriptor"}, - {"name": "color blend", "type": "blend descriptor"}, + {"name": "alpha blend", "type": "blend component"}, + {"name": "color blend", "type": "blend component"}, {"name": "write mask", "type": "color write mask", "default": "all"} ] }, @@ -718,6 +722,13 @@ {"name": "descriptor", "type": "render pipeline descriptor", "annotation": "const*"} ] }, + { + "name": "create render pipeline 2", + "returns": "render pipeline", + "args": [ + {"name": "descriptor", "type": "render pipeline descriptor 2", "annotation": "const*"} + ] + }, { "name": "create sampler", "returns": "sampler", @@ -824,8 +835,8 @@ {"name": "format", "type": "texture format"}, {"name": "depth write enabled", "type": "bool", "default": "false"}, {"name": "depth compare", "type": "compare function", "default": "always"}, - {"name": "stencil front", "type": "stencil state face descriptor"}, - {"name": "stencil back", "type": "stencil state face descriptor"}, + {"name": "stencil front", "type": "stencil face state"}, + {"name": "stencil back", "type": "stencil face state"}, {"name": "stencil read mask", "type": "uint32_t", "default": "0xFFFFFFFF"}, {"name": "stencil write mask", "type": "uint32_t", "default": "0xFFFFFFFF"} ] @@ -1539,6 +1550,84 @@ } ] }, + + "vertex state": { + "category": "structure", + "extensible": true, + "members": [ + {"name": "module", "type": "shader module"}, + {"name": "entry point", "type": "char", "annotation": "const*", "length": "strlen"}, + {"name": "buffer count", "type": "uint32_t"}, + {"name": "buffers", "type": "vertex buffer layout", "annotation": "const*", "length": "buffer count"} + ] + }, + + "primitive state": { + "category": "structure", + "extensible": true, + "members": [ + {"name": "topology", "type": "primitive topology", "default": "triangle list"}, + {"name": "strip index format", "type": "index format", "default": "undefined"}, + {"name": "front face", "type": "front face", "default": "CCW"}, + {"name": "cull mode", "type": "cull mode", "default": "none"} + ] + }, + + "depth stencil state": { + "category": "structure", + "extensible": true, + "members": [ + {"name": "format", "type": "texture format"}, + {"name": "depth write enabled", "type": "bool", "default": "false"}, + {"name": "depth compare", "type": "compare function", "default": "always"}, + {"name": "stencil front", "type": "stencil face state"}, + {"name": "stencil back", "type": "stencil face state"}, + {"name": "stencil read mask", "type": "uint32_t", "default": "0xFFFFFFFF"}, + {"name": "stencil write mask", "type": "uint32_t", "default": "0xFFFFFFFF"}, + {"name": "depth bias", "type": "int32_t", "default": "0"}, + {"name": "depth bias slope scale", "type": "float", "default": "0.0f"}, + {"name": "depth bias clamp", "type": "float", "default": "0.0f"} + ] + }, + + "multisample state": { + "category": "structure", + "extensible": true, + "members": [ + {"name": "count", "type": "uint32_t", "default": "1"}, + {"name": "mask", "type": "uint32_t", "default": "0xFFFFFFFF"}, + {"name": "alpha to coverage enabled", "type": "bool", "default": "false"} + ] + }, + + "fragment state": { + "category": "structure", + "extensible": true, + "members": [ + {"name": "module", "type": "shader module"}, + {"name": "entry point", "type": "char", "annotation": "const*", "length": "strlen"}, + {"name": "target count", "type": "uint32_t"}, + {"name": "targets", "type": "color target state", "annotation": "const*", "length": "target count"} + ] + }, + "color target state": { + "category": "structure", + "extensible": true, + "members": [ + {"name": "format", "type": "texture format"}, + {"name": "blend", "type": "blend state", "annotation": "const*", "optional": true}, + {"name": "write mask", "type": "color write mask", "default": "all"} + ] + }, + "blend state": { + "category": "structure", + "extensible": false, + "members": [ + {"name": "color", "type": "blend component"}, + {"name": "alpha", "type": "blend component"} + ] + }, + "render pipeline descriptor": { "category": "structure", "extensible": true, @@ -1558,6 +1647,21 @@ {"name": "alpha to coverage enabled", "type": "bool", "default": "false"} ] }, + + "render pipeline descriptor 2": { + "category": "structure", + "extensible": true, + "members": [ + {"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true}, + {"name": "layout", "type": "pipeline layout", "optional": true}, + {"name": "vertex", "type": "vertex state"}, + {"name": "primitive", "type": "primitive state"}, + {"name": "depth stencil", "type": "depth stencil state", "annotation": "const*", "optional": true}, + {"name": "multisample", "type": "multisample state"}, + {"name": "fragment", "type": "fragment state", "annotation": "const*", "optional": true} + ] + }, + "render pipeline descriptor dummy extension": { "category": "structure", "chained": true, @@ -1639,7 +1743,7 @@ {"value": 7, "name": "decrement wrap"} ] }, - "stencil state face descriptor": { + "stencil face state": { "category": "structure", "extensible": false, "members": [ @@ -1649,6 +1753,10 @@ {"name": "pass op", "type": "stencil operation", "default": "keep"} ] }, + "stencil state face descriptor": { + "category": "typedef", + "type": "stencil face state" + }, "surface": { "category": "object" }, diff --git a/src/dawn_native/Device.cpp b/src/dawn_native/Device.cpp index 8102600571..768350c5d6 100644 --- a/src/dawn_native/Device.cpp +++ b/src/dawn_native/Device.cpp @@ -797,6 +797,22 @@ namespace dawn_native { const RenderPipelineDescriptor* descriptor) { RenderPipelineBase* result = nullptr; + // TODO: Enable this warning once the tests have been converted to either use the new + // format or expect the deprecation warning. + /*EmitDeprecationWarning( + "The format of RenderPipelineDescriptor has changed, and will soon require the " + "new structure. Please begin using CreateRenderPipeline2() instead.");*/ + + if (ConsumedError(CreateRenderPipelineInternal(&result, descriptor))) { + return RenderPipelineBase::MakeError(this); + } + + return result; + } + RenderPipelineBase* DeviceBase::CreateRenderPipeline2( + const RenderPipelineDescriptor2* descriptor) { + RenderPipelineBase* result = nullptr; + if (ConsumedError(CreateRenderPipelineInternal(&result, descriptor))) { return RenderPipelineBase::MakeError(this); } @@ -1056,10 +1072,93 @@ namespace dawn_native { return {}; } + MaybeError DeviceBase::CreateRenderPipelineInternal( + RenderPipelineBase** result, + const RenderPipelineDescriptor2* descriptor) { + // Convert descriptor to the older format it before proceeding. + // TODO: Convert the rest of the code to operate on the newer format. + RenderPipelineDescriptor normalizedDescriptor; + + VertexStateDescriptor vertexState; + normalizedDescriptor.vertexState = &vertexState; + + RasterizationStateDescriptor rasterizationState; + normalizedDescriptor.rasterizationState = &rasterizationState; + + normalizedDescriptor.label = descriptor->label; + normalizedDescriptor.layout = descriptor->layout; + normalizedDescriptor.vertexStage.module = descriptor->vertex.module; + normalizedDescriptor.vertexStage.entryPoint = descriptor->vertex.entryPoint; + normalizedDescriptor.primitiveTopology = descriptor->primitive.topology; + normalizedDescriptor.sampleCount = descriptor->multisample.count; + normalizedDescriptor.sampleMask = descriptor->multisample.mask; + normalizedDescriptor.alphaToCoverageEnabled = + descriptor->multisample.alphaToCoverageEnabled; + + vertexState.vertexBufferCount = descriptor->vertex.bufferCount; + vertexState.vertexBuffers = descriptor->vertex.buffers; + vertexState.indexFormat = descriptor->primitive.stripIndexFormat; + + rasterizationState.frontFace = descriptor->primitive.frontFace; + rasterizationState.cullMode = descriptor->primitive.cullMode; + + DepthStencilStateDescriptor depthStencilState; + if (descriptor->depthStencil) { + const DepthStencilState* depthStencil = descriptor->depthStencil; + normalizedDescriptor.depthStencilState = &depthStencilState; + + depthStencilState.format = depthStencil->format; + depthStencilState.depthWriteEnabled = depthStencil->depthWriteEnabled; + depthStencilState.depthCompare = depthStencil->depthCompare; + depthStencilState.stencilFront = depthStencil->stencilFront; + depthStencilState.stencilBack = depthStencil->stencilBack; + depthStencilState.stencilReadMask = depthStencil->stencilReadMask; + depthStencilState.stencilWriteMask = depthStencil->stencilWriteMask; + rasterizationState.depthBias = depthStencil->depthBias; + rasterizationState.depthBiasSlopeScale = depthStencil->depthBiasSlopeScale; + rasterizationState.depthBiasClamp = depthStencil->depthBiasClamp; + } + + ProgrammableStageDescriptor fragmentStage; + std::vector colorStates; + if (descriptor->fragment) { + const FragmentState* fragment = descriptor->fragment; + normalizedDescriptor.fragmentStage = &fragmentStage; + + fragmentStage.module = fragment->module; + fragmentStage.entryPoint = fragment->entryPoint; + + for (uint32_t i = 0; i < fragment->targetCount; ++i) { + const ColorTargetState& target = fragment->targets[i]; + ColorStateDescriptor colorState; + colorState.format = target.format; + colorState.writeMask = target.writeMask; + + if (target.blend) { + const BlendState* blend = target.blend; + colorState.colorBlend.srcFactor = blend->color.srcFactor; + colorState.colorBlend.dstFactor = blend->color.dstFactor; + colorState.colorBlend.operation = blend->color.operation; + + colorState.alphaBlend.srcFactor = blend->alpha.srcFactor; + colorState.alphaBlend.dstFactor = blend->alpha.dstFactor; + colorState.alphaBlend.operation = blend->alpha.operation; + } + colorStates.push_back(colorState); + } + + normalizedDescriptor.colorStateCount = fragment->targetCount; + normalizedDescriptor.colorStates = colorStates.data(); + } + + return CreateRenderPipelineInternal(result, &normalizedDescriptor); + } + MaybeError DeviceBase::CreateRenderPipelineInternal( RenderPipelineBase** result, const RenderPipelineDescriptor* descriptor) { DAWN_TRY(ValidateIsAlive()); + if (IsValidationEnabled()) { DAWN_TRY(ValidateRenderPipelineDescriptor(this, descriptor)); } diff --git a/src/dawn_native/Device.h b/src/dawn_native/Device.h index 7764ec6b35..b29f894425 100644 --- a/src/dawn_native/Device.h +++ b/src/dawn_native/Device.h @@ -155,6 +155,7 @@ namespace dawn_native { RenderBundleEncoder* CreateRenderBundleEncoder( const RenderBundleEncoderDescriptor* descriptor); RenderPipelineBase* CreateRenderPipeline(const RenderPipelineDescriptor* descriptor); + RenderPipelineBase* CreateRenderPipeline2(const RenderPipelineDescriptor2* descriptor); SamplerBase* CreateSampler(const SamplerDescriptor* descriptor); ShaderModuleBase* CreateShaderModule(const ShaderModuleDescriptor* descriptor); SwapChainBase* CreateSwapChain(Surface* surface, const SwapChainDescriptor* descriptor); @@ -307,6 +308,8 @@ namespace dawn_native { MaybeError CreateRenderBundleEncoderInternal( RenderBundleEncoder** result, const RenderBundleEncoderDescriptor* descriptor); + MaybeError CreateRenderPipelineInternal(RenderPipelineBase** result, + const RenderPipelineDescriptor2* descriptor); MaybeError CreateRenderPipelineInternal(RenderPipelineBase** result, const RenderPipelineDescriptor* descriptor); MaybeError CreateSamplerInternal(SamplerBase** result, const SamplerDescriptor* descriptor); diff --git a/src/tests/unittests/validation/RenderPipelineValidationTests.cpp b/src/tests/unittests/validation/RenderPipelineValidationTests.cpp index c36795755e..bd5366d7f9 100644 --- a/src/tests/unittests/validation/RenderPipelineValidationTests.cpp +++ b/src/tests/unittests/validation/RenderPipelineValidationTests.cpp @@ -46,6 +46,15 @@ class RenderPipelineValidationTest : public ValidationTest { // Test cases where creation should succeed TEST_F(RenderPipelineValidationTest, CreationSuccess) { { + // New format + utils::ComboRenderPipelineDescriptor2 descriptor; + descriptor.vertex.module = vsModule; + descriptor.cFragment.module = fsModule; + + device.CreateRenderPipeline2(&descriptor); + } + { + // Deprecated format utils::ComboRenderPipelineDescriptor descriptor(device); descriptor.vertexStage.module = vsModule; descriptor.cFragmentStage.module = fsModule; @@ -75,66 +84,71 @@ TEST_F(RenderPipelineValidationTest, CreationSuccess) { TEST_F(RenderPipelineValidationTest, DepthBiasParameterNotBeNaN) { // Control case, depth bias parameters in ComboRenderPipeline default to 0 which is finite { - utils::ComboRenderPipelineDescriptor descriptor(device); - descriptor.vertexStage.module = vsModule; - descriptor.cFragmentStage.module = fsModule; - device.CreateRenderPipeline(&descriptor); + utils::ComboRenderPipelineDescriptor2 descriptor; + descriptor.vertex.module = vsModule; + descriptor.cFragment.module = fsModule; + descriptor.depthStencil = &descriptor.cDepthStencil; + device.CreateRenderPipeline2(&descriptor); } // Infinite depth bias clamp is valid { - utils::ComboRenderPipelineDescriptor descriptor(device); - descriptor.vertexStage.module = vsModule; - descriptor.cFragmentStage.module = fsModule; - descriptor.cRasterizationState.depthBiasClamp = INFINITY; - device.CreateRenderPipeline(&descriptor); + utils::ComboRenderPipelineDescriptor2 descriptor; + descriptor.vertex.module = vsModule; + descriptor.cFragment.module = fsModule; + descriptor.cDepthStencil.depthBiasClamp = INFINITY; + descriptor.depthStencil = &descriptor.cDepthStencil; + device.CreateRenderPipeline2(&descriptor); } // NAN depth bias clamp is invalid { - utils::ComboRenderPipelineDescriptor descriptor(device); - descriptor.vertexStage.module = vsModule; - descriptor.cFragmentStage.module = fsModule; - descriptor.cRasterizationState.depthBiasClamp = NAN; - ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor)); + utils::ComboRenderPipelineDescriptor2 descriptor; + descriptor.vertex.module = vsModule; + descriptor.cFragment.module = fsModule; + descriptor.cDepthStencil.depthBiasClamp = NAN; + descriptor.depthStencil = &descriptor.cDepthStencil; + ASSERT_DEVICE_ERROR(device.CreateRenderPipeline2(&descriptor)); } // Infinite depth bias slope is valid { - utils::ComboRenderPipelineDescriptor descriptor(device); - descriptor.vertexStage.module = vsModule; - descriptor.cFragmentStage.module = fsModule; - descriptor.cRasterizationState.depthBiasSlopeScale = INFINITY; - device.CreateRenderPipeline(&descriptor); + utils::ComboRenderPipelineDescriptor2 descriptor; + descriptor.vertex.module = vsModule; + descriptor.cFragment.module = fsModule; + descriptor.cDepthStencil.depthBiasSlopeScale = INFINITY; + descriptor.depthStencil = &descriptor.cDepthStencil; + device.CreateRenderPipeline2(&descriptor); } // NAN depth bias slope is invalid { - utils::ComboRenderPipelineDescriptor descriptor(device); - descriptor.vertexStage.module = vsModule; - descriptor.cFragmentStage.module = fsModule; - descriptor.cRasterizationState.depthBiasSlopeScale = NAN; - ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor)); + utils::ComboRenderPipelineDescriptor2 descriptor; + descriptor.vertex.module = vsModule; + descriptor.cFragment.module = fsModule; + descriptor.cDepthStencil.depthBiasSlopeScale = NAN; + descriptor.depthStencil = &descriptor.cDepthStencil; + ASSERT_DEVICE_ERROR(device.CreateRenderPipeline2(&descriptor)); } } -// Tests that at least one color state is required. -TEST_F(RenderPipelineValidationTest, ColorStateRequired) { +// Tests that at least one color target state is required. +TEST_F(RenderPipelineValidationTest, ColorTargetStateRequired) { { // This one succeeds because attachment 0 is the color attachment - utils::ComboRenderPipelineDescriptor descriptor(device); - descriptor.vertexStage.module = vsModule; - descriptor.cFragmentStage.module = fsModule; - descriptor.colorStateCount = 1; + utils::ComboRenderPipelineDescriptor2 descriptor; + descriptor.vertex.module = vsModule; + descriptor.cFragment.module = fsModule; + descriptor.cFragment.targetCount = 1; - device.CreateRenderPipeline(&descriptor); + device.CreateRenderPipeline2(&descriptor); } - { // Fail because lack of color states (and depth/stencil state) - utils::ComboRenderPipelineDescriptor descriptor(device); - descriptor.vertexStage.module = vsModule; - descriptor.cFragmentStage.module = fsModule; - descriptor.colorStateCount = 0; + { // Fail because lack of color target states (and depth/stencil state) + utils::ComboRenderPipelineDescriptor2 descriptor; + descriptor.vertex.module = vsModule; + descriptor.cFragment.module = fsModule; + descriptor.cFragment.targetCount = 0; - ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor)); + ASSERT_DEVICE_ERROR(device.CreateRenderPipeline2(&descriptor)); } } @@ -142,22 +156,22 @@ TEST_F(RenderPipelineValidationTest, ColorStateRequired) { TEST_F(RenderPipelineValidationTest, NonRenderableFormat) { { // Succeeds because RGBA8Unorm is renderable - utils::ComboRenderPipelineDescriptor descriptor(device); - descriptor.vertexStage.module = vsModule; - descriptor.cFragmentStage.module = fsModule; - descriptor.cColorStates[0].format = wgpu::TextureFormat::RGBA8Unorm; + utils::ComboRenderPipelineDescriptor2 descriptor; + descriptor.vertex.module = vsModule; + descriptor.cFragment.module = fsModule; + descriptor.cTargets[0].format = wgpu::TextureFormat::RGBA8Unorm; - device.CreateRenderPipeline(&descriptor); + device.CreateRenderPipeline2(&descriptor); } { // Fails because RG11B10Ufloat is non-renderable - utils::ComboRenderPipelineDescriptor descriptor(device); - descriptor.vertexStage.module = vsModule; - descriptor.cFragmentStage.module = fsModule; - descriptor.cColorStates[0].format = wgpu::TextureFormat::RG11B10Ufloat; + utils::ComboRenderPipelineDescriptor2 descriptor; + descriptor.vertex.module = vsModule; + descriptor.cFragment.module = fsModule; + descriptor.cTargets[0].format = wgpu::TextureFormat::RG11B10Ufloat; - ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor)); + ASSERT_DEVICE_ERROR(device.CreateRenderPipeline2(&descriptor)); } } @@ -196,21 +210,21 @@ TEST_F(RenderPipelineValidationTest, FragmentOutputFormatCompatibility) { /// Tests that the sample count of the render pipeline must be valid. TEST_F(RenderPipelineValidationTest, SampleCount) { { - utils::ComboRenderPipelineDescriptor descriptor(device); - descriptor.vertexStage.module = vsModule; - descriptor.cFragmentStage.module = fsModule; - descriptor.sampleCount = 4; + utils::ComboRenderPipelineDescriptor2 descriptor; + descriptor.vertex.module = vsModule; + descriptor.cFragment.module = fsModule; + descriptor.multisample.count = 4; - device.CreateRenderPipeline(&descriptor); + device.CreateRenderPipeline2(&descriptor); } { - utils::ComboRenderPipelineDescriptor descriptor(device); - descriptor.vertexStage.module = vsModule; - descriptor.cFragmentStage.module = fsModule; - descriptor.sampleCount = 3; + utils::ComboRenderPipelineDescriptor2 descriptor; + descriptor.vertex.module = vsModule; + descriptor.cFragment.module = fsModule; + descriptor.multisample.count = 3; - ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor)); + ASSERT_DEVICE_ERROR(device.CreateRenderPipeline2(&descriptor)); } } @@ -360,23 +374,23 @@ TEST_F(RenderPipelineValidationTest, SampleCountCompatibilityWithRenderPass) { // when the alphaToCoverage mode is enabled. TEST_F(RenderPipelineValidationTest, AlphaToCoverageAndSampleCount) { { - utils::ComboRenderPipelineDescriptor descriptor(device); - descriptor.vertexStage.module = vsModule; - descriptor.cFragmentStage.module = fsModule; - descriptor.sampleCount = 4; - descriptor.alphaToCoverageEnabled = true; + utils::ComboRenderPipelineDescriptor2 descriptor; + descriptor.vertex.module = vsModule; + descriptor.cFragment.module = fsModule; + descriptor.multisample.count = 4; + descriptor.multisample.alphaToCoverageEnabled = true; - device.CreateRenderPipeline(&descriptor); + device.CreateRenderPipeline2(&descriptor); } { - utils::ComboRenderPipelineDescriptor descriptor(device); - descriptor.vertexStage.module = vsModule; - descriptor.cFragmentStage.module = fsModule; - descriptor.sampleCount = 1; - descriptor.alphaToCoverageEnabled = true; + utils::ComboRenderPipelineDescriptor2 descriptor; + descriptor.vertex.module = vsModule; + descriptor.cFragment.module = fsModule; + descriptor.multisample.count = 1; + descriptor.multisample.alphaToCoverageEnabled = true; - ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor)); + ASSERT_DEVICE_ERROR(device.CreateRenderPipeline2(&descriptor)); } } @@ -586,37 +600,37 @@ TEST_F(RenderPipelineValidationTest, EntryPointNameValidation) { } )"); - utils::ComboRenderPipelineDescriptor descriptor(device); - descriptor.vertexStage.module = module; - descriptor.vertexStage.entryPoint = "vertex_main"; - descriptor.cFragmentStage.module = module; - descriptor.cFragmentStage.entryPoint = "fragment_main"; + utils::ComboRenderPipelineDescriptor2 descriptor; + descriptor.vertex.module = module; + descriptor.vertex.entryPoint = "vertex_main"; + descriptor.cFragment.module = module; + descriptor.cFragment.entryPoint = "fragment_main"; // Success case. - device.CreateRenderPipeline(&descriptor); + device.CreateRenderPipeline2(&descriptor); // Test for the vertex stage entryPoint name. { // The entryPoint name doesn't exist in the module. - descriptor.vertexStage.entryPoint = "main"; - ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor)); + descriptor.vertex.entryPoint = "main"; + ASSERT_DEVICE_ERROR(device.CreateRenderPipeline2(&descriptor)); // The entryPoint name exists, but not for the correct stage. - descriptor.vertexStage.entryPoint = "fragment_main"; - ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor)); + descriptor.vertex.entryPoint = "fragment_main"; + ASSERT_DEVICE_ERROR(device.CreateRenderPipeline2(&descriptor)); } - descriptor.vertexStage.entryPoint = "vertex_main"; + descriptor.vertex.entryPoint = "vertex_main"; // Test for the fragment stage entryPoint name. { // The entryPoint name doesn't exist in the module. - descriptor.cFragmentStage.entryPoint = "main"; - ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor)); + descriptor.cFragment.entryPoint = "main"; + ASSERT_DEVICE_ERROR(device.CreateRenderPipeline2(&descriptor)); // The entryPoint name exists, but not for the correct stage. - descriptor.cFragmentStage.entryPoint = "vertex_main"; - ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor)); + descriptor.cFragment.entryPoint = "vertex_main"; + ASSERT_DEVICE_ERROR(device.CreateRenderPipeline2(&descriptor)); } } @@ -639,33 +653,33 @@ TEST_F(RenderPipelineValidationTest, VertexAttribCorrectEntryPoint) { } )"); - utils::ComboRenderPipelineDescriptor descriptor(device); - descriptor.vertexStage.module = module; - descriptor.cFragmentStage.module = fsModule; + utils::ComboRenderPipelineDescriptor2 descriptor; + descriptor.vertex.module = module; + descriptor.cFragment.module = fsModule; - descriptor.cVertexState.vertexBufferCount = 1; - descriptor.cVertexState.cVertexBuffers[0].attributeCount = 1; - descriptor.cVertexState.cVertexBuffers[0].arrayStride = 16; - descriptor.cVertexState.cAttributes[0].format = wgpu::VertexFormat::Float32x4; - descriptor.cVertexState.cAttributes[0].offset = 0; + descriptor.vertex.bufferCount = 1; + descriptor.cBuffers[0].attributeCount = 1; + descriptor.cBuffers[0].arrayStride = 16; + descriptor.cAttributes[0].format = wgpu::VertexFormat::Float32x4; + descriptor.cAttributes[0].offset = 0; // Success cases, the attribute used by the entryPoint is declared in the pipeline. - descriptor.vertexStage.entryPoint = "vertex0"; - descriptor.cVertexState.cAttributes[0].shaderLocation = 0; - device.CreateRenderPipeline(&descriptor); + descriptor.vertex.entryPoint = "vertex0"; + descriptor.cAttributes[0].shaderLocation = 0; + device.CreateRenderPipeline2(&descriptor); - descriptor.vertexStage.entryPoint = "vertex1"; - descriptor.cVertexState.cAttributes[0].shaderLocation = 1; - device.CreateRenderPipeline(&descriptor); + descriptor.vertex.entryPoint = "vertex1"; + descriptor.cAttributes[0].shaderLocation = 1; + device.CreateRenderPipeline2(&descriptor); // Error cases, the attribute used by the entryPoint isn't declared in the pipeline. - descriptor.vertexStage.entryPoint = "vertex1"; - descriptor.cVertexState.cAttributes[0].shaderLocation = 0; - ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor)); + descriptor.vertex.entryPoint = "vertex1"; + descriptor.cAttributes[0].shaderLocation = 0; + ASSERT_DEVICE_ERROR(device.CreateRenderPipeline2(&descriptor)); - descriptor.vertexStage.entryPoint = "vertex0"; - descriptor.cVertexState.cAttributes[0].shaderLocation = 1; - ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor)); + descriptor.vertex.entryPoint = "vertex0"; + descriptor.cAttributes[0].shaderLocation = 1; + ASSERT_DEVICE_ERROR(device.CreateRenderPipeline2(&descriptor)); } // Test that fragment output validation is for the correct entryPoint @@ -686,27 +700,27 @@ TEST_F(RenderPipelineValidationTest, FragmentOutputCorrectEntryPoint) { } )"); - utils::ComboRenderPipelineDescriptor descriptor(device); - descriptor.vertexStage.module = vsModule; - descriptor.cFragmentStage.module = module; + utils::ComboRenderPipelineDescriptor2 descriptor; + descriptor.vertex.module = vsModule; + descriptor.cFragment.module = module; // Success case, the component type matches between the pipeline and the entryPoint - descriptor.cFragmentStage.entryPoint = "fragmentFloat"; - descriptor.cColorStates[0].format = wgpu::TextureFormat::RGBA32Float; - device.CreateRenderPipeline(&descriptor); + descriptor.cFragment.entryPoint = "fragmentFloat"; + descriptor.cTargets[0].format = wgpu::TextureFormat::RGBA32Float; + device.CreateRenderPipeline2(&descriptor); - descriptor.cFragmentStage.entryPoint = "fragmentUint"; - descriptor.cColorStates[0].format = wgpu::TextureFormat::RGBA32Uint; - device.CreateRenderPipeline(&descriptor); + descriptor.cFragment.entryPoint = "fragmentUint"; + descriptor.cTargets[0].format = wgpu::TextureFormat::RGBA32Uint; + device.CreateRenderPipeline2(&descriptor); // Error case, the component type doesn't match between the pipeline and the entryPoint - descriptor.cFragmentStage.entryPoint = "fragmentUint"; - descriptor.cColorStates[0].format = wgpu::TextureFormat::RGBA32Float; - ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor)); + descriptor.cFragment.entryPoint = "fragmentUint"; + descriptor.cTargets[0].format = wgpu::TextureFormat::RGBA32Float; + ASSERT_DEVICE_ERROR(device.CreateRenderPipeline2(&descriptor)); - descriptor.cFragmentStage.entryPoint = "fragmentFloat"; - descriptor.cColorStates[0].format = wgpu::TextureFormat::RGBA32Uint; - ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor)); + descriptor.cFragment.entryPoint = "fragmentFloat"; + descriptor.cTargets[0].format = wgpu::TextureFormat::RGBA32Uint; + ASSERT_DEVICE_ERROR(device.CreateRenderPipeline2(&descriptor)); } // Test that fragment output validation is for the correct entryPoint @@ -743,25 +757,25 @@ TEST_F(RenderPipelineValidationTest, DISABLED_BindingsFromCorrectEntryPoint) { device, {{1, wgpu::ShaderStage::Vertex, wgpu::BufferBindingType::Uniform}}); wgpu::PipelineLayout layout1 = utils::MakeBasicPipelineLayout(device, &bgl1); - utils::ComboRenderPipelineDescriptor descriptor(device); - descriptor.vertexStage.module = module; - descriptor.cFragmentStage.module = fsModule; + utils::ComboRenderPipelineDescriptor2 descriptor; + descriptor.vertex.module = module; + descriptor.cFragment.module = fsModule; // Success case, the BGL matches the bindings used by the entryPoint - descriptor.vertexStage.entryPoint = "vertex0"; + descriptor.vertex.entryPoint = "vertex0"; descriptor.layout = layout0; - device.CreateRenderPipeline(&descriptor); + device.CreateRenderPipeline2(&descriptor); - descriptor.vertexStage.entryPoint = "vertex1"; + descriptor.vertex.entryPoint = "vertex1"; descriptor.layout = layout1; - device.CreateRenderPipeline(&descriptor); + device.CreateRenderPipeline2(&descriptor); // Error case, the BGL doesn't match the bindings used by the entryPoint - descriptor.vertexStage.entryPoint = "vertex1"; + descriptor.vertex.entryPoint = "vertex1"; descriptor.layout = layout0; - ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor)); + ASSERT_DEVICE_ERROR(device.CreateRenderPipeline2(&descriptor)); - descriptor.vertexStage.entryPoint = "vertex0"; + descriptor.vertex.entryPoint = "vertex0"; descriptor.layout = layout1; - ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor)); + ASSERT_DEVICE_ERROR(device.CreateRenderPipeline2(&descriptor)); } diff --git a/src/utils/ComboRenderPipelineDescriptor.cpp b/src/utils/ComboRenderPipelineDescriptor.cpp index 73defe6ec4..046ceaa38a 100644 --- a/src/utils/ComboRenderPipelineDescriptor.cpp +++ b/src/utils/ComboRenderPipelineDescriptor.cpp @@ -18,6 +18,8 @@ namespace utils { + // For creating deprecated render pipeline descriptors + ComboVertexStateDescriptor::ComboVertexStateDescriptor() { wgpu::VertexStateDescriptor* descriptor = this; @@ -114,4 +116,96 @@ namespace utils { } } + ComboRenderPipelineDescriptor2::ComboRenderPipelineDescriptor2() { + wgpu::RenderPipelineDescriptor2* descriptor = this; + + // Set defaults for the vertex state. + { + wgpu::VertexState* vertex = &descriptor->vertex; + vertex->module = nullptr; + vertex->entryPoint = "main"; + vertex->bufferCount = 0; + + // Fill the default values for vertexBuffers and vertexAttributes in buffers. + for (uint32_t i = 0; i < kMaxVertexAttributes; ++i) { + cAttributes[i].shaderLocation = 0; + cAttributes[i].offset = 0; + cAttributes[i].format = wgpu::VertexFormat::Float32; + } + for (uint32_t i = 0; i < kMaxVertexBuffers; ++i) { + cBuffers[i].arrayStride = 0; + cBuffers[i].stepMode = wgpu::InputStepMode::Vertex; + cBuffers[i].attributeCount = 0; + cBuffers[i].attributes = nullptr; + } + // cBuffers[i].attributes points to somewhere in cAttributes. + // cBuffers[0].attributes points to &cAttributes[0] by default. Assuming + // cBuffers[0] has two attributes, then cBuffers[1].attributes should point to + // &cAttributes[2]. Likewise, if cBuffers[1] has 3 attributes, then + // cBuffers[2].attributes should point to &cAttributes[5]. + cBuffers[0].attributes = &cAttributes[0]; + vertex->buffers = &cBuffers[0]; + } + + // Set the defaults for the primitive state + { + wgpu::PrimitiveState* primitive = &descriptor->primitive; + primitive->topology = wgpu::PrimitiveTopology::TriangleList; + primitive->stripIndexFormat = wgpu::IndexFormat::Undefined; + primitive->frontFace = wgpu::FrontFace::CCW; + primitive->cullMode = wgpu::CullMode::None; + } + + // Set the defaults for the depth-stencil state + { + wgpu::StencilFaceState stencilFace; + stencilFace.compare = wgpu::CompareFunction::Always; + stencilFace.failOp = wgpu::StencilOperation::Keep; + stencilFace.depthFailOp = wgpu::StencilOperation::Keep; + stencilFace.passOp = wgpu::StencilOperation::Keep; + + cDepthStencil.format = wgpu::TextureFormat::Depth24PlusStencil8; + cDepthStencil.depthWriteEnabled = false; + cDepthStencil.depthCompare = wgpu::CompareFunction::Always; + cDepthStencil.stencilBack = stencilFace; + cDepthStencil.stencilFront = stencilFace; + cDepthStencil.stencilReadMask = 0xff; + cDepthStencil.stencilWriteMask = 0xff; + cDepthStencil.depthBias = 0; + cDepthStencil.depthBiasSlopeScale = 0.0; + cDepthStencil.depthBiasClamp = 0.0; + } + + // Set the defaults for the multisample state + { + wgpu::MultisampleState* multisample = &descriptor->multisample; + multisample->count = 1; + multisample->mask = 0xFFFFFFFF; + multisample->alphaToCoverageEnabled = false; + } + + // Set the defaults for the fragment state + { + cFragment.module = nullptr; + cFragment.entryPoint = "main"; + cFragment.targetCount = 1; + cFragment.targets = &cTargets[0]; + descriptor->fragment = &cFragment; + + wgpu::BlendComponent blendComponent; + blendComponent.srcFactor = wgpu::BlendFactor::One; + blendComponent.dstFactor = wgpu::BlendFactor::Zero; + blendComponent.operation = wgpu::BlendOperation::Add; + + for (uint32_t i = 0; i < kMaxColorAttachments; ++i) { + cTargets[i].format = wgpu::TextureFormat::RGBA8Unorm; + cTargets[i].blend = nullptr; + cTargets[i].writeMask = wgpu::ColorWriteMask::All; + + cBlends[i].color = blendComponent; + cBlends[i].alpha = blendComponent; + } + } + } + } // namespace utils diff --git a/src/utils/ComboRenderPipelineDescriptor.h b/src/utils/ComboRenderPipelineDescriptor.h index ce8eb308b1..67ee058617 100644 --- a/src/utils/ComboRenderPipelineDescriptor.h +++ b/src/utils/ComboRenderPipelineDescriptor.h @@ -23,6 +23,7 @@ namespace utils { + // For creating deprecated render pipeline descriptors class ComboVertexStateDescriptor : public wgpu::VertexStateDescriptor { public: ComboVertexStateDescriptor(); @@ -53,6 +54,25 @@ namespace utils { wgpu::DepthStencilStateDescriptor cDepthStencilState; }; + // For creating the new style of render pipeline descriptors + class ComboRenderPipelineDescriptor2 : public wgpu::RenderPipelineDescriptor2 { + public: + ComboRenderPipelineDescriptor2(); + + ComboRenderPipelineDescriptor2(const ComboRenderPipelineDescriptor2&) = delete; + ComboRenderPipelineDescriptor2& operator=(const ComboRenderPipelineDescriptor2&) = delete; + ComboRenderPipelineDescriptor2(ComboRenderPipelineDescriptor2&&) = delete; + ComboRenderPipelineDescriptor2& operator=(ComboRenderPipelineDescriptor2&&) = delete; + + std::array cBuffers; + std::array cAttributes; + std::array cTargets; + std::array cBlends; + + wgpu::DepthStencilState cDepthStencil; + wgpu::FragmentState cFragment; + }; + } // namespace utils #endif // UTILS_COMBORENDERPIPELINEDESCRIPTOR_H_