Update the validation tests to use utils::WireHelper

This enables running the validation uses using the wire with
the command line flag --use-wire

Bug: dawn:654
Change-Id: I17a642a132c8b6321195ec6869e5f86aebdd1c51
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/38620
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Stephen White <senorblanco@chromium.org>
This commit is contained in:
Austin Eng 2021-01-27 23:02:24 +00:00 committed by Commit Bot service account
parent e37a4b067a
commit 78440d66f3
14 changed files with 195 additions and 35 deletions

View File

@ -12,9 +12,12 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "unittests/validation/ValidationTest.h"
#include <gtest/gtest.h> #include <gtest/gtest.h>
int main(int argc, char** argv) { int main(int argc, char** argv) {
InitDawnValidationTestEnvironment(argc, argv);
testing::InitGoogleTest(&argc, argv); testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS(); return RUN_ALL_TESTS();
} }

View File

@ -85,6 +85,7 @@ TEST_F(BindGroupValidationTest, NextInChainNullptr) {
// Check that nextInChain != nullptr is an error. // Check that nextInChain != nullptr is an error.
wgpu::ChainedStruct chainedDescriptor; wgpu::ChainedStruct chainedDescriptor;
chainedDescriptor.sType = wgpu::SType::ShaderModuleWGSLDescriptor;
descriptor.nextInChain = &chainedDescriptor; descriptor.nextInChain = &chainedDescriptor;
ASSERT_DEVICE_ERROR(device.CreateBindGroup(&descriptor)); ASSERT_DEVICE_ERROR(device.CreateBindGroup(&descriptor));
} }

View File

