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:
parent
7eb37948ab
commit
335573116c
10
dawn.json
10
dawn.json
|
@ -1251,6 +1251,13 @@
|
|||
"args": [
|
||||
{"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": 1005, "name": "chromium experimental dp4a", "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": {
|
||||
|
|
|
@ -228,6 +228,7 @@
|
|||
"DeviceCreateErrorTexture",
|
||||
"DeviceGetAdapter",
|
||||
"DeviceGetQueue",
|
||||
"DeviceGetSupportedSurfaceUsage",
|
||||
"DeviceInjectError"
|
||||
],
|
||||
"client_special_objects": [
|
||||
|
|
|
@ -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`.
|
|
@ -1242,6 +1242,15 @@ TextureBase* DeviceBase::APICreateTexture(const TextureDescriptor* descriptor) {
|
|||
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
|
||||
|
||||
BufferBase* DeviceBase::APICreateErrorBuffer(const BufferDescriptor* desc) {
|
||||
|
@ -1814,6 +1823,18 @@ ResultOrError<Ref<TextureViewBase>> DeviceBase::CreateTextureView(
|
|||
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
|
||||
|
||||
DynamicUploader* DeviceBase::GetDynamicUploader() const {
|
||||
|
|
|
@ -261,6 +261,8 @@ class DeviceBase : public RefCountedWithExternalCount {
|
|||
ResultOrError<Ref<TextureViewBase>> CreateTextureView(TextureBase* texture,
|
||||
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.
|
||||
BindGroupBase* APICreateBindGroup(const BindGroupDescriptor* descriptor);
|
||||
BindGroupLayoutBase* APICreateBindGroupLayout(const BindGroupLayoutDescriptor* descriptor);
|
||||
|
@ -284,6 +286,8 @@ class DeviceBase : public RefCountedWithExternalCount {
|
|||
SwapChainBase* APICreateSwapChain(Surface* surface, const SwapChainDescriptor* descriptor);
|
||||
TextureBase* APICreateTexture(const TextureDescriptor* descriptor);
|
||||
|
||||
wgpu::TextureUsage APIGetSupportedSurfaceUsage(Surface* surface);
|
||||
|
||||
InternalPipelineStore* GetInternalPipelineStore();
|
||||
|
||||
// For Dawn Wire
|
||||
|
@ -492,6 +496,9 @@ class DeviceBase : public RefCountedWithExternalCount {
|
|||
const RenderPipelineDescriptor* descriptor) = 0;
|
||||
virtual void SetLabelImpl();
|
||||
|
||||
virtual ResultOrError<wgpu::TextureUsage> GetSupportedSurfaceUsageImpl(
|
||||
const Surface* surface) const = 0;
|
||||
|
||||
virtual MaybeError TickImpl() = 0;
|
||||
void FlushCallbackTaskQueue();
|
||||
|
||||
|
|
|
@ -102,6 +102,11 @@ static constexpr FeatureEnumAndInfoList kFeatureNameAndInfoList = {{
|
|||
"Public API methods (except encoding) will have implicit device synchronization. So they "
|
||||
"will be safe to be used on multiple threads.",
|
||||
"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) {
|
||||
|
@ -146,6 +151,8 @@ Feature FromAPIFeature(wgpu::FeatureName feature) {
|
|||
return Feature::BGRA8UnormStorage;
|
||||
case wgpu::FeatureName::ImplicitDeviceSynchronization:
|
||||
return Feature::ImplicitDeviceSynchronization;
|
||||
case wgpu::FeatureName::SurfaceCapabilities:
|
||||
return Feature::SurfaceCapabilities;
|
||||
}
|
||||
return Feature::InvalidEnum;
|
||||
}
|
||||
|
@ -186,6 +193,8 @@ wgpu::FeatureName ToAPIFeature(Feature feature) {
|
|||
return wgpu::FeatureName::BGRA8UnormStorage;
|
||||
case Feature::ImplicitDeviceSynchronization:
|
||||
return wgpu::FeatureName::ImplicitDeviceSynchronization;
|
||||
case Feature::SurfaceCapabilities:
|
||||
return wgpu::FeatureName::SurfaceCapabilities;
|
||||
|
||||
case Feature::EnumCount:
|
||||
break;
|
||||
|
|
|
@ -46,6 +46,7 @@ enum class Feature {
|
|||
MultiPlanarFormats,
|
||||
DawnNative,
|
||||
ImplicitDeviceSynchronization,
|
||||
SurfaceCapabilities,
|
||||
|
||||
EnumCount,
|
||||
InvalidEnum = EnumCount,
|
||||
|
|
|
@ -57,9 +57,20 @@ MaybeError ValidateSwapChainDescriptor(const DeviceBase* device,
|
|||
"Format (%s) is not %s, which is (currently) the only accepted format.",
|
||||
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,
|
||||
"Usage (%s) is not %s, which is (currently) the only accepted usage.",
|
||||
descriptor->usage, wgpu::TextureUsage::RenderAttachment);
|
||||
"Usage (%s) is not %s, which is (currently) the only accepted usage. Other "
|
||||
"usage flags require enabling %s",
|
||||
descriptor->usage, wgpu::TextureUsage::RenderAttachment,
|
||||
wgpu::FeatureName::SurfaceCapabilities);
|
||||
}
|
||||
|
||||
DAWN_INVALID_IF(descriptor->width == 0 || descriptor->height == 0,
|
||||
"Swap Chain size (width: %u, height: %u) is empty.", descriptor->width,
|
||||
|
|
|
@ -27,6 +27,13 @@ Device::Device(AdapterBase* adapter,
|
|||
|
||||
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 {
|
||||
return ToBackend(GetAdapter())->GetBackend()->GetFunctions();
|
||||
}
|
||||
|
|
|
@ -30,6 +30,9 @@ class Device : public DeviceBase {
|
|||
const TogglesState& deviceToggles);
|
||||
~Device() override;
|
||||
|
||||
ResultOrError<wgpu::TextureUsage> GetSupportedSurfaceUsageImpl(
|
||||
const Surface* surface) const override;
|
||||
|
||||
const PlatformFunctions* GetFunctions() const;
|
||||
ComPtr<IDXGIFactory4> GetFactory() const;
|
||||
|
||||
|
|
|
@ -84,6 +84,7 @@ MaybeError Adapter::InitializeImpl() {
|
|||
|
||||
void Adapter::InitializeSupportedFeaturesImpl() {
|
||||
EnableFeature(Feature::TextureCompressionBC);
|
||||
EnableFeature(Feature::SurfaceCapabilities);
|
||||
}
|
||||
|
||||
MaybeError Adapter::InitializeSupportedLimitsImpl(CombinedLimits* limits) {
|
||||
|
|
|
@ -121,6 +121,7 @@ void Adapter::InitializeSupportedFeaturesImpl() {
|
|||
EnableFeature(Feature::IndirectFirstInstance);
|
||||
EnableFeature(Feature::RG11B10UfloatRenderable);
|
||||
EnableFeature(Feature::DepthClipControl);
|
||||
EnableFeature(Feature::SurfaceCapabilities);
|
||||
|
||||
if (AreTimestampQueriesSupported()) {
|
||||
EnableFeature(Feature::TimestampQuery);
|
||||
|
|
|
@ -517,6 +517,7 @@ class Adapter : public AdapterBase {
|
|||
EnableFeature(Feature::ShaderF16);
|
||||
EnableFeature(Feature::RG11B10UfloatRenderable);
|
||||
EnableFeature(Feature::BGRA8UnormStorage);
|
||||
EnableFeature(Feature::SurfaceCapabilities);
|
||||
}
|
||||
|
||||
void InitializeVendorArchitectureImpl() override {
|
||||
|
|
|
@ -130,6 +130,9 @@ class Device final : public DeviceBase {
|
|||
WGPUCreateRenderPipelineAsyncCallback callback,
|
||||
void* userdata) override;
|
||||
|
||||
ResultOrError<wgpu::TextureUsage> GetSupportedSurfaceUsageImpl(
|
||||
const Surface* surface) const override;
|
||||
|
||||
void DestroyImpl() override;
|
||||
MaybeError WaitForIdleForDestruction() override;
|
||||
bool HasPendingCommands() const override;
|
||||
|
|
|
@ -240,6 +240,13 @@ void Device::InitializeRenderPipelineAsyncImpl(Ref<RenderPipelineBase> renderPip
|
|||
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() {
|
||||
uint64_t frontendCompletedSerial{GetCompletedCommandSerial()};
|
||||
// sometimes we increase the serials, in which case the completed serial in
|
||||
|
|
|
@ -188,6 +188,11 @@ ResultOrError<Ref<TextureViewBase>> Device::CreateTextureViewImpl(
|
|||
return AcquireRef(new TextureView(texture, descriptor));
|
||||
}
|
||||
|
||||
ResultOrError<wgpu::TextureUsage> Device::GetSupportedSurfaceUsageImpl(
|
||||
const Surface* surface) const {
|
||||
return wgpu::TextureUsage::RenderAttachment;
|
||||
}
|
||||
|
||||
void Device::DestroyImpl() {
|
||||
ASSERT(GetState() == State::Disconnected);
|
||||
|
||||
|
|
|
@ -155,6 +155,9 @@ class Device final : public DeviceBase {
|
|||
TextureBase* texture,
|
||||
const TextureViewDescriptor* descriptor) override;
|
||||
|
||||
ResultOrError<wgpu::TextureUsage> GetSupportedSurfaceUsageImpl(
|
||||
const Surface* surface) const override;
|
||||
|
||||
ResultOrError<ExecutionSerial> CheckAndUpdateCompletedSerials() override;
|
||||
|
||||
void DestroyImpl() override;
|
||||
|
|
|
@ -253,6 +253,13 @@ ResultOrError<Ref<TextureViewBase>> Device::CreateTextureViewImpl(
|
|||
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() {
|
||||
if (!mHasPendingCommands) {
|
||||
return;
|
||||
|
|
|
@ -125,6 +125,9 @@ class Device final : public DeviceBase {
|
|||
Ref<RenderPipelineBase> CreateUninitializedRenderPipelineImpl(
|
||||
const RenderPipelineDescriptor* descriptor) override;
|
||||
|
||||
ResultOrError<wgpu::TextureUsage> GetSupportedSurfaceUsageImpl(
|
||||
const Surface* surface) const override;
|
||||
|
||||
GLenum GetBGRAInternalFormat() const;
|
||||
ResultOrError<ExecutionSerial> CheckAndUpdateCompletedSerials() override;
|
||||
void DestroyImpl() override;
|
||||
|
|
|
@ -263,6 +263,8 @@ void Adapter::InitializeSupportedFeaturesImpl() {
|
|||
// features.
|
||||
EnableFeature(Feature::MultiPlanarFormats);
|
||||
#endif // DAWN_PLATFORM_IS(ANDROID) || DAWN_PLATFORM_IS(CHROMEOS)
|
||||
|
||||
EnableFeature(Feature::SurfaceCapabilities);
|
||||
}
|
||||
|
||||
MaybeError Adapter::InitializeSupportedLimitsImpl(CombinedLimits* limits) {
|
||||
|
|
|
@ -217,6 +217,11 @@ void Device::InitializeRenderPipelineAsyncImpl(Ref<RenderPipelineBase> renderPip
|
|||
RenderPipeline::InitializeAsync(std::move(renderPipeline), callback, userdata);
|
||||
}
|
||||
|
||||
ResultOrError<wgpu::TextureUsage> Device::GetSupportedSurfaceUsageImpl(
|
||||
const Surface* surface) const {
|
||||
return SwapChain::GetSupportedSurfaceUsage(this, surface);
|
||||
}
|
||||
|
||||
MaybeError Device::TickImpl() {
|
||||
RecycleCompletedCommands();
|
||||
|
||||
|
|
|
@ -155,6 +155,9 @@ class Device final : public DeviceBase {
|
|||
WGPUCreateRenderPipelineAsyncCallback callback,
|
||||
void* userdata) override;
|
||||
|
||||
ResultOrError<wgpu::TextureUsage> GetSupportedSurfaceUsageImpl(
|
||||
const Surface* surface) const override;
|
||||
|
||||
ResultOrError<VulkanDeviceKnobs> CreateDevice(VkPhysicalDevice physicalDevice);
|
||||
void GatherQueueFromDevice();
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace dawn::native::vulkan {
|
|||
|
||||
namespace {
|
||||
|
||||
ResultOrError<VkSurfaceKHR> CreateVulkanSurface(Adapter* adapter, Surface* surface) {
|
||||
ResultOrError<VkSurfaceKHR> CreateVulkanSurface(const Adapter* adapter, const Surface* surface) {
|
||||
const VulkanGlobalInfo& info = adapter->GetVulkanInstance()->GetGlobalInfo();
|
||||
const VulkanFunctions& fn = adapter->GetVulkanInstance()->GetFunctions();
|
||||
VkInstance instance = adapter->GetVulkanInstance()->GetVkInstance();
|
||||
|
@ -205,6 +205,33 @@ uint32_t MinImageCountForPresentMode(VkPresentModeKHR mode) {
|
|||
|
||||
} // 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
|
||||
ResultOrError<Ref<SwapChain>> SwapChain::Create(Device* device,
|
||||
Surface* surface,
|
||||
|
|
|
@ -33,6 +33,10 @@ class SwapChain : public SwapChainBase {
|
|||
Surface* surface,
|
||||
SwapChainBase* previousSwapChain,
|
||||
const SwapChainDescriptor* descriptor);
|
||||
|
||||
static ResultOrError<wgpu::TextureUsage> GetSupportedSurfaceUsage(const Device* device,
|
||||
const Surface* surface);
|
||||
|
||||
~SwapChain() override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -12,10 +12,12 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "dawn/tests/DawnTest.h"
|
||||
#include <vector>
|
||||
|
||||
#include "dawn/common/Constants.h"
|
||||
#include "dawn/common/Log.h"
|
||||
#include "dawn/tests/DawnTest.h"
|
||||
#include "dawn/utils/ComboRenderPipelineDescriptor.h"
|
||||
#include "dawn/utils/WGPUHelpers.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(SwapChainWithAdditionalUsageTests,
|
||||
D3D12Backend(),
|
||||
MetalBackend(),
|
||||
NullBackend(),
|
||||
VulkanBackend());
|
||||
|
|
|
@ -121,6 +121,11 @@ class DeviceMock : public DeviceBase {
|
|||
(TextureBase*, const TextureViewDescriptor*),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(ResultOrError<wgpu::TextureUsage>,
|
||||
GetSupportedSurfaceUsageImpl,
|
||||
(const Surface*),
|
||||
(const, override));
|
||||
|
||||
MOCK_METHOD(MaybeError, TickImpl, (), (override));
|
||||
|
||||
MOCK_METHOD(ResultOrError<ExecutionSerial>, CheckAndUpdateCompletedSerials, (), (override));
|
||||
|
|
|
@ -25,6 +25,7 @@ bool IsFeatureSupported(WGPUFeatureName feature) {
|
|||
case WGPUFeatureName_DawnNative:
|
||||
case WGPUFeatureName_DawnShaderFloat16: // Deprecated
|
||||
case WGPUFeatureName_ImplicitDeviceSynchronization:
|
||||
case WGPUFeatureName_SurfaceCapabilities:
|
||||
return false;
|
||||
case WGPUFeatureName_Depth32FloatStencil8:
|
||||
case WGPUFeatureName_TimestampQuery:
|
||||
|
|
|
@ -221,6 +221,12 @@ WGPUAdapter Device::GetAdapter() {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
WGPUTextureUsage Device::GetSupportedSurfaceUsage(WGPUSurface) {
|
||||
// Not implemented in the wire.
|
||||
UNREACHABLE();
|
||||
return WGPUTextureUsage_RenderAttachment;
|
||||
}
|
||||
|
||||
WGPUQueue Device::GetQueue() {
|
||||
// The queue is lazily created because if a Device is created by
|
||||
// Reserve/Inject, we cannot send the GetQueue message until
|
||||
|
|
|
@ -70,6 +70,7 @@ class Device final : public ObjectBase {
|
|||
void SetFeatures(const WGPUFeatureName* features, uint32_t featuresCount);
|
||||
|
||||
WGPUAdapter GetAdapter(); // Not implemented in the wire.
|
||||
WGPUTextureUsage GetSupportedSurfaceUsage(WGPUSurface); // Not implemented in the wire.
|
||||
WGPUQueue GetQueue();
|
||||
|
||||
void CancelCallbacksForDisconnect() override;
|
||||
|
|
Loading…
Reference in New Issue