blob: b237dea0774dfc69a46b9f3b1b12368f9e399e1d [file] [log] [blame] [edit]
///////////////////////////////////////////////////////////////////////////////
// //
// dxexp.cpp //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// Provides a command-line tool to detect the status of D3D experimental //
// feature support for experimental shaders. //
// //
///////////////////////////////////////////////////////////////////////////////
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <atlbase.h>
#include <d3d12.h>
#include <dxgi1_4.h>
#include <stdio.h>
#include <windows.h>
#pragma comment(lib, "d3d12.lib")
#pragma comment(lib, "dxgi.lib")
#pragma comment(lib, "dxguid.lib")
// A more recent Windows SDK than currently required is needed for these.
typedef HRESULT(WINAPI *D3D12EnableExperimentalFeaturesFn)(
UINT NumFeatures, __in_ecount(NumFeatures) const IID *pIIDs,
__in_ecount_opt(NumFeatures) void *pConfigurationStructs,
__in_ecount_opt(NumFeatures) UINT *pConfigurationStructSizes);
static const GUID D3D12ExperimentalShaderModelsID =
{/* 76f5573e-f13a-40f5-b297-81ce9e18933f */
0x76f5573e,
0xf13a,
0x40f5,
{0xb2, 0x97, 0x81, 0xce, 0x9e, 0x18, 0x93, 0x3f}};
static HRESULT AtlCheck(HRESULT hr) {
if (FAILED(hr))
AtlThrow(hr);
return hr;
}
// Not defined in Creators Update version of d3d12.h:
#if WDK_NTDDI_VERSION <= NTDDI_WIN10_RS2
#define D3D12_FEATURE_D3D12_OPTIONS3 ((D3D12_FEATURE)21)
typedef enum D3D12_COMMAND_LIST_SUPPORT_FLAGS {
D3D12_COMMAND_LIST_SUPPORT_FLAG_NONE = 0,
D3D12_COMMAND_LIST_SUPPORT_FLAG_DIRECT =
(1 << D3D12_COMMAND_LIST_TYPE_DIRECT),
D3D12_COMMAND_LIST_SUPPORT_FLAG_BUNDLE =
(1 << D3D12_COMMAND_LIST_TYPE_BUNDLE),
D3D12_COMMAND_LIST_SUPPORT_FLAG_COMPUTE =
(1 << D3D12_COMMAND_LIST_TYPE_COMPUTE),
D3D12_COMMAND_LIST_SUPPORT_FLAG_COPY = (1 << D3D12_COMMAND_LIST_TYPE_COPY),
D3D12_COMMAND_LIST_SUPPORT_FLAG_VIDEO_DECODE = (1 << 4),
D3D12_COMMAND_LIST_SUPPORT_FLAG_VIDEO_PROCESS = (1 << 5)
} D3D12_COMMAND_LIST_SUPPORT_FLAGS;
typedef enum D3D12_VIEW_INSTANCING_TIER {
D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED = 0,
D3D12_VIEW_INSTANCING_TIER_1 = 1,
D3D12_VIEW_INSTANCING_TIER_2 = 2,
D3D12_VIEW_INSTANCING_TIER_3 = 3
} D3D12_VIEW_INSTANCING_TIER;
typedef struct D3D12_FEATURE_DATA_D3D12_OPTIONS3 {
BOOL CopyQueueTimestampQueriesSupported;
BOOL CastingFullyTypedFormatSupported;
DWORD WriteBufferImmediateSupportFlags;
D3D12_VIEW_INSTANCING_TIER ViewInstancingTier;
BOOL BarycentricsSupported;
} D3D12_FEATURE_DATA_D3D12_OPTIONS3;
#endif
#ifndef NTDDI_WIN10_RS3
#define NTDDI_WIN10_RS3 0x0A000004
#endif
#if WDK_NTDDI_VERSION <= NTDDI_WIN10_RS3
#define D3D12_FEATURE_D3D12_OPTIONS4 ((D3D12_FEATURE)23)
typedef enum D3D12_SHARED_RESOURCE_COMPATIBILITY_TIER {
D3D12_SHARED_RESOURCE_COMPATIBILITY_TIER_0,
D3D12_SHARED_RESOURCE_COMPATIBILITY_TIER_1,
} D3D12_SHARED_RESOURCE_COMPATIBILITY_TIER;
typedef struct D3D12_FEATURE_DATA_D3D12_OPTIONS4 {
BOOL ReservedBufferPlacementSupported;
D3D12_SHARED_RESOURCE_COMPATIBILITY_TIER SharedResourceCompatibilityTier;
BOOL Native16BitShaderOpsSupported;
} D3D12_FEATURE_DATA_D3D12_OPTIONS4;
#endif
#ifndef NTDDI_WIN10_RS4
#define NTDDI_WIN10_RS4 0x0A000005
#endif
#if WDK_NTDDI_VERSION <= NTDDI_WIN10_RS4
#define D3D12_FEATURE_D3D12_OPTIONS5 ((D3D12_FEATURE)27)
typedef enum D3D12_RENDER_PASS_TIER {
D3D12_RENDER_PASS_TIER_0 = 0,
D3D12_RENDER_PASS_TIER_1 = 1,
D3D12_RENDER_PASS_TIER_2 = 2
} D3D12_RENDER_PASS_TIER;
typedef enum D3D12_RAYTRACING_TIER {
D3D12_RAYTRACING_TIER_NOT_SUPPORTED = 0,
D3D12_RAYTRACING_TIER_1_0 = 10 D3D12_RAYTRACING_TIER_1_1 = 11
} D3D12_RAYTRACING_TIER;
typedef struct D3D12_FEATURE_DATA_D3D12_OPTIONS5 {
BOOL SRVOnlyTiledResourceTier3;
D3D12_RENDER_PASS_TIER RenderPassesTier;
D3D12_RAYTRACING_TIER RaytracingTier;
} D3D12_FEATURE_DATA_D3D12_OPTIONS5;
#endif
#ifndef NTDDI_WIN10_NI
#define NTDDI_WIN10_NI 0x0A00000C
#endif
#if WDK_NTDDI_VERSION <= NTDDI_WIN10_NI
#define D3D12_FEATURE_D3D12_OPTIONS14 ((D3D12_FEATURE)43)
typedef struct D3D12_FEATURE_DATA_D3D12_OPTIONS14 {
BOOL AdvancedTextureOpsSupported;
BOOL WriteableMSAATexturesSupported;
BOOL IndependentFrontAndBackStencilRefMaskSupported;
} D3D12_FEATURE_DATA_D3D12_OPTIONS14;
#endif
#pragma warning(disable : 4063)
#define D3D12_RAYTRACING_TIER_1_1 ((D3D12_RAYTRACING_TIER)11)
#define D3D_SHADER_MODEL_6_1 ((D3D_SHADER_MODEL)0x61)
#define D3D_SHADER_MODEL_6_2 ((D3D_SHADER_MODEL)0x62)
#define D3D_SHADER_MODEL_6_3 ((D3D_SHADER_MODEL)0x63)
#define D3D_SHADER_MODEL_6_4 ((D3D_SHADER_MODEL)0x64)
#define D3D_SHADER_MODEL_6_5 ((D3D_SHADER_MODEL)0x65)
#define D3D_SHADER_MODEL_6_6 ((D3D_SHADER_MODEL)0x66)
#define D3D_SHADER_MODEL_6_7 ((D3D_SHADER_MODEL)0x67)
#define D3D_SHADER_MODEL_6_8 ((D3D_SHADER_MODEL)0x68)
#define DXEXP_HIGHEST_SHADER_MODEL D3D_SHADER_MODEL_6_8
static const char *BoolToStrJson(bool value) {
return value ? "true" : "false";
}
static const char *BoolToStrText(bool value) { return value ? "YES" : "NO"; }
static const char *(*BoolToStr)(bool value);
static bool IsOutputJson;
#define json_printf(...) \
if (IsOutputJson) { \
printf(__VA_ARGS__); \
}
#define text_printf(...) \
if (!IsOutputJson) { \
printf(__VA_ARGS__); \
}
static const char *ShaderModelToStr(D3D_SHADER_MODEL SM) {
switch ((UINT32)SM) {
case D3D_SHADER_MODEL_5_1:
return "5.1";
case D3D_SHADER_MODEL_6_0:
return "6.0";
case D3D_SHADER_MODEL_6_1:
return "6.1";
case D3D_SHADER_MODEL_6_2:
return "6.2";
case D3D_SHADER_MODEL_6_3:
return "6.3";
case D3D_SHADER_MODEL_6_4:
return "6.4";
case D3D_SHADER_MODEL_6_5:
return "6.5";
case D3D_SHADER_MODEL_6_6:
return "6.6";
case D3D_SHADER_MODEL_6_7:
return "6.7";
case D3D_SHADER_MODEL_6_8:
return "6.8";
default:
return "ERROR";
}
}
static const char *ViewInstancingTierToStr(D3D12_VIEW_INSTANCING_TIER Tier) {
switch (Tier) {
case D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED:
return "NO";
case D3D12_VIEW_INSTANCING_TIER_1:
return "Tier1";
case D3D12_VIEW_INSTANCING_TIER_2:
return "Tier2";
case D3D12_VIEW_INSTANCING_TIER_3:
return "Tier3";
default:
return "ERROR";
}
}
static const char *RaytracingTierToStr(D3D12_RAYTRACING_TIER Tier) {
switch (Tier) {
case D3D12_RAYTRACING_TIER_NOT_SUPPORTED:
return "NO";
case D3D12_RAYTRACING_TIER_1_0:
return "1.0";
case D3D12_RAYTRACING_TIER_1_1:
return "1.1";
default:
return "ERROR";
}
}
static HRESULT
GetHighestShaderModel(ID3D12Device *pDevice,
D3D12_FEATURE_DATA_SHADER_MODEL &DeviceSM) {
HRESULT hr = E_INVALIDARG;
D3D_SHADER_MODEL SM = DXEXP_HIGHEST_SHADER_MODEL;
while (hr == E_INVALIDARG && SM >= D3D_SHADER_MODEL_6_0) {
DeviceSM.HighestShaderModel = SM;
hr = pDevice->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &DeviceSM,
sizeof(DeviceSM));
SM = (D3D_SHADER_MODEL)((UINT32)SM - 1);
}
return hr;
}
static HRESULT PrintAdapters() {
HRESULT hr = S_OK;
char comma = ' ';
json_printf("{ \"adapters\" : [\n");
try {
CComPtr<IDXGIFactory2> pFactory;
AtlCheck(CreateDXGIFactory2(0, IID_PPV_ARGS(&pFactory)));
UINT AdapterIndex = 0;
for (;;) {
CComPtr<IDXGIAdapter1> pAdapter;
CComPtr<ID3D12Device> pDevice;
HRESULT hrEnum = pFactory->EnumAdapters1(AdapterIndex, &pAdapter);
if (hrEnum == DXGI_ERROR_NOT_FOUND)
break;
AtlCheck(hrEnum);
DXGI_ADAPTER_DESC1 AdapterDesc;
D3D12_FEATURE_DATA_D3D12_OPTIONS1 DeviceOptions;
D3D12_FEATURE_DATA_D3D12_OPTIONS3 DeviceOptions3;
D3D12_FEATURE_DATA_D3D12_OPTIONS4 DeviceOptions4;
D3D12_FEATURE_DATA_D3D12_OPTIONS5 DeviceOptions5;
D3D12_FEATURE_DATA_D3D12_OPTIONS14 DeviceOptions14;
memset(&DeviceOptions, 0, sizeof(DeviceOptions));
memset(&DeviceOptions3, 0, sizeof(DeviceOptions3));
memset(&DeviceOptions4, 0, sizeof(DeviceOptions4));
memset(&DeviceOptions5, 0, sizeof(DeviceOptions5));
memset(&DeviceOptions14, 0, sizeof(DeviceOptions14));
D3D12_FEATURE_DATA_SHADER_MODEL DeviceSM;
AtlCheck(pAdapter->GetDesc1(&AdapterDesc));
AtlCheck(D3D12CreateDevice(pAdapter, D3D_FEATURE_LEVEL_11_0,
IID_PPV_ARGS(&pDevice)));
AtlCheck(pDevice->CheckFeatureSupport(
D3D12_FEATURE_D3D12_OPTIONS1, &DeviceOptions, sizeof(DeviceOptions)));
pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3,
&DeviceOptions3, sizeof(DeviceOptions3));
pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS4,
&DeviceOptions4, sizeof(DeviceOptions4));
pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5,
&DeviceOptions5, sizeof(DeviceOptions5));
pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS14,
&DeviceOptions14, sizeof(DeviceOptions14));
AtlCheck(GetHighestShaderModel(pDevice, DeviceSM));
const char *Format =
IsOutputJson
? "%c { \"name\": \"%S\", \"sm\": \"%s\", \"wave\": %s, \"i64\": "
"%s, \"bary\": %s, \"view-inst\": \"%s\", \"16bit\": %s, "
"\"raytracing\": \"%s\", \"ato\":\"%s\" }\n"
: "%c %S - Highest SM [%s] Wave [%s] I64 [%s] Barycentrics [%s] "
"View Instancing [%s] 16bit Support [%s] Raytracing [%s] "
"Advanced Texture Ops [%s]\n";
printf(Format, comma, AdapterDesc.Description,
ShaderModelToStr(DeviceSM.HighestShaderModel),
BoolToStr(DeviceOptions.WaveOps),
BoolToStr(DeviceOptions.Int64ShaderOps),
BoolToStr(DeviceOptions3.BarycentricsSupported),
ViewInstancingTierToStr(DeviceOptions3.ViewInstancingTier),
BoolToStr(DeviceOptions4.Native16BitShaderOpsSupported),
RaytracingTierToStr(DeviceOptions5.RaytracingTier),
BoolToStr(DeviceOptions14.AdvancedTextureOpsSupported));
AdapterIndex++;
comma = IsOutputJson ? ',' : ' ';
}
} catch (ATL::CAtlException &e) {
hr = e.m_hr;
json_printf("%c { \"err\": \"unable to print information for adapters - "
"0x%08x\" }\n",
comma, (unsigned int)hr);
text_printf("%s", "Unable to print information for adapters.\n");
}
json_printf(" ] }\n");
return hr;
}
// Return codes:
// 0 - experimental mode worked
// 1 - cannot load d3d12.dll
// 2 - cannot find D3D12EnableExperimentalFeatures
// 3 - experimental shader mode interface unsupported
// 4 - other error
int main(int argc, const char *argv[]) {
BoolToStr = BoolToStrText;
IsOutputJson = false;
if (argc > 1) {
const char *pArg = argv[1];
if (0 == strcmp(pArg, "-?") || 0 == strcmp(pArg, "--?") ||
0 == strcmp(pArg, "/?")) {
printf("Checks the available of D3D support for experimental shader "
"models.\n\n");
printf("dxexp [-json]\n\n");
printf("Sets errorlevel to 0 on success, non-zero for failure cases.\n");
return 4;
} else if (0 == strcmp(pArg, "-json") || 0 == strcmp(pArg, "/json")) {
IsOutputJson = true;
BoolToStr = BoolToStrJson;
} else {
printf("Unrecognized command line arguments.\n");
return 4;
}
}
DWORD err;
HMODULE hRuntime;
hRuntime = LoadLibraryW(L"d3d12.dll");
if (hRuntime == NULL) {
err = GetLastError();
printf("Failed to load library d3d12.dll - Win32 error %u\n",
(unsigned int)err);
return 1;
}
json_printf("{ \"noexp\":\n");
text_printf(
"Adapter feature support without experimental shaders enabled:\n");
if (FAILED(PrintAdapters())) {
return 4;
}
FreeLibrary(hRuntime);
json_printf(" , \"exp\":");
text_printf(
"-------------------------------------------------------------\n");
hRuntime = LoadLibraryW(L"d3d12.dll");
if (hRuntime == NULL) {
err = GetLastError();
printf("Failed to load library d3d12.dll - Win32 error %u\n",
(unsigned int)err);
return 1;
}
D3D12EnableExperimentalFeaturesFn pD3D12EnableExperimentalFeatures =
(D3D12EnableExperimentalFeaturesFn)GetProcAddress(
hRuntime, "D3D12EnableExperimentalFeatures");
if (pD3D12EnableExperimentalFeatures == nullptr) {
err = GetLastError();
printf("Failed to find export 'D3D12EnableExperimentalFeatures' in "
"d3d12.dll - Win32 error %u%s\n",
(unsigned int)err,
err == ERROR_PROC_NOT_FOUND
? " (The specified procedure could not be found.)"
: "");
printf("Consider verifying the operating system version - Creators Update "
"or newer "
"is currently required.\n");
PrintAdapters();
return 2;
}
HRESULT hr = pD3D12EnableExperimentalFeatures(
1, &D3D12ExperimentalShaderModelsID, nullptr, nullptr);
if (SUCCEEDED(hr)) {
text_printf("Experimental shader model feature succeeded.\n");
hr = PrintAdapters();
json_printf("\n}\n");
return (SUCCEEDED(hr)) ? 0 : 4;
} else if (hr == E_NOINTERFACE) {
text_printf(
"Experimental shader model feature failed with error E_NOINTERFACE.\n");
text_printf(
"The most likely cause is that Windows Developer mode is not on.\n");
text_printf("See "
"https://msdn.microsoft.com/en-us/windows/uwp/get-started/"
"enable-your-device-for-development\n");
json_printf("{ \"err\": \"E_NOINTERFACE\" }");
json_printf("\n}\n");
return 3;
} else if (hr == E_INVALIDARG) {
text_printf(
"Experimental shader model feature failed with error E_INVALIDARG.\n");
text_printf("This means the configuration of a feature is incorrect, the "
"set of features passed\n"
"in are known to be incompatible with each other, or other "
"errors occured,\n"
"and is generally unexpected for the experimental shader model "
"feature.\n");
json_printf("{ \"err\": \"E_INVALIDARG\" }");
json_printf("\n}\n");
return 4;
} else {
text_printf("Experimental shader model feature failed with unexpected "
"HRESULT 0x%08x.\n",
(unsigned int)hr);
json_printf("{ \"err\": \"0x%08x\" }", (unsigned int)hr);
json_printf("\n}\n");
return 4;
}
}