blob: 885e2a3a18f826b57f11b4e7f10dca952a956476 [file]
// 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/D3D12Info.h"
#include <array>
#include <utility>
#include "src/dawn/common/GPUInfo.h"
#include "src/dawn/native/d3d/D3DError.h"
#include "src/dawn/native/d3d12/BackendD3D12.h"
#include "src/dawn/native/d3d12/PhysicalDeviceD3D12.h"
#include "src/dawn/native/d3d12/PlatformFunctionsD3D12.h"
namespace dawn::native::d3d12 {
namespace {
#ifdef DAWN_USE_AGILITY_SDK
std::vector<D3D12DeviceInfo::LinAlgWMMSupport> GatherLinAlgWaveMatrixMultiplySupports(
ComPtr<ID3D12Device> d3d12Device,
uint32_t waveLaneCountMin) {
std::vector<D3D12DeviceInfo::LinAlgWMMSupport> result;
auto typesToQuery = std::array{
D3D12_LINEAR_ALGEBRA_DATATYPE_SINT32, //
D3D12_LINEAR_ALGEBRA_DATATYPE_UINT32, //
D3D12_LINEAR_ALGEBRA_DATATYPE_FLOAT16, //
D3D12_LINEAR_ALGEBRA_DATATYPE_FLOAT32, //
D3D12_LINEAR_ALGEBRA_DATATYPE_SINT8, //
D3D12_LINEAR_ALGEBRA_DATATYPE_UINT8, //
};
for (auto dataTypeAB : typesToQuery) {
for (auto dataTypeAcc : typesToQuery) {
D3D12_FEATURE_DATA_LINEAR_ALGEBRA_MATRIX_OPERATION_SUPPORT opSupport{};
opSupport.OperationType = D3D12_LINEAR_ALGEBRA_OPERATION_TYPE_WAVE_MATRIX_MULTIPLY;
opSupport.WaveMatrixMultiply = {};
// Set WaveSize to waveLaneCountMin only. We assume if shapes are returned for this
// size, they are supported for all supported wave sizes (waveLaneCountMin to
// waveLaneCountMax).
// TODO(crbug.com/527055544): We should be able to set this to '0' instead.
DAWN_ASSERT(waveLaneCountMin != 0);
opSupport.WaveMatrixMultiply.Inputs.WaveSize = waveLaneCountMin;
opSupport.WaveMatrixMultiply.Inputs.MatrixAComponentType = dataTypeAB;
opSupport.WaveMatrixMultiply.Inputs.MatrixBComponentType = dataTypeAB;
opSupport.WaveMatrixMultiply.Inputs.AccumulatorComponentType = dataTypeAcc;
// First call to get number of shapes
opSupport.WaveMatrixMultiply.NumShapes = 0;
opSupport.WaveMatrixMultiply.Shapes = nullptr;
if (FAILED(d3d12Device->CheckFeatureSupport(
D3D12_FEATURE_LINEAR_ALGEBRA_LINEAR_ALGEBRA_MATRIX_OPERATION_SUPPORT,
&opSupport, sizeof(opSupport)))) {
continue;
}
uint32_t numShapes = opSupport.WaveMatrixMultiply.NumShapes;
if (numShapes == 0) {
continue;
}
// Second call to populate shapes
std::vector<D3D12_LINEAR_ALGEBRA_MATRIX_MULTIPLY_SHAPE> shapes(numShapes);
opSupport.WaveMatrixMultiply.Shapes = shapes.data();
if (FAILED(d3d12Device->CheckFeatureSupport(
D3D12_FEATURE_LINEAR_ALGEBRA_LINEAR_ALGEBRA_MATRIX_OPERATION_SUPPORT,
&opSupport, sizeof(opSupport)))) {
continue;
}
// Add support entry
auto wmm = opSupport.WaveMatrixMultiply;
wmm.Shapes = nullptr; // Clear so that we don't attempt to use this
result.emplace_back(wmm.Inputs, wmm.SupportFlags, std::move(shapes));
}
}
return result;
}
#endif // DAWN_USE_AGILITY_SDK
} // namespace
ResultOrError<D3D12DeviceInfo> GatherDeviceInfo(const PhysicalDevice& physicalDevice) {
D3D12DeviceInfo info = {};
ComPtr<ID3D12Device> d3d12Device = physicalDevice.GetDevice();
// Newer builds replace D3D_FEATURE_DATA_ARCHITECTURE with
// D3D_FEATURE_DATA_ARCHITECTURE1. However, D3D_FEATURE_DATA_ARCHITECTURE can be used
// for backwards compat.
// https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/ne-d3d12-d3d12_feature
D3D12_FEATURE_DATA_ARCHITECTURE arch = {};
DAWN_TRY(CheckHRESULT(
d3d12Device->CheckFeatureSupport(D3D12_FEATURE_ARCHITECTURE, &arch, sizeof(arch)),
"ID3D12Device::CheckFeatureSupport"));
info.isUMA = arch.UMA;
info.isCacheCoherentUMA = arch.CacheCoherentUMA;
D3D12_FEATURE_DATA_D3D12_OPTIONS featureOptions = {};
DAWN_TRY(CheckHRESULT(d3d12Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS,
&featureOptions, sizeof(featureOptions)),
"ID3D12Device::CheckFeatureSupport"));
info.resourceHeapTier = featureOptions.ResourceHeapTier;
info.resourceBindingTier = featureOptions.ResourceBindingTier;
D3D12_FEATURE_DATA_D3D12_OPTIONS2 featureOptions2 = {};
if (SUCCEEDED(d3d12Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS2, &featureOptions2,
sizeof(featureOptions2)))) {
info.programmableSamplePositionsTier = featureOptions2.ProgrammableSamplePositionsTier;
}
D3D12_FEATURE_DATA_D3D12_OPTIONS3 featureOptions3 = {};
if (SUCCEEDED(d3d12Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &featureOptions3,
sizeof(featureOptions3)))) {
info.supportsCastingFullyTypedFormat = featureOptions3.CastingFullyTypedFormatSupported;
}
// Used to share resources cross-API. If we query CheckFeatureSupport for
// D3D12_FEATURE_D3D12_OPTIONS4 successfully, then we can use cross-API sharing.
info.supportsSharedResourceCapabilityTier1 = false;
D3D12_FEATURE_DATA_D3D12_OPTIONS4 featureOptions4 = {};
if (SUCCEEDED(d3d12Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS4, &featureOptions4,
sizeof(featureOptions4)))) {
// Tier 1 support additionally enables the NV12 format. Since only the NV12 format
// is used by Dawn, check for Tier 1.
if (featureOptions4.SharedResourceCompatibilityTier >=
D3D12_SHARED_RESOURCE_COMPATIBILITY_TIER_1) {
info.supportsSharedResourceCapabilityTier1 = true;
}
// featureOptions4.MSAA64KBAlignedTextureSupported indicates whether 64KB-aligned MSAA
// textures are supported.
info.use64KBAlignedMSAATexture = featureOptions4.MSAA64KBAlignedTextureSupported;
// To support shader f16 feature, both featureOptions4.Native16BitShaderOpsSupported and
// using shader model version >= 6.2 are required.
info.supportsNative16BitShaderOps = featureOptions4.Native16BitShaderOpsSupported;
}
// D3D12_HEAP_FLAG_CREATE_NOT_ZEROED is available anytime that ID3D12Device8 is exposed, or a
// check for D3D12_FEATURE_D3D12_OPTIONS7 succeeds.
D3D12_FEATURE_DATA_D3D12_OPTIONS7 featureOptions7 = {};
if (SUCCEEDED(d3d12Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, &featureOptions7,
sizeof(featureOptions7)))) {
info.supportsHeapFlagCreateNotZeroed = true;
}
D3D12_FEATURE_DATA_D3D12_OPTIONS8 featureOptions8 = {};
if (SUCCEEDED(d3d12Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS8, &featureOptions8,
sizeof(featureOptions8)))) {
info.supportsTextureCompressionUnaligned = featureOptions8.UnalignedBlockTexturesSupported;
}
D3D12_FEATURE_DATA_D3D12_OPTIONS13 featureOptions13 = {};
if (SUCCEEDED(d3d12Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS13, &featureOptions13,
sizeof(featureOptions13)))) {
info.supportsTextureCopyBetweenDimensions =
featureOptions13.TextureCopyBetweenDimensionsSupported;
info.supportsUnrestrictedBufferTextureCopyPitch =
featureOptions13.UnrestrictedBufferTextureCopyPitchSupported;
}
#if D3D12_SDK_VERSION >= 612
D3D12_FEATURE_DATA_D3D12_OPTIONS18 featureOptions18 = {};
if (SUCCEEDED(d3d12Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS18, &featureOptions18,
sizeof(featureOptions18)))) {
info.supportsRenderPass = featureOptions18.RenderPassesValid;
}
#endif
info.supportsRootSignatureVersion1_1 = false;
D3D12_FEATURE_DATA_ROOT_SIGNATURE featureDataRootSignature = {};
featureDataRootSignature.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1;
if (SUCCEEDED(d3d12Device->CheckFeatureSupport(D3D12_FEATURE_ROOT_SIGNATURE,
&featureDataRootSignature,
sizeof(featureDataRootSignature)))) {
info.supportsRootSignatureVersion1_1 =
featureDataRootSignature.HighestVersion >= D3D_ROOT_SIGNATURE_VERSION_1_1;
}
D3D12_FEATURE_DATA_EXISTING_HEAPS existingHeapInfo = {};
if (SUCCEEDED(d3d12Device->CheckFeatureSupport(D3D12_FEATURE_EXISTING_HEAPS, &existingHeapInfo,
sizeof(existingHeapInfo)))) {
info.supportsExistingHeap = existingHeapInfo.Supported;
}
// D3D_SHADER_MODEL_6_10 is only defined in the Agility SDK headers; guard it
// so builds that fall back to the Windows SDK header still compile.
D3D12_FEATURE_DATA_SHADER_MODEL knownShaderModels[] = {
#ifdef DAWN_USE_AGILITY_SDK
{D3D_SHADER_MODEL_6_10},
#endif
{D3D_SHADER_MODEL_6_9}, {D3D_SHADER_MODEL_6_8}, {D3D_SHADER_MODEL_6_7},
{D3D_SHADER_MODEL_6_6}, {D3D_SHADER_MODEL_6_5}, {D3D_SHADER_MODEL_6_4},
{D3D_SHADER_MODEL_6_3}, {D3D_SHADER_MODEL_6_2}, {D3D_SHADER_MODEL_6_1},
{D3D_SHADER_MODEL_6_0}, {D3D_SHADER_MODEL_5_1}};
uint32_t driverShaderModel = 0;
for (D3D12_FEATURE_DATA_SHADER_MODEL shaderModel : knownShaderModels) {
if (SUCCEEDED(d3d12Device->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &shaderModel,
sizeof(shaderModel)))) {
driverShaderModel = shaderModel.HighestShaderModel;
break;
}
}
if (driverShaderModel < D3D_SHADER_MODEL_5_1) {
return DAWN_INTERNAL_ERROR("Driver doesn't support Shader Model 5.1 or higher");
}
// D3D_SHADER_MODEL is encoded as 0xMm with M the major version and m the minor version
DAWN_ASSERT(driverShaderModel <= 0xFF);
uint32_t shaderModelMajor = (driverShaderModel & 0xF0) >> 4;
uint32_t shaderModelMinor = (driverShaderModel & 0xF);
DAWN_ASSERT(shaderModelMajor < 10);
DAWN_ASSERT(shaderModelMinor < 16);
// TODO(crbug.com/513251803): Don't use shader model as decimal value
info.highestSupportedShaderModel = 10 * shaderModelMajor + shaderModelMinor;
// Device support wave intrinsics if shader model >= SM6.0 and capabilities flag WaveOps is set.
// https://github.com/Microsoft/DirectXShaderCompiler/wiki/Wave-Intrinsics
if (driverShaderModel >= D3D_SHADER_MODEL_6_0) {
D3D12_FEATURE_DATA_D3D12_OPTIONS1 featureOptions1 = {};
if (SUCCEEDED(d3d12Device->CheckFeatureSupport(
D3D12_FEATURE_D3D12_OPTIONS1, &featureOptions1, sizeof(featureOptions1)))) {
info.supportsWaveOps = featureOptions1.WaveOps;
info.waveLaneCountMin = featureOptions1.WaveLaneCountMin;
// Currently the WaveLaneCountMax queried from D3D12 API is not reliable and the meaning
// is unclear. The result is recorded into D3D12DeviceInfo, but is not intended to be
// used now.
info.waveLaneCountMax = featureOptions1.WaveLaneCountMax;
if (driverShaderModel >= D3D_SHADER_MODEL_6_6 && featureOptions1.Int64ShaderOps) {
D3D12_FEATURE_DATA_D3D12_OPTIONS9 featureOptions9 = {};
if (SUCCEEDED(d3d12Device->CheckFeatureSupport(
D3D12_FEATURE_D3D12_OPTIONS9, &featureOptions9, sizeof(featureOptions9)))) {
info.supportsInt64Atomics = featureOptions9.AtomicInt64OnTypedResourceSupported;
}
}
}
}
{
DXGI_ADAPTER_DESC adapterDesc;
DAWN_TRY(CheckHRESULT(physicalDevice.GetHardwareAdapter()->GetDesc(&adapterDesc),
"IDXGIAdapter3::GetDesc"));
info.dedicatedVideoMemory = adapterDesc.DedicatedVideoMemory;
info.sharedSystemMemory = adapterDesc.SharedSystemMemory;
}
#ifdef DAWN_USE_AGILITY_SDK
info.linAlgWaveMatrixMultiplySupports =
GatherLinAlgWaveMatrixMultiplySupports(d3d12Device, info.waveLaneCountMin);
#endif
return std::move(info);
}
} // namespace dawn::native::d3d12