diff --git a/src/common/Constants.h b/src/common/Constants.h index be8668e7bb..998991f574 100644 --- a/src/common/Constants.h +++ b/src/common/Constants.h @@ -25,9 +25,14 @@ static constexpr uint32_t kNumStages = 3; static constexpr uint8_t kMaxColorAttachments = 8u; static constexpr uint32_t kTextureBytesPerRowAlignment = 256u; static constexpr uint32_t kMaxInterStageShaderComponents = 60u; + +// Compute constants static constexpr uint32_t kMaxComputeWorkgroupStorageSize = 16352u; static constexpr uint32_t kMaxComputeWorkgroupInvocations = 256u; static constexpr uint32_t kMaxComputePerDimensionDispatchSize = 65535u; +static constexpr uint32_t kMaxComputeWorkgroupSizeX = 256; +static constexpr uint32_t kMaxComputeWorkgroupSizeY = 256; +static constexpr uint32_t kMaxComputeWorkgroupSizeZ = 64; // Per stage limits static constexpr uint32_t kMaxSampledTexturesPerShaderStage = 16; diff --git a/src/dawn_native/vulkan/AdapterVk.cpp b/src/dawn_native/vulkan/AdapterVk.cpp index a8f936e683..3ad6279401 100644 --- a/src/dawn_native/vulkan/AdapterVk.cpp +++ b/src/dawn_native/vulkan/AdapterVk.cpp @@ -17,6 +17,8 @@ #include "dawn_native/vulkan/BackendVk.h" #include "dawn_native/vulkan/DeviceVk.h" +#include "common/GPUInfo.h" + namespace dawn_native { namespace vulkan { Adapter::Adapter(Backend* backend, VkPhysicalDevice physicalDevice) @@ -108,6 +110,131 @@ namespace dawn_native { namespace vulkan { return DAWN_INTERNAL_ERROR("Vulkan independentBlend feature required."); } + // Check base WebGPU limits are supported. + const VkPhysicalDeviceLimits& limits = mDeviceInfo.properties.limits; + if (limits.maxImageDimension1D < kMaxTextureDimension1D) { + return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxTextureDimension1D"); + } + if (limits.maxImageDimension2D < kMaxTextureDimension2D || + limits.maxImageDimensionCube < kMaxTextureDimension2D || + limits.maxFramebufferWidth < kMaxTextureDimension2D || + limits.maxFramebufferHeight < kMaxTextureDimension2D || + limits.maxViewportDimensions[0] < kMaxTextureDimension2D || + limits.maxViewportDimensions[1] < kMaxTextureDimension2D || + limits.viewportBoundsRange[1] < kMaxTextureDimension2D) { + return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxTextureDimension2D"); + } + if (limits.maxImageDimension3D < kMaxTextureDimension3D) { + return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxTextureDimension3D"); + } + if (limits.maxImageArrayLayers < kMaxTextureArrayLayers) { + return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxTextureArrayLayers"); + } + if (limits.maxBoundDescriptorSets < kMaxBindGroups) { + return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxBindGroups"); + } + if (limits.maxDescriptorSetUniformBuffersDynamic < + kMaxDynamicUniformBuffersPerPipelineLayout) { + return DAWN_INTERNAL_ERROR( + "Insufficient Vulkan limits for maxDynamicUniformBuffersPerPipelineLayout"); + } + if (limits.maxDescriptorSetStorageBuffersDynamic < + kMaxDynamicStorageBuffersPerPipelineLayout) { + return DAWN_INTERNAL_ERROR( + "Insufficient Vulkan limits for maxDynamicStorageBuffersPerPipelineLayout"); + } + if (limits.maxPerStageDescriptorSampledImages < kMaxSampledTexturesPerShaderStage) { + return DAWN_INTERNAL_ERROR( + "Insufficient Vulkan limits for maxDynamicStorageBuffersPerPipelineLayout"); + } + if (limits.maxPerStageDescriptorSampledImages < kMaxSampledTexturesPerShaderStage) { + return DAWN_INTERNAL_ERROR( + "Insufficient Vulkan limits for maxSampledTexturesPerShaderStage"); + } + if (limits.maxPerStageDescriptorSamplers < kMaxSamplersPerShaderStage) { + return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxSamplersPerShaderStage"); + } + if (limits.maxPerStageDescriptorStorageBuffers < kMaxStorageBuffersPerShaderStage) { + return DAWN_INTERNAL_ERROR( + "Insufficient Vulkan limits for maxStorageBuffersPerShaderStage"); + } + if (limits.maxPerStageDescriptorStorageImages < kMaxStorageTexturesPerShaderStage) { + return DAWN_INTERNAL_ERROR( + "Insufficient Vulkan limits for maxStorageTexturesPerShaderStage"); + } + if (limits.maxPerStageDescriptorUniformBuffers < kMaxUniformBuffersPerShaderStage) { + return DAWN_INTERNAL_ERROR( + "Insufficient Vulkan limits for maxUniformBuffersPerShaderStage"); + } + if (limits.maxUniformBufferRange < kMaxUniformBufferBindingSize) { + return DAWN_INTERNAL_ERROR( + "Insufficient Vulkan limits for maxUniformBufferBindingSize"); + } + if (limits.maxStorageBufferRange < kMaxStorageBufferBindingSize) { + return DAWN_INTERNAL_ERROR( + "Insufficient Vulkan limits for maxStorageBufferBindingSize"); + } + if (limits.minUniformBufferOffsetAlignment > kMinUniformBufferOffsetAlignment) { + return DAWN_INTERNAL_ERROR( + "Insufficient Vulkan limits for minUniformBufferOffsetAlignment"); + } + if (limits.minStorageBufferOffsetAlignment > kMinStorageBufferOffsetAlignment) { + return DAWN_INTERNAL_ERROR( + "Insufficient Vulkan limits for minStorageBufferOffsetAlignment"); + } + if (limits.maxVertexInputBindings < kMaxVertexBuffers) { + return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxVertexBuffers"); + } + if (limits.maxVertexInputAttributes < kMaxVertexAttributes) { + return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxVertexAttributes"); + } + if (limits.maxVertexInputBindingStride < kMaxVertexBufferArrayStride || + limits.maxVertexInputAttributeOffset < kMaxVertexBufferArrayStride - 1) { + return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxVertexBufferArrayStride"); + } + if (limits.maxVertexOutputComponents < kMaxInterStageShaderComponents || + limits.maxFragmentInputComponents < kMaxInterStageShaderComponents) { + return DAWN_INTERNAL_ERROR( + "Insufficient Vulkan limits for maxInterStageShaderComponents"); + } + if (limits.maxComputeSharedMemorySize < kMaxComputeWorkgroupStorageSize) { + return DAWN_INTERNAL_ERROR( + "Insufficient Vulkan limits for maxComputeWorkgroupStorageSize"); + } + if (limits.maxComputeWorkGroupInvocations < kMaxComputeWorkgroupInvocations) { + return DAWN_INTERNAL_ERROR( + "Insufficient Vulkan limits for maxComputeWorkgroupInvocations"); + } + if (limits.maxComputeWorkGroupSize[0] < kMaxComputeWorkgroupSizeX || + limits.maxComputeWorkGroupSize[1] < kMaxComputeWorkgroupSizeY || + limits.maxComputeWorkGroupSize[2] < kMaxComputeWorkgroupSizeZ) { + return DAWN_INTERNAL_ERROR( + "Insufficient Vulkan limits for maxComputeWorkgroupSize"); + } + if (limits.maxComputeWorkGroupCount[0] < kMaxComputePerDimensionDispatchSize || + limits.maxComputeWorkGroupCount[1] < kMaxComputePerDimensionDispatchSize || + limits.maxComputeWorkGroupCount[2] < kMaxComputePerDimensionDispatchSize) { + return DAWN_INTERNAL_ERROR( + "Insufficient Vulkan limits for maxComputePerDimensionDispatchSize"); + } + if (limits.maxColorAttachments < kMaxColorAttachments) { + return DAWN_INTERNAL_ERROR("Insufficient Vulkan limits for maxColorAttachments"); + } + + // 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 + + kMaxStorageTexturesPerShaderStage + + kMaxStorageBuffersPerShaderStage) { + return DAWN_INTERNAL_ERROR( + "Insufficient Vulkan maxFragmentCombinedOutputResources limit"); + } + } + return {}; }