mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-15 16:16:08 +00:00
Add the entry point of CreateReadyComputePipeline
This patch adds the entry point of CreateReadyComputePipeline in both dawn_native and dawn_wire. TODOs: 1. Add more tests in dawn_unittests and dawn_end2end_tests. 2. Put the main logic of creating a pipeline into a separate thread. BUG=dawn:529 TEST=dawn_end2end_tests Change-Id: I7edd269a5422a8b85320a7f9173df925decba633 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/30060 Commit-Queue: Jiawei Shao <jiawei.shao@intel.com> Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
committed by
Commit Bot service account
parent
47a6a94e15
commit
ae5f950444
@@ -215,6 +215,7 @@ test("dawn_unittests") {
|
||||
"unittests/wire/WireArgumentTests.cpp",
|
||||
"unittests/wire/WireBasicTests.cpp",
|
||||
"unittests/wire/WireBufferMappingTests.cpp",
|
||||
"unittests/wire/WireCreateReadyPipelineTests.cpp",
|
||||
"unittests/wire/WireDisconnectTests.cpp",
|
||||
"unittests/wire/WireErrorCallbackTests.cpp",
|
||||
"unittests/wire/WireExtensionTests.cpp",
|
||||
@@ -273,6 +274,7 @@ source_set("dawn_end2end_tests_sources") {
|
||||
"end2end/ComputeSharedMemoryTests.cpp",
|
||||
"end2end/ComputeStorageBufferBarrierTests.cpp",
|
||||
"end2end/CopyTests.cpp",
|
||||
"end2end/CreateReadyPipelineTests.cpp",
|
||||
"end2end/CullingTests.cpp",
|
||||
"end2end/DebugMarkerTests.cpp",
|
||||
"end2end/DeprecatedAPITests.cpp",
|
||||
|
||||
137
src/tests/end2end/CreateReadyPipelineTests.cpp
Normal file
137
src/tests/end2end/CreateReadyPipelineTests.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
// Copyright 2020 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/DawnTest.h"
|
||||
|
||||
#include "utils/WGPUHelpers.h"
|
||||
|
||||
namespace {
|
||||
struct CreateReadyPipelineTask {
|
||||
wgpu::ComputePipeline computePipeline;
|
||||
bool isCompleted = false;
|
||||
std::string message;
|
||||
};
|
||||
} // anonymous namespace
|
||||
|
||||
class CreateReadyPipelineTest : public DawnTest {};
|
||||
|
||||
// Verify the basic use of CreateReadyComputePipeline works on all backends.
|
||||
TEST_P(CreateReadyPipelineTest, BasicUseOfCreateReadyComputePipeline) {
|
||||
const char* computeShader = R"(
|
||||
#version 450
|
||||
layout(std140, set = 0, binding = 0) buffer SSBO { uint value; } ssbo;
|
||||
void main() {
|
||||
ssbo.value = 1u;
|
||||
})";
|
||||
|
||||
wgpu::ComputePipelineDescriptor csDesc;
|
||||
csDesc.computeStage.module =
|
||||
utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, computeShader);
|
||||
csDesc.computeStage.entryPoint = "main";
|
||||
|
||||
CreateReadyPipelineTask task;
|
||||
device.CreateReadyComputePipeline(
|
||||
&csDesc,
|
||||
[](WGPUCreateReadyPipelineStatus status, WGPUComputePipeline returnPipeline,
|
||||
const char* message, void* userdata) {
|
||||
ASSERT_EQ(WGPUCreateReadyPipelineStatus::WGPUCreateReadyPipelineStatus_Success, status);
|
||||
|
||||
CreateReadyPipelineTask* task = static_cast<CreateReadyPipelineTask*>(userdata);
|
||||
task->computePipeline = wgpu::ComputePipeline::Acquire(returnPipeline);
|
||||
task->isCompleted = true;
|
||||
task->message = message;
|
||||
},
|
||||
&task);
|
||||
|
||||
wgpu::BufferDescriptor bufferDesc;
|
||||
bufferDesc.size = sizeof(uint32_t);
|
||||
bufferDesc.usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc;
|
||||
wgpu::Buffer ssbo = device.CreateBuffer(&bufferDesc);
|
||||
|
||||
wgpu::CommandBuffer commands;
|
||||
{
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
|
||||
|
||||
while (!task.isCompleted) {
|
||||
WaitABit();
|
||||
}
|
||||
ASSERT_TRUE(task.message.empty());
|
||||
ASSERT_NE(nullptr, task.computePipeline.Get());
|
||||
wgpu::BindGroup bindGroup =
|
||||
utils::MakeBindGroup(device, task.computePipeline.GetBindGroupLayout(0),
|
||||
{
|
||||
{0, ssbo, 0, sizeof(uint32_t)},
|
||||
});
|
||||
pass.SetBindGroup(0, bindGroup);
|
||||
pass.SetPipeline(task.computePipeline);
|
||||
|
||||
pass.Dispatch(1);
|
||||
pass.EndPass();
|
||||
|
||||
commands = encoder.Finish();
|
||||
}
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
constexpr uint32_t kExpected = 1u;
|
||||
EXPECT_BUFFER_U32_EQ(kExpected, ssbo, 0);
|
||||
}
|
||||
|
||||
// Verify CreateReadyComputePipeline() works as expected when there is any error that happens during
|
||||
// the creation of the compute pipeline. The SPEC requires that during the call of
|
||||
// CreateReadyComputePipeline() any error won't be forwarded to the error scope / unhandled error
|
||||
// callback.
|
||||
TEST_P(CreateReadyPipelineTest, CreateComputePipelineFailed) {
|
||||
DAWN_SKIP_TEST_IF(IsDawnValidationSkipped());
|
||||
|
||||
const char* computeShader = R"(
|
||||
#version 450
|
||||
layout(std140, set = 0, binding = 0) buffer SSBO { uint value; } ssbo;
|
||||
void main() {
|
||||
ssbo.value = 1u;
|
||||
})";
|
||||
|
||||
wgpu::ComputePipelineDescriptor csDesc;
|
||||
csDesc.computeStage.module =
|
||||
utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, computeShader);
|
||||
csDesc.computeStage.entryPoint = "main0";
|
||||
|
||||
CreateReadyPipelineTask task;
|
||||
device.CreateReadyComputePipeline(
|
||||
&csDesc,
|
||||
[](WGPUCreateReadyPipelineStatus status, WGPUComputePipeline returnPipeline,
|
||||
const char* message, void* userdata) {
|
||||
ASSERT_EQ(WGPUCreateReadyPipelineStatus::WGPUCreateReadyPipelineStatus_Error, status);
|
||||
|
||||
CreateReadyPipelineTask* task = static_cast<CreateReadyPipelineTask*>(userdata);
|
||||
task->computePipeline = wgpu::ComputePipeline::Acquire(returnPipeline);
|
||||
task->isCompleted = true;
|
||||
task->message = message;
|
||||
},
|
||||
&task);
|
||||
|
||||
while (!task.isCompleted) {
|
||||
WaitABit();
|
||||
}
|
||||
|
||||
ASSERT_FALSE(task.message.empty());
|
||||
ASSERT_EQ(nullptr, task.computePipeline.Get());
|
||||
}
|
||||
|
||||
DAWN_INSTANTIATE_TEST(CreateReadyPipelineTest,
|
||||
D3D12Backend(),
|
||||
MetalBackend(),
|
||||
OpenGLBackend(),
|
||||
VulkanBackend());
|
||||
127
src/tests/unittests/wire/WireCreateReadyPipelineTests.cpp
Normal file
127
src/tests/unittests/wire/WireCreateReadyPipelineTests.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
// Copyright 2020 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;
|
||||
|
||||
namespace {
|
||||
|
||||
// Mock class to add expectations on the wire calling callbacks
|
||||
class MockCreateReadyComputePipelineCallback {
|
||||
public:
|
||||
MOCK_METHOD(void,
|
||||
Call,
|
||||
(WGPUCreateReadyPipelineStatus status,
|
||||
WGPUComputePipeline pipeline,
|
||||
const char* message,
|
||||
void* userdata));
|
||||
};
|
||||
|
||||
std::unique_ptr<StrictMock<MockCreateReadyComputePipelineCallback>>
|
||||
mockCreateReadyComputePipelineCallback;
|
||||
void ToMockCreateReadyComputePipelineCallback(WGPUCreateReadyPipelineStatus status,
|
||||
WGPUComputePipeline pipeline,
|
||||
const char* message,
|
||||
void* userdata) {
|
||||
mockCreateReadyComputePipelineCallback->Call(status, pipeline, message, userdata);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class WireCreateReadyPipelineTest : public WireTest {
|
||||
public:
|
||||
void SetUp() override {
|
||||
WireTest::SetUp();
|
||||
|
||||
mockCreateReadyComputePipelineCallback =
|
||||
std::make_unique<StrictMock<MockCreateReadyComputePipelineCallback>>();
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
WireTest::TearDown();
|
||||
|
||||
// Delete mock so that expectations are checked
|
||||
mockCreateReadyComputePipelineCallback = nullptr;
|
||||
}
|
||||
|
||||
void FlushClient() {
|
||||
WireTest::FlushClient();
|
||||
Mock::VerifyAndClearExpectations(&mockCreateReadyComputePipelineCallback);
|
||||
}
|
||||
|
||||
void FlushServer() {
|
||||
WireTest::FlushServer();
|
||||
Mock::VerifyAndClearExpectations(&mockCreateReadyComputePipelineCallback);
|
||||
}
|
||||
};
|
||||
|
||||
// Test when creating a compute pipeline with CreateReadyComputePipeline() successfully.
|
||||
TEST_F(WireCreateReadyPipelineTest, CreateReadyComputePipelineSuccess) {
|
||||
WGPUShaderModuleDescriptor csDescriptor{};
|
||||
WGPUShaderModule csModule = wgpuDeviceCreateShaderModule(device, &csDescriptor);
|
||||
WGPUShaderModule apiCsModule = api.GetNewShaderModule();
|
||||
EXPECT_CALL(api, DeviceCreateShaderModule(apiDevice, _)).WillOnce(Return(apiCsModule));
|
||||
|
||||
WGPUComputePipelineDescriptor descriptor{};
|
||||
descriptor.computeStage.module = csModule;
|
||||
descriptor.computeStage.entryPoint = "main";
|
||||
|
||||
wgpuDeviceCreateReadyComputePipeline(device, &descriptor,
|
||||
ToMockCreateReadyComputePipelineCallback, this);
|
||||
|
||||
EXPECT_CALL(api, OnDeviceCreateReadyComputePipelineCallback(apiDevice, _, _, _))
|
||||
.WillOnce(InvokeWithoutArgs([&]() {
|
||||
api.CallDeviceCreateReadyComputePipelineCallback(
|
||||
apiDevice, WGPUCreateReadyPipelineStatus_Success, nullptr, "");
|
||||
}));
|
||||
|
||||
FlushClient();
|
||||
|
||||
EXPECT_CALL(*mockCreateReadyComputePipelineCallback,
|
||||
Call(WGPUCreateReadyPipelineStatus_Success, _, StrEq(""), this))
|
||||
.Times(1);
|
||||
|
||||
FlushServer();
|
||||
}
|
||||
|
||||
// Test when creating a compute pipeline with CreateReadyComputePipeline() results in an error.
|
||||
TEST_F(WireCreateReadyPipelineTest, CreateReadyComputePipelineError) {
|
||||
WGPUShaderModuleDescriptor csDescriptor{};
|
||||
WGPUShaderModule csModule = wgpuDeviceCreateShaderModule(device, &csDescriptor);
|
||||
WGPUShaderModule apiCsModule = api.GetNewShaderModule();
|
||||
EXPECT_CALL(api, DeviceCreateShaderModule(apiDevice, _)).WillOnce(Return(apiCsModule));
|
||||
|
||||
WGPUComputePipelineDescriptor descriptor{};
|
||||
descriptor.computeStage.module = csModule;
|
||||
descriptor.computeStage.entryPoint = "main";
|
||||
|
||||
wgpuDeviceCreateReadyComputePipeline(device, &descriptor,
|
||||
ToMockCreateReadyComputePipelineCallback, this);
|
||||
|
||||
EXPECT_CALL(api, OnDeviceCreateReadyComputePipelineCallback(apiDevice, _, _, _))
|
||||
.WillOnce(InvokeWithoutArgs([&]() {
|
||||
api.CallDeviceCreateReadyComputePipelineCallback(
|
||||
apiDevice, WGPUCreateReadyPipelineStatus_Error, nullptr, "Some error message");
|
||||
}));
|
||||
|
||||
FlushClient();
|
||||
|
||||
EXPECT_CALL(*mockCreateReadyComputePipelineCallback,
|
||||
Call(WGPUCreateReadyPipelineStatus_Error, _, StrEq("Some error message"), this))
|
||||
.Times(1);
|
||||
|
||||
FlushServer();
|
||||
}
|
||||
Reference in New Issue
Block a user