@ -808,6 +808,9 @@ TEST_F(BufferValidationTest, GetMappedRange_OnErrorBuffer) {
// Test validation of the GetMappedRange parameters // Test validation of the GetMappedRange parameters
TEST_F(BufferValidationTest, GetMappedRange_OffsetSizeOOB) { TEST_F(BufferValidationTest, GetMappedRange_OffsetSizeOOB) {
// TODO(crbug.com/dawn/651): Fix failures on the wire.
DAWN_SKIP_TEST_IF(UsesWire());
// Valid case: full range is ok // Valid case: full range is ok
{ {
wgpu::Buffer buffer = CreateMapWriteBuffer(8); wgpu::Buffer buffer = CreateMapWriteBuffer(8);

View File

@ -1904,10 +1904,10 @@ TEST_F(CopyCommandTest_T2T, CopyWithinSameTexture) {
class CopyCommandTest_CompressedTextureFormats : public CopyCommandTest { class CopyCommandTest_CompressedTextureFormats : public CopyCommandTest {
protected: protected:
wgpu::Device CreateTestDevice() override { WGPUDevice CreateTestDevice() override {
dawn_native::DeviceDescriptor descriptor; dawn_native::DeviceDescriptor descriptor;
descriptor.requiredExtensions = {"texture_compression_bc"}; descriptor.requiredExtensions = {"texture_compression_bc"};
return wgpu::Device::Acquire(adapter.CreateDevice(&descriptor)); return adapter.CreateDevice(&descriptor);
} }
wgpu::Texture Create2DTexture(wgpu::TextureFormat format, wgpu::Texture Create2DTexture(wgpu::TextureFormat format,

View File

@ -51,6 +51,7 @@ TEST_F(ErrorScopeValidationTest, Success) {
EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_NoError, _, this)).Times(1); EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_NoError, _, this)).Times(1);
device.PopErrorScope(ToMockDevicePopErrorScopeCallback, this); device.PopErrorScope(ToMockDevicePopErrorScopeCallback, this);
FlushWire();
} }
// Test the simple case where the error scope catches an error. // Test the simple case where the error scope catches an error.
@ -63,6 +64,7 @@ TEST_F(ErrorScopeValidationTest, CatchesError) {
EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_Validation, _, this)).Times(1); EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_Validation, _, this)).Times(1);
device.PopErrorScope(ToMockDevicePopErrorScopeCallback, this); device.PopErrorScope(ToMockDevicePopErrorScopeCallback, this);
FlushWire();
} }
// Test that errors bubble to the parent scope if not handled by the current scope. // Test that errors bubble to the parent scope if not handled by the current scope.
@ -77,11 +79,13 @@ TEST_F(ErrorScopeValidationTest, ErrorBubbles) {
// OutOfMemory does not match Validation error. // OutOfMemory does not match Validation error.
EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_NoError, _, this)).Times(1); EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_NoError, _, this)).Times(1);
device.PopErrorScope(ToMockDevicePopErrorScopeCallback, this); device.PopErrorScope(ToMockDevicePopErrorScopeCallback, this);
FlushWire();
// Parent validation error scope captures the error. // Parent validation error scope captures the error.
EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_Validation, _, this + 1)) EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_Validation, _, this + 1))
.Times(1); .Times(1);
device.PopErrorScope(ToMockDevicePopErrorScopeCallback, this + 1); device.PopErrorScope(ToMockDevicePopErrorScopeCallback, this + 1);
FlushWire();
} }
// Test that if an error scope matches an error, it does not bubble to the parent scope. // Test that if an error scope matches an error, it does not bubble to the parent scope.
@ -96,11 +100,13 @@ TEST_F(ErrorScopeValidationTest, HandledErrorsStopBubbling) {
// Inner scope catches the error. // Inner scope catches the error.
EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_Validation, _, this)).Times(1); EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_Validation, _, this)).Times(1);
device.PopErrorScope(ToMockDevicePopErrorScopeCallback, this); device.PopErrorScope(ToMockDevicePopErrorScopeCallback, this);
FlushWire();
// Parent scope does not see the error. // Parent scope does not see the error.
EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_NoError, _, this + 1)) EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_NoError, _, this + 1))
.Times(1); .Times(1);
device.PopErrorScope(ToMockDevicePopErrorScopeCallback, this + 1); device.PopErrorScope(ToMockDevicePopErrorScopeCallback, this + 1);
FlushWire();
} }
// Test that if no error scope handles an error, it goes to the device UncapturedError callback // Test that if no error scope handles an error, it goes to the device UncapturedError callback
@ -113,6 +119,7 @@ TEST_F(ErrorScopeValidationTest, UnhandledErrorsMatchUncapturedErrorCallback) {
EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_NoError, _, this)).Times(1); EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_NoError, _, this)).Times(1);
device.PopErrorScope(ToMockDevicePopErrorScopeCallback, this); device.PopErrorScope(ToMockDevicePopErrorScopeCallback, this);
FlushWire();
} }
// Check that push/popping error scopes must be balanced. // Check that push/popping error scopes must be balanced.
@ -127,6 +134,7 @@ TEST_F(ErrorScopeValidationTest, PushPopBalanced) {
EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_NoError, _, this + 1)) EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_NoError, _, this + 1))
.Times(1); .Times(1);
device.PopErrorScope(ToMockDevicePopErrorScopeCallback, this + 1); device.PopErrorScope(ToMockDevicePopErrorScopeCallback, this + 1);
FlushWire();
EXPECT_FALSE(device.PopErrorScope(ToMockDevicePopErrorScopeCallback, this + 2)); EXPECT_FALSE(device.PopErrorScope(ToMockDevicePopErrorScopeCallback, this + 2));
} }
@ -145,6 +153,7 @@ TEST_F(ErrorScopeValidationTest, CallbackAfterQueueSubmit) {
// Side effects of Queue::Submit only are seen after Tick() // Side effects of Queue::Submit only are seen after Tick()
device.Tick(); device.Tick();
FlushWire();
} }
// Test that parent error scopes do not call their callbacks until after an enclosed Queue::Submit // Test that parent error scopes do not call their callbacks until after an enclosed Queue::Submit
@ -164,6 +173,7 @@ TEST_F(ErrorScopeValidationTest, CallbackAfterQueueSubmitNested) {
// Side effects of Queue::Submit only are seen after Tick() // Side effects of Queue::Submit only are seen after Tick()
device.Tick(); device.Tick();
FlushWire();
} }
// Test a callback that returns asynchronously followed by a synchronous one // Test a callback that returns asynchronously followed by a synchronous one
@ -183,11 +193,15 @@ TEST_F(ErrorScopeValidationTest, AsynchronousThenSynchronous) {
// Side effects of Queue::Submit only are seen after Tick() // Side effects of Queue::Submit only are seen after Tick()
device.Tick(); device.Tick();
FlushWire();
} }
// Test that if the device is destroyed before the callback occurs, it is called with NoError // Test that if the device is destroyed before the callback occurs, it is called with NoError
// because all previous operations are waited upon before the destruction returns. // because all previous operations are waited upon before the destruction returns.
TEST_F(ErrorScopeValidationTest, DeviceDestroyedBeforeCallback) { TEST_F(ErrorScopeValidationTest, DeviceDestroyedBeforeCallback) {
// TODO(crbug.com/dawn/652): This has different behavior on the wire and should be consistent.
DAWN_SKIP_TEST_IF(UsesWire());
wgpu::Queue queue = device.GetDefaultQueue(); wgpu::Queue queue = device.GetDefaultQueue();
device.PushErrorScope(wgpu::ErrorFilter::OutOfMemory); device.PushErrorScope(wgpu::ErrorFilter::OutOfMemory);

View File

@ -93,6 +93,10 @@ TEST_F(FenceValidationTest, GetCompletedValue) {
// Test that OnCompletion handlers are called immediately for // Test that OnCompletion handlers are called immediately for
// already completed fence values // already completed fence values
TEST_F(FenceValidationTest, OnCompletionImmediate) { TEST_F(FenceValidationTest, OnCompletionImmediate) {
// TODO(crbug.com/dawn/653): This has wrong different behavior on the wire, but fences will be
// removed soon.
DAWN_SKIP_TEST_IF(UsesWire());
wgpu::FenceDescriptor descriptor; wgpu::FenceDescriptor descriptor;
descriptor.initialValue = 1; descriptor.initialValue = 1;
wgpu::Fence fence = queue.CreateFence(&descriptor); wgpu::Fence fence = queue.CreateFence(&descriptor);
@ -127,6 +131,10 @@ TEST_F(FenceValidationTest, OnCompletionLargerThanSignaled) {
} }
TEST_F(FenceValidationTest, GetCompletedValueInsideCallback) { TEST_F(FenceValidationTest, GetCompletedValueInsideCallback) {
// TODO(crbug.com/dawn/653): This has wrong different behavior on the wire, but fences will be
// removed soon.
DAWN_SKIP_TEST_IF(UsesWire());
wgpu::FenceDescriptor descriptor; wgpu::FenceDescriptor descriptor;
descriptor.initialValue = 1; descriptor.initialValue = 1;
wgpu::Fence fence = queue.CreateFence(&descriptor); wgpu::Fence fence = queue.CreateFence(&descriptor);

View File

@ -38,6 +38,11 @@ class GetBindGroupLayoutTests : public ValidationTest {
// Test that GetBindGroupLayout returns the same object for the same index // Test that GetBindGroupLayout returns the same object for the same index
// and for matching layouts. // and for matching layouts.
TEST_F(GetBindGroupLayoutTests, SameObject) { TEST_F(GetBindGroupLayoutTests, SameObject) {
// This test works assuming Dawn Native's object deduplication.
// Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
// Native.
DAWN_SKIP_TEST_IF(UsesWire());
wgpu::ShaderModule vsModule = utils::CreateShaderModuleFromWGSL(device, R"( wgpu::ShaderModule vsModule = utils::CreateShaderModuleFromWGSL(device, R"(
[[block]] struct S { [[block]] struct S {
[[offset(0)]] pos : vec4<f32>; [[offset(0)]] pos : vec4<f32>;
@ -86,6 +91,11 @@ TEST_F(GetBindGroupLayoutTests, SameObject) {
// - shader stage visibility is the stage that adds the binding. // - shader stage visibility is the stage that adds the binding.
// - dynamic offsets is false // - dynamic offsets is false
TEST_F(GetBindGroupLayoutTests, DefaultShaderStageAndDynamicOffsets) { TEST_F(GetBindGroupLayoutTests, DefaultShaderStageAndDynamicOffsets) {
// This test works assuming Dawn Native's object deduplication.
// Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
// Native.
DAWN_SKIP_TEST_IF(UsesWire());
wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"( wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
[[block]] struct S { [[block]] struct S {
[[offset(0)]] pos : vec4<f32>; [[offset(0)]] pos : vec4<f32>;
@ -124,6 +134,11 @@ TEST_F(GetBindGroupLayoutTests, DefaultShaderStageAndDynamicOffsets) {
// Test GetBindGroupLayout works with a compute pipeline // Test GetBindGroupLayout works with a compute pipeline
TEST_F(GetBindGroupLayoutTests, ComputePipeline) { TEST_F(GetBindGroupLayoutTests, ComputePipeline) {
// This test works assuming Dawn Native's object deduplication.
// Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
// Native.
DAWN_SKIP_TEST_IF(UsesWire());
wgpu::ShaderModule csModule = utils::CreateShaderModuleFromWGSL(device, R"( wgpu::ShaderModule csModule = utils::CreateShaderModuleFromWGSL(device, R"(
[[block]] struct S { [[block]] struct S {
[[offset(0)]] pos : vec4<f32>; [[offset(0)]] pos : vec4<f32>;
@ -156,6 +171,11 @@ TEST_F(GetBindGroupLayoutTests, ComputePipeline) {
// Test that the binding type matches the shader. // Test that the binding type matches the shader.
TEST_F(GetBindGroupLayoutTests, BindingType) { TEST_F(GetBindGroupLayoutTests, BindingType) {
// This test works assuming Dawn Native's object deduplication.
// Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
// Native.
DAWN_SKIP_TEST_IF(UsesWire());
wgpu::BindGroupLayoutEntry binding = {}; wgpu::BindGroupLayoutEntry binding = {};
binding.binding = 0; binding.binding = 0;
binding.buffer.hasDynamicOffset = false; binding.buffer.hasDynamicOffset = false;
@ -242,6 +262,11 @@ TEST_F(GetBindGroupLayoutTests, BindingType) {
// Test that texture view dimension matches the shader. // Test that texture view dimension matches the shader.
TEST_F(GetBindGroupLayoutTests, ViewDimension) { TEST_F(GetBindGroupLayoutTests, ViewDimension) {
// This test works assuming Dawn Native's object deduplication.
// Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
// Native.
DAWN_SKIP_TEST_IF(UsesWire());
wgpu::BindGroupLayoutEntry binding = {}; wgpu::BindGroupLayoutEntry binding = {};
binding.binding = 0; binding.binding = 0;
binding.visibility = wgpu::ShaderStage::Fragment; binding.visibility = wgpu::ShaderStage::Fragment;
@ -314,6 +339,11 @@ TEST_F(GetBindGroupLayoutTests, ViewDimension) {
// Test that texture component type matches the shader. // Test that texture component type matches the shader.
TEST_F(GetBindGroupLayoutTests, TextureComponentType) { TEST_F(GetBindGroupLayoutTests, TextureComponentType) {
// This test works assuming Dawn Native's object deduplication.
// Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
// Native.
DAWN_SKIP_TEST_IF(UsesWire());
wgpu::BindGroupLayoutEntry binding = {}; wgpu::BindGroupLayoutEntry binding = {};
binding.binding = 0; binding.binding = 0;
binding.visibility = wgpu::ShaderStage::Fragment; binding.visibility = wgpu::ShaderStage::Fragment;
@ -355,6 +385,11 @@ TEST_F(GetBindGroupLayoutTests, TextureComponentType) {
// Test that binding= indices match. // Test that binding= indices match.
TEST_F(GetBindGroupLayoutTests, BindingIndices) { TEST_F(GetBindGroupLayoutTests, BindingIndices) {
// This test works assuming Dawn Native's object deduplication.
// Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
// Native.
DAWN_SKIP_TEST_IF(UsesWire());
wgpu::BindGroupLayoutEntry binding = {}; wgpu::BindGroupLayoutEntry binding = {};
binding.visibility = wgpu::ShaderStage::Fragment; binding.visibility = wgpu::ShaderStage::Fragment;
binding.buffer.type = wgpu::BufferBindingType::Uniform; binding.buffer.type = wgpu::BufferBindingType::Uniform;
@ -436,6 +471,11 @@ TEST_F(GetBindGroupLayoutTests, DuplicateBinding) {
// Test that minBufferSize is set on the BGL and that the max of the min buffer sizes is used. // Test that minBufferSize is set on the BGL and that the max of the min buffer sizes is used.
TEST_F(GetBindGroupLayoutTests, MinBufferSize) { TEST_F(GetBindGroupLayoutTests, MinBufferSize) {
// This test works assuming Dawn Native's object deduplication.
// Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
// Native.
DAWN_SKIP_TEST_IF(UsesWire());
wgpu::ShaderModule vsModule4 = utils::CreateShaderModuleFromWGSL(device, R"( wgpu::ShaderModule vsModule4 = utils::CreateShaderModuleFromWGSL(device, R"(
[[block]] struct S { [[block]] struct S {
[[offset(0)]] pos : f32; [[offset(0)]] pos : f32;
@ -517,6 +557,11 @@ TEST_F(GetBindGroupLayoutTests, MinBufferSize) {
// Test that the visibility is correctly aggregated if two stages have the exact same binding. // Test that the visibility is correctly aggregated if two stages have the exact same binding.
TEST_F(GetBindGroupLayoutTests, StageAggregation) { TEST_F(GetBindGroupLayoutTests, StageAggregation) {
// This test works assuming Dawn Native's object deduplication.
// Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
// Native.
DAWN_SKIP_TEST_IF(UsesWire());
wgpu::ShaderModule vsModuleNoSampler = utils::CreateShaderModuleFromWGSL(device, R"( wgpu::ShaderModule vsModuleNoSampler = utils::CreateShaderModuleFromWGSL(device, R"(
[[stage(vertex)]] fn main() -> void { [[stage(vertex)]] fn main() -> void {
})"); })");
@ -687,6 +732,11 @@ TEST_F(GetBindGroupLayoutTests, OutOfRangeIndex) {
// Test that unused indices return the empty bind group layout. // Test that unused indices return the empty bind group layout.
TEST_F(GetBindGroupLayoutTests, UnusedIndex) { TEST_F(GetBindGroupLayoutTests, UnusedIndex) {
// This test works assuming Dawn Native's object deduplication.
// Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
// Native.
DAWN_SKIP_TEST_IF(UsesWire());
wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"( wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
[[block]] struct S { [[block]] struct S {
[[offset(0)]] pos : vec4<f32>; [[offset(0)]] pos : vec4<f32>;
@ -712,6 +762,11 @@ TEST_F(GetBindGroupLayoutTests, UnusedIndex) {
// Test that after explicitly creating a pipeline with a pipeline layout, calling // Test that after explicitly creating a pipeline with a pipeline layout, calling
// GetBindGroupLayout reflects the same bind group layouts. // GetBindGroupLayout reflects the same bind group layouts.
TEST_F(GetBindGroupLayoutTests, Reflection) { TEST_F(GetBindGroupLayoutTests, Reflection) {
// This test works assuming Dawn Native's object deduplication.
// Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
// Native.
DAWN_SKIP_TEST_IF(UsesWire());
wgpu::BindGroupLayoutEntry binding = {}; wgpu::BindGroupLayoutEntry binding = {};
binding.binding = 0; binding.binding = 0;
binding.buffer.type = wgpu::BufferBindingType::Uniform; binding.buffer.type = wgpu::BufferBindingType::Uniform;

View File

@ -391,6 +391,10 @@ TEST_F(MinBufferSizeBindGroupCreationTests, BindingTooSmall) {
// Check two layouts with different minimum size are unequal // Check two layouts with different minimum size are unequal
TEST_F(MinBufferSizeBindGroupCreationTests, LayoutEquality) { TEST_F(MinBufferSizeBindGroupCreationTests, LayoutEquality) {
// Returning the same pointer is an implementation detail of Dawn Native.
// It is not the same semantic with the Wire.
DAWN_SKIP_TEST_IF(UsesWire());
auto MakeLayout = [&](uint64_t size) { auto MakeLayout = [&](uint64_t size) {
return utils::MakeBindGroupLayout( return utils::MakeBindGroupLayout(
device, device,

View File

@ -110,13 +110,18 @@ TEST_F(OcclusionQueryValidationTest, InvalidOcclusionQuerySet) {
// Fail to begin render pass if the occlusionQuerySet is created from other device // Fail to begin render pass if the occlusionQuerySet is created from other device
{ {
wgpu::Device otherDevice = adapter.CreateDevice(); wgpu::Device otherDevice = RegisterDevice(adapter.CreateDevice());
wgpu::QuerySet occlusionQuerySetOnOther = wgpu::QuerySet occlusionQuerySetOnOther =
CreateQuerySet(otherDevice, wgpu::QueryType::Occlusion, 2); CreateQuerySet(otherDevice, wgpu::QueryType::Occlusion, 2);
renderPass.occlusionQuerySet = occlusionQuerySetOnOther; renderPass.occlusionQuerySet = occlusionQuerySetOnOther;
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.BeginRenderPass(&renderPass); wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
pass.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish()); ASSERT_DEVICE_ERROR(encoder.Finish());
// Clear this out so we don't hold a reference. The query set
// must be destroyed before the device local to this test case.
renderPass.occlusionQuerySet = wgpu::QuerySet();
} }
// Fail to submit occlusion query with a destroyed query set // Fail to submit occlusion query with a destroyed query set
@ -219,10 +224,10 @@ TEST_F(OcclusionQueryValidationTest, InvalidBeginAndEnd) {
class TimestampQueryValidationTest : public QuerySetValidationTest { class TimestampQueryValidationTest : public QuerySetValidationTest {
protected: protected:
wgpu::Device CreateTestDevice() override { WGPUDevice CreateTestDevice() override {
dawn_native::DeviceDescriptor descriptor; dawn_native::DeviceDescriptor descriptor;
descriptor.requiredExtensions = {"timestamp_query"}; descriptor.requiredExtensions = {"timestamp_query"};
return wgpu::Device::Acquire(adapter.CreateDevice(&descriptor)); return adapter.CreateDevice(&descriptor);
} }
}; };
@ -422,10 +427,10 @@ TEST_F(TimestampQueryValidationTest, WriteTimestampOnRenderPassEncoder) {
class PipelineStatisticsQueryValidationTest : public QuerySetValidationTest { class PipelineStatisticsQueryValidationTest : public QuerySetValidationTest {
protected: protected:
wgpu::Device CreateTestDevice() override { WGPUDevice CreateTestDevice() override {
dawn_native::DeviceDescriptor descriptor; dawn_native::DeviceDescriptor descriptor;
descriptor.requiredExtensions = {"pipeline_statistics_query"}; descriptor.requiredExtensions = {"pipeline_statistics_query"};
return wgpu::Device::Acquire(adapter.CreateDevice(&descriptor)); return adapter.CreateDevice(&descriptor);
} }
}; };
@ -563,7 +568,7 @@ TEST_F(ResolveQuerySetValidationTest, ResolveToInvalidBufferAndOffset) {
// Fail to resolve query set to a buffer created from another device // Fail to resolve query set to a buffer created from another device
{ {
wgpu::Device otherDevice = adapter.CreateDevice(); wgpu::Device otherDevice = RegisterDevice(adapter.CreateDevice());
wgpu::Buffer bufferOnOther = wgpu::Buffer bufferOnOther =
CreateBuffer(otherDevice, kBufferSize, wgpu::BufferUsage::QueryResolve); CreateBuffer(otherDevice, kBufferSize, wgpu::BufferUsage::QueryResolve);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();

View File

@ -559,10 +559,10 @@ namespace {
class WriteTextureTest_CompressedTextureFormats : public QueueWriteTextureValidationTest { class WriteTextureTest_CompressedTextureFormats : public QueueWriteTextureValidationTest {
protected: protected:
wgpu::Device CreateTestDevice() override { WGPUDevice CreateTestDevice() override {
dawn_native::DeviceDescriptor descriptor; dawn_native::DeviceDescriptor descriptor;
descriptor.requiredExtensions = {"texture_compression_bc"}; descriptor.requiredExtensions = {"texture_compression_bc"};
return wgpu::Device::Acquire(adapter.CreateDevice(&descriptor)); return adapter.CreateDevice(&descriptor);
} }
wgpu::Texture Create2DTexture(wgpu::TextureFormat format, wgpu::Texture Create2DTexture(wgpu::TextureFormat format,

View File

@ -393,10 +393,10 @@ namespace {
// compressed texture formats. // compressed texture formats.
class CompressedTextureFormatsValidationTests : public TextureValidationTest { class CompressedTextureFormatsValidationTests : public TextureValidationTest {
protected: protected:
wgpu::Device CreateTestDevice() override { WGPUDevice CreateTestDevice() override {
dawn_native::DeviceDescriptor descriptor; dawn_native::DeviceDescriptor descriptor;
descriptor.requiredExtensions = {"texture_compression_bc"}; descriptor.requiredExtensions = {"texture_compression_bc"};
return wgpu::Device::Acquire(adapter.CreateDevice(&descriptor)); return adapter.CreateDevice(&descriptor);
} }
wgpu::TextureDescriptor CreateDefaultTextureDescriptor() { wgpu::TextureDescriptor CreateDefaultTextureDescriptor() {

View File

@ -20,10 +20,10 @@
class UnsafeAPIValidationTest : public ValidationTest { class UnsafeAPIValidationTest : public ValidationTest {
protected: protected:
wgpu::Device CreateTestDevice() override { WGPUDevice CreateTestDevice() override {
dawn_native::DeviceDescriptor descriptor; dawn_native::DeviceDescriptor descriptor;
descriptor.forceEnabledToggles.push_back("disallow_unsafe_apis"); descriptor.forceEnabledToggles.push_back("disallow_unsafe_apis");
return wgpu::Device::Acquire(adapter.CreateDevice(&descriptor)); return adapter.CreateDevice(&descriptor);
} }
}; };

View File

@ -15,12 +15,41 @@
#include "tests/unittests/validation/ValidationTest.h" #include "tests/unittests/validation/ValidationTest.h"
#include "common/Assert.h" #include "common/Assert.h"
#include "common/SystemUtils.h"
#include "dawn/dawn_proc.h" #include "dawn/dawn_proc.h"
#include "dawn/webgpu.h" #include "dawn/webgpu.h"
#include "dawn_native/NullBackend.h" #include "dawn_native/NullBackend.h"
#include "utils/WireHelper.h"
#include <algorithm> #include <algorithm>
namespace {
bool gUseWire = false;
std::string gWireTraceDir = "";
} // namespace
void InitDawnValidationTestEnvironment(int argc, char** argv) {
for (int i = 1; i < argc; ++i) {
if (strcmp("-w", argv[i]) == 0 || strcmp("--use-wire", argv[i]) == 0) {
gUseWire = true;
continue;
}
constexpr const char kWireTraceDirArg[] = "--wire-trace-dir=";
size_t argLen = sizeof(kWireTraceDirArg) - 1;
if (strncmp(argv[i], kWireTraceDirArg, argLen) == 0) {
gWireTraceDir = argv[i] + argLen;
continue;
}
}
}
ValidationTest::ValidationTest()
: mWireHelper(utils::CreateWireHelper(gUseWire, gWireTraceDir.c_str())) {
}
void ValidationTest::SetUp() { void ValidationTest::SetUp() {
instance = std::make_unique<dawn_native::Instance>(); instance = std::make_unique<dawn_native::Instance>();
instance->DiscoverDefaultAdapters(); instance->DiscoverDefaultAdapters();
@ -42,25 +71,29 @@ void ValidationTest::SetUp() {
ASSERT(foundNullAdapter); ASSERT(foundNullAdapter);
dawnProcSetProcs(&dawn_native::GetProcs()); std::tie(device, backendDevice) = mWireHelper->RegisterDevice(CreateTestDevice());
device = CreateTestDevice();
device.SetUncapturedErrorCallback(ValidationTest::OnDeviceError, this); device.SetUncapturedErrorCallback(ValidationTest::OnDeviceError, this);
std::string traceName =
std::string(::testing::UnitTest::GetInstance()->current_test_info()->test_suite_name()) +
"_" + ::testing::UnitTest::GetInstance()->current_test_info()->name();
mWireHelper->BeginWireTrace(traceName.c_str());
} }
ValidationTest::~ValidationTest() { ValidationTest::~ValidationTest() {
// We need to destroy Dawn objects before setting the procs to null otherwise the dawn*Release // We need to destroy Dawn objects before setting the procs to null otherwise the dawn*Release
// will call a nullptr // will call a nullptr
device = wgpu::Device(); device = wgpu::Device();
dawnProcSetProcs(nullptr); mWireHelper.reset();
} }
void ValidationTest::TearDown() { void ValidationTest::TearDown() {
FlushWire();
ASSERT_FALSE(mExpectError); ASSERT_FALSE(mExpectError);
if (device) { if (device) {
EXPECT_EQ(mLastWarningCount, EXPECT_EQ(mLastWarningCount,
dawn_native::GetDeprecationWarningCountForTesting(device.Get())); dawn_native::GetDeprecationWarningCountForTesting(backendDevice));
} }
} }
@ -76,7 +109,20 @@ std::string ValidationTest::GetLastDeviceErrorMessage() const {
return mDeviceErrorMessage; return mDeviceErrorMessage;
} }
void ValidationTest::WaitForAllOperations(const wgpu::Device& device) const { wgpu::Device ValidationTest::RegisterDevice(WGPUDevice backendDevice) {
return mWireHelper->RegisterDevice(backendDevice).first;
}
bool ValidationTest::UsesWire() const {
return gUseWire;
}
void ValidationTest::FlushWire() {
EXPECT_TRUE(mWireHelper->FlushClient());
EXPECT_TRUE(mWireHelper->FlushServer());
}
void ValidationTest::WaitForAllOperations(const wgpu::Device& device) {
wgpu::Queue queue = device.GetDefaultQueue(); wgpu::Queue queue = device.GetDefaultQueue();
wgpu::Fence fence = queue.CreateFence(); wgpu::Fence fence = queue.CreateFence();
@ -84,11 +130,13 @@ void ValidationTest::WaitForAllOperations(const wgpu::Device& device) const {
queue.Signal(fence, 1); queue.Signal(fence, 1);
while (fence.GetCompletedValue() < 1) { while (fence.GetCompletedValue() < 1) {
device.Tick(); device.Tick();
FlushWire();
} }
// TODO(cwallez@chromium.org): It's not clear why we need this additional tick. Investigate it // TODO(cwallez@chromium.org): It's not clear why we need this additional tick. Investigate it
// once WebGPU has defined the ordering of callbacks firing. // once WebGPU has defined the ordering of callbacks firing.
device.Tick(); device.Tick();
FlushWire();
} }
bool ValidationTest::HasWGSL() const { bool ValidationTest::HasWGSL() const {
@ -100,14 +148,14 @@ bool ValidationTest::HasWGSL() const {
} }
bool ValidationTest::HasToggleEnabled(const char* toggle) const { bool ValidationTest::HasToggleEnabled(const char* toggle) const {
auto toggles = dawn_native::GetTogglesUsed(device.Get()); auto toggles = dawn_native::GetTogglesUsed(backendDevice);
return std::find_if(toggles.begin(), toggles.end(), [toggle](const char* name) { return std::find_if(toggles.begin(), toggles.end(), [toggle](const char* name) {
return strcmp(toggle, name) == 0; return strcmp(toggle, name) == 0;
}) != toggles.end(); }) != toggles.end();
} }
wgpu::Device ValidationTest::CreateTestDevice() { WGPUDevice ValidationTest::CreateTestDevice() {
return wgpu::Device::Acquire(adapter.CreateDevice()); return adapter.CreateDevice();
} }
// static // static

View File

@ -21,8 +21,10 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#define ASSERT_DEVICE_ERROR(statement) \ #define ASSERT_DEVICE_ERROR(statement) \
FlushWire(); \
StartExpectDeviceError(); \ StartExpectDeviceError(); \
statement; \ statement; \
FlushWire(); \
if (!EndExpectDeviceError()) { \ if (!EndExpectDeviceError()) { \
FAIL() << "Expected device error in:\n " << #statement; \ FAIL() << "Expected device error in:\n " << #statement; \
} \ } \
@ -41,15 +43,24 @@
#define EXPECT_DEPRECATION_WARNING(statement) \ #define EXPECT_DEPRECATION_WARNING(statement) \
do { \ do { \
size_t warningsBefore = dawn_native::GetDeprecationWarningCountForTesting(device.Get()); \ FlushWire(); \
size_t warningsBefore = dawn_native::GetDeprecationWarningCountForTesting(backendDevice); \
statement; \ statement; \
size_t warningsAfter = dawn_native::GetDeprecationWarningCountForTesting(device.Get()); \ FlushWire(); \
size_t warningsAfter = dawn_native::GetDeprecationWarningCountForTesting(backendDevice); \
EXPECT_EQ(mLastWarningCount, warningsBefore); \ EXPECT_EQ(mLastWarningCount, warningsBefore); \
mLastWarningCount = warningsAfter; \ mLastWarningCount = warningsAfter; \
} while (0) } while (0)
namespace utils {
class WireHelper;
} // namespace utils
void InitDawnValidationTestEnvironment(int argc, char** argv);
class ValidationTest : public testing::Test { class ValidationTest : public testing::Test {
public: public:
ValidationTest();
~ValidationTest() override; ~ValidationTest() override;
void SetUp() override; void SetUp() override;
@ -59,7 +70,12 @@ class ValidationTest : public testing::Test {
bool EndExpectDeviceError(); bool EndExpectDeviceError();
std::string GetLastDeviceErrorMessage() const; std::string GetLastDeviceErrorMessage() const;
void WaitForAllOperations(const wgpu::Device& device) const; wgpu::Device RegisterDevice(WGPUDevice backendDevice);
bool UsesWire() const;
void FlushWire();
void WaitForAllOperations(const wgpu::Device& device);
// Helper functions to create objects to test validation. // Helper functions to create objects to test validation.
@ -79,15 +95,18 @@ class ValidationTest : public testing::Test {
bool HasToggleEnabled(const char* toggle) const; bool HasToggleEnabled(const char* toggle) const;
protected: protected:
virtual wgpu::Device CreateTestDevice(); virtual WGPUDevice CreateTestDevice();
wgpu::Device device;
dawn_native::Adapter adapter;
std::unique_ptr<dawn_native::Instance> instance; std::unique_ptr<dawn_native::Instance> instance;
dawn_native::Adapter adapter;
wgpu::Device device;
WGPUDevice backendDevice;
size_t mLastWarningCount = 0; size_t mLastWarningCount = 0;
private: private:
std::unique_ptr<utils::WireHelper> mWireHelper;
static void OnDeviceError(WGPUErrorType type, const char* message, void* userdata); static void OnDeviceError(WGPUErrorType type, const char* message, void* userdata);
std::string mDeviceErrorMessage; std::string mDeviceErrorMessage;
bool mExpectError = false; bool mExpectError = false;