Add Device::GetSupportedSurfaceUsage() method.

This method will return supported usage flags that can be used to create
a swap chain.

Bug: dawn:1760
Change-Id: I7699c2c4ef7142c6bd06e72239d6e4f9112f15a3
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/127440
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Quyen Le <lehoangquyen@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
Le Hoang Quyen 2023-04-20 20:42:05 +00:00 committed by Dawn LUCI CQ
parent 7eb37948ab
commit 335573116c
29 changed files with 339 additions and 6 deletions

View File

@ -1251,6 +1251,13 @@
"args": [ "args": [
{"name": "descriptor", "type": "texture descriptor", "annotation": "const*"} {"name": "descriptor", "type": "texture descriptor", "annotation": "const*"}
] ]
},
{
"name": "get supported surface usage",
"returns": "texture usage",
"args": [
{"name": "surface", "type": "surface"}
]
} }
] ]
}, },
@ -1467,7 +1474,8 @@
{"value": 1004, "name": "dawn native", "tags": ["dawn", "native"]}, {"value": 1004, "name": "dawn native", "tags": ["dawn", "native"]},
{"value": 1005, "name": "chromium experimental dp4a", "tags": ["dawn"]}, {"value": 1005, "name": "chromium experimental dp4a", "tags": ["dawn"]},
{"value": 1006, "name": "timestamp query inside passes", "tags": ["dawn"]}, {"value": 1006, "name": "timestamp query inside passes", "tags": ["dawn"]},
{"value": 1007, "name": "implicit device synchronization", "tags": ["dawn", "native"]} {"value": 1007, "name": "implicit device synchronization", "tags": ["dawn", "native"]},
{"value": 1008, "name": "surface capabilities", "tags": ["dawn", "native"]}
] ]
}, },
"filter mode": { "filter mode": {

View File

@ -228,6 +228,7 @@
"DeviceCreateErrorTexture", "DeviceCreateErrorTexture",
"DeviceGetAdapter", "DeviceGetAdapter",
"DeviceGetQueue", "DeviceGetQueue",
"DeviceGetSupportedSurfaceUsage",
"DeviceInjectError" "DeviceInjectError"
], ],
"client_special_objects": [ "client_special_objects": [

View File

@ -0,0 +1,20 @@
# Surface Capabilities
The `surface-capabilities` feature allows querying a surface's capabilities and creating a swap chain with additional usage flags.
Additional functionality:
- Adds `wgpu::Device::GetSupportedSurfaceUsage(wgpu::Surface)` method for querying the surface's supported usage flags. One or the combination of these flags can be used to create a swap chain.
Example Usage:
```
wgpu::TextureUsage supportedUsage = device.GetSupportedSurfaceUsage(surface);
wgpu::SwapChainDescriptor desc = {};
// set usage flags.
desc.usage = supportedUsage;
device.CreateSwapChain(surface, &desc);
```
Notes:
- If this feature is not enabled, only `wgpu::TextureUsage::RenderAttachment` flag is allowed to be used in `wgpu::SwapChainDescriptor::usage`.

View File

@ -1242,6 +1242,15 @@ TextureBase* DeviceBase::APICreateTexture(const TextureDescriptor* descriptor) {
return result.Detach(); return result.Detach();
} }
wgpu::TextureUsage DeviceBase::APIGetSupportedSurfaceUsage(Surface* surface) {
wgpu::TextureUsage result;
if (ConsumedError(GetSupportedSurfaceUsage(surface), &result,
"calling %s.GetSupportedSurfaceUsage().", this)) {
return wgpu::TextureUsage::None;
}
return result;
}
// For Dawn Wire // For Dawn Wire
BufferBase* DeviceBase::APICreateErrorBuffer(const BufferDescriptor* desc) { BufferBase* DeviceBase::APICreateErrorBuffer(const BufferDescriptor* desc) {
@ -1814,6 +1823,18 @@ ResultOrError<Ref<TextureViewBase>> DeviceBase::CreateTextureView(
return CreateTextureViewImpl(texture, &desc); return CreateTextureViewImpl(texture, &desc);
} }
ResultOrError<wgpu::TextureUsage> DeviceBase::GetSupportedSurfaceUsage(
const Surface* surface) const {
DAWN_TRY(ValidateIsAlive());
if (IsValidationEnabled()) {
DAWN_INVALID_IF(!HasFeature(Feature::SurfaceCapabilities), "%s is not enabled.",
wgpu::FeatureName::SurfaceCapabilities);
}
return GetSupportedSurfaceUsageImpl(surface);
}
// Other implementation details // Other implementation details
DynamicUploader* DeviceBase::GetDynamicUploader() const { DynamicUploader* DeviceBase::GetDynamicUploader() const {

View File

@ -261,6 +261,8 @@ class DeviceBase : public RefCountedWithExternalCount {
ResultOrError<Ref<TextureViewBase>> CreateTextureView(TextureBase* texture, ResultOrError<Ref<TextureViewBase>> CreateTextureView(TextureBase* texture,
const TextureViewDescriptor* descriptor); const TextureViewDescriptor* descriptor);
ResultOrError<wgpu::TextureUsage> GetSupportedSurfaceUsage(const Surface* surface) const;
// Implementation of API object creation methods. DO NOT use them in a reentrant manner. // Implementation of API object creation methods. DO NOT use them in a reentrant manner.
BindGroupBase* APICreateBindGroup(const BindGroupDescriptor* descriptor); BindGroupBase* APICreateBindGroup(const BindGroupDescriptor* descriptor);
BindGroupLayoutBase* APICreateBindGroupLayout(const BindGroupLayoutDescriptor* descriptor); BindGroupLayoutBase* APICreateBindGroupLayout(const BindGroupLayoutDescriptor* descriptor);
@ -284,6 +286,8 @@ class DeviceBase : public RefCountedWithExternalCount {
SwapChainBase* APICreateSwapChain(Surface* surface, const SwapChainDescriptor* descriptor); SwapChainBase* APICreateSwapChain(Surface* surface, const SwapChainDescriptor* descriptor);
TextureBase* APICreateTexture(const TextureDescriptor* descriptor); TextureBase* APICreateTexture(const TextureDescriptor* descriptor);
wgpu::TextureUsage APIGetSupportedSurfaceUsage(Surface* surface);
InternalPipelineStore* GetInternalPipelineStore(); InternalPipelineStore* GetInternalPipelineStore();
// For Dawn Wire // For Dawn Wire
@ -492,6 +496,9 @@ class DeviceBase : public RefCountedWithExternalCount {
const RenderPipelineDescriptor* descriptor) = 0; const RenderPipelineDescriptor* descriptor) = 0;
virtual void SetLabelImpl(); virtual void SetLabelImpl();
virtual ResultOrError<wgpu::TextureUsage> GetSupportedSurfaceUsageImpl(
const Surface* surface) const = 0;
virtual MaybeError TickImpl() = 0; virtual MaybeError TickImpl() = 0;
void FlushCallbackTaskQueue(); void FlushCallbackTaskQueue();

View File

@ -102,6 +102,11 @@ static constexpr FeatureEnumAndInfoList kFeatureNameAndInfoList = {{
"Public API methods (except encoding) will have implicit device synchronization. So they " "Public API methods (except encoding) will have implicit device synchronization. So they "
"will be safe to be used on multiple threads.", "will be safe to be used on multiple threads.",
"https://bugs.chromium.org/p/dawn/issues/detail?id=1662", FeatureInfo::FeatureState::Stable}}, "https://bugs.chromium.org/p/dawn/issues/detail?id=1662", FeatureInfo::FeatureState::Stable}},
{Feature::SurfaceCapabilities,
{"surface-capabilities",
"Support querying Surface's capabilities such as supported usage flags. This feature also "
"enables swap chain to be created with usage other than RenderAttachment.",
"https://bugs.chromium.org/p/dawn/issues/detail?id=1760", FeatureInfo::FeatureState::Stable}},
}}; }};
Feature FromAPIFeature(wgpu::FeatureName feature) { Feature FromAPIFeature(wgpu::FeatureName feature) {
@ -146,6 +151,8 @@ Feature FromAPIFeature(wgpu::FeatureName feature) {
return Feature::BGRA8UnormStorage; return Feature::BGRA8UnormStorage;
case wgpu::FeatureName::ImplicitDeviceSynchronization: case wgpu::FeatureName::ImplicitDeviceSynchronization:
return Feature::ImplicitDeviceSynchronization; return Feature::ImplicitDeviceSynchronization;
case wgpu::FeatureName::SurfaceCapabilities:
return Feature::SurfaceCapabilities;
} }
return Feature::InvalidEnum; return Feature::InvalidEnum;
} }
@ -186,6 +193,8 @@ wgpu::FeatureName ToAPIFeature(Feature feature) {
return wgpu::FeatureName::BGRA8UnormStorage; return wgpu::FeatureName::BGRA8UnormStorage;
case Feature::ImplicitDeviceSynchronization: case Feature::ImplicitDeviceSynchronization:
return wgpu::FeatureName::ImplicitDeviceSynchronization; return wgpu::FeatureName::ImplicitDeviceSynchronization;
case Feature::SurfaceCapabilities:
return wgpu::FeatureName::SurfaceCapabilities;
case Feature::EnumCount: case Feature::EnumCount:
break; break;

View File

@ -46,6 +46,7 @@ enum class Feature {
MultiPlanarFormats, MultiPlanarFormats,
DawnNative, DawnNative,
ImplicitDeviceSynchronization, ImplicitDeviceSynchronization,
SurfaceCapabilities,
EnumCount, EnumCount,
InvalidEnum = EnumCount, InvalidEnum = EnumCount,

View File

@ -57,9 +57,20 @@ MaybeError ValidateSwapChainDescriptor(const DeviceBase* device,
"Format (%s) is not %s, which is (currently) the only accepted format.", "Format (%s) is not %s, which is (currently) the only accepted format.",
descriptor->format, kRequireSwapChainFormat); descriptor->format, kRequireSwapChainFormat);
if (device->HasFeature(Feature::SurfaceCapabilities)) {
wgpu::TextureUsage validUsage;
DAWN_TRY_ASSIGN(validUsage, device->GetSupportedSurfaceUsage(surface));
DAWN_INVALID_IF(
(descriptor->usage | validUsage) != validUsage,
"Usage (%s) is not supported, %s are (currently) the only accepted usage flags.",
descriptor->usage, validUsage);
} else {
DAWN_INVALID_IF(descriptor->usage != wgpu::TextureUsage::RenderAttachment, DAWN_INVALID_IF(descriptor->usage != wgpu::TextureUsage::RenderAttachment,
"Usage (%s) is not %s, which is (currently) the only accepted usage.", "Usage (%s) is not %s, which is (currently) the only accepted usage. Other "
descriptor->usage, wgpu::TextureUsage::RenderAttachment); "usage flags require enabling %s",
descriptor->usage, wgpu::TextureUsage::RenderAttachment,
wgpu::FeatureName::SurfaceCapabilities);
}
DAWN_INVALID_IF(descriptor->width == 0 || descriptor->height == 0, DAWN_INVALID_IF(descriptor->width == 0 || descriptor->height == 0,
"Swap Chain size (width: %u, height: %u) is empty.", descriptor->width, "Swap Chain size (width: %u, height: %u) is empty.", descriptor->width,

View File

@ -27,6 +27,13 @@ Device::Device(AdapterBase* adapter,
Device::~Device() = default; Device::~Device() = default;
ResultOrError<wgpu::TextureUsage> Device::GetSupportedSurfaceUsageImpl(
const Surface* surface) const {
wgpu::TextureUsage usages =
wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding;
return usages;
}
const PlatformFunctions* Device::GetFunctions() const { const PlatformFunctions* Device::GetFunctions() const {
return ToBackend(GetAdapter())->GetBackend()->GetFunctions(); return ToBackend(GetAdapter())->GetBackend()->GetFunctions();
} }

View File

@ -30,6 +30,9 @@ class Device : public DeviceBase {
const TogglesState& deviceToggles); const TogglesState& deviceToggles);
~Device() override; ~Device() override;
ResultOrError<wgpu::TextureUsage> GetSupportedSurfaceUsageImpl(
const Surface* surface) const override;
const PlatformFunctions* GetFunctions() const; const PlatformFunctions* GetFunctions() const;
ComPtr<IDXGIFactory4> GetFactory() const; ComPtr<IDXGIFactory4> GetFactory() const;

View File

@ -84,6 +84,7 @@ MaybeError Adapter::InitializeImpl() {
void Adapter::InitializeSupportedFeaturesImpl() { void Adapter::InitializeSupportedFeaturesImpl() {
EnableFeature(Feature::TextureCompressionBC); EnableFeature(Feature::TextureCompressionBC);
EnableFeature(Feature::SurfaceCapabilities);
} }
MaybeError Adapter::InitializeSupportedLimitsImpl(CombinedLimits* limits) { MaybeError Adapter::InitializeSupportedLimitsImpl(CombinedLimits* limits) {

View File

@ -121,6 +121,7 @@ void Adapter::InitializeSupportedFeaturesImpl() {
EnableFeature(Feature::IndirectFirstInstance); EnableFeature(Feature::IndirectFirstInstance);
EnableFeature(Feature::RG11B10UfloatRenderable); EnableFeature(Feature::RG11B10UfloatRenderable);
EnableFeature(Feature::DepthClipControl); EnableFeature(Feature::DepthClipControl);
EnableFeature(Feature::SurfaceCapabilities);
if (AreTimestampQueriesSupported()) { if (AreTimestampQueriesSupported()) {
EnableFeature(Feature::TimestampQuery); EnableFeature(Feature::TimestampQuery);

View File

@ -517,6 +517,7 @@ class Adapter : public AdapterBase {
EnableFeature(Feature::ShaderF16); EnableFeature(Feature::ShaderF16);
EnableFeature(Feature::RG11B10UfloatRenderable); EnableFeature(Feature::RG11B10UfloatRenderable);
EnableFeature(Feature::BGRA8UnormStorage); EnableFeature(Feature::BGRA8UnormStorage);
EnableFeature(Feature::SurfaceCapabilities);
} }
void InitializeVendorArchitectureImpl() override { void InitializeVendorArchitectureImpl() override {

View File

@ -130,6 +130,9 @@ class Device final : public DeviceBase {
WGPUCreateRenderPipelineAsyncCallback callback, WGPUCreateRenderPipelineAsyncCallback callback,
void* userdata) override; void* userdata) override;
ResultOrError<wgpu::TextureUsage> GetSupportedSurfaceUsageImpl(
const Surface* surface) const override;
void DestroyImpl() override; void DestroyImpl() override;
MaybeError WaitForIdleForDestruction() override; MaybeError WaitForIdleForDestruction() override;
bool HasPendingCommands() const override; bool HasPendingCommands() const override;

View File

@ -240,6 +240,13 @@ void Device::InitializeRenderPipelineAsyncImpl(Ref<RenderPipelineBase> renderPip
RenderPipeline::InitializeAsync(std::move(renderPipeline), callback, userdata); RenderPipeline::InitializeAsync(std::move(renderPipeline), callback, userdata);
} }
ResultOrError<wgpu::TextureUsage> Device::GetSupportedSurfaceUsageImpl(
const Surface* surface) const {
wgpu::TextureUsage usages =
wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding;
return usages;
}
ResultOrError<ExecutionSerial> Device::CheckAndUpdateCompletedSerials() { ResultOrError<ExecutionSerial> Device::CheckAndUpdateCompletedSerials() {
uint64_t frontendCompletedSerial{GetCompletedCommandSerial()}; uint64_t frontendCompletedSerial{GetCompletedCommandSerial()};
// sometimes we increase the serials, in which case the completed serial in // sometimes we increase the serials, in which case the completed serial in

View File

@ -188,6 +188,11 @@ ResultOrError<Ref<TextureViewBase>> Device::CreateTextureViewImpl(
return AcquireRef(new TextureView(texture, descriptor)); return AcquireRef(new TextureView(texture, descriptor));
} }
ResultOrError<wgpu::TextureUsage> Device::GetSupportedSurfaceUsageImpl(
const Surface* surface) const {
return wgpu::TextureUsage::RenderAttachment;
}
void Device::DestroyImpl() { void Device::DestroyImpl() {
ASSERT(GetState() == State::Disconnected); ASSERT(GetState() == State::Disconnected);

View File

@ -155,6 +155,9 @@ class Device final : public DeviceBase {
TextureBase* texture, TextureBase* texture,
const TextureViewDescriptor* descriptor) override; const TextureViewDescriptor* descriptor) override;
ResultOrError<wgpu::TextureUsage> GetSupportedSurfaceUsageImpl(
const Surface* surface) const override;
ResultOrError<ExecutionSerial> CheckAndUpdateCompletedSerials() override; ResultOrError<ExecutionSerial> CheckAndUpdateCompletedSerials() override;
void DestroyImpl() override; void DestroyImpl() override;

View File

@ -253,6 +253,13 @@ ResultOrError<Ref<TextureViewBase>> Device::CreateTextureViewImpl(
return AcquireRef(new TextureView(texture, descriptor)); return AcquireRef(new TextureView(texture, descriptor));
} }
ResultOrError<wgpu::TextureUsage> Device::GetSupportedSurfaceUsageImpl(
const Surface* surface) const {
wgpu::TextureUsage usages =
wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding;
return usages;
}
void Device::SubmitFenceSync() { void Device::SubmitFenceSync() {
if (!mHasPendingCommands) { if (!mHasPendingCommands) {
return; return;

View File

@ -125,6 +125,9 @@ class Device final : public DeviceBase {
Ref<RenderPipelineBase> CreateUninitializedRenderPipelineImpl( Ref<RenderPipelineBase> CreateUninitializedRenderPipelineImpl(
const RenderPipelineDescriptor* descriptor) override; const RenderPipelineDescriptor* descriptor) override;
ResultOrError<wgpu::TextureUsage> GetSupportedSurfaceUsageImpl(
const Surface* surface) const override;
GLenum GetBGRAInternalFormat() const; GLenum GetBGRAInternalFormat() const;
ResultOrError<ExecutionSerial> CheckAndUpdateCompletedSerials() override; ResultOrError<ExecutionSerial> CheckAndUpdateCompletedSerials() override;
void DestroyImpl() override; void DestroyImpl() override;

View File

@ -263,6 +263,8 @@ void Adapter::InitializeSupportedFeaturesImpl() {
// features. // features.
EnableFeature(Feature::MultiPlanarFormats); EnableFeature(Feature::MultiPlanarFormats);
#endif // DAWN_PLATFORM_IS(ANDROID) || DAWN_PLATFORM_IS(CHROMEOS) #endif // DAWN_PLATFORM_IS(ANDROID) || DAWN_PLATFORM_IS(CHROMEOS)
EnableFeature(Feature::SurfaceCapabilities);
} }
MaybeError Adapter::InitializeSupportedLimitsImpl(CombinedLimits* limits) { MaybeError Adapter::InitializeSupportedLimitsImpl(CombinedLimits* limits) {

View File

@ -217,6 +217,11 @@ void Device::InitializeRenderPipelineAsyncImpl(Ref<RenderPipelineBase> renderPip
RenderPipeline::InitializeAsync(std::move(renderPipeline), callback, userdata); RenderPipeline::InitializeAsync(std::move(renderPipeline), callback, userdata);
} }
ResultOrError<wgpu::TextureUsage> Device::GetSupportedSurfaceUsageImpl(
const Surface* surface) const {
return SwapChain::GetSupportedSurfaceUsage(this, surface);
}
MaybeError Device::TickImpl() { MaybeError Device::TickImpl() {
RecycleCompletedCommands(); RecycleCompletedCommands();

View File

@ -155,6 +155,9 @@ class Device final : public DeviceBase {
WGPUCreateRenderPipelineAsyncCallback callback, WGPUCreateRenderPipelineAsyncCallback callback,
void* userdata) override; void* userdata) override;
ResultOrError<wgpu::TextureUsage> GetSupportedSurfaceUsageImpl(
const Surface* surface) const override;
ResultOrError<VulkanDeviceKnobs> CreateDevice(VkPhysicalDevice physicalDevice); ResultOrError<VulkanDeviceKnobs> CreateDevice(VkPhysicalDevice physicalDevice);
void GatherQueueFromDevice(); void GatherQueueFromDevice();

View File

@ -36,7 +36,7 @@ namespace dawn::native::vulkan {
namespace { namespace {
ResultOrError<VkSurfaceKHR> CreateVulkanSurface(Adapter* adapter, Surface* surface) { ResultOrError<VkSurfaceKHR> CreateVulkanSurface(const Adapter* adapter, const Surface* surface) {
const VulkanGlobalInfo& info = adapter->GetVulkanInstance()->GetGlobalInfo(); const VulkanGlobalInfo& info = adapter->GetVulkanInstance()->GetGlobalInfo();
const VulkanFunctions& fn = adapter->GetVulkanInstance()->GetFunctions(); const VulkanFunctions& fn = adapter->GetVulkanInstance()->GetFunctions();
VkInstance instance = adapter->GetVulkanInstance()->GetVkInstance(); VkInstance instance = adapter->GetVulkanInstance()->GetVkInstance();
@ -205,6 +205,33 @@ uint32_t MinImageCountForPresentMode(VkPresentModeKHR mode) {
} // anonymous namespace } // anonymous namespace
// static
ResultOrError<wgpu::TextureUsage> SwapChain::GetSupportedSurfaceUsage(const Device* device,
const Surface* surface) {
Adapter* adapter = ToBackend(device->GetAdapter());
const VulkanFunctions& fn = adapter->GetVulkanInstance()->GetFunctions();
VkInstance instanceVk = adapter->GetVulkanInstance()->GetVkInstance();
VkPhysicalDevice physicalDeviceVk = adapter->GetPhysicalDevice();
VkSurfaceKHR surfaceVk;
VkSurfaceCapabilitiesKHR surfaceCapsVk;
DAWN_TRY_ASSIGN(surfaceVk, CreateVulkanSurface(adapter, surface));
DAWN_TRY(CheckVkSuccess(
fn.GetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDeviceVk, surfaceVk, &surfaceCapsVk),
"GetPhysicalDeviceSurfaceCapabilitiesKHR"));
wgpu::TextureUsage supportedUsages = wgpu::TextureUsage::RenderAttachment;
if (surfaceCapsVk.supportedUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT) {
supportedUsages |= wgpu::TextureUsage::TextureBinding;
}
fn.DestroySurfaceKHR(instanceVk, surfaceVk, nullptr);
return supportedUsages;
}
// static // static
ResultOrError<Ref<SwapChain>> SwapChain::Create(Device* device, ResultOrError<Ref<SwapChain>> SwapChain::Create(Device* device,
Surface* surface, Surface* surface,

View File

@ -33,6 +33,10 @@ class SwapChain : public SwapChainBase {
Surface* surface, Surface* surface,
SwapChainBase* previousSwapChain, SwapChainBase* previousSwapChain,
const SwapChainDescriptor* descriptor); const SwapChainDescriptor* descriptor);
static ResultOrError<wgpu::TextureUsage> GetSupportedSurfaceUsage(const Device* device,
const Surface* surface);
~SwapChain() override; ~SwapChain() override;
private: private:

View File

@ -12,10 +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 "dawn/tests/DawnTest.h" #include <vector>
#include "dawn/common/Constants.h" #include "dawn/common/Constants.h"
#include "dawn/common/Log.h" #include "dawn/common/Log.h"
#include "dawn/tests/DawnTest.h"
#include "dawn/utils/ComboRenderPipelineDescriptor.h"
#include "dawn/utils/WGPUHelpers.h" #include "dawn/utils/WGPUHelpers.h"
#include "webgpu/webgpu_glfw.h" #include "webgpu/webgpu_glfw.h"
@ -235,4 +237,162 @@ TEST_P(SwapChainTests, SwitchingDevice) {
} }
} }
// Test that calling Device.GetSupportedSurfaceUsage() will throw an error because
// SurfaceCapabilities is not enabled.
TEST_P(SwapChainTests, ErrorGetSurfaceSupportedUsage) {
DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("skip_validation"));
EXPECT_FALSE(device.HasFeature(wgpu::FeatureName::SurfaceCapabilities));
ASSERT_DEVICE_ERROR_MSG(
{
auto usageFlags = device.GetSupportedSurfaceUsage(surface);
EXPECT_EQ(usageFlags, wgpu::TextureUsage::None);
},
testing::HasSubstr("FeatureName::SurfaceCapabilities is not enabled"));
}
// Test that creating swapchain with TextureBinding usage without enabling SurfaceCapabilities
// feature should fail.
TEST_P(SwapChainTests, ErrorCreateWithTextureBindingUsage) {
DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("skip_validation"));
EXPECT_FALSE(device.HasFeature(wgpu::FeatureName::SurfaceCapabilities));
auto desc = baseDescriptor;
desc.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment;
ASSERT_DEVICE_ERROR_MSG(
{ auto swapchain = device.CreateSwapChain(surface, &desc); },
testing::HasSubstr("require enabling FeatureName::SurfaceCapabilities"));
}
class SwapChainWithAdditionalUsageTests : public SwapChainTests {
protected:
std::vector<wgpu::FeatureName> GetRequiredFeatures() override {
std::vector<wgpu::FeatureName> features;
if (!UsesWire() && SupportsFeatures({wgpu::FeatureName::SurfaceCapabilities})) {
features.push_back(wgpu::FeatureName::SurfaceCapabilities);
}
return features;
}
void SetUp() override {
SwapChainTests::SetUp();
// If parent class skipped the test, we should skip as well.
if (surface == nullptr) {
GTEST_SKIP();
}
DAWN_TEST_UNSUPPORTED_IF(!SupportsFeatures({wgpu::FeatureName::SurfaceCapabilities}));
}
void SampleTexture(wgpu::TextureView view,
uint32_t width,
uint32_t height,
utils::RGBA8 expectedColor) {
wgpu::TextureDescriptor texDescriptor;
texDescriptor.size = {width, height, 1};
texDescriptor.format = wgpu::TextureFormat::RGBA8Unorm;
texDescriptor.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc |
wgpu::TextureUsage::CopyDst;
texDescriptor.mipLevelCount = 1;
texDescriptor.sampleCount = 1;
wgpu::Texture dstTexture = device.CreateTexture(&texDescriptor);
wgpu::TextureView dstView = dstTexture.CreateView();
// Create a render pipeline to blit |view| into |dstView|.
utils::ComboRenderPipelineDescriptor pipelineDesc;
pipelineDesc.vertex.module = utils::CreateShaderModule(device, R"(
@vertex
fn main(@builtin(vertex_index) VertexIndex : u32) -> @builtin(position) vec4f {
var pos = array(
vec2f(-1.0, -1.0),
vec2f(-1.0, 1.0),
vec2f( 1.0, -1.0),
vec2f(-1.0, 1.0),
vec2f( 1.0, -1.0),
vec2f( 1.0, 1.0));
return vec4f(pos[VertexIndex], 0.0, 1.0);
}
)");
pipelineDesc.cFragment.module = utils::CreateShaderModule(device, R"(
@group(0) @binding(0) var texture : texture_2d<f32>;
@fragment
fn main(@builtin(position) coord: vec4f) -> @location(0) vec4f {
return textureLoad(texture, vec2i(coord.xy), 0);
}
)");
pipelineDesc.cTargets[0].format = texDescriptor.format;
// Submit a render pass to perform the blit from |view| to |dstView|.
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
{
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDesc);
wgpu::BindGroup bindGroup =
utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0), {{0, view}});
utils::ComboRenderPassDescriptor renderPassInfo({dstView});
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassInfo);
pass.SetPipeline(pipeline);
pass.SetBindGroup(0, bindGroup);
pass.Draw(6);
pass.End();
}
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
EXPECT_TEXTURE_EQ(expectedColor, dstTexture, {0, 0});
EXPECT_TEXTURE_EQ(expectedColor, dstTexture, {width - 1, height - 1});
}
};
TEST_P(SwapChainWithAdditionalUsageTests, GetSurfaceSupportedUsage) {
auto usageFlags = device.GetSupportedSurfaceUsage(surface);
EXPECT_NE(usageFlags, wgpu::TextureUsage::None);
}
// Test that sampling from swapchain is supported.
TEST_P(SwapChainWithAdditionalUsageTests, SamplingFromSwapChain) {
// Skip all tests if readable surface doesn't support texture binding
DAWN_TEST_UNSUPPORTED_IF(
(device.GetSupportedSurfaceUsage(surface) & wgpu::TextureUsage::TextureBinding) == 0);
auto desc = baseDescriptor;
desc.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment;
wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &desc);
ClearTexture(swapchain.GetCurrentTextureView(), {1.0, 0.0, 0.0, 1.0});
SampleTexture(swapchain.GetCurrentTextureView(), baseDescriptor.width, baseDescriptor.height,
utils::RGBA8::kRed);
swapchain.Present();
}
// Test that including unsupported usage flag will result in error.
TEST_P(SwapChainWithAdditionalUsageTests, ErrorIncludeUnsupportedUsage) {
DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("skip_validation"));
auto supportedUsage = device.GetSupportedSurfaceUsage(surface);
// Assuming StorageBinding is not supported.
DAWN_TEST_UNSUPPORTED_IF((supportedUsage & wgpu::TextureUsage::StorageBinding) != 0);
auto desc = baseDescriptor;
desc.usage = supportedUsage | wgpu::TextureUsage::StorageBinding;
ASSERT_DEVICE_ERROR_MSG({ auto swapchain = device.CreateSwapChain(surface, &desc); },
testing::HasSubstr("is not supported"));
}
DAWN_INSTANTIATE_TEST(SwapChainTests, MetalBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(SwapChainTests, MetalBackend(), VulkanBackend());
DAWN_INSTANTIATE_TEST(SwapChainWithAdditionalUsageTests,
D3D12Backend(),
MetalBackend(),
NullBackend(),
VulkanBackend());

View File

@ -121,6 +121,11 @@ class DeviceMock : public DeviceBase {
(TextureBase*, const TextureViewDescriptor*), (TextureBase*, const TextureViewDescriptor*),
(override)); (override));
MOCK_METHOD(ResultOrError<wgpu::TextureUsage>,
GetSupportedSurfaceUsageImpl,
(const Surface*),
(const, override));
MOCK_METHOD(MaybeError, TickImpl, (), (override)); MOCK_METHOD(MaybeError, TickImpl, (), (override));
MOCK_METHOD(ResultOrError<ExecutionSerial>, CheckAndUpdateCompletedSerials, (), (override)); MOCK_METHOD(ResultOrError<ExecutionSerial>, CheckAndUpdateCompletedSerials, (), (override));

View File

@ -25,6 +25,7 @@ bool IsFeatureSupported(WGPUFeatureName feature) {
case WGPUFeatureName_DawnNative: case WGPUFeatureName_DawnNative:
case WGPUFeatureName_DawnShaderFloat16: // Deprecated case WGPUFeatureName_DawnShaderFloat16: // Deprecated
case WGPUFeatureName_ImplicitDeviceSynchronization: case WGPUFeatureName_ImplicitDeviceSynchronization:
case WGPUFeatureName_SurfaceCapabilities:
return false; return false;
case WGPUFeatureName_Depth32FloatStencil8: case WGPUFeatureName_Depth32FloatStencil8:
case WGPUFeatureName_TimestampQuery: case WGPUFeatureName_TimestampQuery:

View File

@ -221,6 +221,12 @@ WGPUAdapter Device::GetAdapter() {
return nullptr; return nullptr;
} }
WGPUTextureUsage Device::GetSupportedSurfaceUsage(WGPUSurface) {
// Not implemented in the wire.
UNREACHABLE();
return WGPUTextureUsage_RenderAttachment;
}
WGPUQueue Device::GetQueue() { WGPUQueue Device::GetQueue() {
// The queue is lazily created because if a Device is created by // The queue is lazily created because if a Device is created by
// Reserve/Inject, we cannot send the GetQueue message until // Reserve/Inject, we cannot send the GetQueue message until

View File

@ -70,6 +70,7 @@ class Device final : public ObjectBase {
void SetFeatures(const WGPUFeatureName* features, uint32_t featuresCount); void SetFeatures(const WGPUFeatureName* features, uint32_t featuresCount);
WGPUAdapter GetAdapter(); // Not implemented in the wire. WGPUAdapter GetAdapter(); // Not implemented in the wire.
WGPUTextureUsage GetSupportedSurfaceUsage(WGPUSurface); // Not implemented in the wire.
WGPUQueue GetQueue(); WGPUQueue GetQueue();
void CancelCallbacksForDisconnect() override; void CancelCallbacksForDisconnect() override;