Wire: Add support from optional struct/integer const*

This will allow implementing the following part of the WebGPU IDL using
a nullable pointer instead of an extra hasDepthStencilState boolean:

partial interface GPURenderPipelineDescriptor {
    GPUDepthStencilStateDescriptor? depthStencilState;
};

BUG=dawn:102

Change-Id: Iae709831ad857fcef073f18753ab39567a8797da
Reviewed-on: https://dawn-review.googlesource.com/c/4500
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Yunchao He <yunchao.he@intel.com>
This commit is contained in:
Corentin Wallez 2019-02-13 10:15:38 +00:00 committed by Commit Bot service account
parent bb5696bcd3
commit f872e6924c
3 changed files with 155 additions and 1 deletions

View File

@ -863,7 +863,7 @@
{"name": "primitive topology", "type": "primitive topology"},
{"name": "attachments state", "type": "attachments state descriptor", "annotation": "const*"},
{"name": "sample count", "type": "uint32_t"},
{"name": "depth stencil state", "type": "depth stencil state descriptor", "annotation": "const*"},
{"name": "depth stencil state", "type": "depth stencil state descriptor", "annotation": "const*", "optional": true},
{"name": "num blend states", "type": "uint32_t"},
{"name": "blend states", "type": "blend state descriptor", "annotation": "const*", "length": "num blend states"}
]

View File

