d3d_common.cpp (20367B)
1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR PolyForm-Strict-1.0.0) 3 4 #include "d3d_common.h" 5 #include "gpu_device.h" 6 7 #include "common/assert.h" 8 #include "common/error.h" 9 #include "common/file_system.h" 10 #include "common/gsvector.h" 11 #include "common/log.h" 12 #include "common/string_util.h" 13 14 #include "fmt/format.h" 15 16 #include <d3d11.h> 17 #include <d3dcompiler.h> 18 #include <dxgi1_5.h> 19 20 Log_SetChannel(D3DCommon); 21 22 const char* D3DCommon::GetFeatureLevelString(D3D_FEATURE_LEVEL feature_level) 23 { 24 static constexpr std::array<std::tuple<D3D_FEATURE_LEVEL, const char*>, 11> feature_level_names = {{ 25 {D3D_FEATURE_LEVEL_1_0_CORE, "D3D_FEATURE_LEVEL_1_0_CORE"}, 26 {D3D_FEATURE_LEVEL_9_1, "D3D_FEATURE_LEVEL_9_1"}, 27 {D3D_FEATURE_LEVEL_9_2, "D3D_FEATURE_LEVEL_9_2"}, 28 {D3D_FEATURE_LEVEL_9_3, "D3D_FEATURE_LEVEL_9_3"}, 29 {D3D_FEATURE_LEVEL_10_0, "D3D_FEATURE_LEVEL_10_0"}, 30 {D3D_FEATURE_LEVEL_10_1, "D3D_FEATURE_LEVEL_10_1"}, 31 {D3D_FEATURE_LEVEL_11_0, "D3D_FEATURE_LEVEL_11_0"}, 32 {D3D_FEATURE_LEVEL_11_1, "D3D_FEATURE_LEVEL_11_1"}, 33 {D3D_FEATURE_LEVEL_12_0, "D3D_FEATURE_LEVEL_12_0"}, 34 {D3D_FEATURE_LEVEL_12_1, "D3D_FEATURE_LEVEL_12_1"}, 35 {D3D_FEATURE_LEVEL_12_2, "D3D_FEATURE_LEVEL_12_2"}, 36 }}; 37 38 for (const auto& [fl, name] : feature_level_names) 39 { 40 if (fl == feature_level) 41 return name; 42 } 43 44 return "D3D_FEATURE_LEVEL_UNKNOWN"; 45 } 46 47 const char* D3DCommon::GetFeatureLevelShaderModelString(D3D_FEATURE_LEVEL feature_level) 48 { 49 static constexpr std::array<std::tuple<D3D_FEATURE_LEVEL, const char*>, 4> feature_level_names = {{ 50 {D3D_FEATURE_LEVEL_10_0, "sm40"}, 51 {D3D_FEATURE_LEVEL_10_1, "sm41"}, 52 {D3D_FEATURE_LEVEL_11_0, "sm50"}, 53 {D3D_FEATURE_LEVEL_11_1, "sm50"}, 54 }}; 55 56 for (const auto& [fl, name] : feature_level_names) 57 { 58 if (fl == feature_level) 59 return name; 60 } 61 62 return "unk"; 63 } 64 65 D3D_FEATURE_LEVEL D3DCommon::GetDeviceMaxFeatureLevel(IDXGIAdapter1* adapter) 66 { 67 static constexpr std::array requested_feature_levels = { 68 D3D_FEATURE_LEVEL_12_2, D3D_FEATURE_LEVEL_12_1, D3D_FEATURE_LEVEL_12_0, D3D_FEATURE_LEVEL_11_1, 69 D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0}; 70 71 D3D_FEATURE_LEVEL max_supported_level = requested_feature_levels.back(); 72 HRESULT hr = D3D11CreateDevice(adapter, adapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, 73 requested_feature_levels.data(), static_cast<UINT>(requested_feature_levels.size()), 74 D3D11_SDK_VERSION, nullptr, &max_supported_level, nullptr); 75 if (FAILED(hr)) 76 WARNING_LOG("D3D11CreateDevice() for getting max feature level failed: 0x{:08X}", static_cast<unsigned>(hr)); 77 78 return max_supported_level; 79 } 80 81 Microsoft::WRL::ComPtr<IDXGIFactory5> D3DCommon::CreateFactory(bool debug, Error* error) 82 { 83 UINT flags = 0; 84 if (debug) 85 flags |= DXGI_CREATE_FACTORY_DEBUG; 86 87 Microsoft::WRL::ComPtr<IDXGIFactory5> factory; 88 const HRESULT hr = CreateDXGIFactory2(flags, IID_PPV_ARGS(factory.GetAddressOf())); 89 if (FAILED(hr)) 90 Error::SetHResult(error, "Failed to create DXGI factory: ", hr); 91 92 return factory; 93 } 94 95 static std::string FixupDuplicateAdapterNames(const GPUDevice::AdapterInfoList& adapter_names, std::string adapter_name) 96 { 97 if (std::any_of(adapter_names.begin(), adapter_names.end(), 98 [&adapter_name](const GPUDevice::AdapterInfo& other) { return (adapter_name == other.name); })) 99 { 100 std::string original_adapter_name = std::move(adapter_name); 101 102 u32 current_extra = 2; 103 do 104 { 105 adapter_name = fmt::format("{} ({})", original_adapter_name.c_str(), current_extra); 106 current_extra++; 107 } while ( 108 std::any_of(adapter_names.begin(), adapter_names.end(), 109 [&adapter_name](const GPUDevice::AdapterInfo& other) { return (adapter_name == other.name); })); 110 } 111 112 return adapter_name; 113 } 114 115 GPUDevice::AdapterInfoList D3DCommon::GetAdapterInfoList() 116 { 117 GPUDevice::AdapterInfoList adapters; 118 119 Microsoft::WRL::ComPtr<IDXGIFactory5> factory = CreateFactory(false, nullptr); 120 if (!factory) 121 return adapters; 122 123 Microsoft::WRL::ComPtr<IDXGIAdapter1> adapter; 124 for (u32 index = 0;; index++) 125 { 126 HRESULT hr = factory->EnumAdapters1(index, adapter.ReleaseAndGetAddressOf()); 127 if (hr == DXGI_ERROR_NOT_FOUND) 128 break; 129 130 if (FAILED(hr)) 131 { 132 ERROR_LOG("IDXGIFactory2::EnumAdapters() returned {:08X}", static_cast<unsigned>(hr)); 133 continue; 134 } 135 136 // Unfortunately we can't get any properties such as feature level without creating the device. 137 // So just assume a max of the D3D11 max across the board. 138 GPUDevice::AdapterInfo ai; 139 ai.name = FixupDuplicateAdapterNames(adapters, GetAdapterName(adapter.Get())); 140 ai.max_texture_size = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; 141 ai.max_multisamples = 8; 142 ai.supports_sample_shading = true; 143 144 Microsoft::WRL::ComPtr<IDXGIOutput> output; 145 if (SUCCEEDED(hr = adapter->EnumOutputs(0, output.ReleaseAndGetAddressOf()))) 146 { 147 UINT num_modes = 0; 148 if (SUCCEEDED(hr = output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &num_modes, nullptr))) 149 { 150 std::vector<DXGI_MODE_DESC> dmodes(num_modes); 151 if (SUCCEEDED(hr = output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &num_modes, dmodes.data()))) 152 { 153 for (const DXGI_MODE_DESC& mode : dmodes) 154 { 155 ai.fullscreen_modes.push_back(GPUDevice::GetFullscreenModeString( 156 mode.Width, mode.Height, 157 static_cast<float>(mode.RefreshRate.Numerator) / static_cast<float>(mode.RefreshRate.Denominator))); 158 } 159 } 160 else 161 { 162 ERROR_LOG("GetDisplayModeList() (2) failed: {:08X}", static_cast<unsigned>(hr)); 163 } 164 } 165 else 166 { 167 ERROR_LOG("GetDisplayModeList() failed: {:08X}", static_cast<unsigned>(hr)); 168 } 169 } 170 else 171 { 172 // Adapter may not have any outputs, don't spam the error log in this case. 173 if (hr != DXGI_ERROR_NOT_FOUND) 174 ERROR_LOG("EnumOutputs() failed: {:08X}", static_cast<unsigned>(hr)); 175 } 176 177 adapters.push_back(std::move(ai)); 178 } 179 180 return adapters; 181 } 182 183 bool D3DCommon::GetRequestedExclusiveFullscreenModeDesc(IDXGIFactory5* factory, const RECT& window_rect, u32 width, 184 u32 height, float refresh_rate, DXGI_FORMAT format, 185 DXGI_MODE_DESC* fullscreen_mode, IDXGIOutput** output) 186 { 187 // We need to find which monitor the window is located on. 188 const GSVector4i client_rc_vec(window_rect.left, window_rect.top, window_rect.right, window_rect.bottom); 189 190 // The window might be on a different adapter to which we are rendering.. so we have to enumerate them all. 191 HRESULT hr; 192 Microsoft::WRL::ComPtr<IDXGIOutput> first_output, intersecting_output; 193 194 for (u32 adapter_index = 0; !intersecting_output; adapter_index++) 195 { 196 Microsoft::WRL::ComPtr<IDXGIAdapter1> adapter; 197 hr = factory->EnumAdapters1(adapter_index, adapter.GetAddressOf()); 198 if (hr == DXGI_ERROR_NOT_FOUND) 199 break; 200 else if (FAILED(hr)) 201 continue; 202 203 for (u32 output_index = 0;; output_index++) 204 { 205 Microsoft::WRL::ComPtr<IDXGIOutput> this_output; 206 DXGI_OUTPUT_DESC output_desc; 207 hr = adapter->EnumOutputs(output_index, this_output.GetAddressOf()); 208 if (hr == DXGI_ERROR_NOT_FOUND) 209 break; 210 else if (FAILED(hr) || FAILED(this_output->GetDesc(&output_desc))) 211 continue; 212 213 const GSVector4i output_rc(output_desc.DesktopCoordinates.left, output_desc.DesktopCoordinates.top, 214 output_desc.DesktopCoordinates.right, output_desc.DesktopCoordinates.bottom); 215 if (!client_rc_vec.rintersects(output_rc)) 216 { 217 intersecting_output = std::move(this_output); 218 break; 219 } 220 221 // Fallback to the first monitor. 222 if (!first_output) 223 first_output = std::move(this_output); 224 } 225 } 226 227 if (!intersecting_output) 228 { 229 if (!first_output) 230 { 231 ERROR_LOG("No DXGI output found. Can't use exclusive fullscreen."); 232 return false; 233 } 234 235 WARNING_LOG("No DXGI output found for window, using first."); 236 intersecting_output = std::move(first_output); 237 } 238 239 DXGI_MODE_DESC request_mode = {}; 240 request_mode.Width = width; 241 request_mode.Height = height; 242 request_mode.Format = format; 243 request_mode.RefreshRate.Numerator = static_cast<UINT>(std::floor(refresh_rate * 1000.0f)); 244 request_mode.RefreshRate.Denominator = 1000u; 245 246 if (FAILED(hr = intersecting_output->FindClosestMatchingMode(&request_mode, fullscreen_mode, nullptr)) || 247 request_mode.Format != format) 248 { 249 ERROR_LOG("Failed to find closest matching mode, hr={:08X}", static_cast<unsigned>(hr)); 250 return false; 251 } 252 253 *output = intersecting_output.Get(); 254 intersecting_output->AddRef(); 255 return true; 256 } 257 258 Microsoft::WRL::ComPtr<IDXGIAdapter1> D3DCommon::GetAdapterByName(IDXGIFactory5* factory, std::string_view name) 259 { 260 if (name.empty()) 261 return {}; 262 263 // This might seem a bit odd to cache the names.. but there's a method to the madness. 264 // We might have two GPUs with the same name... :) 265 GPUDevice::AdapterInfoList adapters; 266 267 Microsoft::WRL::ComPtr<IDXGIAdapter1> adapter; 268 for (u32 index = 0;; index++) 269 { 270 const HRESULT hr = factory->EnumAdapters1(index, adapter.ReleaseAndGetAddressOf()); 271 if (hr == DXGI_ERROR_NOT_FOUND) 272 break; 273 274 if (FAILED(hr)) 275 { 276 ERROR_LOG("IDXGIFactory2::EnumAdapters() returned {:08X}", static_cast<unsigned>(hr)); 277 continue; 278 } 279 280 std::string adapter_name = FixupDuplicateAdapterNames(adapters, GetAdapterName(adapter.Get())); 281 if (adapter_name == name) 282 { 283 VERBOSE_LOG("Found adapter '{}'", adapter_name); 284 return adapter; 285 } 286 287 GPUDevice::AdapterInfo ai; 288 ai.name = std::move(adapter_name); 289 adapters.push_back(std::move(ai)); 290 } 291 292 ERROR_LOG("Adapter '{}' not found.", name); 293 return {}; 294 } 295 296 Microsoft::WRL::ComPtr<IDXGIAdapter1> D3DCommon::GetFirstAdapter(IDXGIFactory5* factory) 297 { 298 Microsoft::WRL::ComPtr<IDXGIAdapter1> adapter; 299 HRESULT hr = factory->EnumAdapters1(0, adapter.GetAddressOf()); 300 if (FAILED(hr)) 301 ERROR_LOG("IDXGIFactory2::EnumAdapters() for first adapter returned {:08X}", static_cast<unsigned>(hr)); 302 303 return adapter; 304 } 305 306 Microsoft::WRL::ComPtr<IDXGIAdapter1> D3DCommon::GetChosenOrFirstAdapter(IDXGIFactory5* factory, std::string_view name) 307 { 308 Microsoft::WRL::ComPtr<IDXGIAdapter1> adapter = GetAdapterByName(factory, name); 309 if (!adapter) 310 adapter = GetFirstAdapter(factory); 311 312 return adapter; 313 } 314 315 std::string D3DCommon::GetAdapterName(IDXGIAdapter1* adapter) 316 { 317 std::string ret; 318 319 DXGI_ADAPTER_DESC1 desc; 320 HRESULT hr = adapter->GetDesc1(&desc); 321 if (SUCCEEDED(hr)) 322 { 323 ret = StringUtil::WideStringToUTF8String(desc.Description); 324 } 325 else 326 { 327 ERROR_LOG("IDXGIAdapter1::GetDesc() returned {:08X}", static_cast<unsigned>(hr)); 328 } 329 330 if (ret.empty()) 331 ret = "(Unknown)"; 332 333 return ret; 334 } 335 336 std::string D3DCommon::GetDriverVersionFromLUID(const LUID& luid) 337 { 338 std::string ret; 339 340 HKEY hKey; 341 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\DirectX", 0, KEY_READ, &hKey) == ERROR_SUCCESS) 342 { 343 DWORD max_key_len = 0, adapter_count = 0; 344 if (RegQueryInfoKeyW(hKey, nullptr, nullptr, nullptr, &adapter_count, &max_key_len, nullptr, nullptr, nullptr, 345 nullptr, nullptr, nullptr) == ERROR_SUCCESS) 346 { 347 std::vector<WCHAR> current_name(max_key_len + 1); 348 for (DWORD i = 0; i < adapter_count; ++i) 349 { 350 DWORD subKeyLength = static_cast<DWORD>(current_name.size()); 351 if (RegEnumKeyExW(hKey, i, current_name.data(), &subKeyLength, nullptr, nullptr, nullptr, nullptr) == 352 ERROR_SUCCESS) 353 { 354 LUID current_luid = {}; 355 DWORD current_luid_size = sizeof(uint64_t); 356 if (RegGetValueW(hKey, current_name.data(), L"AdapterLuid", RRF_RT_QWORD, nullptr, ¤t_luid, 357 ¤t_luid_size) == ERROR_SUCCESS && 358 current_luid.HighPart == luid.HighPart && current_luid.LowPart == luid.LowPart) 359 { 360 LARGE_INTEGER driver_version = {}; 361 DWORD driver_version_size = sizeof(driver_version); 362 if (RegGetValueW(hKey, current_name.data(), L"DriverVersion", RRF_RT_QWORD, nullptr, &driver_version, 363 &driver_version_size) == ERROR_SUCCESS) 364 { 365 WORD nProduct = HIWORD(driver_version.HighPart); 366 WORD nVersion = LOWORD(driver_version.HighPart); 367 WORD nSubVersion = HIWORD(driver_version.LowPart); 368 WORD nBuild = LOWORD(driver_version.LowPart); 369 ret = fmt::format("{}.{}.{}.{}", nProduct, nVersion, nSubVersion, nBuild); 370 } 371 } 372 } 373 } 374 } 375 376 RegCloseKey(hKey); 377 } 378 379 return ret; 380 } 381 382 u32 D3DCommon::GetShaderModelForFeatureLevel(D3D_FEATURE_LEVEL feature_level) 383 { 384 switch (feature_level) 385 { 386 case D3D_FEATURE_LEVEL_10_0: 387 return 40; 388 389 case D3D_FEATURE_LEVEL_10_1: 390 return 41; 391 392 case D3D_FEATURE_LEVEL_11_0: 393 case D3D_FEATURE_LEVEL_11_1: 394 default: 395 return 50; 396 } 397 } 398 399 std::optional<DynamicHeapArray<u8>> D3DCommon::CompileShader(u32 shader_model, bool debug_device, GPUShaderStage stage, 400 std::string_view source, const char* entry_point, 401 Error* error) 402 { 403 const char* target; 404 switch (shader_model) 405 { 406 case 40: 407 { 408 static constexpr std::array<const char*, static_cast<u32>(GPUShaderStage::MaxCount)> targets = { 409 {"vs_4_0", "ps_4_0", "gs_4_0", "cs_4_0"}}; 410 target = targets[static_cast<int>(stage)]; 411 } 412 break; 413 414 case 41: 415 { 416 static constexpr std::array<const char*, static_cast<u32>(GPUShaderStage::MaxCount)> targets = { 417 {"vs_4_1", "ps_4_1", "gs_4_0", "cs_4_1"}}; 418 target = targets[static_cast<int>(stage)]; 419 } 420 break; 421 422 case 50: 423 { 424 static constexpr std::array<const char*, static_cast<u32>(GPUShaderStage::MaxCount)> targets = { 425 {"vs_5_0", "ps_5_0", "gs_5_0", "cs_5_0"}}; 426 target = targets[static_cast<int>(stage)]; 427 } 428 break; 429 430 default: 431 Error::SetStringFmt(error, "Unknown shader model: {}", shader_model); 432 return {}; 433 } 434 435 static constexpr UINT flags_non_debug = D3DCOMPILE_OPTIMIZATION_LEVEL3; 436 static constexpr UINT flags_debug = D3DCOMPILE_SKIP_OPTIMIZATION | D3DCOMPILE_DEBUG; 437 438 Microsoft::WRL::ComPtr<ID3DBlob> blob; 439 Microsoft::WRL::ComPtr<ID3DBlob> error_blob; 440 const HRESULT hr = 441 D3DCompile(source.data(), source.size(), "0", nullptr, nullptr, entry_point, target, 442 debug_device ? flags_debug : flags_non_debug, 0, blob.GetAddressOf(), error_blob.GetAddressOf()); 443 444 std::string_view error_string; 445 if (error_blob) 446 { 447 error_string = 448 std::string_view(static_cast<const char*>(error_blob->GetBufferPointer()), error_blob->GetBufferSize()); 449 } 450 451 if (FAILED(hr)) 452 { 453 ERROR_LOG("Failed to compile '{}':\n{}", target, error_string); 454 GPUDevice::DumpBadShader(source, error_string); 455 Error::SetHResult(error, "D3DCompile() failed: ", hr); 456 return {}; 457 } 458 459 if (!error_string.empty()) 460 WARNING_LOG("'{}' compiled with warnings:\n{}", target, error_string); 461 462 error_blob.Reset(); 463 464 return DynamicHeapArray<u8>(static_cast<const u8*>(blob->GetBufferPointer()), blob->GetBufferSize()); 465 } 466 467 static constexpr std::array<D3DCommon::DXGIFormatMapping, static_cast<int>(GPUTexture::Format::MaxCount)> 468 s_format_mapping = {{ 469 // clang-format off 470 // d3d_format srv_format rtv_format dsv_format 471 {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN }, // Unknown 472 {DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN }, // RGBA8 473 {DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN }, // BGRA8 474 {DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_UNKNOWN }, // RGB565 475 {DXGI_FORMAT_B5G5R5A1_UNORM, DXGI_FORMAT_B5G5R5A1_UNORM, DXGI_FORMAT_B5G5R5A1_UNORM, DXGI_FORMAT_UNKNOWN }, // RGBA5551 476 {DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_UNKNOWN }, // R8 477 {DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D16_UNORM }, // D16 478 {DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_D24_UNORM_S8_UINT }, // D24S8 479 {DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_D32_FLOAT }, // D32F 480 {DXGI_FORMAT_R32G8X24_TYPELESS, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS,DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, DXGI_FORMAT_D32_FLOAT_S8X24_UINT }, // D32FS8 481 {DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_UNKNOWN }, // R16 482 {DXGI_FORMAT_R16_SINT, DXGI_FORMAT_R16_SINT, DXGI_FORMAT_R16_SINT, DXGI_FORMAT_UNKNOWN }, // R16I 483 {DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_UNKNOWN }, // R16U 484 {DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_UNKNOWN }, // R16F 485 {DXGI_FORMAT_R32_SINT, DXGI_FORMAT_R32_SINT, DXGI_FORMAT_R32_SINT, DXGI_FORMAT_UNKNOWN }, // R32I 486 {DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_UNKNOWN }, // R32U 487 {DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN }, // R32F 488 {DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_UNKNOWN }, // RG8 489 {DXGI_FORMAT_R16G16_UNORM, DXGI_FORMAT_R16G16_UNORM, DXGI_FORMAT_R16G16_UNORM, DXGI_FORMAT_UNKNOWN }, // RG16 490 {DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_UNKNOWN }, // RG16F 491 {DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_UNKNOWN }, // RG32F 492 {DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_UNKNOWN }, // RGBA16 493 {DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN }, // RGBA16F 494 {DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN }, // RGBA32F 495 {DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_UNKNOWN }, // RGB10A2 496 // clang-format on 497 }}; 498 499 const D3DCommon::DXGIFormatMapping& D3DCommon::GetFormatMapping(GPUTexture::Format format) 500 { 501 DebugAssert(static_cast<u8>(format) < s_format_mapping.size()); 502 return s_format_mapping[static_cast<u8>(format)]; 503 } 504 505 GPUTexture::Format D3DCommon::GetFormatForDXGIFormat(DXGI_FORMAT format) 506 { 507 for (u32 i = 0; i < static_cast<u32>(GPUTexture::Format::MaxCount); i++) 508 { 509 if (s_format_mapping[i].resource_format == format) 510 return static_cast<GPUTexture::Format>(i); 511 } 512 513 return GPUTexture::Format::Unknown; 514 }