| // Copyright 2019 The Dawn & Tint Authors | |
| // | |
| // Redistribution and use in source and binary forms, with or without | |
| // modification, are permitted provided that the following conditions are met: | |
| // | |
| // 1. Redistributions of source code must retain the above copyright notice, this | |
| // list of conditions and the following disclaimer. | |
| // | |
| // 2. Redistributions in binary form must reproduce the above copyright notice, | |
| // this list of conditions and the following disclaimer in the documentation | |
| // and/or other materials provided with the distribution. | |
| // | |
| // 3. Neither the name of the copyright holder nor the names of its | |
| // contributors may be used to endorse or promote products derived from | |
| // this software without specific prior written permission. | |
| // | |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
| // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | |
| // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
| // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| #include "src/dawn/native/d3d12/PhysicalDeviceD3D12.h" | |
| #include <algorithm> | |
| #include <string> | |
| #include <utility> | |
| #include <vector> | |
| #include "dawn/platform/DawnPlatform.h" | |
| #include "src/dawn/common/Constants.h" | |
| #include "src/dawn/common/GPUInfo.h" | |
| #include "src/dawn/common/WindowsUtils.h" | |
| #include "src/dawn/native/ChainUtils.h" | |
| #include "src/dawn/native/Instance.h" | |
| #include "src/dawn/native/d3d/D3DError.h" | |
| #include "src/dawn/native/d3d12/BackendD3D12.h" | |
| #include "src/dawn/native/d3d12/DeviceD3D12.h" | |
| #include "src/dawn/native/d3d12/PlatformFunctionsD3D12.h" | |
| #include "src/dawn/native/d3d12/UtilsD3D12.h" | |
| #include "src/utils/compiler.h" | |
| #include "src/utils/platform.h" | |
| namespace dawn::native::d3d12 { | |
| // The D3D12_MESSAGE_ID_CREATERESOURCE_INVALIDALIGNMENT_SMALLRESOURCE(1380) was introduced | |
| // in SDK 10.0.26100.0. Redefine the message name to allows it to be compiled on both | |
| // SDK 10.0.22621.0 and SDK 10.0.26100.0. | |
| #if D3D12_SDK_VERSION >= 612 | |
| const D3D12_MESSAGE_ID DAWN_MESSAGE_ID_CREATERESOURCE_INVALIDALIGNMENT_SMALLRESOURCE = | |
| D3D12_MESSAGE_ID_CREATERESOURCE_INVALIDALIGNMENT_SMALLRESOURCE; | |
| #else | |
| const D3D12_MESSAGE_ID DAWN_MESSAGE_ID_CREATERESOURCE_INVALIDALIGNMENT_SMALLRESOURCE = | |
| D3D12_MESSAGE_ID(1380); | |
| #endif | |
| PhysicalDevice::PhysicalDevice(Backend* backend, ComPtr<IDXGIAdapter3> hardwareAdapter) | |
| : Base(backend, std::move(hardwareAdapter), wgpu::BackendType::D3D12) {} | |
| PhysicalDevice::~PhysicalDevice() { | |
| CleanUpDebugLayerFilters(); | |
| } | |
| bool PhysicalDevice::SupportsExternalImages() const { | |
| // Via dawn::native::d3d::ExternalImageDXGI::Create | |
| return true; | |
| } | |
| bool PhysicalDevice::SupportsFeatureLevel(wgpu::FeatureLevel, InstanceBase* instance) const { | |
| return true; | |
| } | |
| uint32_t PhysicalDevice::GetAppliedShaderModelUnderToggles(const TogglesState& toggles) const { | |
| uint32_t appliedShaderModel = GetDeviceInfo().highestSupportedShaderModel; | |
| if ((appliedShaderModel >= 66) && | |
| toggles.IsEnabled(Toggle::D3D12DontUseShaderModel66OrHigher)) { | |
| appliedShaderModel = 65; | |
| } | |
| return appliedShaderModel; | |
| } | |
| const D3D12DeviceInfo& PhysicalDevice::GetDeviceInfo() const { | |
| return mDeviceInfo; | |
| } | |
| Backend* PhysicalDevice::GetBackend() const { | |
| return static_cast<Backend*>(Base::GetBackend()); | |
| } | |
| ComPtr<ID3D12Device> PhysicalDevice::GetDevice() const { | |
| return mD3d12Device; | |
| } | |
| MaybeError PhysicalDevice::InitializeImpl() { | |
| DAWN_TRY(Base::InitializeImpl()); | |
| // D3D12 cannot check for feature support without a device. | |
| // Create the device to populate the adapter properties then reuse it when needed for actual | |
| // rendering. | |
| DAWN_TRY_ASSIGN(mD3d12Device, GetBackend()->CreateD3DDevice(GetHardwareAdapter())); | |
| // Check if we should block the use of D3D12 on the current device. | |
| DAWN_TRY(ValidateUseOfD3D12()); | |
| DAWN_TRY(InitializeDebugLayerFilters()); | |
| DAWN_TRY_ASSIGN(mDeviceInfo, GatherDeviceInfo(*this)); | |
| // Base::InitializeImpl() cannot distinguish between discrete and integrated GPUs, so we need to | |
| // overwrite it here. | |
| if (mAdapterType == wgpu::AdapterType::DiscreteGPU && mDeviceInfo.isUMA) { | |
| mAdapterType = wgpu::AdapterType::IntegratedGPU; | |
| } | |
| mSubgroupMinSize = mDeviceInfo.waveLaneCountMin; | |
| mSubgroupMaxSize = mDeviceInfo.waveLaneCountMax; | |
| return {}; | |
| } | |
| bool PhysicalDevice::AreTimestampQueriesSupported() const { | |
| D3D12_COMMAND_QUEUE_DESC queueDesc = {}; | |
| queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; | |
| queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; | |
| ComPtr<ID3D12CommandQueue> d3d12CommandQueue; | |
| HRESULT hr = mD3d12Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&d3d12CommandQueue)); | |
| if (FAILED(hr)) { | |
| return false; | |
| } | |
| // GetTimestampFrequency returns an error HRESULT when there are bugs in Windows container | |
| // and vGPU implementations. | |
| uint64_t timeStampFrequency; | |
| hr = d3d12CommandQueue->GetTimestampFrequency(&timeStampFrequency); | |
| if (FAILED(hr)) { | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool PhysicalDevice::SupportsBufferMapExtendedUsages() const { | |
| return GetDeviceInfo().isUMA && GetDeviceInfo().isCacheCoherentUMA; | |
| } | |
| void PhysicalDevice::InitializeSupportedFeaturesImpl() { | |
| EnableFeature(Feature::TextureCompressionBC); | |
| EnableFeature(Feature::TextureCompressionBCSliced3D); | |
| EnableFeature(Feature::DawnMultiPlanarFormats); | |
| EnableFeature(Feature::Depth32FloatStencil8); | |
| EnableFeature(Feature::IndirectFirstInstance); | |
| EnableFeature(Feature::RG11B10UfloatRenderable); | |
| EnableFeature(Feature::DepthClipControl); | |
| EnableFeature(Feature::Float32Filterable); | |
| EnableFeature(Feature::Float32Blendable); | |
| EnableFeature(Feature::DualSourceBlending); | |
| EnableFeature(Feature::Unorm16TextureFormats); | |
| EnableFeature(Feature::Unorm16Filterable); | |
| EnableFeature(Feature::Unorm16FormatsForExternalTexture); | |
| EnableFeature(Feature::AdapterPropertiesMemoryHeaps); | |
| EnableFeature(Feature::AdapterPropertiesD3D); | |
| EnableFeature(Feature::MultiPlanarRenderTargets); | |
| EnableFeature(Feature::SharedBufferMemoryD3D12Resource); | |
| EnableFeature(Feature::ShaderModuleCompilationOptions); | |
| EnableFeature(Feature::StaticSamplers); | |
| EnableFeature(Feature::MultiDrawIndirect); | |
| EnableFeature(Feature::ClipDistances); | |
| EnableFeature(Feature::FlexibleTextureViews); | |
| EnableFeature(Feature::TextureFormatsTier1); | |
| EnableFeature(Feature::TextureComponentSwizzle); | |
| EnableFeature(Feature::PrimitiveIndex); | |
| EnableFeature(Feature::DawnLoadResolveTexture); | |
| EnableFeature(Feature::DawnPartialLoadResolveTexture); | |
| if (AreTimestampQueriesSupported()) { | |
| EnableFeature(Feature::TimestampQuery); | |
| EnableFeature(Feature::ChromiumExperimentalTimestampQueryInsidePasses); | |
| } | |
| HRESULT hr; | |
| #if defined(DAWN_USE_BUILT_DXC) | |
| // ShaderF16 features require DXC version being 1.4 or higher, shader model supporting 6.2 or | |
| // higher, and native supporting F16 shader ops. | |
| if (mDeviceInfo.highestSupportedShaderModel >= 62 && mDeviceInfo.supportsNative16BitShaderOps) { | |
| EnableFeature(Feature::ShaderF16); | |
| } | |
| // Subgroups feature requires SM >= 6.0 and capabilities flags. | |
| if (mDeviceInfo.supportsWaveOps) { | |
| EnableFeature(Feature::Subgroups); | |
| } | |
| // SubgroupSizeControl feature requires SM >= 6.6 for HLSL attribute `[WaveSize]`. | |
| if (mDeviceInfo.supportsWaveOps && mDeviceInfo.highestSupportedShaderModel >= 66) { | |
| EnableFeature(Feature::SubgroupSizeControl); | |
| } | |
| if (mDeviceInfo.supportsInt64Atomics) { | |
| EnableFeature(Feature::AtomicVec2uMinMax); | |
| } | |
| #ifdef DAWN_USE_AGILITY_SDK | |
| // Note: '70' means SM 6.10 | |
| // TODO(crbug.com/513251803): Don't use shader model as decimal value | |
| if (mDeviceInfo.highestSupportedShaderModel >= 70) { | |
| D3D12_FEATURE_DATA_LINEAR_ALGEBRA_SUPPORT linearAlgebraSupport = {}; | |
| hr = mD3d12Device->CheckFeatureSupport(D3D12_FEATURE_LINEAR_ALGEBRA_SUPPORT, | |
| &linearAlgebraSupport, sizeof(linearAlgebraSupport)); | |
| if (SUCCEEDED(hr) && | |
| linearAlgebraSupport.LinearAlgebraTier >= D3D12_LINEAR_ALGEBRA_TIER_1_0) { | |
| EnableFeature(Feature::ChromiumExperimentalSubgroupMatrix); | |
| } | |
| } | |
| #endif // DAWN_USE_AGILITY_SDK | |
| #endif // DAWN_USE_BUILT_DXC | |
| D3D12_FEATURE_DATA_FORMAT_SUPPORT bgra8unormFormatInfo = {}; | |
| bgra8unormFormatInfo.Format = DXGI_FORMAT_B8G8R8A8_UNORM; | |
| hr = mD3d12Device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &bgra8unormFormatInfo, | |
| sizeof(bgra8unormFormatInfo)); | |
| if (SUCCEEDED(hr) && | |
| (bgra8unormFormatInfo.Support1 & D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW)) { | |
| EnableFeature(Feature::BGRA8UnormStorage); | |
| } | |
| if (GetDeviceInfo().supportsExistingHeap) { | |
| EnableFeature(Feature::HostMappedPointer); | |
| } | |
| EnableFeature(Feature::SharedTextureMemoryDXGISharedHandle); | |
| EnableFeature(Feature::SharedTextureMemoryD3D12Resource); | |
| EnableFeature(Feature::SharedFenceDXGISharedHandle); | |
| if (SupportsBufferMapExtendedUsages()) { | |
| EnableFeature(Feature::BufferMapExtendedUsages); | |
| } | |
| // Temporarily only enable SharedBufferMemoryD3D12SharedMemoryFileMappingHandle on cache | |
| // coherent UMA. | |
| // TODO(386255678): enable SharedBufferMemoryD3D12SharedMemoryFileMappingHandle on other | |
| // architectures. | |
| if (GetDeviceInfo().supportsExistingHeap && SupportsBufferMapExtendedUsages()) { | |
| EnableFeature(Feature::SharedBufferMemoryD3D12SharedMemoryFileMappingHandle); | |
| } | |
| if (GetDeviceInfo().supportsTextureCompressionUnaligned) { | |
| EnableFeature(Feature::TextureCompressionUnaligned); | |
| } | |
| // Only check one format here because of D3D12 "Supported as a Set" mechanism: if any format | |
| // in the set is supported by the device, all formats in the set are supported. | |
| D3D12_FEATURE_DATA_FORMAT_SUPPORT r8unormFormatSupport = {}; | |
| r8unormFormatSupport.Format = DXGI_FORMAT_R8_UNORM; | |
| hr = mD3d12Device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &r8unormFormatSupport, | |
| sizeof(r8unormFormatSupport)); | |
| if (SUCCEEDED(hr) && (r8unormFormatSupport.Support2 & D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD) && | |
| (r8unormFormatSupport.Support2 & D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE)) { | |
| EnableFeature(Feature::TextureFormatsTier2); | |
| } | |
| // Tier 2 hardware supports at least 1 million descriptors in a heap. | |
| // Tier 3 hardware supports essentially the full 32-bit range. | |
| if (GetDeviceInfo().resourceBindingTier >= D3D12_RESOURCE_BINDING_TIER_2) { | |
| EnableFeature(Feature::ChromiumExperimentalSamplingResourceTable); | |
| } | |
| } | |
| MaybeError PhysicalDevice::InitializeSupportedLimitsImpl(CombinedLimits* limits) { | |
| D3D12_FEATURE_DATA_D3D12_OPTIONS featureData = {}; | |
| DAWN_TRY(CheckHRESULT(mD3d12Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, | |
| &featureData, sizeof(featureData)), | |
| "CheckFeatureSupport D3D12_FEATURE_D3D12_OPTIONS")); | |
| // Check if the device is at least D3D_FEATURE_LEVEL_11_1 or D3D_FEATURE_LEVEL_11_0 | |
| const D3D_FEATURE_LEVEL levelsToQuery[]{D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0}; | |
| D3D12_FEATURE_DATA_FEATURE_LEVELS featureLevels; | |
| featureLevels.NumFeatureLevels = sizeof(levelsToQuery) / sizeof(D3D_FEATURE_LEVEL); | |
| featureLevels.pFeatureLevelsRequested = levelsToQuery; | |
| DAWN_TRY(CheckHRESULT(mD3d12Device->CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS, | |
| &featureLevels, sizeof(featureLevels)), | |
| "CheckFeatureSupport D3D12_FEATURE_FEATURE_LEVELS")); | |
| if (featureLevels.MaxSupportedFeatureLevel == D3D_FEATURE_LEVEL_11_0 && | |
| featureData.ResourceBindingTier < D3D12_RESOURCE_BINDING_TIER_2) { | |
| return DAWN_VALIDATION_ERROR( | |
| "At least Resource Binding Tier 2 is required for D3D12 Feature Level 11.0 " | |
| "devices."); | |
| } | |
| GetDefaultLimitsForSupportedFeatureLevel(limits); | |
| // https://docs.microsoft.com/en-us/windows/win32/direct3d12/hardware-feature-levels | |
| // Limits that are the same across D3D feature levels | |
| limits->v1.maxTextureDimension1D = D3D12_REQ_TEXTURE1D_U_DIMENSION; | |
| limits->v1.maxTextureDimension2D = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; | |
| limits->v1.maxTextureDimension3D = D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; | |
| limits->v1.maxTextureArrayLayers = D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; | |
| // Slot values can be 0-15, inclusive: | |
| // https://docs.microsoft.com/en-ca/windows/win32/api/d3d12/ns-d3d12-d3d12_input_element_desc | |
| limits->v1.maxVertexBuffers = 16; | |
| // Both SV_VertexID and SV_InstanceID will consume vertex input slots. | |
| limits->v1.maxVertexAttributes = D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT - 2; | |
| // Note: WebGPU requires FL11.1+ | |
| // https://docs.microsoft.com/en-us/windows/win32/direct3d12/hardware-support | |
| // Resource Binding Tier: 1 2 3 | |
| // Max(CBV+UAV+SRV) 1M 1M 1M+ | |
| // Max CBV per stage 14 14 full | |
| // Max SRV per stage 128 full full | |
| // Max UAV in all stages 64 64 full | |
| // Max Samplers per stage 16 2048 2048 | |
| // https://docs.microsoft.com/en-us/windows-hardware/test/hlk/testref/efad06e8-51d1-40ce-ad5c-573a134b4bb6 | |
| // "full" means the full heap can be used. This is tested | |
| // to work for 1 million descriptors, and 1.1M for tier 3. | |
| uint32_t maxCBVsPerStage; | |
| uint32_t maxSRVsPerStage; | |
| uint32_t maxUAVsAllStages; | |
| uint32_t maxSamplersPerStage; | |
| switch (featureData.ResourceBindingTier) { | |
| case D3D12_RESOURCE_BINDING_TIER_1: | |
| maxCBVsPerStage = 14; | |
| maxSRVsPerStage = 128; | |
| maxUAVsAllStages = 64; | |
| maxSamplersPerStage = 16; | |
| break; | |
| case D3D12_RESOURCE_BINDING_TIER_2: | |
| maxCBVsPerStage = 14; | |
| maxSRVsPerStage = 1'000'000; | |
| maxUAVsAllStages = 64; | |
| maxSamplersPerStage = 2048; | |
| break; | |
| case D3D12_RESOURCE_BINDING_TIER_3: | |
| default: | |
| maxCBVsPerStage = 1'100'000; | |
| maxSRVsPerStage = 1'100'000; | |
| maxUAVsAllStages = 1'100'000; | |
| maxSamplersPerStage = 2048; | |
| break; | |
| } | |
| DAWN_ASSERT(maxUAVsAllStages / 4 > limits->v1.maxStorageTexturesPerShaderStage); | |
| DAWN_ASSERT(maxUAVsAllStages / 4 > limits->v1.maxStorageBuffersPerShaderStage); | |
| uint32_t maxUAVsPerStage = maxUAVsAllStages / 2; | |
| limits->v1.maxUniformBuffersPerShaderStage = maxCBVsPerStage; | |
| // Allocate half of the UAVs to storage buffers, and half to storage textures. | |
| limits->v1.maxStorageTexturesPerShaderStage = maxUAVsPerStage / 2; | |
| limits->v1.maxStorageBuffersPerShaderStage = maxUAVsPerStage - maxUAVsPerStage / 2; | |
| limits->compat.maxStorageTexturesInFragmentStage = limits->v1.maxStorageTexturesPerShaderStage; | |
| limits->compat.maxStorageBuffersInFragmentStage = limits->v1.maxStorageBuffersPerShaderStage; | |
| limits->compat.maxStorageTexturesInVertexStage = limits->v1.maxStorageTexturesPerShaderStage; | |
| limits->compat.maxStorageBuffersInVertexStage = limits->v1.maxStorageBuffersPerShaderStage; | |
| limits->v1.maxSampledTexturesPerShaderStage = maxSRVsPerStage; | |
| limits->v1.maxSamplersPerShaderStage = maxSamplersPerStage; | |
| limits->v1.maxColorAttachments = D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; | |
| // This is maxColorAttachments times 16, the color format with the largest cost. | |
| limits->v1.maxColorAttachmentBytesPerSample = D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT * 16; | |
| // We want to support a minimum of 10 and 8 for these limits (see https://crbug.com/440381283). | |
| limits->v1.maxDynamicUniformBuffersPerPipelineLayout = 10; | |
| limits->v1.maxDynamicStorageBuffersPerPipelineLayout = 8; | |
| limits->v1.maxImmediateSize = kMaxImmediateDataBytes; | |
| // https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/sm5-attributes-numthreads | |
| limits->v1.maxComputeWorkgroupSizeX = D3D12_CS_THREAD_GROUP_MAX_X; | |
| limits->v1.maxComputeWorkgroupSizeY = D3D12_CS_THREAD_GROUP_MAX_Y; | |
| limits->v1.maxComputeWorkgroupSizeZ = D3D12_CS_THREAD_GROUP_MAX_Z; | |
| limits->v1.maxComputeInvocationsPerWorkgroup = D3D12_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP; | |
| // https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ns-d3d12-d3d12_dispatch_arguments | |
| limits->v1.maxComputeWorkgroupsPerDimension = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; | |
| // https://docs.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-devices-downlevel-compute-shaders | |
| // Thread Group Shared Memory is limited to 16Kb on downlevel hardware. This is less than | |
| // the 32Kb that is available to Direct3D 11 hardware. D3D12 is also 32kb. | |
| limits->v1.maxComputeWorkgroupStorageSize = 32768; | |
| // Max number of "constants" where each constant is a 16-byte float4 | |
| limits->v1.maxUniformBufferBindingSize = D3D12_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * 16; | |
| // D3D12 has no documented limit on the buffer size. | |
| limits->v1.maxBufferSize = kAssumedMaxBufferSize; | |
| // 1 for SV_Position and 1 for (SV_IsFrontFace OR SV_SampleIndex). | |
| // See the discussions in https://github.com/gpuweb/gpuweb/issues/1962 for more details. | |
| limits->v1.maxInterStageShaderVariables = D3D12_PS_INPUT_REGISTER_COUNT - 2; | |
| if (mDeviceInfo.supportsExistingHeap) { | |
| // The alignment of host mapped pointer and host mapped buffer size is same as the one of | |
| // D3D12_HEAP_DESC.alignment. | |
| limits->hostMappedPointerLimits.hostMappedPointerAlignment = | |
| D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT; | |
| } | |
| // Using base limits for: | |
| // TODO(crbug.com/dawn/685): | |
| // - maxVertexBufferArrayStride | |
| if (gpu_info::IsQualcommACPI(GetVendorId()) && | |
| gpu_info::GetQualcommACPIGen(GetVendorId(), GetDeviceId()) < | |
| gpu_info::QualcommACPIGen::Adreno8xx) { | |
| // Due to hardware limitation, Raw Buffers can only address 2^28 bytes instead of the | |
| // guaranteed 2^31 bytes. | |
| limits->v1.maxStorageBufferBindingSize = 1 << 28; | |
| } else { | |
| limits->v1.maxStorageBufferBindingSize = kAssumedMaxBufferSize; | |
| } | |
| // Final check that the limits we computed don't exceed the root signature size. The inputs | |
| // to this check should be the same on all devices, so this is basically a static_assert. | |
| { | |
| // https://docs.microsoft.com/en-us/windows/win32/direct3d12/root-signature-limits | |
| // In DWORDS. Descriptor tables cost 1, Root constants cost 1, Root descriptors cost 2. | |
| static constexpr uint32_t kMaxRootSignatureSize = 64u; | |
| // Max of: | |
| // - 2 root constants for the baseVertex/baseInstance constants. | |
| // - 3 root constants for num workgroups X, Y, Z | |
| static constexpr uint32_t kShaderBuiltinSlots = 3; | |
| // Slots not used at all. (This is just for the assert. We could use these slots later.) | |
| static constexpr uint32_t kUnusedSlots = 1; | |
| DAWN_ASSERT( | |
| // bind groups: 1 for CBV+UAV+SRV table + 1 for sampler table | |
| 2 * limits->v1.maxBindGroups + | |
| // dynamic uniform buffers: 2 for root descriptor | |
| 2 * limits->v1.maxDynamicUniformBuffersPerPipelineLayout + | |
| // dynamic storage buffers: 1 for the size constant, 1 for the offset constant | |
| 2 * limits->v1.maxDynamicStorageBuffersPerPipelineLayout + | |
| // immediates: 1 slot per 4 bytes | |
| limits->v1.maxImmediateSize / kImmediateElementByteSize + | |
| // builtins and unused slots | |
| kShaderBuiltinSlots + kUnusedSlots == | |
| kMaxRootSignatureSize); | |
| } | |
| return {}; | |
| } | |
| FeatureValidationResult PhysicalDevice::ValidateFeatureSupportedWithTogglesImpl( | |
| wgpu::FeatureName feature, | |
| const TogglesState& toggles) const { | |
| // Toggle states of adapters and devices can change whether DXC is used and which shader model | |
| // version is applied. Validate features that requires DXC and/or specific shader model | |
| // version here. | |
| if (!toggles.IsEnabled(Toggle::UseDXC)) { | |
| // Disable features that require DXC. Note that required DXC version for each feature is | |
| // checked in InitializeSupportedFeaturesImpl. | |
| switch (feature) { | |
| case wgpu::FeatureName::ShaderF16: | |
| case wgpu::FeatureName::Subgroups: | |
| case wgpu::FeatureName::SubgroupSizeControl: | |
| case wgpu::FeatureName::ChromiumExperimentalSamplingResourceTable: | |
| case wgpu::FeatureName::AtomicVec2uMinMax: | |
| return FeatureValidationResult( | |
| absl::StrFormat("Feature %s requires DXC for D3D12.", feature)); | |
| default: | |
| break; | |
| } | |
| } | |
| // Validate applied shader version. | |
| switch (feature) { | |
| // The feature `shader-f16` requires using shader model 6.2 or higher. | |
| // Note: DXC is enabled for this feature at this point in the code. | |
| case wgpu::FeatureName::ShaderF16: { | |
| if (!(GetAppliedShaderModelUnderToggles(toggles) >= 62)) { | |
| return FeatureValidationResult(absl::StrFormat( | |
| "Feature %s requires shader model 6.2 or higher for D3D12.", feature)); | |
| } | |
| break; | |
| } | |
| case wgpu::FeatureName::AtomicVec2uMinMax: { | |
| if (!(GetAppliedShaderModelUnderToggles(toggles) >= 66)) { | |
| return FeatureValidationResult(absl::StrFormat( | |
| "Feature %s requires shader model 6.6 or higher for D3D12.", feature)); | |
| } | |
| break; | |
| } | |
| // The function subgroupBroadcast(f16) fails for some edge cases on Intel Gen-9 devices. | |
| // See crbug.com/391680973. We disable subgroups on this device unless the user has | |
| // explicitly enabled the 'enable_subgroups_intel_gen9' toggle. | |
| // Note: DXC is enabled for this feature at this point in the code. | |
| case wgpu::FeatureName::Subgroups: | |
| if (gpu_info::IsIntelGen9(GetVendorId(), GetDeviceId()) && | |
| !toggles.IsEnabled(Toggle::EnableSubgroupsIntelGen9)) { | |
| return FeatureValidationResult( | |
| absl::StrFormat("Intel Gen-9 devices require " | |
| "`enable_subgroups_intel_gen9` to enable %s.", | |
| feature)); | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| return {}; | |
| } | |
| MaybeError PhysicalDevice::InitializeDebugLayerFilters() { | |
| // If the debug layer is not installed, return immediately. | |
| ComPtr<ID3D12InfoQueue> infoQueue; | |
| if (FAILED(mD3d12Device.As(&infoQueue))) { | |
| return {}; | |
| } | |
| D3D12_MESSAGE_ID denyIds[] = { | |
| // | |
| // Permanent IDs: list of warnings that are not applicable | |
| // | |
| // Resource sub-allocation partially maps pre-allocated heaps. This means the | |
| // entire physical addresses space may have no resources or have many resources | |
| // assigned the same heap. | |
| D3D12_MESSAGE_ID_HEAP_ADDRESS_RANGE_HAS_NO_RESOURCE, | |
| D3D12_MESSAGE_ID_HEAP_ADDRESS_RANGE_INTERSECTS_MULTIPLE_BUFFERS, | |
| // The debug layer validates pipeline objects when they are created. Dawn validates | |
| // them when them when they are set. Therefore, since the issue is caught at a later | |
| // time, we can silence this warnings. | |
| D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_RENDERTARGETVIEW_NOT_SET, | |
| // Adding a clear color during resource creation would require heuristics or delayed | |
| // creation. | |
| // https://crbug.com/dawn/418 | |
| D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE, | |
| D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_MISMATCHINGCLEARVALUE, | |
| // Dawn enforces proper Unmaps at a later time. | |
| // https://crbug.com/dawn/422 | |
| D3D12_MESSAGE_ID_EXECUTECOMMANDLISTS_GPU_WRITTEN_READBACK_RESOURCE_MAPPED, | |
| // WebGPU allows empty scissors without empty viewports. | |
| D3D12_MESSAGE_ID_DRAW_EMPTY_SCISSOR_RECTANGLE, | |
| // Backend textures can be reused across different frontend textures, | |
| // which can result in changes to the label of the backend texture if | |
| // the user has assigned distinct labels to the different frontend textures. | |
| D3D12_MESSAGE_ID_SETPRIVATEDATA_CHANGINGPARAMS, | |
| // | |
| // Temporary IDs: list of warnings that should be fixed or promoted | |
| // | |
| // For small placed resource alignment, we first request the small alignment, which may | |
| // get rejected and generate a debug error. Then, we request 0 to get the allowed | |
| // allowed alignment. | |
| D3D12_MESSAGE_ID_CREATERESOURCE_INVALIDALIGNMENT, | |
| // This message id is added for invalid small resource alignment. | |
| DAWN_MESSAGE_ID_CREATERESOURCE_INVALIDALIGNMENT_SMALLRESOURCE, | |
| // WebGPU allows OOB vertex buffer access and relies on D3D12's robust buffer access | |
| // behavior. | |
| D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_VERTEX_BUFFER_TOO_SMALL, | |
| // WebGPU allows setVertexBuffer with offset that equals to the whole vertex buffer | |
| // size. | |
| // Even this means that no vertex buffer view has been set in D3D12 backend. | |
| // https://crbug.com/dawn/1255 | |
| D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_VERTEX_BUFFER_NOT_SET, | |
| // When using f16 in vertex attributes the debug layer may report float16_t as type | |
| // `unknown`, resulting in a CREATEINPUTLAYOUT_TYPE_MISMATCH warning. | |
| // https://crbug.com/tint/1473 | |
| D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_TYPE_MISMATCH, | |
| }; | |
| // Create a retrieval filter with a deny list to suppress messages. | |
| // Any messages remaining will be converted to Dawn errors. | |
| D3D12_INFO_QUEUE_FILTER filter{}; | |
| // Filter out info/message and only create errors from warnings or worse. | |
| D3D12_MESSAGE_SEVERITY severities[] = { | |
| D3D12_MESSAGE_SEVERITY_INFO, | |
| D3D12_MESSAGE_SEVERITY_MESSAGE, | |
| }; | |
| filter.DenyList.NumSeverities = ARRAYSIZE(severities); | |
| filter.DenyList.pSeverityList = severities; | |
| filter.DenyList.NumIDs = ARRAYSIZE(denyIds); | |
| filter.DenyList.pIDList = denyIds; | |
| // To avoid flooding the console, a storage-filter is also used to | |
| // prevent messages from getting logged. | |
| DAWN_TRY( | |
| CheckHRESULT(infoQueue->PushStorageFilter(&filter), "ID3D12InfoQueue::PushStorageFilter")); | |
| DAWN_TRY(CheckHRESULT(infoQueue->PushRetrievalFilter(&filter), | |
| "ID3D12InfoQueue::PushRetrievalFilter")); | |
| return {}; | |
| } | |
| void PhysicalDevice::CleanUpDebugLayerFilters() { | |
| // The device may not exist if this adapter failed to initialize. | |
| if (mD3d12Device == nullptr) { | |
| return; | |
| } | |
| // If the debug layer is not installed, return immediately to avoid crashing the process. | |
| ComPtr<ID3D12InfoQueue> infoQueue; | |
| if (FAILED(mD3d12Device.As(&infoQueue))) { | |
| return; | |
| } | |
| infoQueue->PopRetrievalFilter(); | |
| infoQueue->PopStorageFilter(); | |
| } | |
| void PhysicalDevice::SetupBackendAdapterToggles(dawn::platform::Platform* platform, | |
| TogglesState* adapterToggles) const { | |
| // We don't check if the compiler libraries is available here. Compiler libraries are checked | |
| // and loaded according to device's UseDXC toggle during device creation, and the creation would | |
| // just fail if required compiler is not available. This is to avoid expensive loading of DLLs | |
| // that we will not use immediately (or at all). | |
| #ifdef DAWN_USE_BUILT_DXC | |
| if (GetDeviceInfo().highestSupportedShaderModel < 60) { | |
| // If shader model < 6.0, though, we must use FXC. | |
| adapterToggles->ForceSet(Toggle::UseDXC, false); | |
| } | |
| const bool useDxc = platform->IsFeatureEnabled(dawn::platform::Features::kWebGPUUseDXC); | |
| adapterToggles->Default(Toggle::UseDXC, useDxc); | |
| #else | |
| adapterToggles->ForceSet(Toggle::UseDXC, false); | |
| adapterToggles->Default(Toggle::UseDXC, false); | |
| #endif | |
| const uint32_t deviceId = GetDeviceId(); | |
| const uint32_t vendorId = GetVendorId(); | |
| // On Intel Gen12 D3D driver < 32.0.101.5762, using shader model 6.6 will cause unexpected | |
| // result when adding/subtracting I32/U32 vector/scalar with vector/scalar in constant | |
| // initialized array. See https://crbug.com/tint/2189 and https://crbug.com/dawn/2470 for more | |
| // information. | |
| if (gpu_info::IsIntelGen12HP(vendorId, deviceId) || | |
| gpu_info::IsIntelGen12LP(vendorId, deviceId)) { | |
| const gpu_info::IntelWindowsDriverVersion kFixedDriverVersion = {32, 0, 101, 5762}; | |
| if (gpu_info::IntelWindowsDriverVersion(GetDriverVersion()) < kFixedDriverVersion) { | |
| adapterToggles->Default(Toggle::D3D12DontUseShaderModel66OrHigher, true); | |
| } | |
| } | |
| // Workaround for textureDimensions() produces incorrect results with shader model 6.6 on Intel | |
| // D3D driver > 27.20.100.8935 and < 27.20.100.9684 on Intel Gen9 and Gen9.5 GPUs. | |
| // See https://crbug.com/dawn/2448 for more information. | |
| if (gpu_info::IsIntelGen9(vendorId, deviceId)) { | |
| gpu_info::IntelWindowsDriverVersion intelDriverVersion(GetDriverVersion()); | |
| if (intelDriverVersion > gpu_info::IntelWindowsDriverVersion({27, 20, 100, 8935}) && | |
| intelDriverVersion < gpu_info::IntelWindowsDriverVersion({27, 20, 100, 9684})) { | |
| adapterToggles->ForceSet(Toggle::D3D12DontUseShaderModel66OrHigher, true); | |
| } | |
| } | |
| // On Intel Gen11 D3D12 GPUs using shader model 6.6 causes many unexpected issues. | |
| // See https://crbug.com/374606634 for more information. | |
| if (gpu_info::IsIntelGen11(vendorId, deviceId)) { | |
| adapterToggles->ForceSet(Toggle::D3D12DontUseShaderModel66OrHigher, true); | |
| } | |
| // On Intel Gen12LP fragment shader is possible to run with wave lane count of 8 | |
| // while driver reporting WaveLaneCountMin being 16. | |
| if (gpu_info::IsIntelGen12LP(vendorId, deviceId)) { | |
| adapterToggles->Default(Toggle::D3D12RelaxMinSubgroupSizeTo8, true); | |
| } | |
| } | |
| void PhysicalDevice::SetupBackendDeviceToggles(dawn::platform::Platform* platform, | |
| TogglesState* deviceToggles) const { | |
| #ifdef DAWN_USE_BUILT_DXC | |
| const bool dxcAvailable = true; | |
| #else | |
| const bool dxcAvailable = false; | |
| #endif | |
| const bool useResourceHeapTier2 = (GetDeviceInfo().resourceHeapTier >= 2); | |
| deviceToggles->Default(Toggle::UseD3D12ResourceHeapTier2, useResourceHeapTier2); | |
| deviceToggles->Default(Toggle::UseD3D12RenderPass, GetDeviceInfo().supportsRenderPass); | |
| deviceToggles->Default(Toggle::UseD3D12ResidencyManagement, true); | |
| deviceToggles->Default(Toggle::D3D12AlwaysUseTypelessFormatsForCastableTexture, | |
| !GetDeviceInfo().supportsCastingFullyTypedFormat); | |
| deviceToggles->Default(Toggle::ApplyClearBigIntegerColorValueWithDraw, true); | |
| // The restriction on the source box specifying a portion of the depth stencil texture in | |
| // CopyTextureRegion() is only available on the D3D12 platforms which doesn't support | |
| // programmable sample positions. | |
| deviceToggles->Default( | |
| Toggle::D3D12UseTempBufferInDepthStencilTextureAndBufferCopyWithNonZeroBufferOffset, | |
| GetDeviceInfo().programmableSamplePositionsTier == 0); | |
| // Disable optimizations when using FXC | |
| // See https://crbug.com/dawn/1203 | |
| deviceToggles->Default(Toggle::FxcOptimizations, false); | |
| // By default use the maximum shader-visible heap size allowed. | |
| deviceToggles->Default(Toggle::UseD3D12SmallShaderVisibleHeapForTesting, false); | |
| // By default use D3D12 Root Signature Version 1.1 when possible, otherwise we should force | |
| // disable this toggle. | |
| // Additionally, DESCRIPTORS_STATIC_KEEPING_BUFFER_BOUNDS_CHECKS was only added in the | |
| // Windows 10 2018 Spring Creator's Update. Force disable the toggle if we do not have | |
| // at least WWDM 2.4. | |
| // https://microsoft.github.io/DirectX-Specs/d3d/ResourceBinding.html#flags-added-in-root-signature-version-11 | |
| if (!GetDeviceInfo().supportsRootSignatureVersion1_1 || GetDriverVersion()[0] < 24) { | |
| deviceToggles->ForceSet(Toggle::D3D12UseRootSignatureVersion1_1, false); | |
| } else { | |
| deviceToggles->Default(Toggle::D3D12UseRootSignatureVersion1_1, | |
| GetDeviceInfo().supportsRootSignatureVersion1_1); | |
| } | |
| // By default create MSAA textures with 64KB (D3D12_SMALL_MSAA_RESOURCE_PLACEMENT_ALIGNMENT) | |
| // alignment when possible, otherwise we should never enable this toggle. | |
| if (!GetDeviceInfo().use64KBAlignedMSAATexture) { | |
| deviceToggles->ForceSet(Toggle::D3D12Use64KBAlignedMSAATexture, false); | |
| } | |
| deviceToggles->Default(Toggle::D3D12Use64KBAlignedMSAATexture, | |
| GetDeviceInfo().use64KBAlignedMSAATexture); | |
| // By default use D3D12_HEAP_FLAG_CREATE_NOT_ZEROED when possible, otherwise we should never | |
| // enable this toggle. | |
| if (!GetDeviceInfo().supportsHeapFlagCreateNotZeroed) { | |
| deviceToggles->ForceSet(Toggle::D3D12CreateNotZeroedHeap, false); | |
| } | |
| deviceToggles->Default(Toggle::D3D12CreateNotZeroedHeap, | |
| GetDeviceInfo().supportsHeapFlagCreateNotZeroed); | |
| // By default allow relaxed row pitch and offset in buffer-texture copies when possible, | |
| // otherwise we should never enable this toggle. | |
| if (!GetDeviceInfo().supportsUnrestrictedBufferTextureCopyPitch) { | |
| deviceToggles->ForceSet(Toggle::D3D12RelaxBufferTextureCopyPitchAndOffsetAlignment, false); | |
| } | |
| deviceToggles->Default(Toggle::D3D12RelaxBufferTextureCopyPitchAndOffsetAlignment, | |
| GetDeviceInfo().supportsUnrestrictedBufferTextureCopyPitch); | |
| // Native support of packed 4x8 integer dot product required shader model 6.4 or higher, and | |
| // DXC 1.4 or higher. | |
| if (!(GetAppliedShaderModelUnderToggles(*deviceToggles) >= 64) || | |
| !deviceToggles->IsEnabled(Toggle::UseDXC) || !dxcAvailable) { | |
| deviceToggles->ForceSet(Toggle::PolyFillPacked4x8DotProduct, true); | |
| } | |
| // Native support of pack/unpack 4x8 intrinsics required shader model 6.6 or higher, and | |
| // DXC 1.4 or higher. | |
| if (!(GetAppliedShaderModelUnderToggles(*deviceToggles) >= 66) || | |
| !deviceToggles->IsEnabled(Toggle::UseDXC) || !dxcAvailable) { | |
| deviceToggles->ForceSet(Toggle::D3D12PolyFillPackUnpack4x8, true); | |
| } | |
| uint32_t deviceId = GetDeviceId(); | |
| uint32_t vendorId = GetVendorId(); | |
| // Currently this workaround is only needed on Intel Gen12, Xe, Xe2 and Xe3 GPUs. | |
| // See http://crbug.com/341991439 for more information. | |
| if (gpu_info::IsIntelGen12LP(vendorId, deviceId) || | |
| gpu_info::IsIntelGen12HP(vendorId, deviceId) || | |
| gpu_info::IsIntelXeLPG(vendorId, deviceId) || gpu_info::IsIntelXe2LPG(vendorId, deviceId) || | |
| gpu_info::IsIntelXe2HPG(vendorId, deviceId) || | |
| gpu_info::IsIntelXe3LPG(vendorId, deviceId)) { | |
| deviceToggles->Default(Toggle::D3D12DecomposeWorkgroupAccess, true); | |
| } | |
| // Currently this workaround is only needed on Intel Gen9, Gen9.5 and Gen11 GPUs. | |
| // See http://crbug.com/1161355 for more information. | |
| if (gpu_info::IsIntelGen9(vendorId, deviceId) || gpu_info::IsIntelGen11(vendorId, deviceId)) { | |
| const gpu_info::IntelWindowsDriverVersion kFixedDriverVersion = {31, 0, 101, 2114}; | |
| if (gpu_info::IntelWindowsDriverVersion(GetDriverVersion()) < kFixedDriverVersion) { | |
| deviceToggles->Default( | |
| Toggle::UseTempBufferInSmallFormatTextureToTextureCopyFromGreaterToLessMipLevel, | |
| true); | |
| } | |
| } | |
| // Currently this workaround is only needed on Intel Gen9, Gen9.5, Gen12 and Xe GPUs. | |
| // See http://crbug.com/dawn/1487 for more information. | |
| if (gpu_info::IsIntelGen9(vendorId, deviceId) || gpu_info::IsIntelGen12LP(vendorId, deviceId) || | |
| gpu_info::IsIntelGen12HP(vendorId, deviceId) || | |
| gpu_info::IsIntelXeLPG(vendorId, deviceId)) { | |
| deviceToggles->Default(Toggle::D3D12ForceClearCopyableDepthStencilTextureOnCreation, true); | |
| } | |
| // Currently this workaround is only needed on Intel Gen12 and Xe GPUs. | |
| // See http://crbug.com/dawn/1487 for more information. | |
| if (gpu_info::IsIntelGen12LP(vendorId, deviceId) || | |
| gpu_info::IsIntelGen12HP(vendorId, deviceId) || | |
| gpu_info::IsIntelXeLPG(vendorId, deviceId)) { | |
| deviceToggles->Default(Toggle::D3D12DontSetClearValueOnDepthTextureCreation, true); | |
| } | |
| // This workaround is only needed on Intel Gen12LP with driver prior to 30.0.101.1692. | |
| // See http://crbug.com/dawn/949 for more information. | |
| if (gpu_info::IsIntelGen12LP(vendorId, deviceId)) { | |
| const gpu_info::IntelWindowsDriverVersion kFixedDriverVersion = {30, 0, 101, 1692}; | |
| if (gpu_info::IntelWindowsDriverVersion(GetDriverVersion()) < kFixedDriverVersion) { | |
| deviceToggles->Default(Toggle::D3D12AllocateExtraMemoryFor2DArrayColorTexture, true); | |
| } | |
| } | |
| // This workaround is needed on Intel Gen9 GPUs with driver >= 31.0.101.2121 and Gen12LP GPUs | |
| // with driver >= 31.0.101.4091. See http://crbug.com/dawn/1083 for more information. | |
| bool useBlitForT2T = false; | |
| if (gpu_info::IsIntelGen9(vendorId, deviceId)) { | |
| const gpu_info::IntelWindowsDriverVersion kFirstBuggyDriverVersion = {31, 0, 101, 2121}; | |
| useBlitForT2T = | |
| gpu_info::IntelWindowsDriverVersion(GetDriverVersion()) >= kFirstBuggyDriverVersion; | |
| } else if (gpu_info::IsIntelGen12LP(vendorId, deviceId)) { | |
| const gpu_info::IntelWindowsDriverVersion kFirstBuggyDriverVersion = {31, 0, 101, 4091}; | |
| useBlitForT2T = | |
| gpu_info::IntelWindowsDriverVersion(GetDriverVersion()) >= kFirstBuggyDriverVersion; | |
| } | |
| if (useBlitForT2T) { | |
| deviceToggles->Default(Toggle::UseBlitForDepthTextureToTextureCopyToNonzeroSubresource, | |
| true); | |
| } | |
| // D3D driver has a bug resolving overlapping queries to a same buffer on Intel Gen12 GPUs. This | |
| // workaround is needed on the driver version >= 30.0.101.3413. | |
| // TODO(crbug.com/dawn/1546): Remove the workaround when the bug is fixed in D3D driver. | |
| if (gpu_info::IsIntelGen12LP(vendorId, deviceId) || | |
| gpu_info::IsIntelGen12HP(vendorId, deviceId)) { | |
| const gpu_info::IntelWindowsDriverVersion kFirstBuggyDriverVersion = {30, 0, 101, 3413}; | |
| if (gpu_info::IntelWindowsDriverVersion(GetDriverVersion()) >= kFirstBuggyDriverVersion) { | |
| deviceToggles->Default(Toggle::ClearBufferBeforeResolveQueries, true); | |
| } | |
| } | |
| // B2T copy failed with stencil8 format on Intel ACM/MTL/ARL GPUs. See | |
| // https://issues.chromium.org/issues/368085621 for more information. | |
| if (gpu_info::IsIntelGen12HP(vendorId, deviceId) || | |
| gpu_info::IsIntelXeLPG(vendorId, deviceId)) { | |
| deviceToggles->Default(Toggle::UseBlitForBufferToStencilTextureCopy, true); | |
| } | |
| // Workaround for the depth-stencil texture fails to be cleared if the clear value is specified | |
| // in the D3D12_RENDER_PASS_BEGINNING_ACCESS structure of BeginRenderPass on Intel ACM and ARL. | |
| // This workaround is needed on the driver version < 32.0.101.8247. | |
| // See https://issues.chromium.org/issues/430338408. | |
| if (gpu_info::IsIntelGen12HP(vendorId, deviceId) || | |
| gpu_info::IsIntelXeLPG(vendorId, deviceId)) { | |
| const gpu_info::IntelWindowsDriverVersion kFixedDriverVersion = {32, 0, 101, 8247}; | |
| if (gpu_info::IntelWindowsDriverVersion(GetDriverVersion()) < kFixedDriverVersion) { | |
| deviceToggles->ForceSet(Toggle::UseD3D12RenderPass, false); | |
| } | |
| } | |
| // Currently these workarounds are needed on Intel Gen9.5 and Gen11 GPUs, as well as | |
| // AMD GPUS. | |
| // See http://crbug.com/1237175, http://crbug.com/dawn/1628, and http://crbug.com/dawn/2032 | |
| // for more information. | |
| if ((gpu_info::IsIntelGen9(vendorId, deviceId) && !gpu_info::IsSkylake(deviceId)) || | |
| gpu_info::IsIntelGen11(vendorId, deviceId) || gpu_info::IsAMD(vendorId)) { | |
| deviceToggles->Default( | |
| Toggle::DisableSubAllocationFor2DTextureWithCopyDstOrRenderAttachment, true); | |
| // Now we don't need to force clearing depth stencil textures with CopyDst as all the depth | |
| // stencil textures (can only be 2D textures) will be created with CreateCommittedResource() | |
| // instead of CreatePlacedResource(). | |
| deviceToggles->Default(Toggle::D3D12ForceClearCopyableDepthStencilTextureOnCreation, false); | |
| } | |
| // Collapse redundant subgroup min and max operations to workaround a driver crash on older AMD | |
| // GPUs. Should only affect AMD Windows Driver versions < 31.0.22000.0, but because this is a | |
| // harmless "optimizing" workaround go ahead enable for all versions. See: | |
| // https://crbug.com/508265321. | |
| if (gpu_info::IsAMD(vendorId)) { | |
| deviceToggles->Default(Toggle::CollapseSubgroupMinMax, true); | |
| } | |
| // Currently this toggle is only needed on Intel Gen9 and Gen9.5 GPUs. | |
| // See http://crbug.com/dawn/1579 for more information. | |
| if (gpu_info::IsIntelGen9(vendorId, deviceId)) { | |
| const gpu_info::IntelWindowsDriverVersion kFixedDriverVersion = {31, 0, 101, 2121}; | |
| if (gpu_info::IntelWindowsDriverVersion(GetDriverVersion()) < kFixedDriverVersion) { | |
| // We can add workaround when the blending operation is "Add", DstFactor is "Zero" and | |
| // SrcFactor is "DstAlpha". | |
| deviceToggles->ForceSet( | |
| Toggle::D3D12ReplaceAddWithMinusWhenDstFactorIsZeroAndSrcFactorIsDstAlpha, true); | |
| // Unfortunately we cannot add workaround for other cases. | |
| deviceToggles->ForceSet( | |
| Toggle::NoWorkaroundDstAlphaAsSrcBlendFactorForBothColorAndAlphaDoesNotWork, true); | |
| } | |
| } | |
| // Currently these workarounds are only needed on Intel Gen9 and Gen11 GPUs. | |
| // See http://crbug.com/dawn/484 for more information. | |
| if (gpu_info::IsIntelGen9(vendorId, deviceId) || gpu_info::IsIntelGen11(vendorId, deviceId)) { | |
| deviceToggles->Default(Toggle::D3D12DontUseNotZeroedHeapFlagOnTexturesAsCommitedResources, | |
| true); | |
| } | |
| if (!mDeviceInfo.supportsTextureCopyBetweenDimensions) { | |
| deviceToggles->ForceSet( | |
| Toggle::D3D12UseTempBufferInTextureToTextureCopyBetweenDifferentDimensions, true); | |
| } | |
| // Polyfill reflect builtin for vec2<f32> on Intel device if using FXC. | |
| // See https://crbug.com/tint/1798 for more information. | |
| if (gpu_info::IsIntel(vendorId) && !deviceToggles->IsEnabled(Toggle::UseDXC)) { | |
| deviceToggles->Default(Toggle::D3D12PolyfillReflectVec2F32, true); | |
| } | |
| // Currently this workaround is needed on old Intel drivers and newer version of Windows 11. | |
| // See http://crbug.com/dawn/2308 for more information. | |
| if (gpu_info::IsIntel(vendorId)) { | |
| constexpr uint64_t kAffectedMinimumWindowsBuildNumber = 25957u; | |
| const gpu_info::IntelWindowsDriverVersion kAffectedMaximumDriverVersion = {27, 20, 100, | |
| 9664}; | |
| if (GetBackend()->GetFunctions()->GetWindowsBuildNumber() >= | |
| kAffectedMinimumWindowsBuildNumber && | |
| gpu_info::IntelWindowsDriverVersion(GetDriverVersion()) <= | |
| kAffectedMaximumDriverVersion) { | |
| deviceToggles->Default(Toggle::DisableResourceSuballocation, true); | |
| } | |
| } | |
| if (gpu_info::IsNvidia(vendorId)) { | |
| deviceToggles->Default(Toggle::D3D12ForceStencilComponentReplicateSwizzle, true); | |
| deviceToggles->Default(Toggle::D3D12ExpandShaderResourceStateTransitionsToCopySource, true); | |
| } | |
| // Use packed DXGI_FORMAT_D24_UNORM_S8_UINT format on Qualcomm devices to workaround texture | |
| // loading/sampling issues for depth24plus-stencil8 texture. Note that Qualcomm D3D12 drivers | |
| // only report ACPI ids. | |
| // See https://crbug.com/411268750 for more information. | |
| if (gpu_info::IsQualcommACPI(vendorId)) { | |
| deviceToggles->Default(Toggle::UsePackedDepth24UnormStencil8Format, true); | |
| } | |
| // Enable the integer range analysis for shader robustness by default if the corresponding | |
| // platform feature is enabled. | |
| deviceToggles->Default( | |
| Toggle::EnableIntegerRangeAnalysisInRobustness, | |
| platform->IsFeatureEnabled(platform::Features::kWebGPUEnableRangeAnalysisForRobustness)); | |
| // Enable the use of HLSL 2021 if the corresponding platform feature is enabled. | |
| deviceToggles->Default(Toggle::D3D12UseHLSL2021, | |
| platform->IsFeatureEnabled(platform::Features::kWebGPUUseHLSL2021)); | |
| } | |
| MaybeError PhysicalDevice::ValidateUseOfD3D12() const { | |
| uint32_t deviceId = GetDeviceId(); | |
| uint32_t vendorId = GetVendorId(); | |
| // D3D12 is no longer allowed on 4th Generation Intel Processor Graphics. | |
| // https://www.intel.com/content/www/us/en/support/articles/000057520/graphics.html | |
| if (gpu_info::IsIntelGen7(vendorId, deviceId)) { | |
| return DAWN_VALIDATION_ERROR("D3D12 backend is not allowed on Intel gen-7 GPUs."); | |
| } | |
| return {}; | |
| } | |
| ResultOrError<Ref<DeviceBase>> PhysicalDevice::CreateDeviceImpl( | |
| AdapterBase* adapter, | |
| const UnpackedPtr<DeviceDescriptor>& descriptor, | |
| const TogglesState& deviceToggles, | |
| Ref<DeviceBase::DeviceLostEvent>&& lostEvent) { | |
| return Device::Create(adapter, descriptor, deviceToggles, std::move(lostEvent)); | |
| } | |
| // Resets the backend device and creates a new one. If any D3D12 objects belonging to the | |
| // current ID3D12Device have not been destroyed, a non-zero value will be returned upon Reset() | |
| // and the subsequent call to CreateDevice will return a handle the existing device instead of | |
| // creating a new one. | |
| MaybeError PhysicalDevice::ResetInternalDeviceForTestingImpl() { | |
| [[maybe_unused]] auto refCount = mD3d12Device.Reset(); | |
| DAWN_ASSERT(refCount == 0); | |
| DAWN_TRY(Initialize()); | |
| return {}; | |
| } | |
| void PhysicalDevice::PopulateBackendProperties(UnpackedPtr<AdapterInfo>& info, | |
| const TogglesState& toggles) const { | |
| if (auto* memoryHeapProperties = info.Get<AdapterPropertiesMemoryHeaps>()) { | |
| // https://microsoft.github.io/DirectX-Specs/d3d/D3D12GPUUploadHeaps.html describes | |
| // the properties of D3D12 Default/Upload/Readback heaps. | |
| if (mDeviceInfo.isUMA) { | |
| // TODO(https://crbug.com/512465980): Use dawn::HeapArray | |
| auto* heapInfo = new MemoryHeapInfo[1]; | |
| memoryHeapProperties->heapInfo = DAWN_UNSAFE_TODO({heapInfo, 1}); | |
| heapInfo[0].size = | |
| std::max(mDeviceInfo.dedicatedVideoMemory, mDeviceInfo.sharedSystemMemory); | |
| if (mDeviceInfo.isCacheCoherentUMA) { | |
| heapInfo[0].properties = | |
| wgpu::HeapProperty::DeviceLocal | wgpu::HeapProperty::HostVisible | | |
| wgpu::HeapProperty::HostCoherent | wgpu::HeapProperty::HostCached; | |
| } else { | |
| heapInfo[0].properties = | |
| wgpu::HeapProperty::DeviceLocal | wgpu::HeapProperty::HostVisible | | |
| wgpu::HeapProperty::HostUncached | wgpu::HeapProperty::HostCached; | |
| } | |
| } else { | |
| // TODO(https://crbug.com/512465980): Use dawn::HeapArray | |
| auto* heapInfo = new MemoryHeapInfo[2]; | |
| memoryHeapProperties->heapInfo = DAWN_UNSAFE_TODO({heapInfo, 2}); | |
| heapInfo[0].size = mDeviceInfo.dedicatedVideoMemory; | |
| heapInfo[0].properties = wgpu::HeapProperty::DeviceLocal; | |
| DAWN_UNSAFE_TODO(heapInfo[1]).size = mDeviceInfo.sharedSystemMemory; | |
| DAWN_UNSAFE_TODO(heapInfo[1]).properties = | |
| wgpu::HeapProperty::HostVisible | wgpu::HeapProperty::HostCoherent | | |
| wgpu::HeapProperty::HostUncached | wgpu::HeapProperty::HostCached; | |
| } | |
| } | |
| if (auto* d3dProperties = info.Get<AdapterPropertiesD3D>()) { | |
| // Report highest supported shader model version, instead of actual applied version. | |
| d3dProperties->shaderModel = GetDeviceInfo().highestSupportedShaderModel; | |
| } | |
| if (auto* subgroupMatrixConfigs = info.Get<AdapterPropertiesSubgroupMatrixConfigs>()) { | |
| std::vector<SubgroupMatrixConfig> supportedConfigs = | |
| EnumerateSubgroupMatrixConfigs(toggles); | |
| size_t count = supportedConfigs.size(); | |
| // TODO(https://crbug.com/512465980): Use dawn::HeapArray | |
| SubgroupMatrixConfig* configs = new SubgroupMatrixConfig[count]; | |
| subgroupMatrixConfigs->configs = DAWN_UNSAFE_TODO({configs, supportedConfigs.size()}); | |
| // TODO(https://crbug.com/524406299): use dawn::Span::CopyFrom. | |
| DAWN_UNSAFE_TODO( | |
| memcpy(configs, supportedConfigs.data(), count * sizeof(SubgroupMatrixConfig))); | |
| } | |
| } | |
| std::vector<SubgroupMatrixConfig> PhysicalDevice::EnumerateSubgroupMatrixConfigs( | |
| const TogglesState& toggles) const { | |
| #ifdef DAWN_USE_AGILITY_SDK | |
| auto ToWgpuType = | |
| [](D3D12_LINEAR_ALGEBRA_DATATYPE dataType) -> wgpu::SubgroupMatrixComponentType { | |
| switch (dataType) { | |
| case D3D12_LINEAR_ALGEBRA_DATATYPE_SINT32: | |
| return wgpu::SubgroupMatrixComponentType::I32; | |
| case D3D12_LINEAR_ALGEBRA_DATATYPE_UINT32: | |
| return wgpu::SubgroupMatrixComponentType::U32; | |
| case D3D12_LINEAR_ALGEBRA_DATATYPE_FLOAT16: | |
| return wgpu::SubgroupMatrixComponentType::F16; | |
| case D3D12_LINEAR_ALGEBRA_DATATYPE_FLOAT32: | |
| return wgpu::SubgroupMatrixComponentType::F32; | |
| case D3D12_LINEAR_ALGEBRA_DATATYPE_SINT8: | |
| return wgpu::SubgroupMatrixComponentType::I8; | |
| case D3D12_LINEAR_ALGEBRA_DATATYPE_UINT8: | |
| return wgpu::SubgroupMatrixComponentType::U8; | |
| default: | |
| DAWN_UNREACHABLE(); | |
| } | |
| DAWN_UNREACHABLE(); | |
| }; | |
| auto IsFloat = [](D3D12_LINEAR_ALGEBRA_DATATYPE dataType) { | |
| return dataType == D3D12_LINEAR_ALGEBRA_DATATYPE_FLOAT16 || | |
| dataType == D3D12_LINEAR_ALGEBRA_DATATYPE_FLOAT32; | |
| }; | |
| auto ByteSize = [](D3D12_LINEAR_ALGEBRA_DATATYPE dataType) { | |
| switch (dataType) { | |
| case D3D12_LINEAR_ALGEBRA_DATATYPE_SINT32: | |
| return 4; | |
| case D3D12_LINEAR_ALGEBRA_DATATYPE_UINT32: | |
| return 4; | |
| case D3D12_LINEAR_ALGEBRA_DATATYPE_FLOAT16: | |
| return 2; | |
| case D3D12_LINEAR_ALGEBRA_DATATYPE_FLOAT32: | |
| return 4; | |
| case D3D12_LINEAR_ALGEBRA_DATATYPE_SINT8: | |
| return 1; | |
| case D3D12_LINEAR_ALGEBRA_DATATYPE_UINT8: | |
| return 1; | |
| default: | |
| DAWN_UNREACHABLE(); | |
| } | |
| DAWN_UNREACHABLE(); | |
| }; | |
| std::vector<SubgroupMatrixConfig> subgroupMatrixConfigs; | |
| for (auto& wmms : GetDeviceInfo().linAlgWaveMatrixMultiplySupports) { | |
| DAWN_ASSERT(wmms.Inputs.MatrixAComponentType == wmms.Inputs.MatrixBComponentType); | |
| auto dataTypeAB = wmms.Inputs.MatrixAComponentType; | |
| auto dataTypeAcc = wmms.Inputs.AccumulatorComponentType; | |
| // Don't mix ints and floats as we don't support this (no subgroupMatrixMultiply | |
| // overloads in Tint). | |
| // TODO(crbug.com/527051317): Remove this if we do add support to Tint. | |
| if (IsFloat(dataTypeAB) != IsFloat(dataTypeAcc)) { | |
| continue; | |
| } | |
| // Skip if input types are larger than output type - we don't support this in Tint | |
| // e.g. f32 -> f16 | |
| if (ByteSize(dataTypeAB) > ByteSize(dataTypeAcc)) { | |
| continue; | |
| } | |
| if (gpu_info::IsMicrosoftWARP(mVendorId, mDeviceId)) { | |
| // On WARP 1.65535.20-preview, CheckFeatureSupport returns shapes for SINT8 and UINT8, | |
| // even though these types are not supported. | |
| // TODO(crbug.com/527049636): Remove once this is fixed in WARP. | |
| if (ByteSize(dataTypeAB) == 1 || ByteSize(dataTypeAcc) == 1) { | |
| continue; | |
| } | |
| } | |
| if (!IsFeatureSupportedWithToggles(wgpu::FeatureName::ShaderF16, toggles)) { | |
| if (IsFloat(dataTypeAB) || IsFloat(dataTypeAcc)) { | |
| continue; | |
| } | |
| } | |
| for (auto& shape : wmms.Shapes) { | |
| SubgroupMatrixConfig config; | |
| config.M = shape.M; | |
| config.N = shape.N; | |
| config.K = shape.K; | |
| config.componentType = ToWgpuType(dataTypeAB); | |
| config.resultComponentType = ToWgpuType(dataTypeAcc); | |
| subgroupMatrixConfigs.push_back(config); | |
| } | |
| } | |
| return subgroupMatrixConfigs; | |
| #else | |
| return {}; | |
| #endif // DAWN_USE_AGILITY_SDK | |
| } | |
| } // namespace dawn::native::d3d12 |