Populate supported Vulkan limits from the backend

This commit also unifies the initialization process for Adapters.
InitializeImpl() initializes the actual backend adapter.
InitializeSupportedFeaturesImpl() checks base WebGPU features and
discovers additional supported features.
InitializeSupportedLimitsImpl() checks base WebGPU limits and
queries the adapter's maximum supported limits.

Some of these limits from the backend are still overriden in the
frontend because they are limited by internal Dawn constants.

Bug: dawn:685
Change-Id: I43efb0b678dd45f8f89cd62d13104dd00b197da1
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/64980
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Brandon Jones <bajones@chromium.org>
This commit is contained in:
Austin Eng 2021-10-19 22:52:14 +00:00 committed by Dawn LUCI CQ
parent bf9b3cc5a9
commit d97b29cd86
11 changed files with 321 additions and 200 deletions

View File

@ -14,16 +14,51 @@
#include "dawn_native/Adapter.h" #include "dawn_native/Adapter.h"
#include "common/Constants.h"
#include "dawn_native/Instance.h" #include "dawn_native/Instance.h"
namespace dawn_native { namespace dawn_native {
AdapterBase::AdapterBase(InstanceBase* instance, wgpu::BackendType backend) AdapterBase::AdapterBase(InstanceBase* instance, wgpu::BackendType backend)
: mInstance(instance), mBackend(backend) { : mInstance(instance), mBackend(backend) {
GetDefaultLimits(&mLimits.v1);
mSupportedFeatures.EnableFeature(Feature::DawnInternalUsages); mSupportedFeatures.EnableFeature(Feature::DawnInternalUsages);
} }
MaybeError AdapterBase::Initialize() {
DAWN_TRY(InitializeImpl());
DAWN_TRY(InitializeSupportedFeaturesImpl());
DAWN_TRY(InitializeSupportedLimitsImpl(&mLimits));
// Enforce internal Dawn constants.
mLimits.v1.maxVertexBufferArrayStride =
std::min(mLimits.v1.maxVertexBufferArrayStride, kMaxVertexBufferArrayStride);
mLimits.v1.maxBindGroups = std::min(mLimits.v1.maxBindGroups, kMaxBindGroups);
mLimits.v1.maxVertexAttributes =
std::min(mLimits.v1.maxVertexAttributes, uint32_t(kMaxVertexAttributes));
mLimits.v1.maxVertexBuffers =
std::min(mLimits.v1.maxVertexBuffers, uint32_t(kMaxVertexBuffers));
mLimits.v1.maxInterStageShaderComponents =
std::min(mLimits.v1.maxInterStageShaderComponents, kMaxInterStageShaderComponents);
mLimits.v1.maxSampledTexturesPerShaderStage = std::min(
mLimits.v1.maxSampledTexturesPerShaderStage, kMaxSampledTexturesPerShaderStage);
mLimits.v1.maxSamplersPerShaderStage =
std::min(mLimits.v1.maxSamplersPerShaderStage, kMaxSamplersPerShaderStage);
mLimits.v1.maxStorageBuffersPerShaderStage =
std::min(mLimits.v1.maxStorageBuffersPerShaderStage, kMaxStorageBuffersPerShaderStage);
mLimits.v1.maxStorageTexturesPerShaderStage = std::min(
mLimits.v1.maxStorageTexturesPerShaderStage, kMaxStorageTexturesPerShaderStage);
mLimits.v1.maxUniformBuffersPerShaderStage =
std::min(mLimits.v1.maxUniformBuffersPerShaderStage, kMaxUniformBuffersPerShaderStage);
mLimits.v1.maxDynamicUniformBuffersPerPipelineLayout =
std::min(mLimits.v1.maxDynamicUniformBuffersPerPipelineLayout,
kMaxDynamicUniformBuffersPerPipelineLayout);
mLimits.v1.maxDynamicStorageBuffersPerPipelineLayout =
std::min(mLimits.v1.maxDynamicStorageBuffersPerPipelineLayout,
kMaxDynamicStorageBuffersPerPipelineLayout);
return {};
}
wgpu::BackendType AdapterBase::GetBackendType() const { wgpu::BackendType AdapterBase::GetBackendType() const {
return mBackend; return mBackend;
} }

View File

@ -33,6 +33,8 @@ namespace dawn_native {
AdapterBase(InstanceBase* instance, wgpu::BackendType backend); AdapterBase(InstanceBase* instance, wgpu::BackendType backend);
virtual ~AdapterBase() = default; virtual ~AdapterBase() = default;
MaybeError Initialize();
wgpu::BackendType GetBackendType() const; wgpu::BackendType GetBackendType() const;
wgpu::AdapterType GetAdapterType() const; wgpu::AdapterType GetAdapterType() const;
const std::string& GetDriverDescription() const; const std::string& GetDriverDescription() const;
@ -66,6 +68,14 @@ namespace dawn_native {
private: private:
virtual ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) = 0; virtual ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) = 0;
virtual MaybeError InitializeImpl() = 0;
// Check base WebGPU features and discover supported featurees.
virtual MaybeError InitializeSupportedFeaturesImpl() = 0;
// Check base WebGPU limits and populate supported limits.
virtual MaybeError InitializeSupportedLimitsImpl(CombinedLimits* limits) = 0;
MaybeError CreateDeviceInternal(DeviceBase** result, const DeviceDescriptor* descriptor); MaybeError CreateDeviceInternal(DeviceBase** result, const DeviceDescriptor* descriptor);
virtual MaybeError ResetInternalDeviceForTestingImpl(); virtual MaybeError ResetInternalDeviceForTestingImpl();

View File

@ -61,7 +61,7 @@ namespace dawn_native { namespace d3d12 {
return mDriverVersion; return mDriverVersion;
} }
MaybeError Adapter::Initialize() { MaybeError Adapter::InitializeImpl() {
// D3D12 cannot check for feature support without a device. // D3D12 cannot check for feature support without a device.
// Create the device to populate the adapter properties then reuse it when needed for actual // Create the device to populate the adapter properties then reuse it when needed for actual
// rendering. // rendering.
@ -104,8 +104,6 @@ namespace dawn_native { namespace d3d12 {
mDriverDescription = o.str(); mDriverDescription = o.str();
} }
InitializeSupportedFeatures();
return {}; return {};
} }
@ -130,13 +128,19 @@ namespace dawn_native { namespace d3d12 {
return true; return true;
} }
void Adapter::InitializeSupportedFeatures() { MaybeError Adapter::InitializeSupportedFeaturesImpl() {
if (AreTimestampQueriesSupported()) { if (AreTimestampQueriesSupported()) {
mSupportedFeatures.EnableFeature(Feature::TimestampQuery); mSupportedFeatures.EnableFeature(Feature::TimestampQuery);
} }
mSupportedFeatures.EnableFeature(Feature::TextureCompressionBC); mSupportedFeatures.EnableFeature(Feature::TextureCompressionBC);
mSupportedFeatures.EnableFeature(Feature::PipelineStatisticsQuery); mSupportedFeatures.EnableFeature(Feature::PipelineStatisticsQuery);
mSupportedFeatures.EnableFeature(Feature::MultiPlanarFormats); mSupportedFeatures.EnableFeature(Feature::MultiPlanarFormats);
return {};
}
MaybeError Adapter::InitializeSupportedLimitsImpl(CombinedLimits* limits) {
GetDefaultLimits(&limits->v1);
return {};
} }
MaybeError Adapter::InitializeDebugLayerFilters() { MaybeError Adapter::InitializeDebugLayerFilters() {

View File

@ -39,15 +39,16 @@ namespace dawn_native { namespace d3d12 {
ComPtr<ID3D12Device> GetDevice() const; ComPtr<ID3D12Device> GetDevice() const;
const gpu_info::D3DDriverVersion& GetDriverVersion() const; const gpu_info::D3DDriverVersion& GetDriverVersion() const;
MaybeError Initialize();
private: private:
ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) override; ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) override;
MaybeError ResetInternalDeviceForTestingImpl() override; MaybeError ResetInternalDeviceForTestingImpl() override;
bool AreTimestampQueriesSupported() const; bool AreTimestampQueriesSupported() const;
void InitializeSupportedFeatures(); MaybeError InitializeImpl() override;
MaybeError InitializeSupportedFeaturesImpl() override;
MaybeError InitializeSupportedLimitsImpl(CombinedLimits* limits) override;
MaybeError InitializeDebugLayerFilters(); MaybeError InitializeDebugLayerFilters();
void CleanUpDebugLayerFilters(); void CleanUpDebugLayerFilters();

View File

@ -163,7 +163,7 @@ namespace dawn_native { namespace d3d12 {
ResultOrError<std::unique_ptr<AdapterBase>> adapter = ResultOrError<std::unique_ptr<AdapterBase>> adapter =
CreateAdapterFromIDXGIAdapter(this, dxgiAdapter); CreateAdapterFromIDXGIAdapter(this, dxgiAdapter);
if (adapter.IsError()) { if (adapter.IsError()) {
adapter.AcquireError(); GetInstance()->ConsumedError(adapter.AcquireError());
continue; continue;
} }

View File

@ -263,8 +263,6 @@ namespace dawn_native { namespace metal {
NSString* osVersion = [[NSProcessInfo processInfo] operatingSystemVersionString]; NSString* osVersion = [[NSProcessInfo processInfo] operatingSystemVersionString];
mDriverDescription = mDriverDescription =
"Metal driver on " + std::string(systemName) + [osVersion UTF8String]; "Metal driver on " + std::string(systemName) + [osVersion UTF8String];
InitializeSupportedFeatures();
} }
// AdapterBase Implementation // AdapterBase Implementation
@ -278,7 +276,11 @@ namespace dawn_native { namespace metal {
return Device::Create(this, mDevice, descriptor); return Device::Create(this, mDevice, descriptor);
} }
void InitializeSupportedFeatures() { MaybeError InitializeImpl() override {
return {};
}
MaybeError InitializeSupportedFeaturesImpl() override {
#if defined(DAWN_PLATFORM_MACOS) #if defined(DAWN_PLATFORM_MACOS)
if ([*mDevice supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v1]) { if ([*mDevice supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v1]) {
mSupportedFeatures.EnableFeature(Feature::TextureCompressionBC); mSupportedFeatures.EnableFeature(Feature::TextureCompressionBC);
@ -315,6 +317,13 @@ namespace dawn_native { namespace metal {
if (@available(macOS 10.11, iOS 11.0, *)) { if (@available(macOS 10.11, iOS 11.0, *)) {
mSupportedFeatures.EnableFeature(Feature::DepthClamping); mSupportedFeatures.EnableFeature(Feature::DepthClamping);
} }
return {};
}
MaybeError InitializeSupportedLimitsImpl(CombinedLimits* limits) override {
GetDefaultLimits(&limits->v1);
return {};
} }
NSPRef<id<MTLDevice>> mDevice; NSPRef<id<MTLDevice>> mDevice;
@ -339,7 +348,10 @@ namespace dawn_native { namespace metal {
NSRef<NSArray<id<MTLDevice>>> devices = AcquireNSRef(MTLCopyAllDevices()); NSRef<NSArray<id<MTLDevice>>> devices = AcquireNSRef(MTLCopyAllDevices());
for (id<MTLDevice> device in devices.Get()) { for (id<MTLDevice> device in devices.Get()) {
adapters.push_back(std::make_unique<Adapter>(GetInstance(), device)); std::unique_ptr<Adapter> adapter = std::make_unique<Adapter>(GetInstance(), device);
if (!GetInstance()->ConsumedError(adapter->Initialize())) {
adapters.push_back(std::move(adapter));
}
} }
} }
#endif #endif
@ -348,8 +360,10 @@ namespace dawn_native { namespace metal {
if (@available(iOS 8.0, *)) { if (@available(iOS 8.0, *)) {
supportedVersion = YES; supportedVersion = YES;
// iOS only has a single device so MTLCopyAllDevices doesn't exist there. // iOS only has a single device so MTLCopyAllDevices doesn't exist there.
adapters.push_back( std::unique_ptr<Adapter> adapter = std::make_unique<Adapter>(GetInstance(), MTLCreateSystemDefaultDevice());
std::make_unique<Adapter>(GetInstance(), MTLCreateSystemDefaultDevice())); if (!GetInstance()->ConsumedError(adapter->Initialize())) {
adapters.push_back(std::move(adapter));
}
} }
#endif #endif
if (!supportedVersion) { if (!supportedVersion) {

View File

@ -27,9 +27,8 @@ namespace dawn_native { namespace null {
Adapter::Adapter(InstanceBase* instance) : AdapterBase(instance, wgpu::BackendType::Null) { Adapter::Adapter(InstanceBase* instance) : AdapterBase(instance, wgpu::BackendType::Null) {
mPCIInfo.name = "Null backend"; mPCIInfo.name = "Null backend";
mAdapterType = wgpu::AdapterType::CPU; mAdapterType = wgpu::AdapterType::CPU;
MaybeError err = Initialize();
// Enable all features by default for the convenience of tests. ASSERT(err.IsSuccess());
mSupportedFeatures.featuresBitSet.set();
} }
Adapter::~Adapter() = default; Adapter::~Adapter() = default;
@ -43,6 +42,21 @@ namespace dawn_native { namespace null {
mSupportedFeatures = GetInstance()->FeatureNamesToFeaturesSet(requiredFeatures); mSupportedFeatures = GetInstance()->FeatureNamesToFeaturesSet(requiredFeatures);
} }
MaybeError Adapter::InitializeImpl() {
return {};
}
MaybeError Adapter::InitializeSupportedFeaturesImpl() {
// Enable all features by default for the convenience of tests.
mSupportedFeatures.featuresBitSet.set();
return {};
}
MaybeError Adapter::InitializeSupportedLimitsImpl(CombinedLimits* limits) {
GetDefaultLimits(&limits->v1);
return {};
}
ResultOrError<DeviceBase*> Adapter::CreateDeviceImpl(const DeviceDescriptor* descriptor) { ResultOrError<DeviceBase*> Adapter::CreateDeviceImpl(const DeviceDescriptor* descriptor) {
return Device::Create(this, descriptor); return Device::Create(this, descriptor);
} }
@ -56,7 +70,8 @@ namespace dawn_native { namespace null {
// There is always a single Null adapter because it is purely CPU based and doesn't // There is always a single Null adapter because it is purely CPU based and doesn't
// depend on the system. // depend on the system.
std::vector<std::unique_ptr<AdapterBase>> adapters; std::vector<std::unique_ptr<AdapterBase>> adapters;
adapters.push_back(std::make_unique<Adapter>(GetInstance())); std::unique_ptr<Adapter> adapter = std::make_unique<Adapter>(GetInstance());
adapters.push_back(std::move(adapter));
return adapters; return adapters;
} }
}; };

View File

@ -177,6 +177,10 @@ namespace dawn_native { namespace null {
void SetSupportedFeatures(const std::vector<const char*>& requiredFeatures); void SetSupportedFeatures(const std::vector<const char*>& requiredFeatures);
private: private:
MaybeError InitializeImpl() override;
MaybeError InitializeSupportedFeaturesImpl() override;
MaybeError InitializeSupportedLimitsImpl(CombinedLimits* limits) override;
ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) override; ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) override;
}; };

View File

@ -123,9 +123,21 @@ namespace dawn_native { namespace opengl {
: AdapterBase(instance, backendType) { : AdapterBase(instance, backendType) {
} }
MaybeError Initialize(const AdapterDiscoveryOptions* options) { MaybeError InitializeGLFunctions(void* (*getProc)(const char*)) {
// Use getProc to populate the dispatch table // Use getProc to populate the dispatch table
DAWN_TRY(mFunctions.Initialize(options->getProc)); return mFunctions.Initialize(getProc);
}
~Adapter() override = default;
// AdapterBase Implementation
bool SupportsExternalImages() const override {
// Via dawn_native::opengl::WrapExternalEGLImage
return GetBackendType() == wgpu::BackendType::OpenGLES;
}
private:
MaybeError InitializeImpl() override {
if (mFunctions.GetVersion().IsES()) { if (mFunctions.GetVersion().IsES()) {
ASSERT(GetBackendType() == wgpu::BackendType::OpenGLES); ASSERT(GetBackendType() == wgpu::BackendType::OpenGLES);
} else { } else {
@ -187,29 +199,10 @@ namespace dawn_native { namespace opengl {
mAdapterType = wgpu::AdapterType::CPU; mAdapterType = wgpu::AdapterType::CPU;
} }
InitializeSupportedFeatures();
return {}; return {};
} }
~Adapter() override = default; MaybeError InitializeSupportedFeaturesImpl() override {
// AdapterBase Implementation
bool SupportsExternalImages() const override {
// Via dawn_native::opengl::WrapExternalEGLImage
return GetBackendType() == wgpu::BackendType::OpenGLES;
}
private:
OpenGLFunctions mFunctions;
ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) override {
// There is no limit on the number of devices created from this adapter because they can
// all share the same backing OpenGL context.
return Device::Create(this, descriptor, mFunctions);
}
void InitializeSupportedFeatures() {
// TextureCompressionBC // TextureCompressionBC
{ {
// BC1, BC2 and BC3 are not supported in OpenGL or OpenGL ES core features. // BC1, BC2 and BC3 are not supported in OpenGL or OpenGL ES core features.
@ -252,7 +245,22 @@ namespace dawn_native { namespace opengl {
mSupportedFeatures.EnableFeature(dawn_native::Feature::TextureCompressionBC); mSupportedFeatures.EnableFeature(dawn_native::Feature::TextureCompressionBC);
} }
} }
return {};
} }
MaybeError InitializeSupportedLimitsImpl(CombinedLimits* limits) override {
GetDefaultLimits(&limits->v1);
return {};
}
ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) override {
// There is no limit on the number of devices created from this adapter because they can
// all share the same backing OpenGL context.
return Device::Create(this, descriptor, mFunctions);
}
OpenGLFunctions mFunctions;
}; };
// Implementation of the OpenGL backend's BackendConnection // Implementation of the OpenGL backend's BackendConnection
@ -284,7 +292,8 @@ namespace dawn_native { namespace opengl {
std::unique_ptr<Adapter> adapter = std::make_unique<Adapter>( std::unique_ptr<Adapter> adapter = std::make_unique<Adapter>(
GetInstance(), static_cast<wgpu::BackendType>(optionsBase->backendType)); GetInstance(), static_cast<wgpu::BackendType>(optionsBase->backendType));
DAWN_TRY(adapter->Initialize(options)); DAWN_TRY(adapter->InitializeGLFunctions(options->getProc));
DAWN_TRY(adapter->Initialize());
mCreatedAdapter = true; mCreatedAdapter = true;
std::vector<std::unique_ptr<AdapterBase>> adapters; std::vector<std::unique_ptr<AdapterBase>> adapters;

View File

@ -40,9 +40,8 @@ namespace dawn_native { namespace vulkan {
return mBackend; return mBackend;
} }
MaybeError Adapter::Initialize() { MaybeError Adapter::InitializeImpl() {
DAWN_TRY_ASSIGN(mDeviceInfo, GatherDeviceInfo(*this)); DAWN_TRY_ASSIGN(mDeviceInfo, GatherDeviceInfo(*this));
DAWN_TRY(CheckCoreWebGPUSupport());
if (mDeviceInfo.HasExt(DeviceExt::DriverProperties)) { if (mDeviceInfo.HasExt(DeviceExt::DriverProperties)) {
mDriverDescription = mDeviceInfo.driverProperties.driverName; mDriverDescription = mDeviceInfo.driverProperties.driverName;
@ -54,8 +53,6 @@ namespace dawn_native { namespace vulkan {
"Vulkan driver version: " + std::to_string(mDeviceInfo.properties.driverVersion); "Vulkan driver version: " + std::to_string(mDeviceInfo.properties.driverVersion);
} }
InitializeSupportedFeatures();
mPCIInfo.deviceId = mDeviceInfo.properties.deviceID; mPCIInfo.deviceId = mDeviceInfo.properties.deviceID;
mPCIInfo.vendorId = mDeviceInfo.properties.vendorID; mPCIInfo.vendorId = mDeviceInfo.properties.vendorID;
mPCIInfo.name = mDeviceInfo.properties.deviceName; mPCIInfo.name = mDeviceInfo.properties.deviceName;
@ -78,10 +75,7 @@ namespace dawn_native { namespace vulkan {
return {}; return {};
} }
MaybeError Adapter::CheckCoreWebGPUSupport() { MaybeError Adapter::InitializeSupportedFeaturesImpl() {
Limits baseLimits;
GetDefaultLimits(&baseLimits);
// Needed for viewport Y-flip. // Needed for viewport Y-flip.
if (!mDeviceInfo.HasExt(DeviceExt::Maintenance1)) { if (!mDeviceInfo.HasExt(DeviceExt::Maintenance1)) {
return DAWN_INTERNAL_ERROR("Vulkan 1.1 or Vulkan 1.0 with KHR_Maintenance1 required."); return DAWN_INTERNAL_ERROR("Vulkan 1.1 or Vulkan 1.0 with KHR_Maintenance1 required.");
@ -120,152 +114,7 @@ namespace dawn_native { namespace vulkan {
return DAWN_INTERNAL_ERROR("Vulkan sampleRateShading feature required."); return DAWN_INTERNAL_ERROR("Vulkan sampleRateShading feature required.");
} }
// Check base WebGPU limits are supported. // Initialize supported extensions
const VkPhysicalDeviceLimits& limits = mDeviceInfo.properties.limits;
if (limits.maxImageDimension1D < baseLimits.maxTextureDimension1D) {
return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxTextureDimension1D");
}
if (limits.maxImageDimension2D < baseLimits.maxTextureDimension2D ||
limits.maxImageDimensionCube < baseLimits.maxTextureDimension2D ||
limits.maxFramebufferWidth < baseLimits.maxTextureDimension2D ||
limits.maxFramebufferHeight < baseLimits.maxTextureDimension2D ||
limits.maxViewportDimensions[0] < baseLimits.maxTextureDimension2D ||
limits.maxViewportDimensions[1] < baseLimits.maxTextureDimension2D ||
limits.viewportBoundsRange[1] < baseLimits.maxTextureDimension2D) {
return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxTextureDimension2D");
}
if (limits.maxImageDimension3D < baseLimits.maxTextureDimension3D) {
return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxTextureDimension3D");
}
if (limits.maxImageArrayLayers < baseLimits.maxTextureArrayLayers) {
return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxTextureArrayLayers");
}
if (limits.maxBoundDescriptorSets < baseLimits.maxBindGroups) {
return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxBindGroups");
}
if (limits.maxDescriptorSetUniformBuffersDynamic <
baseLimits.maxDynamicUniformBuffersPerPipelineLayout) {
return DAWN_INTERNAL_ERROR(
"Insufficient Vulkan limits for maxDynamicUniformBuffersPerPipelineLayout");
}
if (limits.maxDescriptorSetStorageBuffersDynamic <
baseLimits.maxDynamicStorageBuffersPerPipelineLayout) {
return DAWN_INTERNAL_ERROR(
"Insufficient Vulkan limits for maxDynamicStorageBuffersPerPipelineLayout");
}
if (limits.maxPerStageDescriptorSampledImages <
baseLimits.maxSampledTexturesPerShaderStage) {
return DAWN_INTERNAL_ERROR(
"Insufficient Vulkan limits for maxSampledTexturesPerShaderStage");
}
if (limits.maxPerStageDescriptorSamplers < baseLimits.maxSamplersPerShaderStage) {
return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxSamplersPerShaderStage");
}
if (limits.maxPerStageDescriptorStorageBuffers <
baseLimits.maxStorageBuffersPerShaderStage) {
return DAWN_INTERNAL_ERROR(
"Insufficient Vulkan limits for maxStorageBuffersPerShaderStage");
}
if (limits.maxPerStageDescriptorStorageImages <
baseLimits.maxStorageTexturesPerShaderStage) {
return DAWN_INTERNAL_ERROR(
"Insufficient Vulkan limits for maxStorageTexturesPerShaderStage");
}
if (limits.maxPerStageDescriptorUniformBuffers <
baseLimits.maxUniformBuffersPerShaderStage) {
return DAWN_INTERNAL_ERROR(
"Insufficient Vulkan limits for maxUniformBuffersPerShaderStage");
}
if (limits.maxUniformBufferRange < baseLimits.maxUniformBufferBindingSize) {
return DAWN_INTERNAL_ERROR(
"Insufficient Vulkan limits for maxUniformBufferBindingSize");
}
if (limits.maxStorageBufferRange < baseLimits.maxStorageBufferBindingSize) {
return DAWN_INTERNAL_ERROR(
"Insufficient Vulkan limits for maxStorageBufferBindingSize");
}
if (limits.minUniformBufferOffsetAlignment > baseLimits.minUniformBufferOffsetAlignment) {
return DAWN_INTERNAL_ERROR(
"Insufficient Vulkan limits for minUniformBufferOffsetAlignment");
}
if (limits.minStorageBufferOffsetAlignment > baseLimits.minStorageBufferOffsetAlignment) {
return DAWN_INTERNAL_ERROR(
"Insufficient Vulkan limits for minStorageBufferOffsetAlignment");
}
if (limits.maxVertexInputBindings < baseLimits.maxVertexBuffers) {
return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxVertexBuffers");
}
if (limits.maxVertexInputAttributes < baseLimits.maxVertexAttributes) {
return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxVertexAttributes");
}
if (limits.maxVertexInputBindingStride < baseLimits.maxVertexBufferArrayStride ||
limits.maxVertexInputAttributeOffset < baseLimits.maxVertexBufferArrayStride - 1) {
return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxVertexBufferArrayStride");
}
if (limits.maxVertexOutputComponents < baseLimits.maxInterStageShaderComponents ||
limits.maxFragmentInputComponents < baseLimits.maxInterStageShaderComponents) {
return DAWN_INTERNAL_ERROR(
"Insufficient Vulkan limits for maxInterStageShaderComponents");
}
if (limits.maxComputeSharedMemorySize < baseLimits.maxComputeWorkgroupStorageSize) {
return DAWN_INTERNAL_ERROR(
"Insufficient Vulkan limits for maxComputeWorkgroupStorageSize");
}
if (limits.maxComputeWorkGroupInvocations < baseLimits.maxComputeInvocationsPerWorkgroup) {
return DAWN_INTERNAL_ERROR(
"Insufficient Vulkan limits for maxComputeInvocationsPerWorkgroup");
}
if (limits.maxComputeWorkGroupSize[0] < baseLimits.maxComputeWorkgroupSizeX ||
limits.maxComputeWorkGroupSize[1] < baseLimits.maxComputeWorkgroupSizeY ||
limits.maxComputeWorkGroupSize[2] < baseLimits.maxComputeWorkgroupSizeZ) {
return DAWN_INTERNAL_ERROR(
"Insufficient Vulkan limits for maxComputeWorkgroupSize");
}
if (limits.maxComputeWorkGroupCount[0] < baseLimits.maxComputeWorkgroupsPerDimension ||
limits.maxComputeWorkGroupCount[1] < baseLimits.maxComputeWorkgroupsPerDimension ||
limits.maxComputeWorkGroupCount[2] < baseLimits.maxComputeWorkgroupsPerDimension) {
return DAWN_INTERNAL_ERROR(
"Insufficient Vulkan limits for maxComputeWorkgroupsPerDimension");
}
if (limits.maxColorAttachments < kMaxColorAttachments) {
return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxColorAttachments");
}
if (!IsSubset(VkSampleCountFlags(VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT),
limits.framebufferColorSampleCounts)) {
return DAWN_INTERNAL_ERROR(
"Insufficient Vulkan limits for framebufferColorSampleCounts");
}
if (!IsSubset(VkSampleCountFlags(VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT),
limits.framebufferDepthSampleCounts)) {
return DAWN_INTERNAL_ERROR(
"Insufficient Vulkan limits for framebufferDepthSampleCounts");
}
// Only check maxFragmentCombinedOutputResources on mobile GPUs. Desktop GPUs drivers seem
// to put incorrect values for this limit with things like 8 or 16 when they can do bindless
// storage buffers.
uint32_t vendorId = mDeviceInfo.properties.vendorID;
if (!gpu_info::IsAMD(vendorId) && !gpu_info::IsIntel(vendorId) &&
!gpu_info::IsNvidia(vendorId)) {
if (limits.maxFragmentCombinedOutputResources <
kMaxColorAttachments + baseLimits.maxStorageTexturesPerShaderStage +
baseLimits.maxStorageBuffersPerShaderStage) {
return DAWN_INTERNAL_ERROR(
"Insufficient Vulkan maxFragmentCombinedOutputResources limit");
}
}
return {};
}
bool Adapter::SupportsExternalImages() const {
// Via dawn_native::vulkan::WrapVulkanImage
return external_memory::Service::CheckSupport(mDeviceInfo) &&
external_semaphore::Service::CheckSupport(mDeviceInfo, mPhysicalDevice,
mBackend->GetFunctions());
}
void Adapter::InitializeSupportedFeatures() {
if (mDeviceInfo.features.textureCompressionBC == VK_TRUE) { if (mDeviceInfo.features.textureCompressionBC == VK_TRUE) {
mSupportedFeatures.EnableFeature(Feature::TextureCompressionBC); mSupportedFeatures.EnableFeature(Feature::TextureCompressionBC);
} }
@ -289,6 +138,186 @@ namespace dawn_native { namespace vulkan {
if (mDeviceInfo.properties.limits.timestampComputeAndGraphics == VK_TRUE) { if (mDeviceInfo.properties.limits.timestampComputeAndGraphics == VK_TRUE) {
mSupportedFeatures.EnableFeature(Feature::TimestampQuery); mSupportedFeatures.EnableFeature(Feature::TimestampQuery);
} }
return {};
}
MaybeError Adapter::InitializeSupportedLimitsImpl(CombinedLimits* limits) {
GetDefaultLimits(&limits->v1);
CombinedLimits baseLimits = *limits;
const VkPhysicalDeviceLimits& vkLimits = mDeviceInfo.properties.limits;
#define CHECK_AND_SET_V1_LIMIT_IMPL(vulkanName, webgpuName, compareOp, msgSegment) \
do { \
if (vkLimits.vulkanName compareOp baseLimits.v1.webgpuName) { \
return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for " #webgpuName \
"." \
" VkPhysicalDeviceLimits::" #vulkanName \
" must be at " msgSegment " " + \
std::to_string(baseLimits.v1.webgpuName)); \
} \
limits->v1.webgpuName = vkLimits.vulkanName; \
} while (false)
#define CHECK_AND_SET_V1_MAX_LIMIT(vulkanName, webgpuName) \
CHECK_AND_SET_V1_LIMIT_IMPL(vulkanName, webgpuName, <, "least")
#define CHECK_AND_SET_V1_MIN_LIMIT(vulkanName, webgpuName) \
CHECK_AND_SET_V1_LIMIT_IMPL(vulkanName, webgpuName, >, "most")
CHECK_AND_SET_V1_MAX_LIMIT(maxImageDimension1D, maxTextureDimension1D);
CHECK_AND_SET_V1_MAX_LIMIT(maxImageDimension2D, maxTextureDimension2D);
CHECK_AND_SET_V1_MAX_LIMIT(maxImageDimensionCube, maxTextureDimension2D);
CHECK_AND_SET_V1_MAX_LIMIT(maxFramebufferWidth, maxTextureDimension2D);
CHECK_AND_SET_V1_MAX_LIMIT(maxFramebufferHeight, maxTextureDimension2D);
CHECK_AND_SET_V1_MAX_LIMIT(maxViewportDimensions[0], maxTextureDimension2D);
CHECK_AND_SET_V1_MAX_LIMIT(maxViewportDimensions[1], maxTextureDimension2D);
CHECK_AND_SET_V1_MAX_LIMIT(viewportBoundsRange[1], maxTextureDimension2D);
limits->v1.maxTextureDimension2D = std::min({
static_cast<uint32_t>(vkLimits.maxImageDimension2D),
static_cast<uint32_t>(vkLimits.maxImageDimensionCube),
static_cast<uint32_t>(vkLimits.maxFramebufferWidth),
static_cast<uint32_t>(vkLimits.maxFramebufferHeight),
static_cast<uint32_t>(vkLimits.maxViewportDimensions[0]),
static_cast<uint32_t>(vkLimits.maxViewportDimensions[1]),
static_cast<uint32_t>(vkLimits.viewportBoundsRange[1]),
});
CHECK_AND_SET_V1_MAX_LIMIT(maxImageDimension3D, maxTextureDimension3D);
CHECK_AND_SET_V1_MAX_LIMIT(maxImageArrayLayers, maxTextureArrayLayers);
CHECK_AND_SET_V1_MAX_LIMIT(maxBoundDescriptorSets, maxBindGroups);
CHECK_AND_SET_V1_MAX_LIMIT(maxDescriptorSetUniformBuffersDynamic,
maxDynamicUniformBuffersPerPipelineLayout);
CHECK_AND_SET_V1_MAX_LIMIT(maxDescriptorSetStorageBuffersDynamic,
maxDynamicStorageBuffersPerPipelineLayout);
CHECK_AND_SET_V1_MAX_LIMIT(maxPerStageDescriptorSampledImages,
maxSampledTexturesPerShaderStage);
CHECK_AND_SET_V1_MAX_LIMIT(maxPerStageDescriptorSamplers, maxSamplersPerShaderStage);
CHECK_AND_SET_V1_MAX_LIMIT(maxPerStageDescriptorStorageBuffers,
maxStorageBuffersPerShaderStage);
CHECK_AND_SET_V1_MAX_LIMIT(maxPerStageDescriptorStorageImages,
maxStorageTexturesPerShaderStage);
CHECK_AND_SET_V1_MAX_LIMIT(maxPerStageDescriptorUniformBuffers,
maxUniformBuffersPerShaderStage);
CHECK_AND_SET_V1_MAX_LIMIT(maxUniformBufferRange, maxUniformBufferBindingSize);
CHECK_AND_SET_V1_MAX_LIMIT(maxStorageBufferRange, maxStorageBufferBindingSize);
CHECK_AND_SET_V1_MIN_LIMIT(minUniformBufferOffsetAlignment,
minUniformBufferOffsetAlignment);
CHECK_AND_SET_V1_MIN_LIMIT(minStorageBufferOffsetAlignment,
minStorageBufferOffsetAlignment);
CHECK_AND_SET_V1_MAX_LIMIT(maxVertexInputBindings, maxVertexBuffers);
CHECK_AND_SET_V1_MAX_LIMIT(maxVertexInputAttributes, maxVertexAttributes);
if (vkLimits.maxVertexInputBindingStride < baseLimits.v1.maxVertexBufferArrayStride ||
vkLimits.maxVertexInputAttributeOffset < baseLimits.v1.maxVertexBufferArrayStride - 1) {
return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxVertexBufferArrayStride");
}
limits->v1.maxVertexBufferArrayStride = std::min(
vkLimits.maxVertexInputBindingStride, vkLimits.maxVertexInputAttributeOffset + 1);
if (vkLimits.maxVertexOutputComponents < baseLimits.v1.maxInterStageShaderComponents ||
vkLimits.maxFragmentInputComponents < baseLimits.v1.maxInterStageShaderComponents) {
return DAWN_INTERNAL_ERROR(
"Insufficient Vulkan limits for maxInterStageShaderComponents");
}
limits->v1.maxInterStageShaderComponents =
std::min(vkLimits.maxVertexOutputComponents, vkLimits.maxFragmentInputComponents);
CHECK_AND_SET_V1_MAX_LIMIT(maxComputeSharedMemorySize, maxComputeWorkgroupStorageSize);
CHECK_AND_SET_V1_MAX_LIMIT(maxComputeWorkGroupInvocations,
maxComputeInvocationsPerWorkgroup);
CHECK_AND_SET_V1_MAX_LIMIT(maxComputeWorkGroupSize[0], maxComputeWorkgroupSizeX);
CHECK_AND_SET_V1_MAX_LIMIT(maxComputeWorkGroupSize[1], maxComputeWorkgroupSizeY);
CHECK_AND_SET_V1_MAX_LIMIT(maxComputeWorkGroupSize[2], maxComputeWorkgroupSizeZ);
CHECK_AND_SET_V1_MAX_LIMIT(maxComputeWorkGroupCount[0], maxComputeWorkgroupsPerDimension);
CHECK_AND_SET_V1_MAX_LIMIT(maxComputeWorkGroupCount[1], maxComputeWorkgroupsPerDimension);
CHECK_AND_SET_V1_MAX_LIMIT(maxComputeWorkGroupCount[2], maxComputeWorkgroupsPerDimension);
limits->v1.maxComputeWorkgroupsPerDimension = std::min({
vkLimits.maxComputeWorkGroupCount[0],
vkLimits.maxComputeWorkGroupCount[1],
vkLimits.maxComputeWorkGroupCount[2],
});
if (vkLimits.maxColorAttachments < kMaxColorAttachments) {
return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxColorAttachments");
}
if (!IsSubset(VkSampleCountFlags(VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT),
vkLimits.framebufferColorSampleCounts)) {
return DAWN_INTERNAL_ERROR(
"Insufficient Vulkan limits for framebufferColorSampleCounts");
}
if (!IsSubset(VkSampleCountFlags(VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT),
vkLimits.framebufferDepthSampleCounts)) {
return DAWN_INTERNAL_ERROR(
"Insufficient Vulkan limits for framebufferDepthSampleCounts");
}
// Only check maxFragmentCombinedOutputResources on mobile GPUs. Desktop GPUs drivers seem
// to put incorrect values for this limit with things like 8 or 16 when they can do bindless
// storage buffers.
uint32_t vendorId = mDeviceInfo.properties.vendorID;
if (!gpu_info::IsAMD(vendorId) && !gpu_info::IsIntel(vendorId) &&
!gpu_info::IsNvidia(vendorId)) {
if (vkLimits.maxFragmentCombinedOutputResources <
kMaxColorAttachments + baseLimits.v1.maxStorageTexturesPerShaderStage +
baseLimits.v1.maxStorageBuffersPerShaderStage) {
return DAWN_INTERNAL_ERROR(
"Insufficient Vulkan maxFragmentCombinedOutputResources limit");
}
uint32_t maxFragmentCombinedOutputResources =
kMaxColorAttachments + limits->v1.maxStorageTexturesPerShaderStage +
limits->v1.maxStorageBuffersPerShaderStage;
if (maxFragmentCombinedOutputResources > vkLimits.maxFragmentCombinedOutputResources) {
// WebGPU's maxFragmentCombinedOutputResources exceeds the Vulkan limit.
// Decrease |maxStorageTexturesPerShaderStage| and |maxStorageBuffersPerShaderStage|
// to fit within the Vulkan limit.
uint32_t countOverLimit = maxFragmentCombinedOutputResources -
vkLimits.maxFragmentCombinedOutputResources;
uint32_t maxStorageTexturesOverBase =
limits->v1.maxStorageTexturesPerShaderStage -
baseLimits.v1.maxStorageTexturesPerShaderStage;
uint32_t maxStorageBuffersOverBase = limits->v1.maxStorageBuffersPerShaderStage -
baseLimits.v1.maxStorageBuffersPerShaderStage;
// Reduce the number of resources by half the overage count, but clamp to
// to ensure we don't go below the base limits.
uint32_t numFewerStorageTextures =
std::min(countOverLimit / 2, maxStorageTexturesOverBase);
uint32_t numFewerStorageBuffers =
std::min((countOverLimit + 1) / 2, maxStorageBuffersOverBase);
if (numFewerStorageTextures == maxStorageTexturesOverBase) {
// If |numFewerStorageTextures| was clamped, subtract the remaining
// from the storage buffers.
numFewerStorageBuffers = countOverLimit - numFewerStorageTextures;
ASSERT(numFewerStorageBuffers <= maxStorageBuffersOverBase);
} else if (numFewerStorageBuffers == maxStorageBuffersOverBase) {
// If |numFewerStorageBuffers| was clamped, subtract the remaining
// from the storage textures.
numFewerStorageTextures = countOverLimit - numFewerStorageBuffers;
ASSERT(numFewerStorageTextures <= maxStorageTexturesOverBase);
}
limits->v1.maxStorageTexturesPerShaderStage -= numFewerStorageTextures;
limits->v1.maxStorageBuffersPerShaderStage -= numFewerStorageBuffers;
}
}
return {};
}
bool Adapter::SupportsExternalImages() const {
// Via dawn_native::vulkan::WrapVulkanImage
return external_memory::Service::CheckSupport(mDeviceInfo) &&
external_semaphore::Service::CheckSupport(mDeviceInfo, mPhysicalDevice,
mBackend->GetFunctions());
} }
ResultOrError<DeviceBase*> Adapter::CreateDeviceImpl(const DeviceDescriptor* descriptor) { ResultOrError<DeviceBase*> Adapter::CreateDeviceImpl(const DeviceDescriptor* descriptor) {

View File

@ -36,12 +36,12 @@ namespace dawn_native { namespace vulkan {
VkPhysicalDevice GetPhysicalDevice() const; VkPhysicalDevice GetPhysicalDevice() const;
Backend* GetBackend() const; Backend* GetBackend() const;
MaybeError Initialize();
private: private:
MaybeError InitializeImpl() override;
MaybeError InitializeSupportedFeaturesImpl() override;
MaybeError InitializeSupportedLimitsImpl(CombinedLimits* limits) override;
ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) override; ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) override;
MaybeError CheckCoreWebGPUSupport();
void InitializeSupportedFeatures();
VkPhysicalDevice mPhysicalDevice; VkPhysicalDevice mPhysicalDevice;
Backend* mBackend; Backend* mBackend;