// Copyright 2017 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/validation/ValidationTest.h" #include "common/Assert.h" #include "dawn/dawn.h" #include "dawn_native/DawnNative.h" #include "dawn_native/NullBackend.h" ValidationTest::ValidationTest() { mInstance = std::make_unique(); mInstance->DiscoverDefaultAdapters(); std::vector adapters = mInstance->GetAdapters(); // Validation tests run against the null backend, find the corresponding adapter bool foundNullAdapter = false; dawn_native::Adapter nullAdapter; for (auto adapter : adapters) { if (adapter.GetBackendType() == dawn_native::BackendType::Null) { nullAdapter = adapter; foundNullAdapter = true; break; } } ASSERT(foundNullAdapter); device = dawn::Device::Acquire(nullAdapter.CreateDevice()); dawnProcTable procs = dawn_native::GetProcs(); dawnSetProcs(&procs); device.SetErrorCallback(ValidationTest::OnDeviceError, static_cast(reinterpret_cast(this))); } ValidationTest::~ValidationTest() { // We need to destroy Dawn objects before setting the procs to null otherwise the dawn*Release // will call a nullptr device = dawn::Device(); dawnSetProcs(nullptr); } void ValidationTest::TearDown() { ASSERT_FALSE(mExpectError); for (auto& expectation : mExpectations) { std::string name = expectation.debugName; if (name.empty()) { name = ""; } ASSERT_TRUE(expectation.gotStatus) << "Didn't get a status for " << name; ASSERT_NE(DAWN_BUILDER_ERROR_STATUS_UNKNOWN, expectation.status) << "Got unknown status for " << name; bool wasSuccess = expectation.status == DAWN_BUILDER_ERROR_STATUS_SUCCESS; ASSERT_EQ(expectation.expectSuccess, wasSuccess) << "Got wrong status value for " << name << ", status was " << expectation.status << " with \"" << expectation.statusMessage << "\""; } } void ValidationTest::StartExpectDeviceError() { mExpectError = true; mError = false; } bool ValidationTest::EndExpectDeviceError() { mExpectError = false; return mError; } std::string ValidationTest::GetLastDeviceErrorMessage() const { return mDeviceErrorMessage; } dawn::RenderPassDescriptor ValidationTest::CreateSimpleRenderPass() { dawn::TextureDescriptor descriptor; descriptor.dimension = dawn::TextureDimension::e2D; descriptor.size.width = 640; descriptor.size.height = 480; descriptor.size.depth = 1; descriptor.arrayLayerCount = 1; descriptor.sampleCount = 1; descriptor.format = dawn::TextureFormat::R8G8B8A8Unorm; descriptor.mipLevelCount = 1; descriptor.usage = dawn::TextureUsageBit::OutputAttachment; auto colorBuffer = device.CreateTexture(&descriptor); auto colorView = colorBuffer.CreateDefaultTextureView(); dawn::RenderPassColorAttachmentDescriptor colorAttachment; colorAttachment.attachment = colorView; colorAttachment.resolveTarget = nullptr; colorAttachment.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f }; colorAttachment.loadOp = dawn::LoadOp::Clear; colorAttachment.storeOp = dawn::StoreOp::Store; return device.CreateRenderPassDescriptorBuilder() .SetColorAttachments(1, &colorAttachment) .GetResult(); } void ValidationTest::OnDeviceError(const char* message, dawnCallbackUserdata userdata) { auto self = reinterpret_cast(static_cast(userdata)); self->mDeviceErrorMessage = message; // Skip this one specific error that is raised when a builder is used after it got an error // this is important because we don't want to wrap all creation tests in ASSERT_DEVICE_ERROR. // Yes the error message is misleading. if (self->mDeviceErrorMessage == "Builder cannot be used after GetResult") { return; } ASSERT_TRUE(self->mExpectError) << "Got unexpected device error: " << message; ASSERT_FALSE(self->mError) << "Got two errors in expect block"; self->mError = true; } void ValidationTest::OnBuilderErrorStatus(dawnBuilderErrorStatus status, const char* message, dawn::CallbackUserdata userdata1, dawn::CallbackUserdata userdata2) { auto* self = reinterpret_cast(static_cast(userdata1)); size_t index = static_cast(userdata2); ASSERT_LT(index, self->mExpectations.size()); auto& expectation = self->mExpectations[index]; ASSERT_FALSE(expectation.gotStatus); expectation.gotStatus = true; expectation.status = status; expectation.statusMessage = message; } ValidationTest::DummyRenderPass ValidationTest::CreateDummyRenderPass() { DummyRenderPass dummy; dummy.width = 400; dummy.height = 400; dummy.attachmentFormat = dawn::TextureFormat::R8G8B8A8Unorm; dawn::TextureDescriptor descriptor; descriptor.dimension = dawn::TextureDimension::e2D; descriptor.size.width = dummy.width; descriptor.size.height = dummy.height; descriptor.size.depth = 1; descriptor.arrayLayerCount = 1; descriptor.sampleCount = 1; descriptor.format = dummy.attachmentFormat; descriptor.mipLevelCount = 1; descriptor.usage = dawn::TextureUsageBit::OutputAttachment; dummy.attachment = device.CreateTexture(&descriptor); dawn::TextureView view = dummy.attachment.CreateDefaultTextureView(); dawn::RenderPassColorAttachmentDescriptor colorAttachment; colorAttachment.attachment = view; colorAttachment.resolveTarget = nullptr; colorAttachment.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f }; colorAttachment.loadOp = dawn::LoadOp::Clear; colorAttachment.storeOp = dawn::StoreOp::Store; dummy.renderPass = AssertWillBeSuccess(device.CreateRenderPassDescriptorBuilder()) .SetColorAttachments(1, &colorAttachment) .GetResult(); return dummy; }