// Copyright 2019 The Dawn Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "tests/unittests/wire/WireTest.h" using namespace testing; using namespace dawn_wire; class WireOptionalTests : public WireTest { public: WireOptionalTests() { } ~WireOptionalTests() override = default; }; // Test passing nullptr instead of objects - object as value version TEST_F(WireOptionalTests, OptionalObjectValue) { WGPUBindGroupLayoutDescriptor bglDesc; bglDesc.nextInChain = nullptr; bglDesc.label = nullptr; bglDesc.bindingCount = 0; WGPUBindGroupLayout bgl = wgpuDeviceCreateBindGroupLayout(device, &bglDesc); WGPUBindGroupLayout apiBindGroupLayout = api.GetNewBindGroupLayout(); EXPECT_CALL(api, DeviceCreateBindGroupLayout(apiDevice, _)) .WillOnce(Return(apiBindGroupLayout)); // The `sampler`, `textureView` and `buffer` members of a binding are optional. WGPUBindGroupBinding binding; binding.binding = 0; binding.sampler = nullptr; binding.textureView = nullptr; binding.buffer = nullptr; WGPUBindGroupDescriptor bgDesc; bgDesc.nextInChain = nullptr; bgDesc.label = nullptr; bgDesc.layout = bgl; bgDesc.bindingCount = 1; bgDesc.bindings = &binding; wgpuDeviceCreateBindGroup(device, &bgDesc); WGPUBindGroup apiDummyBindGroup = api.GetNewBindGroup(); EXPECT_CALL(api, DeviceCreateBindGroup( apiDevice, MatchesLambda([](const WGPUBindGroupDescriptor* desc) -> bool { return desc->nextInChain == nullptr && desc->bindingCount == 1 && desc->bindings[0].binding == 0 && desc->bindings[0].sampler == nullptr && desc->bindings[0].buffer == nullptr && desc->bindings[0].textureView == nullptr; }))) .WillOnce(Return(apiDummyBindGroup)); FlushClient(); } // Test that the wire is able to send optional pointers to structures TEST_F(WireOptionalTests, OptionalStructPointer) { // Create shader module WGPUShaderModuleDescriptor vertexDescriptor; vertexDescriptor.nextInChain = nullptr; vertexDescriptor.label = nullptr; vertexDescriptor.codeSize = 0; WGPUShaderModule vsModule = wgpuDeviceCreateShaderModule(device, &vertexDescriptor); WGPUShaderModule apiVsModule = api.GetNewShaderModule(); EXPECT_CALL(api, DeviceCreateShaderModule(apiDevice, _)).WillOnce(Return(apiVsModule)); // Create the color state descriptor WGPUBlendDescriptor blendDescriptor; blendDescriptor.operation = WGPUBlendOperation_Add; blendDescriptor.srcFactor = WGPUBlendFactor_One; blendDescriptor.dstFactor = WGPUBlendFactor_One; WGPUColorStateDescriptor colorStateDescriptor; colorStateDescriptor.nextInChain = nullptr; colorStateDescriptor.format = WGPUTextureFormat_RGBA8Unorm; colorStateDescriptor.alphaBlend = blendDescriptor; colorStateDescriptor.colorBlend = blendDescriptor; colorStateDescriptor.writeMask = WGPUColorWriteMask_All; // Create the input state WGPUVertexInputDescriptor vertexInput; vertexInput.nextInChain = nullptr; vertexInput.indexFormat = WGPUIndexFormat_Uint32; vertexInput.bufferCount = 0; vertexInput.buffers = nullptr; // Create the rasterization state WGPURasterizationStateDescriptor rasterizationState; rasterizationState.nextInChain = nullptr; rasterizationState.frontFace = WGPUFrontFace_CCW; rasterizationState.cullMode = WGPUCullMode_None; rasterizationState.depthBias = 0; rasterizationState.depthBiasSlopeScale = 0.0; rasterizationState.depthBiasClamp = 0.0; // Create the depth-stencil state WGPUStencilStateFaceDescriptor stencilFace; stencilFace.compare = WGPUCompareFunction_Always; stencilFace.failOp = WGPUStencilOperation_Keep; stencilFace.depthFailOp = WGPUStencilOperation_Keep; stencilFace.passOp = WGPUStencilOperation_Keep; WGPUDepthStencilStateDescriptor depthStencilState; depthStencilState.nextInChain = nullptr; depthStencilState.format = WGPUTextureFormat_Depth24PlusStencil8; depthStencilState.depthWriteEnabled = false; depthStencilState.depthCompare = WGPUCompareFunction_Always; depthStencilState.stencilBack = stencilFace; depthStencilState.stencilFront = stencilFace; depthStencilState.stencilReadMask = 0xff; depthStencilState.stencilWriteMask = 0xff; // Create the pipeline layout WGPUPipelineLayoutDescriptor layoutDescriptor; layoutDescriptor.nextInChain = nullptr; layoutDescriptor.label = nullptr; layoutDescriptor.bindGroupLayoutCount = 0; layoutDescriptor.bindGroupLayouts = nullptr; WGPUPipelineLayout layout = wgpuDeviceCreatePipelineLayout(device, &layoutDescriptor); WGPUPipelineLayout apiLayout = api.GetNewPipelineLayout(); EXPECT_CALL(api, DeviceCreatePipelineLayout(apiDevice, _)).WillOnce(Return(apiLayout)); // Create pipeline WGPURenderPipelineDescriptor pipelineDescriptor; pipelineDescriptor.nextInChain = nullptr; pipelineDescriptor.label = nullptr; pipelineDescriptor.vertexStage.nextInChain = nullptr; pipelineDescriptor.vertexStage.module = vsModule; pipelineDescriptor.vertexStage.entryPoint = "main"; WGPUProgrammableStageDescriptor fragmentStage; fragmentStage.nextInChain = nullptr; fragmentStage.module = vsModule; fragmentStage.entryPoint = "main"; pipelineDescriptor.fragmentStage = &fragmentStage; pipelineDescriptor.colorStateCount = 1; pipelineDescriptor.colorStates = &colorStateDescriptor; pipelineDescriptor.sampleCount = 1; pipelineDescriptor.sampleMask = 0xFFFFFFFF; pipelineDescriptor.alphaToCoverageEnabled = false; pipelineDescriptor.layout = layout; pipelineDescriptor.vertexInput = &vertexInput; pipelineDescriptor.primitiveTopology = WGPUPrimitiveTopology_TriangleList; pipelineDescriptor.rasterizationState = &rasterizationState; // First case: depthStencilState is not null. pipelineDescriptor.depthStencilState = &depthStencilState; wgpuDeviceCreateRenderPipeline(device, &pipelineDescriptor); WGPURenderPipeline apiDummyPipeline = api.GetNewRenderPipeline(); EXPECT_CALL( api, DeviceCreateRenderPipeline( apiDevice, MatchesLambda([](const WGPURenderPipelineDescriptor* desc) -> bool { return desc->depthStencilState != nullptr && desc->depthStencilState->nextInChain == nullptr && desc->depthStencilState->depthWriteEnabled == false && desc->depthStencilState->depthCompare == WGPUCompareFunction_Always && desc->depthStencilState->stencilBack.compare == WGPUCompareFunction_Always && desc->depthStencilState->stencilBack.failOp == WGPUStencilOperation_Keep && desc->depthStencilState->stencilBack.depthFailOp == WGPUStencilOperation_Keep && desc->depthStencilState->stencilBack.passOp == WGPUStencilOperation_Keep && desc->depthStencilState->stencilFront.compare == WGPUCompareFunction_Always && desc->depthStencilState->stencilFront.failOp == WGPUStencilOperation_Keep && desc->depthStencilState->stencilFront.depthFailOp == WGPUStencilOperation_Keep && desc->depthStencilState->stencilFront.passOp == WGPUStencilOperation_Keep && desc->depthStencilState->stencilReadMask == 0xff && desc->depthStencilState->stencilWriteMask == 0xff; }))) .WillOnce(Return(apiDummyPipeline)); FlushClient(); // Second case: depthStencilState is null. pipelineDescriptor.depthStencilState = nullptr; wgpuDeviceCreateRenderPipeline(device, &pipelineDescriptor); EXPECT_CALL(api, DeviceCreateRenderPipeline( apiDevice, MatchesLambda([](const WGPURenderPipelineDescriptor* desc) -> bool { return desc->depthStencilState == nullptr; }))) .WillOnce(Return(apiDummyPipeline)); FlushClient(); }