Implement C INIT macros
Add a unittest that the C defaults match the C++ defaults
Use the init macros in some existing tests that use the C api
Fixed: dawn:2243
Change-Id: I4bf7492a19babac082872cad9bc151dbff3d5a1f
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/185968
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Loko Kung <lokokung@google.com>
diff --git a/generator/templates/api.h b/generator/templates/api.h
index b541b9c..c4c1a3d 100644
--- a/generator/templates/api.h
+++ b/generator/templates/api.h
@@ -75,6 +75,18 @@
#define WGPU_BREAKING_REFERENCE_ADDREF
+#if defined(__cplusplus)
+# if __cplusplus >= 201103L
+# define {{API}}_MAKE_INIT_STRUCT(type, value) (type value)
+# else
+# define {{API}}_MAKE_INIT_STRUCT(type, value) value
+# endif
+#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+# define {{API}}_MAKE_INIT_STRUCT(type, value) ((type) value)
+#else
+# define {{API}}_MAKE_INIT_STRUCT(type, value) value
+#endif
+
{% for constant in by_category["constant"] %}
#define {{API}}_{{constant.name.SNAKE_CASE()}} {{constant.value}}
{% endfor %}
@@ -126,6 +138,26 @@
{{API}}SType sType;
} {{API}}ChainedStructOut {{API}}_STRUCTURE_ATTRIBUTE;
+{% macro render_c_default_value(member) -%}
+ {%- if member.annotation in ["*", "const*"] and member.optional or member.default_value == "nullptr" -%}
+ nullptr
+ {%- elif member.type.category == "object" and member.optional -%}
+ nullptr
+ {%- elif member.type.category in ["enum", "bitmask"] and member.default_value != None -%}
+ {{as_cEnum(member.type.name, Name(member.default_value))}}
+ {%- elif member.default_value != None -%}
+ {{member.default_value}}
+ {%- elif member.type.category == "structure" and member.annotation == "value" -%}
+ {{API}}_{{member.type.name.SNAKE_CASE()}}_INIT
+ {%- else -%}
+ {{- assert(member.json_data.get("no_default", false) == false) -}}
+ {{- assert(member.default_value == None) -}}
+ {}
+ {%- endif -%}
+{% endmacro %}
+
+#define {{API}}_COMMA ,
+
{% for type in by_category["structure"] %}
{% for root in type.chain_roots %}
// Can be chained in {{as_cType(root.name)}}
@@ -148,6 +180,18 @@
{% endfor %}
} {{as_cType(type.name)}} {{API}}_STRUCTURE_ATTRIBUTE;
+ #define {{API}}_{{type.name.SNAKE_CASE()}}_INIT {{API}}_MAKE_INIT_STRUCT({{as_cType(type.name)}}, { \
+ {% if type.extensible %}
+ /*.nextInChain=*/nullptr {{API}}_COMMA \
+ {% endif %}
+ {% if type.chained %}
+ /*.chain=*/{} {{API}}_COMMA \
+ {% endif %}
+ {% for member in type.members %}
+ /*.{{as_varName(member.name)}}=*/{{render_c_default_value(member)}} {{API}}_COMMA \
+ {% endfor %}
+ })
+
{% endfor %}
{% for typeDef in by_category["typedef"] %}
// {{as_cType(typeDef.name)}} is deprecated.
diff --git a/src/dawn/tests/BUILD.gn b/src/dawn/tests/BUILD.gn
index fd3aa8e..e858d83 100644
--- a/src/dawn/tests/BUILD.gn
+++ b/src/dawn/tests/BUILD.gn
@@ -327,6 +327,7 @@
"unittests/CommandAllocatorTests.cpp",
"unittests/ConcurrentCacheTests.cpp",
"unittests/ContentLessObjectCacheTests.cpp",
+ "unittests/DefaultTests.cpp",
"unittests/EnumClassBitmasksTests.cpp",
"unittests/EnumMaskIteratorTests.cpp",
"unittests/EnumeratorTests.cpp",
diff --git a/src/dawn/tests/unittests/DefaultTests.cpp b/src/dawn/tests/unittests/DefaultTests.cpp
new file mode 100644
index 0000000..422dd24
--- /dev/null
+++ b/src/dawn/tests/unittests/DefaultTests.cpp
@@ -0,0 +1,48 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "dawn/webgpu.h"
+#include "dawn/webgpu_cpp.h"
+#include "gtest/gtest.h"
+
+// Test that the C init structs match the C++ default values
+TEST(DefaultTests, CMatchesCpp) {
+ // Test render pipeline descriptor.
+ // It's non-trivial and has nested structs too.
+ wgpu::RenderPipelineDescriptor cppDesc = {};
+ WGPURenderPipelineDescriptor cDesc = WGPU_RENDER_PIPELINE_DESCRIPTOR_INIT;
+
+ EXPECT_EQ(cppDesc.primitive.topology,
+ static_cast<wgpu::PrimitiveTopology>(cDesc.primitive.topology));
+ EXPECT_EQ(cppDesc.primitive.stripIndexFormat,
+ static_cast<wgpu::IndexFormat>(cDesc.primitive.stripIndexFormat));
+ EXPECT_EQ(cppDesc.primitive.frontFace, static_cast<wgpu::FrontFace>(cDesc.primitive.frontFace));
+ EXPECT_EQ(cppDesc.primitive.cullMode, static_cast<wgpu::CullMode>(cDesc.primitive.cullMode));
+ EXPECT_EQ(cppDesc.multisample.count, cDesc.multisample.count);
+ EXPECT_EQ(cppDesc.multisample.mask, cDesc.multisample.mask);
+ EXPECT_EQ(cppDesc.multisample.alphaToCoverageEnabled, cDesc.multisample.alphaToCoverageEnabled);
+}
diff --git a/src/dawn/tests/unittests/wire/WireArgumentTests.cpp b/src/dawn/tests/unittests/wire/WireArgumentTests.cpp
index c2f229f..b2e3b95 100644
--- a/src/dawn/tests/unittests/wire/WireArgumentTests.cpp
+++ b/src/dawn/tests/unittests/wire/WireArgumentTests.cpp
@@ -64,18 +64,14 @@
// Test that the wire is able to send arrays of numerical values
TEST_F(WireArgumentTests, ValueArrayArgument) {
// Create a bindgroup.
- WGPUBindGroupLayoutDescriptor bglDescriptor = {};
- bglDescriptor.entryCount = 0;
- bglDescriptor.entries = nullptr;
+ WGPUBindGroupLayoutDescriptor bglDescriptor = WGPU_BIND_GROUP_LAYOUT_DESCRIPTOR_INIT;
WGPUBindGroupLayout bgl = wgpuDeviceCreateBindGroupLayout(device, &bglDescriptor);
WGPUBindGroupLayout apiBgl = api.GetNewBindGroupLayout();
EXPECT_CALL(api, DeviceCreateBindGroupLayout(apiDevice, _)).WillOnce(Return(apiBgl));
- WGPUBindGroupDescriptor bindGroupDescriptor = {};
+ WGPUBindGroupDescriptor bindGroupDescriptor = WGPU_BIND_GROUP_DESCRIPTOR_INIT;
bindGroupDescriptor.layout = bgl;
- bindGroupDescriptor.entryCount = 0;
- bindGroupDescriptor.entries = nullptr;
WGPUBindGroup bindGroup = wgpuDeviceCreateBindGroup(device, &bindGroupDescriptor);
WGPUBindGroup apiBindGroup = api.GetNewBindGroup();
@@ -111,73 +107,49 @@
// Test that the wire is able to send C strings
TEST_F(WireArgumentTests, CStringArgument) {
// Create shader module
- WGPUShaderModuleDescriptor vertexDescriptor = {};
+ WGPUShaderModuleDescriptor vertexDescriptor = WGPU_SHADER_MODULE_DESCRIPTOR_INIT;
WGPUShaderModule vsModule = wgpuDeviceCreateShaderModule(device, &vertexDescriptor);
WGPUShaderModule apiVsModule = api.GetNewShaderModule();
EXPECT_CALL(api, DeviceCreateShaderModule(apiDevice, _)).WillOnce(Return(apiVsModule));
// Create the color state descriptor
- WGPUBlendComponent blendComponent = {};
- blendComponent.operation = WGPUBlendOperation_Add;
- blendComponent.srcFactor = WGPUBlendFactor_One;
- blendComponent.dstFactor = WGPUBlendFactor_One;
- WGPUBlendState blendState = {};
+ WGPUBlendComponent blendComponent = WGPU_BLEND_COMPONENT_INIT;
+ WGPUBlendState blendState = WGPU_BLEND_STATE_INIT;
blendState.alpha = blendComponent;
blendState.color = blendComponent;
- WGPUColorTargetState colorTargetState = {};
+ WGPUColorTargetState colorTargetState = WGPU_COLOR_TARGET_STATE_INIT;
colorTargetState.format = WGPUTextureFormat_RGBA8Unorm;
colorTargetState.blend = &blendState;
- colorTargetState.writeMask = WGPUColorWriteMask_All;
// Create the depth-stencil state
- WGPUStencilFaceState stencilFace = {};
- stencilFace.compare = WGPUCompareFunction_Always;
- stencilFace.failOp = WGPUStencilOperation_Keep;
- stencilFace.depthFailOp = WGPUStencilOperation_Keep;
- stencilFace.passOp = WGPUStencilOperation_Keep;
+ WGPUStencilFaceState stencilFace = WGPU_STENCIL_FACE_STATE_INIT;
- WGPUDepthStencilState depthStencilState = {};
+ WGPUDepthStencilState depthStencilState = WGPU_DEPTH_STENCIL_STATE_INIT;
depthStencilState.format = WGPUTextureFormat_Depth24PlusStencil8;
- depthStencilState.depthWriteEnabled = false;
depthStencilState.depthCompare = WGPUCompareFunction_Always;
depthStencilState.stencilBack = stencilFace;
depthStencilState.stencilFront = stencilFace;
- depthStencilState.stencilReadMask = 0xff;
- depthStencilState.stencilWriteMask = 0xff;
- depthStencilState.depthBias = 0;
- depthStencilState.depthBiasSlopeScale = 0.0;
- depthStencilState.depthBiasClamp = 0.0;
// Create the pipeline layout
- WGPUPipelineLayoutDescriptor layoutDescriptor = {};
- layoutDescriptor.bindGroupLayoutCount = 0;
- layoutDescriptor.bindGroupLayouts = nullptr;
+ WGPUPipelineLayoutDescriptor layoutDescriptor = WGPU_PIPELINE_LAYOUT_DESCRIPTOR_INIT;
WGPUPipelineLayout layout = wgpuDeviceCreatePipelineLayout(device, &layoutDescriptor);
WGPUPipelineLayout apiLayout = api.GetNewPipelineLayout();
EXPECT_CALL(api, DeviceCreatePipelineLayout(apiDevice, _)).WillOnce(Return(apiLayout));
// Create pipeline
- WGPURenderPipelineDescriptor pipelineDescriptor = {};
+ WGPURenderPipelineDescriptor pipelineDescriptor = WGPU_RENDER_PIPELINE_DESCRIPTOR_INIT;
pipelineDescriptor.vertex.module = vsModule;
pipelineDescriptor.vertex.entryPoint = "main";
- pipelineDescriptor.vertex.bufferCount = 0;
- pipelineDescriptor.vertex.buffers = nullptr;
- WGPUFragmentState fragment = {};
+ WGPUFragmentState fragment = WGPU_FRAGMENT_STATE_INIT;
fragment.module = vsModule;
fragment.entryPoint = "main";
fragment.targetCount = 1;
fragment.targets = &colorTargetState;
pipelineDescriptor.fragment = &fragment;
- pipelineDescriptor.multisample.count = 1;
- pipelineDescriptor.multisample.mask = 0xFFFFFFFF;
- pipelineDescriptor.multisample.alphaToCoverageEnabled = false;
pipelineDescriptor.layout = layout;
- pipelineDescriptor.primitive.topology = WGPUPrimitiveTopology_TriangleList;
- pipelineDescriptor.primitive.frontFace = WGPUFrontFace_CCW;
- pipelineDescriptor.primitive.cullMode = WGPUCullMode_None;
pipelineDescriptor.depthStencil = &depthStencilState;
wgpuDeviceCreateRenderPipeline(device, &pipelineDescriptor);
@@ -199,7 +171,7 @@
WGPUCommandEncoder apiEncoder = api.GetNewCommandEncoder();
EXPECT_CALL(api, DeviceCreateCommandEncoder(apiDevice, nullptr)).WillOnce(Return(apiEncoder));
- WGPUBufferDescriptor descriptor = {};
+ WGPUBufferDescriptor descriptor = WGPU_BUFFER_DESCRIPTOR_INIT;
descriptor.size = 8;
descriptor.usage =
static_cast<WGPUBufferUsage>(WGPUBufferUsage_CopySrc | WGPUBufferUsage_CopyDst);
@@ -251,14 +223,11 @@
// Test that the wire is able to send structures that contain pure values (non-objects)
TEST_F(WireArgumentTests, StructureOfValuesArgument) {
- WGPUSamplerDescriptor descriptor = {};
+ WGPUSamplerDescriptor descriptor = WGPU_SAMPLER_DESCRIPTOR_INIT;
descriptor.magFilter = WGPUFilterMode_Linear;
- descriptor.minFilter = WGPUFilterMode_Nearest;
descriptor.mipmapFilter = WGPUMipmapFilterMode_Linear;
- descriptor.addressModeU = WGPUAddressMode_ClampToEdge;
descriptor.addressModeV = WGPUAddressMode_Repeat;
descriptor.addressModeW = WGPUAddressMode_MirrorRepeat;
- descriptor.lodMinClamp = kLodMin;
descriptor.lodMaxClamp = kLodMax;
descriptor.compare = WGPUCompareFunction_Never;
@@ -284,15 +253,13 @@
// Test that the wire is able to send structures that contain objects
TEST_F(WireArgumentTests, StructureOfObjectArrayArgument) {
- WGPUBindGroupLayoutDescriptor bglDescriptor = {};
- bglDescriptor.entryCount = 0;
- bglDescriptor.entries = nullptr;
+ WGPUBindGroupLayoutDescriptor bglDescriptor = WGPU_BIND_GROUP_LAYOUT_DESCRIPTOR_INIT;
WGPUBindGroupLayout bgl = wgpuDeviceCreateBindGroupLayout(device, &bglDescriptor);
WGPUBindGroupLayout apiBgl = api.GetNewBindGroupLayout();
EXPECT_CALL(api, DeviceCreateBindGroupLayout(apiDevice, _)).WillOnce(Return(apiBgl));
- WGPUPipelineLayoutDescriptor descriptor = {};
+ WGPUPipelineLayoutDescriptor descriptor = WGPU_PIPELINE_LAYOUT_DESCRIPTOR_INIT;
descriptor.bindGroupLayoutCount = 1;
descriptor.bindGroupLayouts = &bgl;
@@ -337,7 +304,7 @@
{},
{}},
};
- WGPUBindGroupLayoutDescriptor bglDescriptor = {};
+ WGPUBindGroupLayoutDescriptor bglDescriptor = WGPU_BIND_GROUP_LAYOUT_DESCRIPTOR_INIT;
bglDescriptor.entryCount = NUM_BINDINGS;
bglDescriptor.entries = entries;
@@ -367,7 +334,7 @@
TEST_F(WireArgumentTests, DISABLED_NullptrInArray) {
WGPUBindGroupLayout nullBGL = nullptr;
- WGPUPipelineLayoutDescriptor descriptor = {};
+ WGPUPipelineLayoutDescriptor descriptor = WGPU_PIPELINE_LAYOUT_DESCRIPTOR_INIT;
descriptor.bindGroupLayoutCount = 1;
descriptor.bindGroupLayouts = &nullBGL;