Test requestAdapter and requestDevice on the wire
Bug: dawn:689 Change-Id: I032cfcba755be241126dfa8447a38625d7183334 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/71523 Reviewed-by: Loko Kung <lokokung@google.com> Commit-Queue: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
07e766728a
commit
f6519cc4e5
|
@ -272,6 +272,7 @@ test("dawn_unittests") {
|
|||
"unittests/validation/VertexStateValidationTests.cpp",
|
||||
"unittests/validation/VideoViewsValidationTests.cpp",
|
||||
"unittests/validation/WriteBufferTests.cpp",
|
||||
"unittests/wire/WireAdapterTests.cpp",
|
||||
"unittests/wire/WireArgumentTests.cpp",
|
||||
"unittests/wire/WireBasicTests.cpp",
|
||||
"unittests/wire/WireBufferMappingTests.cpp",
|
||||
|
@ -284,6 +285,7 @@ test("dawn_unittests") {
|
|||
"unittests/wire/WireInjectInstanceTests.cpp",
|
||||
"unittests/wire/WireInjectSwapChainTests.cpp",
|
||||
"unittests/wire/WireInjectTextureTests.cpp",
|
||||
"unittests/wire/WireInstanceTests.cpp",
|
||||
"unittests/wire/WireMemoryTransferServiceTests.cpp",
|
||||
"unittests/wire/WireOptionalTests.cpp",
|
||||
"unittests/wire/WireQueueTests.cpp",
|
||||
|
|
|
@ -0,0 +1,330 @@
|
|||
// Copyright 2021 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/MockCallback.h"
|
||||
#include "tests/unittests/wire/WireTest.h"
|
||||
|
||||
#include "dawn_wire/WireClient.h"
|
||||
#include "dawn_wire/WireServer.h"
|
||||
|
||||
#include <webgpu/webgpu_cpp.h>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace testing;
|
||||
using namespace dawn_wire;
|
||||
|
||||
class WireAdapterTests : public WireTest {
|
||||
protected:
|
||||
// Bootstrap the tests and create a fake adapter.
|
||||
void SetUp() override {
|
||||
WireTest::SetUp();
|
||||
|
||||
auto reservation = GetWireClient()->ReserveInstance();
|
||||
instance = wgpu::Instance::Acquire(reservation.instance);
|
||||
|
||||
WGPUInstance apiInstance = api.GetNewInstance();
|
||||
EXPECT_CALL(api, InstanceReference(apiInstance));
|
||||
EXPECT_TRUE(GetWireServer()->InjectInstance(apiInstance, reservation.id,
|
||||
reservation.generation));
|
||||
|
||||
wgpu::RequestAdapterOptions options = {};
|
||||
MockCallback<WGPURequestAdapterCallback> cb;
|
||||
auto* userdata = cb.MakeUserdata(this);
|
||||
instance.RequestAdapter(&options, cb.Callback(), userdata);
|
||||
|
||||
// Expect the server to receive the message. Then, mock a fake reply.
|
||||
apiAdapter = api.GetNewAdapter();
|
||||
EXPECT_CALL(api, OnInstanceRequestAdapter(apiInstance, NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(InvokeWithoutArgs([&]() {
|
||||
EXPECT_CALL(api, AdapterGetProperties(apiAdapter, NotNull()))
|
||||
.WillOnce(WithArg<1>(Invoke([&](WGPUAdapterProperties* properties) {
|
||||
*properties = {};
|
||||
properties->name = "";
|
||||
properties->driverDescription = "";
|
||||
})));
|
||||
|
||||
EXPECT_CALL(api, AdapterGetLimits(apiAdapter, NotNull()))
|
||||
.WillOnce(WithArg<1>(Invoke([&](WGPUSupportedLimits* limits) {
|
||||
*limits = {};
|
||||
return true;
|
||||
})));
|
||||
|
||||
EXPECT_CALL(api, AdapterEnumerateFeatures(apiAdapter, nullptr))
|
||||
.WillOnce(Return(0))
|
||||
.WillOnce(Return(0));
|
||||
api.CallInstanceRequestAdapterCallback(
|
||||
apiInstance, WGPURequestAdapterStatus_Success, apiAdapter, nullptr);
|
||||
}));
|
||||
FlushClient();
|
||||
|
||||
// Expect the callback in the client.
|
||||
WGPUAdapter cAdapter;
|
||||
EXPECT_CALL(cb, Call(WGPURequestAdapterStatus_Success, NotNull(), nullptr, this))
|
||||
.WillOnce(SaveArg<1>(&cAdapter));
|
||||
FlushServer();
|
||||
|
||||
EXPECT_NE(cAdapter, nullptr);
|
||||
adapter = wgpu::Adapter::Acquire(cAdapter);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
adapter = nullptr;
|
||||
instance = nullptr;
|
||||
WireTest::TearDown();
|
||||
}
|
||||
|
||||
WGPUAdapter apiAdapter;
|
||||
wgpu::Instance instance;
|
||||
wgpu::Adapter adapter;
|
||||
};
|
||||
|
||||
// Test that the DeviceDescriptor is passed from the client to the server.
|
||||
TEST_F(WireAdapterTests, RequestDevicePassesDescriptor) {
|
||||
MockCallback<WGPURequestDeviceCallback> cb;
|
||||
auto* userdata = cb.MakeUserdata(this);
|
||||
|
||||
// Test an empty descriptor
|
||||
{
|
||||
wgpu::DeviceDescriptor desc = {};
|
||||
adapter.RequestDevice(&desc, cb.Callback(), userdata);
|
||||
|
||||
EXPECT_CALL(api, OnAdapterRequestDevice(apiAdapter, NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(WithArg<1>(Invoke([](const WGPUDeviceDescriptor* apiDesc) {
|
||||
EXPECT_EQ(apiDesc->label, nullptr);
|
||||
EXPECT_EQ(apiDesc->requiredFeaturesCount, 0u);
|
||||
EXPECT_EQ(apiDesc->requiredLimits, nullptr);
|
||||
})));
|
||||
FlushClient();
|
||||
}
|
||||
|
||||
// Test a non-empty descriptor
|
||||
{
|
||||
wgpu::RequiredLimits limits = {};
|
||||
limits.limits.maxStorageTexturesPerShaderStage = 5;
|
||||
|
||||
std::vector<wgpu::FeatureName> features = {wgpu::FeatureName::TextureCompressionETC2,
|
||||
wgpu::FeatureName::TextureCompressionASTC};
|
||||
|
||||
wgpu::DeviceDescriptor desc = {};
|
||||
desc.label = "hello device";
|
||||
desc.requiredLimits = &limits;
|
||||
desc.requiredFeaturesCount = features.size();
|
||||
desc.requiredFeatures = features.data();
|
||||
|
||||
adapter.RequestDevice(&desc, cb.Callback(), userdata);
|
||||
|
||||
EXPECT_CALL(api, OnAdapterRequestDevice(apiAdapter, NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(WithArg<1>(Invoke([&](const WGPUDeviceDescriptor* apiDesc) {
|
||||
EXPECT_STREQ(apiDesc->label, desc.label);
|
||||
|
||||
ASSERT_EQ(apiDesc->requiredFeaturesCount, features.size());
|
||||
for (uint32_t i = 0; i < features.size(); ++i) {
|
||||
EXPECT_EQ(apiDesc->requiredFeatures[i],
|
||||
static_cast<WGPUFeatureName>(features[i]));
|
||||
}
|
||||
|
||||
ASSERT_NE(apiDesc->requiredLimits, nullptr);
|
||||
EXPECT_EQ(apiDesc->requiredLimits->nextInChain, nullptr);
|
||||
EXPECT_EQ(apiDesc->requiredLimits->limits.maxStorageTexturesPerShaderStage,
|
||||
limits.limits.maxStorageTexturesPerShaderStage);
|
||||
})));
|
||||
FlushClient();
|
||||
}
|
||||
|
||||
// Delete the adapter now, or it'll call the mock callback after it's deleted.
|
||||
adapter = nullptr;
|
||||
}
|
||||
|
||||
// Test that RequestDevice forwards the device information to the client.
|
||||
TEST_F(WireAdapterTests, RequestDeviceSuccess) {
|
||||
MockCallback<WGPURequestDeviceCallback> cb;
|
||||
auto* userdata = cb.MakeUserdata(this);
|
||||
|
||||
wgpu::SupportedLimits fakeLimits = {};
|
||||
fakeLimits.limits.maxTextureDimension1D = 433;
|
||||
fakeLimits.limits.maxVertexAttributes = 1243;
|
||||
|
||||
std::initializer_list<wgpu::FeatureName> fakeFeatures = {
|
||||
wgpu::FeatureName::Depth32FloatStencil8,
|
||||
wgpu::FeatureName::TextureCompressionBC,
|
||||
};
|
||||
|
||||
wgpu::DeviceDescriptor desc = {};
|
||||
adapter.RequestDevice(&desc, cb.Callback(), userdata);
|
||||
|
||||
// Expect the server to receive the message. Then, mock a fake reply.
|
||||
WGPUDevice apiDevice = api.GetNewDevice();
|
||||
EXPECT_CALL(api, OnAdapterRequestDevice(apiAdapter, NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(InvokeWithoutArgs([&]() {
|
||||
// Set on device creation to forward callbacks to the client.
|
||||
EXPECT_CALL(api,
|
||||
OnDeviceSetUncapturedErrorCallback(apiDevice, NotNull(), NotNull()))
|
||||
.Times(1);
|
||||
EXPECT_CALL(api, OnDeviceSetLoggingCallback(apiDevice, NotNull(), NotNull()))
|
||||
.Times(1);
|
||||
EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(apiDevice, NotNull(), NotNull()))
|
||||
.Times(1);
|
||||
|
||||
EXPECT_CALL(api, DeviceGetLimits(apiDevice, NotNull()))
|
||||
.WillOnce(WithArg<1>(Invoke([&](WGPUSupportedLimits* limits) {
|
||||
*reinterpret_cast<wgpu::SupportedLimits*>(limits) = fakeLimits;
|
||||
return true;
|
||||
})));
|
||||
|
||||
EXPECT_CALL(api, DeviceEnumerateFeatures(apiDevice, nullptr))
|
||||
.WillOnce(Return(fakeFeatures.size()));
|
||||
|
||||
EXPECT_CALL(api, DeviceEnumerateFeatures(apiDevice, NotNull()))
|
||||
.WillOnce(WithArg<1>(Invoke([&](WGPUFeatureName* features) {
|
||||
for (wgpu::FeatureName feature : fakeFeatures) {
|
||||
*(features++) = static_cast<WGPUFeatureName>(feature);
|
||||
}
|
||||
return fakeFeatures.size();
|
||||
})));
|
||||
|
||||
api.CallAdapterRequestDeviceCallback(apiAdapter, WGPURequestDeviceStatus_Success,
|
||||
apiDevice, nullptr);
|
||||
}));
|
||||
FlushClient();
|
||||
|
||||
// Expect the callback in the client and all the device information to match.
|
||||
EXPECT_CALL(cb, Call(WGPURequestDeviceStatus_Success, NotNull(), nullptr, this))
|
||||
.WillOnce(WithArg<1>(Invoke([&](WGPUDevice cDevice) {
|
||||
wgpu::Device device = wgpu::Device::Acquire(cDevice);
|
||||
|
||||
wgpu::SupportedLimits limits;
|
||||
EXPECT_TRUE(device.GetLimits(&limits));
|
||||
EXPECT_EQ(limits.limits.maxTextureDimension1D,
|
||||
fakeLimits.limits.maxTextureDimension1D);
|
||||
EXPECT_EQ(limits.limits.maxVertexAttributes, fakeLimits.limits.maxVertexAttributes);
|
||||
|
||||
std::vector<wgpu::FeatureName> features;
|
||||
features.resize(device.EnumerateFeatures(nullptr));
|
||||
ASSERT_EQ(features.size(), fakeFeatures.size());
|
||||
EXPECT_EQ(device.EnumerateFeatures(&features[0]), features.size());
|
||||
|
||||
std::unordered_set<wgpu::FeatureName> featureSet(fakeFeatures);
|
||||
for (wgpu::FeatureName feature : features) {
|
||||
EXPECT_EQ(featureSet.erase(feature), 1u);
|
||||
}
|
||||
})));
|
||||
FlushServer();
|
||||
|
||||
// Cleared when the device is destroyed.
|
||||
EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(apiDevice, nullptr, nullptr)).Times(1);
|
||||
EXPECT_CALL(api, OnDeviceSetLoggingCallback(apiDevice, nullptr, nullptr)).Times(1);
|
||||
EXPECT_CALL(api, OnDeviceSetDeviceLostCallback(apiDevice, nullptr, nullptr)).Times(1);
|
||||
}
|
||||
|
||||
// Test that features requested that the implementation supports, but not the
|
||||
// wire reject the callback.
|
||||
TEST_F(WireAdapterTests, RequestFeatureUnsupportedByWire) {
|
||||
MockCallback<WGPURequestDeviceCallback> cb;
|
||||
auto* userdata = cb.MakeUserdata(this);
|
||||
|
||||
std::initializer_list<wgpu::FeatureName> fakeFeatures = {
|
||||
// Some value that is not a valid feature
|
||||
static_cast<wgpu::FeatureName>(-2),
|
||||
wgpu::FeatureName::TextureCompressionASTC,
|
||||
};
|
||||
|
||||
wgpu::DeviceDescriptor desc = {};
|
||||
adapter.RequestDevice(&desc, cb.Callback(), userdata);
|
||||
|
||||
// Expect the server to receive the message. Then, mock a fake reply.
|
||||
// The reply contains features that the device implementation supports, but the
|
||||
// wire does not.
|
||||
WGPUDevice apiDevice = api.GetNewDevice();
|
||||
EXPECT_CALL(api, OnAdapterRequestDevice(apiAdapter, NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(InvokeWithoutArgs([&]() {
|
||||
EXPECT_CALL(api, DeviceEnumerateFeatures(apiDevice, nullptr))
|
||||
.WillOnce(Return(fakeFeatures.size()));
|
||||
|
||||
EXPECT_CALL(api, DeviceEnumerateFeatures(apiDevice, NotNull()))
|
||||
.WillOnce(WithArg<1>(Invoke([&](WGPUFeatureName* features) {
|
||||
for (wgpu::FeatureName feature : fakeFeatures) {
|
||||
*(features++) = static_cast<WGPUFeatureName>(feature);
|
||||
}
|
||||
return fakeFeatures.size();
|
||||
})));
|
||||
|
||||
// The device was actually created, but the wire didn't support its features.
|
||||
// Expect it to be released.
|
||||
EXPECT_CALL(api, DeviceRelease(apiDevice));
|
||||
|
||||
// Fake successful creation. The client still receives a failure due to
|
||||
// unsupported features.
|
||||
api.CallAdapterRequestDeviceCallback(apiAdapter, WGPURequestDeviceStatus_Success,
|
||||
apiDevice, nullptr);
|
||||
}));
|
||||
FlushClient();
|
||||
|
||||
// Expect an error callback since the feature is not supported.
|
||||
EXPECT_CALL(cb, Call(WGPURequestDeviceStatus_Error, nullptr, NotNull(), this)).Times(1);
|
||||
FlushServer();
|
||||
}
|
||||
|
||||
// Test that RequestDevice errors forward to the client.
|
||||
TEST_F(WireAdapterTests, RequestDeviceError) {
|
||||
MockCallback<WGPURequestDeviceCallback> cb;
|
||||
auto* userdata = cb.MakeUserdata(this);
|
||||
|
||||
wgpu::DeviceDescriptor desc = {};
|
||||
adapter.RequestDevice(&desc, cb.Callback(), userdata);
|
||||
|
||||
// Expect the server to receive the message. Then, mock an error.
|
||||
EXPECT_CALL(api, OnAdapterRequestDevice(apiAdapter, NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(InvokeWithoutArgs([&]() {
|
||||
api.CallAdapterRequestDeviceCallback(apiAdapter, WGPURequestDeviceStatus_Error,
|
||||
nullptr, "Request device failed");
|
||||
}));
|
||||
FlushClient();
|
||||
|
||||
// Expect the callback in the client.
|
||||
EXPECT_CALL(
|
||||
cb, Call(WGPURequestDeviceStatus_Error, nullptr, StrEq("Request device failed"), this))
|
||||
.Times(1);
|
||||
FlushServer();
|
||||
}
|
||||
|
||||
// Test that RequestDevice receives unknown status if the adapter is deleted
|
||||
// before the callback happens.
|
||||
TEST_F(WireAdapterTests, RequestDeviceAdapterDestroyedBeforeCallback) {
|
||||
MockCallback<WGPURequestDeviceCallback> cb;
|
||||
auto* userdata = cb.MakeUserdata(this);
|
||||
|
||||
wgpu::DeviceDescriptor desc = {};
|
||||
adapter.RequestDevice(&desc, cb.Callback(), userdata);
|
||||
|
||||
EXPECT_CALL(cb, Call(WGPURequestDeviceStatus_Unknown, nullptr, NotNull(), this)).Times(1);
|
||||
adapter = nullptr;
|
||||
}
|
||||
|
||||
// Test that RequestDevice receives unknown status if the wire is disconnected
|
||||
// before the callback happens.
|
||||
TEST_F(WireAdapterTests, RequestDeviceWireDisconnectedBeforeCallback) {
|
||||
MockCallback<WGPURequestDeviceCallback> cb;
|
||||
auto* userdata = cb.MakeUserdata(this);
|
||||
|
||||
wgpu::DeviceDescriptor desc = {};
|
||||
adapter.RequestDevice(&desc, cb.Callback(), userdata);
|
||||
|
||||
EXPECT_CALL(cb, Call(WGPURequestDeviceStatus_Unknown, nullptr, NotNull(), this)).Times(1);
|
||||
GetWireClient()->Disconnect();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
|
@ -0,0 +1,286 @@
|
|||
// Copyright 2021 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/MockCallback.h"
|
||||
#include "tests/unittests/wire/WireTest.h"
|
||||
|
||||
#include "dawn_wire/WireClient.h"
|
||||
#include "dawn_wire/WireServer.h"
|
||||
|
||||
#include <webgpu/webgpu_cpp.h>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace testing;
|
||||
using namespace dawn_wire;
|
||||
|
||||
class WireInstanceBasicTest : public WireTest {};
|
||||
class WireInstanceTests : public WireTest {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
WireTest::SetUp();
|
||||
|
||||
auto reservation = GetWireClient()->ReserveInstance();
|
||||
instance = wgpu::Instance::Acquire(reservation.instance);
|
||||
|
||||
apiInstance = api.GetNewInstance();
|
||||
EXPECT_CALL(api, InstanceReference(apiInstance));
|
||||
EXPECT_TRUE(GetWireServer()->InjectInstance(apiInstance, reservation.id,
|
||||
reservation.generation));
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
instance = nullptr;
|
||||
WireTest::TearDown();
|
||||
}
|
||||
|
||||
wgpu::Instance instance;
|
||||
WGPUInstance apiInstance;
|
||||
};
|
||||
|
||||
// Test that an Instance can be reserved and injected into the wire.
|
||||
TEST_F(WireInstanceBasicTest, ReserveAndInject) {
|
||||
auto reservation = GetWireClient()->ReserveInstance();
|
||||
wgpu::Instance instance = wgpu::Instance::Acquire(reservation.instance);
|
||||
|
||||
WGPUInstance apiInstance = api.GetNewInstance();
|
||||
EXPECT_CALL(api, InstanceReference(apiInstance));
|
||||
EXPECT_TRUE(
|
||||
GetWireServer()->InjectInstance(apiInstance, reservation.id, reservation.generation));
|
||||
|
||||
instance = nullptr;
|
||||
|
||||
EXPECT_CALL(api, InstanceRelease(apiInstance));
|
||||
FlushClient();
|
||||
}
|
||||
|
||||
// Test that RequestAdapterOptions are passed from the client to the server.
|
||||
TEST_F(WireInstanceTests, RequestAdapterPassesOptions) {
|
||||
MockCallback<WGPURequestAdapterCallback> cb;
|
||||
auto* userdata = cb.MakeUserdata(this);
|
||||
|
||||
for (wgpu::PowerPreference powerPreference :
|
||||
{wgpu::PowerPreference::LowPower, wgpu::PowerPreference::HighPerformance}) {
|
||||
wgpu::RequestAdapterOptions options = {};
|
||||
options.powerPreference = powerPreference;
|
||||
|
||||
instance.RequestAdapter(&options, cb.Callback(), userdata);
|
||||
|
||||
EXPECT_CALL(api, OnInstanceRequestAdapter(apiInstance, NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(WithArg<1>(Invoke([&](const WGPURequestAdapterOptions* apiOptions) {
|
||||
EXPECT_EQ(apiOptions->powerPreference,
|
||||
static_cast<WGPUPowerPreference>(options.powerPreference));
|
||||
EXPECT_EQ(apiOptions->forceFallbackAdapter, options.forceFallbackAdapter);
|
||||
})));
|
||||
FlushClient();
|
||||
}
|
||||
|
||||
// Delete the instance now, or it'll call the mock callback after it's deleted.
|
||||
instance = nullptr;
|
||||
}
|
||||
|
||||
// Test that RequestAdapter forwards the adapter information to the client.
|
||||
TEST_F(WireInstanceTests, RequestAdapterSuccess) {
|
||||
wgpu::RequestAdapterOptions options = {};
|
||||
MockCallback<WGPURequestAdapterCallback> cb;
|
||||
auto* userdata = cb.MakeUserdata(this);
|
||||
instance.RequestAdapter(&options, cb.Callback(), userdata);
|
||||
|
||||
wgpu::AdapterProperties fakeProperties = {};
|
||||
fakeProperties.vendorID = 0x134;
|
||||
fakeProperties.deviceID = 0x918;
|
||||
fakeProperties.name = "fake adapter";
|
||||
fakeProperties.driverDescription = "hello world";
|
||||
fakeProperties.backendType = wgpu::BackendType::D3D12;
|
||||
fakeProperties.adapterType = wgpu::AdapterType::IntegratedGPU;
|
||||
|
||||
wgpu::SupportedLimits fakeLimits = {};
|
||||
fakeLimits.limits.maxTextureDimension1D = 433;
|
||||
fakeLimits.limits.maxVertexAttributes = 1243;
|
||||
|
||||
std::initializer_list<wgpu::FeatureName> fakeFeatures = {
|
||||
wgpu::FeatureName::Depth32FloatStencil8,
|
||||
wgpu::FeatureName::TextureCompressionBC,
|
||||
};
|
||||
|
||||
// Expect the server to receive the message. Then, mock a fake reply.
|
||||
WGPUAdapter apiAdapter = api.GetNewAdapter();
|
||||
EXPECT_CALL(api, OnInstanceRequestAdapter(apiInstance, NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(InvokeWithoutArgs([&]() {
|
||||
EXPECT_CALL(api, AdapterGetProperties(apiAdapter, NotNull()))
|
||||
.WillOnce(SetArgPointee<1>(
|
||||
*reinterpret_cast<WGPUAdapterProperties*>(&fakeProperties)));
|
||||
|
||||
EXPECT_CALL(api, AdapterGetLimits(apiAdapter, NotNull()))
|
||||
.WillOnce(WithArg<1>(Invoke([&](WGPUSupportedLimits* limits) {
|
||||
*reinterpret_cast<wgpu::SupportedLimits*>(limits) = fakeLimits;
|
||||
return true;
|
||||
})));
|
||||
|
||||
EXPECT_CALL(api, AdapterEnumerateFeatures(apiAdapter, nullptr))
|
||||
.WillOnce(Return(fakeFeatures.size()));
|
||||
|
||||
EXPECT_CALL(api, AdapterEnumerateFeatures(apiAdapter, NotNull()))
|
||||
.WillOnce(WithArg<1>(Invoke([&](WGPUFeatureName* features) {
|
||||
for (wgpu::FeatureName feature : fakeFeatures) {
|
||||
*(features++) = static_cast<WGPUFeatureName>(feature);
|
||||
}
|
||||
return fakeFeatures.size();
|
||||
})));
|
||||
api.CallInstanceRequestAdapterCallback(
|
||||
apiInstance, WGPURequestAdapterStatus_Success, apiAdapter, nullptr);
|
||||
}));
|
||||
FlushClient();
|
||||
|
||||
// Expect the callback in the client and all the adapter information to match.
|
||||
EXPECT_CALL(cb, Call(WGPURequestAdapterStatus_Success, NotNull(), nullptr, this))
|
||||
.WillOnce(WithArg<1>(Invoke([&](WGPUAdapter cAdapter) {
|
||||
wgpu::Adapter adapter = wgpu::Adapter::Acquire(cAdapter);
|
||||
|
||||
wgpu::AdapterProperties properties;
|
||||
adapter.GetProperties(&properties);
|
||||
EXPECT_EQ(properties.vendorID, fakeProperties.vendorID);
|
||||
EXPECT_EQ(properties.deviceID, fakeProperties.deviceID);
|
||||
EXPECT_STREQ(properties.name, fakeProperties.name);
|
||||
EXPECT_STREQ(properties.driverDescription, fakeProperties.driverDescription);
|
||||
EXPECT_EQ(properties.backendType, fakeProperties.backendType);
|
||||
EXPECT_EQ(properties.adapterType, fakeProperties.adapterType);
|
||||
|
||||
wgpu::SupportedLimits limits;
|
||||
EXPECT_TRUE(adapter.GetLimits(&limits));
|
||||
EXPECT_EQ(limits.limits.maxTextureDimension1D,
|
||||
fakeLimits.limits.maxTextureDimension1D);
|
||||
EXPECT_EQ(limits.limits.maxVertexAttributes, fakeLimits.limits.maxVertexAttributes);
|
||||
|
||||
std::vector<wgpu::FeatureName> features;
|
||||
features.resize(adapter.EnumerateFeatures(nullptr));
|
||||
ASSERT_EQ(features.size(), fakeFeatures.size());
|
||||
EXPECT_EQ(adapter.EnumerateFeatures(&features[0]), features.size());
|
||||
|
||||
std::unordered_set<wgpu::FeatureName> featureSet(fakeFeatures);
|
||||
for (wgpu::FeatureName feature : features) {
|
||||
EXPECT_EQ(featureSet.erase(feature), 1u);
|
||||
}
|
||||
})));
|
||||
FlushServer();
|
||||
}
|
||||
|
||||
// Test that features returned by the implementation that aren't supported
|
||||
// in the wire are not exposed.
|
||||
TEST_F(WireInstanceTests, RequestAdapterWireLacksFeatureSupport) {
|
||||
wgpu::RequestAdapterOptions options = {};
|
||||
MockCallback<WGPURequestAdapterCallback> cb;
|
||||
auto* userdata = cb.MakeUserdata(this);
|
||||
instance.RequestAdapter(&options, cb.Callback(), userdata);
|
||||
|
||||
std::initializer_list<wgpu::FeatureName> fakeFeatures = {
|
||||
wgpu::FeatureName::Depth24UnormStencil8,
|
||||
// Some value that is not a valid feature
|
||||
static_cast<wgpu::FeatureName>(-2),
|
||||
};
|
||||
|
||||
// Expect the server to receive the message. Then, mock a fake reply.
|
||||
WGPUAdapter apiAdapter = api.GetNewAdapter();
|
||||
EXPECT_CALL(api, OnInstanceRequestAdapter(apiInstance, NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(InvokeWithoutArgs([&]() {
|
||||
EXPECT_CALL(api, AdapterGetProperties(apiAdapter, NotNull()))
|
||||
.WillOnce(WithArg<1>(Invoke([&](WGPUAdapterProperties* properties) {
|
||||
*properties = {};
|
||||
properties->name = "";
|
||||
properties->driverDescription = "";
|
||||
})));
|
||||
|
||||
EXPECT_CALL(api, AdapterGetLimits(apiAdapter, NotNull()))
|
||||
.WillOnce(WithArg<1>(Invoke([&](WGPUSupportedLimits* limits) {
|
||||
*limits = {};
|
||||
return true;
|
||||
})));
|
||||
|
||||
EXPECT_CALL(api, AdapterEnumerateFeatures(apiAdapter, nullptr))
|
||||
.WillOnce(Return(fakeFeatures.size()));
|
||||
|
||||
EXPECT_CALL(api, AdapterEnumerateFeatures(apiAdapter, NotNull()))
|
||||
.WillOnce(WithArg<1>(Invoke([&](WGPUFeatureName* features) {
|
||||
for (wgpu::FeatureName feature : fakeFeatures) {
|
||||
*(features++) = static_cast<WGPUFeatureName>(feature);
|
||||
}
|
||||
return fakeFeatures.size();
|
||||
})));
|
||||
api.CallInstanceRequestAdapterCallback(
|
||||
apiInstance, WGPURequestAdapterStatus_Success, apiAdapter, nullptr);
|
||||
}));
|
||||
FlushClient();
|
||||
|
||||
// Expect the callback in the client and all the adapter information to match.
|
||||
EXPECT_CALL(cb, Call(WGPURequestAdapterStatus_Success, NotNull(), nullptr, this))
|
||||
.WillOnce(WithArg<1>(Invoke([&](WGPUAdapter cAdapter) {
|
||||
wgpu::Adapter adapter = wgpu::Adapter::Acquire(cAdapter);
|
||||
|
||||
wgpu::FeatureName feature;
|
||||
ASSERT_EQ(adapter.EnumerateFeatures(nullptr), 1u);
|
||||
adapter.EnumerateFeatures(&feature);
|
||||
|
||||
EXPECT_EQ(feature, wgpu::FeatureName::Depth24UnormStencil8);
|
||||
})));
|
||||
FlushServer();
|
||||
}
|
||||
|
||||
// Test that RequestAdapter errors forward to the client.
|
||||
TEST_F(WireInstanceTests, RequestAdapterError) {
|
||||
wgpu::RequestAdapterOptions options = {};
|
||||
MockCallback<WGPURequestAdapterCallback> cb;
|
||||
auto* userdata = cb.MakeUserdata(this);
|
||||
instance.RequestAdapter(&options, cb.Callback(), userdata);
|
||||
|
||||
// Expect the server to receive the message. Then, mock an error.
|
||||
EXPECT_CALL(api, OnInstanceRequestAdapter(apiInstance, NotNull(), NotNull(), NotNull()))
|
||||
.WillOnce(InvokeWithoutArgs([&]() {
|
||||
api.CallInstanceRequestAdapterCallback(apiInstance, WGPURequestAdapterStatus_Error,
|
||||
nullptr, "Some error");
|
||||
}));
|
||||
FlushClient();
|
||||
|
||||
// Expect the callback in the client.
|
||||
EXPECT_CALL(cb, Call(WGPURequestAdapterStatus_Error, nullptr, StrEq("Some error"), this))
|
||||
.Times(1);
|
||||
FlushServer();
|
||||
}
|
||||
|
||||
// Test that RequestAdapter receives unknown status if the instance is deleted
|
||||
// before the callback happens.
|
||||
TEST_F(WireInstanceTests, RequestAdapterInstanceDestroyedBeforeCallback) {
|
||||
wgpu::RequestAdapterOptions options = {};
|
||||
MockCallback<WGPURequestAdapterCallback> cb;
|
||||
auto* userdata = cb.MakeUserdata(this);
|
||||
instance.RequestAdapter(&options, cb.Callback(), userdata);
|
||||
|
||||
EXPECT_CALL(cb, Call(WGPURequestAdapterStatus_Unknown, nullptr, NotNull(), this)).Times(1);
|
||||
instance = nullptr;
|
||||
}
|
||||
|
||||
// Test that RequestAdapter receives unknown status if the wire is disconnected
|
||||
// before the callback happens.
|
||||
TEST_F(WireInstanceTests, RequestAdapterWireDisconnectBeforeCallback) {
|
||||
wgpu::RequestAdapterOptions options = {};
|
||||
MockCallback<WGPURequestAdapterCallback> cb;
|
||||
auto* userdata = cb.MakeUserdata(this);
|
||||
instance.RequestAdapter(&options, cb.Callback(), userdata);
|
||||
|
||||
EXPECT_CALL(cb, Call(WGPURequestAdapterStatus_Unknown, nullptr, NotNull(), this)).Times(1);
|
||||
GetWireClient()->Disconnect();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
Loading…
Reference in New Issue