@ -105,6 +105,10 @@
{% for member in members if member.length == "strlen" %}
size_t {{as_varName(member.name)}}Strlen;
{% endfor %}
{% for member in members if member.annotation != "value" and member.type.category != "object" %}
bool has_{{as_varName(member.name)}};
{% endfor %}
};
//* Returns the required transfer size for `record` in addition to the transfer structure.
@ -120,6 +124,9 @@
//* Gather how much space will be needed for pointer members.
{% for member in members if member.annotation != "value" and member.length != "strlen" %}
{% if member.type.category != "object" and member.optional %}
if (record.{{as_varName(member.name)}} != nullptr)
{% endif %}
{
size_t memberLength = {{member_length(member, "record.")}};
result += memberLength * {{member_transfer_sizeof(member)}};
@ -176,6 +183,12 @@
//* Allocate space and write the non-value arguments in it.
{% for member in members if member.annotation != "value" and member.length != "strlen" %}
{% set memberName = as_varName(member.name) %}
{% if member.type.category != "object" and member.optional %}
bool has_{{memberName}} = record.{{memberName}} != nullptr;
transfer->has_{{memberName}} = has_{{memberName}};
if (has_{{memberName}})
{% endif %}
{
size_t memberLength = {{member_length(member, "record.")}};
auto memberBuffer = reinterpret_cast<{{member_transfer_type(member)}}*>(*buffer);
@ -277,6 +290,12 @@
//* Get extra buffer data, and copy pointed to values in extra allocated space.
{% for member in members if member.annotation != "value" and member.length != "strlen" %}
{% set memberName = as_varName(member.name) %}
{% if member.type.category != "object" and member.optional %}
bool has_{{memberName}} = transfer->has_{{memberName}};
record->{{memberName}} = nullptr;
if (has_{{memberName}})
{% endif %}
{
size_t memberLength = {{member_length(member, "record->")}};
auto memberBuffer = reinterpret_cast<const {{member_transfer_type(member)}}*>(buffer);

View File

@ -439,6 +439,141 @@ TEST_F(WireTests, CStringArgument) {
FlushClient();
}
// Test that the wire is able to send optional pointers to structures
TEST_F(WireTests, OptionalStructPointer) {
// Create shader module
dawnShaderModuleDescriptor vertexDescriptor;
vertexDescriptor.nextInChain = nullptr;
vertexDescriptor.codeSize = 0;
dawnShaderModule vsModule = dawnDeviceCreateShaderModule(device, &vertexDescriptor);
dawnShaderModule apiVsModule = api.GetNewShaderModule();
EXPECT_CALL(api, DeviceCreateShaderModule(apiDevice, _))
.WillOnce(Return(apiVsModule));
// Create the blend state descriptor
dawnBlendDescriptor blendDescriptor;
blendDescriptor.operation = DAWN_BLEND_OPERATION_ADD;
blendDescriptor.srcFactor = DAWN_BLEND_FACTOR_ONE;
blendDescriptor.dstFactor = DAWN_BLEND_FACTOR_ONE;
dawnBlendStateDescriptor blendStateDescriptor;
blendStateDescriptor.nextInChain = nullptr;
blendStateDescriptor.alphaBlend = blendDescriptor;
blendStateDescriptor.colorBlend = blendDescriptor;
blendStateDescriptor.colorWriteMask = DAWN_COLOR_WRITE_MASK_ALL;
// Create the input state
dawnInputStateBuilder inputStateBuilder = dawnDeviceCreateInputStateBuilder(device);
dawnInputStateBuilder apiInputStateBuilder = api.GetNewInputStateBuilder();
EXPECT_CALL(api, DeviceCreateInputStateBuilder(apiDevice))
.WillOnce(Return(apiInputStateBuilder));
dawnInputState inputState = dawnInputStateBuilderGetResult(inputStateBuilder);
dawnInputState apiInputState = api.GetNewInputState();
EXPECT_CALL(api, InputStateBuilderGetResult(apiInputStateBuilder))
.WillOnce(Return(apiInputState));
// Create the depth-stencil state
dawnStencilStateFaceDescriptor stencilFace;
stencilFace.compare = DAWN_COMPARE_FUNCTION_ALWAYS;
stencilFace.failOp = DAWN_STENCIL_OPERATION_KEEP;
stencilFace.depthFailOp = DAWN_STENCIL_OPERATION_KEEP;
stencilFace.passOp = DAWN_STENCIL_OPERATION_KEEP;
dawnDepthStencilStateDescriptor depthStencilState;
depthStencilState.nextInChain = nullptr;
depthStencilState.depthWriteEnabled = false;
depthStencilState.depthCompare = DAWN_COMPARE_FUNCTION_ALWAYS;
depthStencilState.stencilBack = stencilFace;
depthStencilState.stencilFront = stencilFace;
depthStencilState.stencilReadMask = 0xff;
depthStencilState.stencilWriteMask = 0xff;
// Create the pipeline layout
dawnPipelineLayoutDescriptor layoutDescriptor;
layoutDescriptor.nextInChain = nullptr;
layoutDescriptor.numBindGroupLayouts = 0;
layoutDescriptor.bindGroupLayouts = nullptr;
dawnPipelineLayout layout = dawnDeviceCreatePipelineLayout(device, &layoutDescriptor);
dawnPipelineLayout apiLayout = api.GetNewPipelineLayout();
EXPECT_CALL(api, DeviceCreatePipelineLayout(apiDevice, _))
.WillOnce(Return(apiLayout));
// Create pipeline
dawnRenderPipelineDescriptor pipelineDescriptor;
pipelineDescriptor.nextInChain = nullptr;
dawnPipelineStageDescriptor vertexStage;
vertexStage.nextInChain = nullptr;
vertexStage.module = vsModule;
vertexStage.entryPoint = "main";
pipelineDescriptor.vertexStage = &vertexStage;
dawnPipelineStageDescriptor fragmentStage;
fragmentStage.nextInChain = nullptr;
fragmentStage.module = vsModule;
fragmentStage.entryPoint = "main";
pipelineDescriptor.fragmentStage = &fragmentStage;
dawnAttachmentsStateDescriptor attachmentsState;
attachmentsState.nextInChain = nullptr;
attachmentsState.numColorAttachments = 1;
dawnAttachmentDescriptor colorAttachment = {nullptr, DAWN_TEXTURE_FORMAT_R8_G8_B8_A8_UNORM};
dawnAttachmentDescriptor* colorAttachmentPtr[] = {&colorAttachment};
attachmentsState.colorAttachments = colorAttachmentPtr;
attachmentsState.hasDepthStencilAttachment = false;
// Even with hasDepthStencilAttachment = false, depthStencilAttachment must point to valid
// data because we don't have optional substructures yet.
attachmentsState.depthStencilAttachment = &colorAttachment;
pipelineDescriptor.attachmentsState = &attachmentsState;
pipelineDescriptor.numBlendStates = 1;
pipelineDescriptor.blendStates = &blendStateDescriptor;
pipelineDescriptor.sampleCount = 1;
pipelineDescriptor.layout = layout;
pipelineDescriptor.inputState = inputState;
pipelineDescriptor.indexFormat = DAWN_INDEX_FORMAT_UINT32;
pipelineDescriptor.primitiveTopology = DAWN_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
// First case: depthStencilState is not null.
pipelineDescriptor.depthStencilState = &depthStencilState;
dawnDeviceCreateRenderPipeline(device, &pipelineDescriptor);
EXPECT_CALL(api, DeviceCreateRenderPipeline(apiDevice, MatchesLambda([](const dawnRenderPipelineDescriptor* desc) -> bool {
return desc->depthStencilState != nullptr &&
desc->depthStencilState->nextInChain == nullptr &&
desc->depthStencilState->depthWriteEnabled == false &&
desc->depthStencilState->depthCompare == DAWN_COMPARE_FUNCTION_ALWAYS &&
desc->depthStencilState->stencilBack.compare == DAWN_COMPARE_FUNCTION_ALWAYS &&
desc->depthStencilState->stencilBack.failOp == DAWN_STENCIL_OPERATION_KEEP &&
desc->depthStencilState->stencilBack.depthFailOp == DAWN_STENCIL_OPERATION_KEEP &&
desc->depthStencilState->stencilBack.passOp == DAWN_STENCIL_OPERATION_KEEP &&
desc->depthStencilState->stencilFront.compare == DAWN_COMPARE_FUNCTION_ALWAYS &&
desc->depthStencilState->stencilFront.failOp == DAWN_STENCIL_OPERATION_KEEP &&
desc->depthStencilState->stencilFront.depthFailOp == DAWN_STENCIL_OPERATION_KEEP &&
desc->depthStencilState->stencilFront.passOp == DAWN_STENCIL_OPERATION_KEEP &&
desc->depthStencilState->stencilReadMask == 0xff &&
desc->depthStencilState->stencilWriteMask == 0xff;
})))
.WillOnce(Return(nullptr));
FlushClient();
// Second case: depthStencilState is null.
pipelineDescriptor.depthStencilState = nullptr;
dawnDeviceCreateRenderPipeline(device, &pipelineDescriptor);
EXPECT_CALL(api, DeviceCreateRenderPipeline(apiDevice, MatchesLambda([](const dawnRenderPipelineDescriptor* desc) -> bool {
return desc->depthStencilState == nullptr;
})))
.WillOnce(Return(nullptr));
EXPECT_CALL(api, ShaderModuleRelease(apiVsModule));
EXPECT_CALL(api, InputStateBuilderRelease(apiInputStateBuilder));
EXPECT_CALL(api, InputStateRelease(apiInputState));
EXPECT_CALL(api, PipelineLayoutRelease(apiLayout));
FlushClient();
}
// Test that the wire is able to send objects as value arguments
TEST_F(WireTests, ObjectAsValueArgument) {
// Create a RenderPassDescriptor