Path: blob/master/drivers/d3d12/rendering_device_driver_d3d12.cpp
21075 views
/**************************************************************************/1/* rendering_device_driver_d3d12.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "rendering_device_driver_d3d12.h"3132#include "d3d12_hooks.h"3334#include "core/config/project_settings.h"35#include "core/io/marshalls.h"36#include "servers/rendering/rendering_device.h"37#include "thirdparty/zlib/zlib.h"3839#include "d3d12_godot_nir_bridge.h"40#include "rendering_context_driver_d3d12.h"4142GODOT_GCC_WARNING_PUSH43GODOT_GCC_WARNING_IGNORE("-Wimplicit-fallthrough")44GODOT_GCC_WARNING_IGNORE("-Wlogical-not-parentheses")45GODOT_GCC_WARNING_IGNORE("-Wmissing-field-initializers")46GODOT_GCC_WARNING_IGNORE("-Wnon-virtual-dtor")47GODOT_GCC_WARNING_IGNORE("-Wshadow")48GODOT_GCC_WARNING_IGNORE("-Wswitch")49GODOT_CLANG_WARNING_PUSH50GODOT_CLANG_WARNING_IGNORE("-Wimplicit-fallthrough")51GODOT_CLANG_WARNING_IGNORE("-Wlogical-not-parentheses")52GODOT_CLANG_WARNING_IGNORE("-Wmissing-field-initializers")53GODOT_CLANG_WARNING_IGNORE("-Wnon-virtual-dtor")54GODOT_CLANG_WARNING_IGNORE("-Wstring-plus-int")55GODOT_CLANG_WARNING_IGNORE("-Wswitch")56GODOT_MSVC_WARNING_PUSH57GODOT_MSVC_WARNING_IGNORE(4200) // "nonstandard extension used: zero-sized array in struct/union".58GODOT_MSVC_WARNING_IGNORE(4806) // "'&': unsafe operation: no value of type 'bool' promoted to type 'uint32_t' can equal the given constant".5960#include <dxgi1_6.h>61#define D3D12MA_D3D12_HEADERS_ALREADY_INCLUDED62#include <thirdparty/d3d12ma/D3D12MemAlloc.h>6364#include <nir_spirv.h>65#include <nir_to_dxil.h>66#include <spirv_to_dxil.h>67extern "C" {68#include <dxil_spirv_nir.h>69}7071GODOT_GCC_WARNING_POP72GODOT_CLANG_WARNING_POP73GODOT_MSVC_WARNING_POP7475#if !defined(_MSC_VER)76#include <guiddef.h>7778#include <thirdparty/directx_headers/include/dxguids/dxguids.h>79#endif8081using Microsoft::WRL::ComPtr;8283// Mesa may define this.84#ifdef UNUSED85#undef UNUSED86#endif8788#ifdef PIX_ENABLED89#if defined(__GNUC__)90#define _MSC_VER 180091#endif92#define USE_PIX93#include <WinPixEventRuntime/pix3.h>94#if defined(__GNUC__)95#undef _MSC_VER96#endif97#endif9899// Runs constant sanity checks on the structure of the descriptor heap pools to catch implementation errors.100#define D3D12_DESCRIPTOR_HEAP_VERIFICATION 0101102// Tracks additional information and prints information about the allocation of descriptor heaps.103#define D3D12_DESCRIPTOR_HEAP_VERBOSE 0104105static const D3D12_RANGE VOID_RANGE = {};106107static const uint32_t MAX_DYNAMIC_BUFFERS = 8u; // Minimum guaranteed by Vulkan.108109/*****************/110/**** GENERIC ****/111/*****************/112113// NOTE: RD's packed format names are reversed in relation to DXGI's; e.g.:.114// - DATA_FORMAT_A8B8G8R8_UNORM_PACK32 -> DXGI_FORMAT_R8G8B8A8_UNORM (packed; note ABGR vs. RGBA).115// - DATA_FORMAT_B8G8R8A8_UNORM -> DXGI_FORMAT_B8G8R8A8_UNORM (not packed; note BGRA order matches).116// TODO: Add YUV formats properly, which would require better support for planes in the RD API.117118const RenderingDeviceDriverD3D12::D3D12Format RenderingDeviceDriverD3D12::RD_TO_D3D12_FORMAT[RDD::DATA_FORMAT_MAX] = {119/* DATA_FORMAT_R4G4_UNORM_PACK8 */ {},120/* DATA_FORMAT_R4G4B4A4_UNORM_PACK16 */ { DXGI_FORMAT_B4G4R4A4_UNORM, DXGI_FORMAT_B4G4R4A4_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(1, 2, 3, 0) },121/* DATA_FORMAT_B4G4R4A4_UNORM_PACK16 */ { DXGI_FORMAT_B4G4R4A4_UNORM, DXGI_FORMAT_B4G4R4A4_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(3, 2, 1, 0) },122/* DATA_FORMAT_R5G6B5_UNORM_PACK16 */ { DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G6R5_UNORM },123/* DATA_FORMAT_B5G6R5_UNORM_PACK16 */ { DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G6R5_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(2, 1, 0, 3) },124/* DATA_FORMAT_R5G5B5A1_UNORM_PACK16 */ { DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G5R5A1_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(1, 2, 3, 0) },125/* DATA_FORMAT_B5G5R5A1_UNORM_PACK16 */ { DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G5R5A1_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(3, 2, 1, 0) },126/* DATA_FORMAT_A1R5G5B5_UNORM_PACK16 */ { DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G5R5A1_UNORM },127/* DATA_FORMAT_R8_UNORM */ { DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_UNORM },128/* DATA_FORMAT_R8_SNORM */ { DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_SNORM },129/* DATA_FORMAT_R8_USCALED */ { DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_UINT },130/* DATA_FORMAT_R8_SSCALED */ { DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_SINT },131/* DATA_FORMAT_R8_UINT */ { DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_UINT },132/* DATA_FORMAT_R8_SINT */ { DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_SINT },133/* DATA_FORMAT_R8_SRGB */ {},134/* DATA_FORMAT_R8G8_UNORM */ { DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_UNORM },135/* DATA_FORMAT_R8G8_SNORM */ { DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_SNORM },136/* DATA_FORMAT_R8G8_USCALED */ { DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_UINT },137/* DATA_FORMAT_R8G8_SSCALED */ { DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_SINT },138/* DATA_FORMAT_R8G8_UINT */ { DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_UINT },139/* DATA_FORMAT_R8G8_SINT */ { DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_SINT },140/* DATA_FORMAT_R8G8_SRGB */ {},141/* DATA_FORMAT_R8G8B8_UNORM */ {},142/* DATA_FORMAT_R8G8B8_SNORM */ {},143/* DATA_FORMAT_R8G8B8_USCALED */ {},144/* DATA_FORMAT_R8G8B8_SSCALED */ {},145/* DATA_FORMAT_R8G8B8_UINT */ {},146/* DATA_FORMAT_R8G8B8_SINT */ {},147/* DATA_FORMAT_R8G8B8_SRGB */ {},148/* DATA_FORMAT_B8G8R8_UNORM */ {},149/* DATA_FORMAT_B8G8R8_SNORM */ {},150/* DATA_FORMAT_B8G8R8_USCALED */ {},151/* DATA_FORMAT_B8G8R8_SSCALED */ {},152/* DATA_FORMAT_B8G8R8_UINT */ {},153/* DATA_FORMAT_B8G8R8_SINT */ {},154/* DATA_FORMAT_B8G8R8_SRGB */ {},155/* DATA_FORMAT_R8G8B8A8_UNORM */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM },156/* DATA_FORMAT_R8G8B8A8_SNORM */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SNORM },157/* DATA_FORMAT_R8G8B8A8_USCALED */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UINT },158/* DATA_FORMAT_R8G8B8A8_SSCALED */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SINT },159/* DATA_FORMAT_R8G8B8A8_UINT */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UINT },160/* DATA_FORMAT_R8G8B8A8_SINT */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SINT },161/* DATA_FORMAT_R8G8B8A8_SRGB */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB },162/* DATA_FORMAT_B8G8R8A8_UNORM */ { DXGI_FORMAT_B8G8R8A8_TYPELESS, DXGI_FORMAT_B8G8R8A8_UNORM },163/* DATA_FORMAT_B8G8R8A8_SNORM */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SNORM },164/* DATA_FORMAT_B8G8R8A8_USCALED */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UINT },165/* DATA_FORMAT_B8G8R8A8_SSCALED */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SINT },166/* DATA_FORMAT_B8G8R8A8_UINT */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UINT },167/* DATA_FORMAT_B8G8R8A8_SINT */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SINT },168/* DATA_FORMAT_B8G8R8A8_SRGB */ { DXGI_FORMAT_B8G8R8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB },169/* DATA_FORMAT_A8B8G8R8_UNORM_PACK32 */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM },170/* DATA_FORMAT_A8B8G8R8_SNORM_PACK32 */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SNORM },171/* DATA_FORMAT_A8B8G8R8_USCALED_PACK32 */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UINT },172/* DATA_FORMAT_A8B8G8R8_SSCALED_PACK32 */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SINT },173/* DATA_FORMAT_A8B8G8R8_UINT_PACK32 */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UINT },174/* DATA_FORMAT_A8B8G8R8_SINT_PACK32 */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SINT },175/* DATA_FORMAT_A8B8G8R8_SRGB_PACK32 */ { DXGI_FORMAT_B8G8R8A8_TYPELESS, DXGI_FORMAT_B8G8R8A8_UNORM_SRGB },176/* DATA_FORMAT_A2R10G10B10_UNORM_PACK32 */ { DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(2, 1, 0, 3) },177/* DATA_FORMAT_A2R10G10B10_SNORM_PACK32 */ {},178/* DATA_FORMAT_A2R10G10B10_USCALED_PACK32 */ { DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UINT, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(2, 1, 0, 3) },179/* DATA_FORMAT_A2R10G10B10_SSCALED_PACK32 */ {},180/* DATA_FORMAT_A2R10G10B10_UINT_PACK32 */ { DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UINT, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(2, 1, 0, 3) },181/* DATA_FORMAT_A2R10G10B10_SINT_PACK32 */ {},182/* DATA_FORMAT_A2B10G10R10_UNORM_PACK32 */ { DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UNORM },183/* DATA_FORMAT_A2B10G10R10_SNORM_PACK32 */ {},184/* DATA_FORMAT_A2B10G10R10_USCALED_PACK32 */ { DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UINT },185/* DATA_FORMAT_A2B10G10R10_SSCALED_PACK32 */ {},186/* DATA_FORMAT_A2B10G10R10_UINT_PACK32 */ { DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UINT },187/* DATA_FORMAT_A2B10G10R10_SINT_PACK32 */ {},188/* DATA_FORMAT_R16_UNORM */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_UNORM },189/* DATA_FORMAT_R16_SNORM */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_SNORM },190/* DATA_FORMAT_R16_USCALED */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_UINT },191/* DATA_FORMAT_R16_SSCALED */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_SINT },192/* DATA_FORMAT_R16_UINT */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_UINT },193/* DATA_FORMAT_R16_SINT */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_SINT },194/* DATA_FORMAT_R16_SFLOAT */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_FLOAT },195/* DATA_FORMAT_R16G16_UNORM */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_UNORM },196/* DATA_FORMAT_R16G16_SNORM */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_SNORM },197/* DATA_FORMAT_R16G16_USCALED */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_UINT },198/* DATA_FORMAT_R16G16_SSCALED */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_SINT },199/* DATA_FORMAT_R16G16_UINT */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_UINT },200/* DATA_FORMAT_R16G16_SINT */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_SINT },201/* DATA_FORMAT_R16G16_SFLOAT */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_FLOAT },202/* DATA_FORMAT_R16G16B16_UNORM */ {},203/* DATA_FORMAT_R16G16B16_SNORM */ {},204/* DATA_FORMAT_R16G16B16_USCALED */ {},205/* DATA_FORMAT_R16G16B16_SSCALED */ {},206/* DATA_FORMAT_R16G16B16_UINT */ {},207/* DATA_FORMAT_R16G16B16_SINT */ {},208/* DATA_FORMAT_R16G16B16_SFLOAT */ {},209/* DATA_FORMAT_R16G16B16A16_UNORM */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_UNORM },210/* DATA_FORMAT_R16G16B16A16_SNORM */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_SNORM },211/* DATA_FORMAT_R16G16B16A16_USCALED */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_UINT },212/* DATA_FORMAT_R16G16B16A16_SSCALED */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_SINT },213/* DATA_FORMAT_R16G16B16A16_UINT */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_UINT },214/* DATA_FORMAT_R16G16B16A16_SINT */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_SINT },215/* DATA_FORMAT_R16G16B16A16_SFLOAT */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_FLOAT },216/* DATA_FORMAT_R32_UINT */ { DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_UINT },217/* DATA_FORMAT_R32_SINT */ { DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_SINT },218/* DATA_FORMAT_R32_SFLOAT */ { DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_FLOAT },219/* DATA_FORMAT_R32G32_UINT */ { DXGI_FORMAT_R32G32_TYPELESS, DXGI_FORMAT_R32G32_UINT },220/* DATA_FORMAT_R32G32_SINT */ { DXGI_FORMAT_R32G32_TYPELESS, DXGI_FORMAT_R32G32_SINT },221/* DATA_FORMAT_R32G32_SFLOAT */ { DXGI_FORMAT_R32G32_TYPELESS, DXGI_FORMAT_R32G32_FLOAT },222/* DATA_FORMAT_R32G32B32_UINT */ { DXGI_FORMAT_R32G32B32_TYPELESS, DXGI_FORMAT_R32G32B32_UINT },223/* DATA_FORMAT_R32G32B32_SINT */ { DXGI_FORMAT_R32G32B32_TYPELESS, DXGI_FORMAT_R32G32B32_SINT },224/* DATA_FORMAT_R32G32B32_SFLOAT */ { DXGI_FORMAT_R32G32B32_TYPELESS, DXGI_FORMAT_R32G32B32_FLOAT },225/* DATA_FORMAT_R32G32B32A32_UINT */ { DXGI_FORMAT_R32G32B32A32_TYPELESS, DXGI_FORMAT_R32G32B32A32_UINT },226/* DATA_FORMAT_R32G32B32A32_SINT */ { DXGI_FORMAT_R32G32B32A32_TYPELESS, DXGI_FORMAT_R32G32B32A32_SINT },227/* DATA_FORMAT_R32G32B32A32_SFLOAT */ { DXGI_FORMAT_R32G32B32A32_TYPELESS, DXGI_FORMAT_R32G32B32A32_FLOAT },228/* DATA_FORMAT_R64_UINT */ {},229/* DATA_FORMAT_R64_SINT */ {},230/* DATA_FORMAT_R64_SFLOAT */ {},231/* DATA_FORMAT_R64G64_UINT */ {},232/* DATA_FORMAT_R64G64_SINT */ {},233/* DATA_FORMAT_R64G64_SFLOAT */ {},234/* DATA_FORMAT_R64G64B64_UINT */ {},235/* DATA_FORMAT_R64G64B64_SINT */ {},236/* DATA_FORMAT_R64G64B64_SFLOAT */ {},237/* DATA_FORMAT_R64G64B64A64_UINT */ {},238/* DATA_FORMAT_R64G64B64A64_SINT */ {},239/* DATA_FORMAT_R64G64B64A64_SFLOAT */ {},240/* DATA_FORMAT_B10G11R11_UFLOAT_PACK32 */ { DXGI_FORMAT_R11G11B10_FLOAT, DXGI_FORMAT_R11G11B10_FLOAT },241/* DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32 */ { DXGI_FORMAT_R9G9B9E5_SHAREDEXP, DXGI_FORMAT_R9G9B9E5_SHAREDEXP },242/* DATA_FORMAT_D16_UNORM */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_UNORM, 0, DXGI_FORMAT_D16_UNORM },243/* DATA_FORMAT_X8_D24_UNORM_PACK32 */ { DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_UNKNOWN, 0, DXGI_FORMAT_D24_UNORM_S8_UINT },244/* DATA_FORMAT_D32_SFLOAT */ { DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_FLOAT, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, DXGI_FORMAT_D32_FLOAT },245/* DATA_FORMAT_S8_UINT */ {},246/* DATA_FORMAT_D16_UNORM_S8_UINT */ {},247/* DATA_FORMAT_D24_UNORM_S8_UINT */ { DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_UNKNOWN, 0, DXGI_FORMAT_D24_UNORM_S8_UINT },248/* DATA_FORMAT_D32_SFLOAT_S8_UINT */ { DXGI_FORMAT_R32G8X24_TYPELESS, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, DXGI_FORMAT_D32_FLOAT_S8X24_UINT },249/* DATA_FORMAT_BC1_RGB_UNORM_BLOCK */ { DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(0, 1, 2, D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1) },250/* DATA_FORMAT_BC1_RGB_SRGB_BLOCK */ { DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM_SRGB, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(0, 1, 2, D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1) },251/* DATA_FORMAT_BC1_RGBA_UNORM_BLOCK */ { DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM },252/* DATA_FORMAT_BC1_RGBA_SRGB_BLOCK */ { DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM_SRGB },253/* DATA_FORMAT_BC2_UNORM_BLOCK */ { DXGI_FORMAT_BC2_TYPELESS, DXGI_FORMAT_BC2_UNORM },254/* DATA_FORMAT_BC2_SRGB_BLOCK */ { DXGI_FORMAT_BC2_TYPELESS, DXGI_FORMAT_BC2_UNORM_SRGB },255/* DATA_FORMAT_BC3_UNORM_BLOCK */ { DXGI_FORMAT_BC3_TYPELESS, DXGI_FORMAT_BC3_UNORM },256/* DATA_FORMAT_BC3_SRGB_BLOCK */ { DXGI_FORMAT_BC3_TYPELESS, DXGI_FORMAT_BC3_UNORM_SRGB },257/* DATA_FORMAT_BC4_UNORM_BLOCK */ { DXGI_FORMAT_BC4_TYPELESS, DXGI_FORMAT_BC4_UNORM },258/* DATA_FORMAT_BC4_SNORM_BLOCK */ { DXGI_FORMAT_BC4_TYPELESS, DXGI_FORMAT_BC4_SNORM },259/* DATA_FORMAT_BC5_UNORM_BLOCK */ { DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_UNORM },260/* DATA_FORMAT_BC5_SNORM_BLOCK */ { DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_SNORM },261/* DATA_FORMAT_BC6H_UFLOAT_BLOCK */ { DXGI_FORMAT_BC6H_TYPELESS, DXGI_FORMAT_BC6H_UF16 },262/* DATA_FORMAT_BC6H_SFLOAT_BLOCK */ { DXGI_FORMAT_BC6H_TYPELESS, DXGI_FORMAT_BC6H_SF16 },263/* DATA_FORMAT_BC7_UNORM_BLOCK */ { DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM },264/* DATA_FORMAT_BC7_SRGB_BLOCK */ { DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM_SRGB },265/* DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK */ {},266/* DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK */ {},267/* DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK */ {},268/* DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK */ {},269/* DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK */ {},270/* DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK */ {},271/* DATA_FORMAT_EAC_R11_UNORM_BLOCK */ {},272/* DATA_FORMAT_EAC_R11_SNORM_BLOCK */ {},273/* DATA_FORMAT_EAC_R11G11_UNORM_BLOCK */ {},274/* DATA_FORMAT_EAC_R11G11_SNORM_BLOCK */ {},275/* DATA_FORMAT_ASTC_4x4_UNORM_BLOCK */ {},276/* DATA_FORMAT_ASTC_4x4_SRGB_BLOCK */ {},277/* DATA_FORMAT_ASTC_5x4_UNORM_BLOCK */ {},278/* DATA_FORMAT_ASTC_5x4_SRGB_BLOCK */ {},279/* DATA_FORMAT_ASTC_5x5_UNORM_BLOCK */ {},280/* DATA_FORMAT_ASTC_5x5_SRGB_BLOCK */ {},281/* DATA_FORMAT_ASTC_6x5_UNORM_BLOCK */ {},282/* DATA_FORMAT_ASTC_6x5_SRGB_BLOCK */ {},283/* DATA_FORMAT_ASTC_6x6_UNORM_BLOCK */ {},284/* DATA_FORMAT_ASTC_6x6_SRGB_BLOCK */ {},285/* DATA_FORMAT_ASTC_8x5_UNORM_BLOCK */ {},286/* DATA_FORMAT_ASTC_8x5_SRGB_BLOCK */ {},287/* DATA_FORMAT_ASTC_8x6_UNORM_BLOCK */ {},288/* DATA_FORMAT_ASTC_8x6_SRGB_BLOCK */ {},289/* DATA_FORMAT_ASTC_8x8_UNORM_BLOCK */ {},290/* DATA_FORMAT_ASTC_8x8_SRGB_BLOCK */ {},291/* DATA_FORMAT_ASTC_10x5_UNORM_BLOCK */ {},292/* DATA_FORMAT_ASTC_10x5_SRGB_BLOCK */ {},293/* DATA_FORMAT_ASTC_10x6_UNORM_BLOCK */ {},294/* DATA_FORMAT_ASTC_10x6_SRGB_BLOCK */ {},295/* DATA_FORMAT_ASTC_10x8_UNORM_BLOCK */ {},296/* DATA_FORMAT_ASTC_10x8_SRGB_BLOCK */ {},297/* DATA_FORMAT_ASTC_10x10_UNORM_BLOCK */ {},298/* DATA_FORMAT_ASTC_10x10_SRGB_BLOCK */ {},299/* DATA_FORMAT_ASTC_12x10_UNORM_BLOCK */ {},300/* DATA_FORMAT_ASTC_12x10_SRGB_BLOCK */ {},301/* DATA_FORMAT_ASTC_12x12_UNORM_BLOCK */ {},302/* DATA_FORMAT_ASTC_12x12_SRGB_BLOCK */ {},303/* DATA_FORMAT_G8B8G8R8_422_UNORM */ {},304/* DATA_FORMAT_B8G8R8G8_422_UNORM */ {},305/* DATA_FORMAT_G8_B8_R8_3PLANE_420_UNORM */ {},306/* DATA_FORMAT_G8_B8R8_2PLANE_420_UNORM */ {},307/* DATA_FORMAT_G8_B8_R8_3PLANE_422_UNORM */ {},308/* DATA_FORMAT_G8_B8R8_2PLANE_422_UNORM */ {},309/* DATA_FORMAT_G8_B8_R8_3PLANE_444_UNORM */ {},310/* DATA_FORMAT_R10X6_UNORM_PACK16 */ {},311/* DATA_FORMAT_R10X6G10X6_UNORM_2PACK16 */ {},312/* DATA_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 */ {},313/* DATA_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 */ {},314/* DATA_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 */ {},315/* DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 */ {},316/* DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 */ {},317/* DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 */ {},318/* DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 */ {},319/* DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 */ {},320/* DATA_FORMAT_R12X4_UNORM_PACK16 */ {},321/* DATA_FORMAT_R12X4G12X4_UNORM_2PACK16 */ {},322/* DATA_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 */ {},323/* DATA_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 */ {},324/* DATA_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 */ {},325/* DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 */ {},326/* DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 */ {},327/* DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 */ {},328/* DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 */ {},329/* DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 */ {},330/* DATA_FORMAT_G16B16G16R16_422_UNORM */ {},331/* DATA_FORMAT_B16G16R16G16_422_UNORM */ {},332/* DATA_FORMAT_G16_B16_R16_3PLANE_420_UNORM */ {},333/* DATA_FORMAT_G16_B16R16_2PLANE_420_UNORM */ {},334/* DATA_FORMAT_G16_B16_R16_3PLANE_422_UNORM */ {},335/* DATA_FORMAT_G16_B16R16_2PLANE_422_UNORM */ {},336/* DATA_FORMAT_G16_B16_R16_3PLANE_444_UNORM */ {},337/* DATA_FORMAT_ASTC_4x4_SFLOAT_BLOCK */ {},338/* DATA_FORMAT_ASTC_5x4_SFLOAT_BLOCK */ {},339/* DATA_FORMAT_ASTC_5x5_SFLOAT_BLOCK */ {},340/* DATA_FORMAT_ASTC_6x5_SFLOAT_BLOCK */ {},341/* DATA_FORMAT_ASTC_6x6_SFLOAT_BLOCK */ {},342/* DATA_FORMAT_ASTC_8x5_SFLOAT_BLOCK */ {},343/* DATA_FORMAT_ASTC_8x6_SFLOAT_BLOCK */ {},344/* DATA_FORMAT_ASTC_8x8_SFLOAT_BLOCK */ {},345/* DATA_FORMAT_ASTC_10x5_SFLOAT_BLOCK*/ {},346/* DATA_FORMAT_ASTC_10x6_SFLOAT_BLOCK */ {},347/* DATA_FORMAT_ASTC_10x8_SFLOAT_BLOCK */ {},348/* DATA_FORMAT_ASTC_10x10_SFLOAT_BLOCK */ {},349/* DATA_FORMAT_ASTC_12x10_SFLOAT_BLOCK */ {},350/* DATA_FORMAT_ASTC_12x12_SFLOAT_BLOCK */ {},351};352353static D3D12_CPU_DESCRIPTOR_HANDLE get_cpu_handle(D3D12_CPU_DESCRIPTOR_HANDLE p_handle, uint64_t p_index, uint32_t p_increment_size) {354p_handle.ptr += p_index * p_increment_size;355return p_handle;356}357358static D3D12_GPU_DESCRIPTOR_HANDLE get_gpu_handle(D3D12_GPU_DESCRIPTOR_HANDLE p_handle, uint64_t p_index, uint32_t p_increment_size) {359p_handle.ptr += p_index * p_increment_size;360return p_handle;361}362363Error RenderingDeviceDriverD3D12::DescriptorHeap::initialize(ID3D12Device *p_device, D3D12_DESCRIPTOR_HEAP_TYPE p_type, uint32_t p_num_descriptors, bool p_shader_visible) {364D3D12MA::VIRTUAL_BLOCK_DESC block_desc = {};365block_desc.Size = p_num_descriptors;366367HRESULT hr = D3D12MA::CreateVirtualBlock(&block_desc, virtual_block.GetAddressOf());368ERR_FAIL_COND_V(FAILED(hr), ERR_CANT_CREATE);369370D3D12_DESCRIPTOR_HEAP_DESC heap_desc = {};371heap_desc.Type = p_type;372heap_desc.NumDescriptors = p_num_descriptors;373heap_desc.Flags = p_shader_visible ? D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE : D3D12_DESCRIPTOR_HEAP_FLAG_NONE;374375hr = p_device->CreateDescriptorHeap(&heap_desc, IID_PPV_ARGS(heap.GetAddressOf()));376ERR_FAIL_COND_V_MSG(FAILED(hr), ERR_CANT_CREATE, "CreateDescriptorHeap failed with error " + vformat("0x%08ux", (uint64_t)hr) + ".");377378#if defined(_MSC_VER) || !defined(_WIN32)379cpu_handle = heap->GetCPUDescriptorHandleForHeapStart();380if (p_shader_visible) {381gpu_handle = heap->GetGPUDescriptorHandleForHeapStart();382}383#else384heap->GetCPUDescriptorHandleForHeapStart(&cpu_handle);385if (p_shader_visible) {386heap->GetGPUDescriptorHandleForHeapStart(&gpu_handle);387}388#endif389390increment_size = p_device->GetDescriptorHandleIncrementSize(p_type);391392return OK;393}394395Error RenderingDeviceDriverD3D12::DescriptorHeap::allocate(uint32_t p_descriptor_count, Allocation &r_allocation) {396D3D12MA::VIRTUAL_ALLOCATION_DESC desc = {};397desc.Size = p_descriptor_count;398399D3D12MA::VirtualAllocation virtual_alloc = {};400uint64_t offset = 0;401HRESULT hr = virtual_block->Allocate(&desc, &virtual_alloc, &offset);402403// This error is expected, and needs to be handled by the caller.404if (hr == E_OUTOFMEMORY) {405return ERR_OUT_OF_MEMORY;406}407408ERR_FAIL_COND_V_MSG(FAILED(hr), ERR_CANT_CREATE, "Allocate failed with error " + vformat("0x%08ux", (uint64_t)hr) + ".");409410r_allocation.virtual_alloc_handle = virtual_alloc.AllocHandle;411r_allocation.cpu_handle = get_cpu_handle(cpu_handle, offset, increment_size);412r_allocation.gpu_handle = get_gpu_handle(gpu_handle, offset, increment_size);413414return OK;415}416417void RenderingDeviceDriverD3D12::DescriptorHeap::free(const Allocation &p_allocation) {418D3D12MA::VirtualAllocation virtual_alloc = {};419virtual_alloc.AllocHandle = p_allocation.virtual_alloc_handle;420421virtual_block->FreeAllocation(virtual_alloc);422}423424void RenderingDeviceDriverD3D12::CPUDescriptorHeapPool::initialize(ID3D12Device *p_device, D3D12_DESCRIPTOR_HEAP_TYPE p_type) {425type = p_type;426increment_size = p_device->GetDescriptorHandleIncrementSize(p_type);427}428429Error RenderingDeviceDriverD3D12::CPUDescriptorHeapPool::allocate(uint32_t p_descriptor_count, ID3D12Device *p_device, Allocation &r_allocation) {430MutexLock lock(mutex);431432bool allocated = false;433for (uint32_t i = 0; i < heaps.size(); i++) {434Error err = heaps[i].allocate(p_descriptor_count, r_allocation);435436if (err == OK) {437r_allocation.heap_index = i;438allocated = true;439break;440}441442// Only "out of memory" error is expected.443ERR_FAIL_COND_V(err != ERR_OUT_OF_MEMORY, err);444}445446// Create new block.447if (!allocated) {448uint32_t heap_index = heaps.size();449450DescriptorHeap heap;451Error err = heap.initialize(p_device, type, MAX(2048u, p_descriptor_count), false);452ERR_FAIL_COND_V(err != OK, err);453454heaps.push_back(std::move(heap));455456err = heaps[heap_index].allocate(p_descriptor_count, r_allocation);457ERR_FAIL_COND_V(err != OK, err);458459r_allocation.heap_index = heap_index;460}461462return OK;463}464465void RenderingDeviceDriverD3D12::CPUDescriptorHeapPool::free(const Allocation &p_allocation) {466if (p_allocation.heap_index != UINT_MAX) {467MutexLock lock(mutex);468heaps[p_allocation.heap_index].free(p_allocation);469}470}471472static const D3D12_COMPARISON_FUNC RD_TO_D3D12_COMPARE_OP[RD::COMPARE_OP_MAX] = {473D3D12_COMPARISON_FUNC_NEVER,474D3D12_COMPARISON_FUNC_LESS,475D3D12_COMPARISON_FUNC_EQUAL,476D3D12_COMPARISON_FUNC_LESS_EQUAL,477D3D12_COMPARISON_FUNC_GREATER,478D3D12_COMPARISON_FUNC_NOT_EQUAL,479D3D12_COMPARISON_FUNC_GREATER_EQUAL,480D3D12_COMPARISON_FUNC_ALWAYS,481};482483uint32_t RenderingDeviceDriverD3D12::SubgroupCapabilities::supported_stages_flags_rd() const {484// If there's a way to check exactly which are supported, I have yet to find it.485return (486RenderingDevice::ShaderStage::SHADER_STAGE_FRAGMENT_BIT |487RenderingDevice::ShaderStage::SHADER_STAGE_COMPUTE_BIT);488}489490uint32_t RenderingDeviceDriverD3D12::SubgroupCapabilities::supported_operations_flags_rd() const {491if (!wave_ops_supported) {492return 0;493} else {494return (495RenderingDevice::SubgroupOperations::SUBGROUP_BASIC_BIT |496RenderingDevice::SubgroupOperations::SUBGROUP_BALLOT_BIT |497RenderingDevice::SubgroupOperations::SUBGROUP_VOTE_BIT |498RenderingDevice::SubgroupOperations::SUBGROUP_SHUFFLE_BIT |499RenderingDevice::SubgroupOperations::SUBGROUP_SHUFFLE_RELATIVE_BIT |500RenderingDevice::SubgroupOperations::SUBGROUP_QUAD_BIT |501RenderingDevice::SubgroupOperations::SUBGROUP_ARITHMETIC_BIT |502RenderingDevice::SubgroupOperations::SUBGROUP_CLUSTERED_BIT);503}504}505506void RenderingDeviceDriverD3D12::_debug_message_func(D3D12_MESSAGE_CATEGORY p_category, D3D12_MESSAGE_SEVERITY p_severity, D3D12_MESSAGE_ID p_id, LPCSTR p_description, void *p_context) {507String type_string;508switch (p_category) {509case D3D12_MESSAGE_CATEGORY_APPLICATION_DEFINED:510type_string = "APPLICATION_DEFINED";511break;512case D3D12_MESSAGE_CATEGORY_MISCELLANEOUS:513type_string = "MISCELLANEOUS";514break;515case D3D12_MESSAGE_CATEGORY_INITIALIZATION:516type_string = "INITIALIZATION";517break;518case D3D12_MESSAGE_CATEGORY_CLEANUP:519type_string = "CLEANUP";520break;521case D3D12_MESSAGE_CATEGORY_COMPILATION:522type_string = "COMPILATION";523break;524case D3D12_MESSAGE_CATEGORY_STATE_CREATION:525type_string = "STATE_CREATION";526break;527case D3D12_MESSAGE_CATEGORY_STATE_SETTING:528type_string = "STATE_SETTING";529break;530case D3D12_MESSAGE_CATEGORY_STATE_GETTING:531type_string = "STATE_GETTING";532break;533case D3D12_MESSAGE_CATEGORY_RESOURCE_MANIPULATION:534type_string = "RESOURCE_MANIPULATION";535break;536case D3D12_MESSAGE_CATEGORY_EXECUTION:537type_string = "EXECUTION";538break;539case D3D12_MESSAGE_CATEGORY_SHADER:540type_string = "SHADER";541break;542}543544String error_message(type_string +545" - Message Id Number: " + String::num_int64(p_id) +546"\n\t" + p_description);547548// Convert D3D12 severity to our own log macros.549switch (p_severity) {550case D3D12_MESSAGE_SEVERITY_MESSAGE:551print_verbose(error_message);552break;553case D3D12_MESSAGE_SEVERITY_INFO:554print_line(error_message);555break;556case D3D12_MESSAGE_SEVERITY_WARNING:557WARN_PRINT(error_message);558break;559case D3D12_MESSAGE_SEVERITY_ERROR:560case D3D12_MESSAGE_SEVERITY_CORRUPTION:561ERR_PRINT(error_message);562CRASH_COND_MSG(Engine::get_singleton()->is_abort_on_gpu_errors_enabled(),563"Crashing, because abort on GPU errors is enabled.");564break;565}566}567568/******************/569/**** RESOURCE ****/570/******************/571572static const D3D12_RESOURCE_DIMENSION RD_TEXTURE_TYPE_TO_D3D12_RESOURCE_DIMENSION[RD::TEXTURE_TYPE_MAX] = {573D3D12_RESOURCE_DIMENSION_TEXTURE1D,574D3D12_RESOURCE_DIMENSION_TEXTURE2D,575D3D12_RESOURCE_DIMENSION_TEXTURE3D,576D3D12_RESOURCE_DIMENSION_TEXTURE2D,577D3D12_RESOURCE_DIMENSION_TEXTURE1D,578D3D12_RESOURCE_DIMENSION_TEXTURE2D,579D3D12_RESOURCE_DIMENSION_TEXTURE2D,580};581582void RenderingDeviceDriverD3D12::_resource_transition_batch(CommandBufferInfo *p_command_buffer, ResourceInfo *p_resource, uint32_t p_subresource, uint32_t p_num_planes, D3D12_RESOURCE_STATES p_new_state) {583DEV_ASSERT(p_subresource != UINT32_MAX); // We don't support an "all-resources" command here.584585ResourceInfo::States *res_states = p_resource->states_ptr;586D3D12_RESOURCE_STATES *curr_state = &res_states->subresource_states[p_subresource];587588// Transitions can be considered redundant if the current state has all the bits of the new state.589// This check does not apply to the common state however, which must resort to checking if the state is the same (0).590bool any_state_is_common = *curr_state == D3D12_RESOURCE_STATE_COMMON || p_new_state == D3D12_RESOURCE_STATE_COMMON;591bool redundant_transition = any_state_is_common ? *curr_state == p_new_state : ((*curr_state) & p_new_state) == p_new_state;592if (redundant_transition) {593bool just_written = *curr_state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS;594bool needs_uav_barrier = just_written && res_states->last_batch_with_uav_barrier != p_command_buffer->res_barriers_batch;595if (needs_uav_barrier) {596if (p_command_buffer->res_barriers.size() < p_command_buffer->res_barriers_count + 1) {597p_command_buffer->res_barriers.resize(p_command_buffer->res_barriers_count + 1);598}599p_command_buffer->res_barriers[p_command_buffer->res_barriers_count] = CD3DX12_RESOURCE_BARRIER::UAV(p_resource->resource);600p_command_buffer->res_barriers_count++;601res_states->last_batch_with_uav_barrier = p_command_buffer->res_barriers_batch;602}603} else {604uint64_t subres_mask_piece = ((uint64_t)1 << (p_subresource & 0b111111));605uint8_t subres_qword = p_subresource >> 6;606607if (p_command_buffer->res_barriers_requests.has(res_states)) {608BarrierRequest &br = p_command_buffer->res_barriers_requests.get(res_states);609DEV_ASSERT(br.dx_resource == p_resource->resource);610DEV_ASSERT(br.subres_mask_qwords == STEPIFY(res_states->subresource_states.size(), 64) / 64);611DEV_ASSERT(br.planes == p_num_planes);612613// First, find if the subresource already has a barrier scheduled.614uint8_t curr_group_idx = 0;615bool same_transition_scheduled = false;616for (curr_group_idx = 0; curr_group_idx < br.groups_count; curr_group_idx++) {617if (unlikely(br.groups[curr_group_idx].states == BarrierRequest::DELETED_GROUP)) {618continue;619}620if ((br.groups[curr_group_idx].subres_mask[subres_qword] & subres_mask_piece)) {621uint32_t state_mask = br.groups[curr_group_idx].states;622same_transition_scheduled = (state_mask & (uint32_t)p_new_state) == (uint32_t)p_new_state;623break;624}625}626if (!same_transition_scheduled) {627bool subres_already_there = curr_group_idx != br.groups_count;628D3D12_RESOURCE_STATES final_states = {};629if (subres_already_there) {630final_states = br.groups[curr_group_idx].states;631final_states |= p_new_state;632bool subres_alone = true;633for (uint8_t i = 0; i < br.subres_mask_qwords; i++) {634if (i == subres_qword) {635if (br.groups[curr_group_idx].subres_mask[i] != subres_mask_piece) {636subres_alone = false;637break;638}639} else {640if (br.groups[curr_group_idx].subres_mask[i] != 0) {641subres_alone = false;642break;643}644}645}646bool relocated = false;647if (subres_alone) {648// Subresource is there by itself.649for (uint8_t i = 0; i < br.groups_count; i++) {650if (unlikely(i == curr_group_idx)) {651continue;652}653if (unlikely(br.groups[i].states == BarrierRequest::DELETED_GROUP)) {654continue;655}656// There's another group with the final states; relocate to it.657if (br.groups[i].states == final_states) {658br.groups[curr_group_idx].subres_mask[subres_qword] &= ~subres_mask_piece;659relocated = true;660break;661}662}663if (relocated) {664// Let's delete the group where it used to be by itself.665if (curr_group_idx == br.groups_count - 1) {666br.groups_count--;667} else {668br.groups[curr_group_idx].states = BarrierRequest::DELETED_GROUP;669}670} else {671// Its current group, where it's alone, can extend its states.672br.groups[curr_group_idx].states = final_states;673}674} else {675// Already there, but not by itself and the state mask is different, so it now belongs to a different group.676br.groups[curr_group_idx].subres_mask[subres_qword] &= ~subres_mask_piece;677subres_already_there = false;678}679} else {680final_states = p_new_state;681}682if (!subres_already_there) {683// See if it fits exactly the states of some of the groups to fit it there.684for (uint8_t i = 0; i < br.groups_count; i++) {685if (unlikely(i == curr_group_idx)) {686continue;687}688if (unlikely(br.groups[i].states == BarrierRequest::DELETED_GROUP)) {689continue;690}691if (br.groups[i].states == final_states) {692br.groups[i].subres_mask[subres_qword] |= subres_mask_piece;693subres_already_there = true;694break;695}696}697if (!subres_already_there) {698// Add a new group to accommodate this subresource.699uint8_t group_to_fill = 0;700if (br.groups_count < BarrierRequest::MAX_GROUPS) {701// There are still free groups.702group_to_fill = br.groups_count;703br.groups_count++;704} else {705// Let's try to take over a deleted one.706for (; group_to_fill < br.groups_count; group_to_fill++) {707if (unlikely(br.groups[group_to_fill].states == BarrierRequest::DELETED_GROUP)) {708break;709}710}711CRASH_COND(group_to_fill == br.groups_count);712}713714br.groups[group_to_fill].states = final_states;715for (uint8_t i = 0; i < br.subres_mask_qwords; i++) {716if (unlikely(i == subres_qword)) {717br.groups[group_to_fill].subres_mask[i] = subres_mask_piece;718} else {719br.groups[group_to_fill].subres_mask[i] = 0;720}721}722}723}724}725} else {726BarrierRequest &br = p_command_buffer->res_barriers_requests[res_states];727br.dx_resource = p_resource->resource;728br.subres_mask_qwords = STEPIFY(p_resource->states_ptr->subresource_states.size(), 64) / 64;729CRASH_COND(p_resource->states_ptr->subresource_states.size() > BarrierRequest::MAX_SUBRESOURCES);730br.planes = p_num_planes;731br.groups[0].states = p_new_state;732for (uint8_t i = 0; i < br.subres_mask_qwords; i++) {733if (unlikely(i == subres_qword)) {734br.groups[0].subres_mask[i] = subres_mask_piece;735} else {736br.groups[0].subres_mask[i] = 0;737}738}739br.groups_count = 1;740}741}742}743744void RenderingDeviceDriverD3D12::_resource_transitions_flush(CommandBufferInfo *p_command_buffer) {745for (const KeyValue<ResourceInfo::States *, BarrierRequest> &E : p_command_buffer->res_barriers_requests) {746ResourceInfo::States *res_states = E.key;747const BarrierRequest &br = E.value;748749uint32_t num_subresources = res_states->subresource_states.size();750751// When there's not a lot of subresources, the empirical finding is that it's better752// to avoid attempting the single-barrier optimization.753static const uint32_t SINGLE_BARRIER_ATTEMPT_MAX_NUM_SUBRESOURCES = 48;754755bool may_do_single_barrier = br.groups_count == 1 && num_subresources * br.planes >= SINGLE_BARRIER_ATTEMPT_MAX_NUM_SUBRESOURCES;756if (may_do_single_barrier) {757// A single group means we may be able to do a single all-subresources barrier.758759{760// First requisite is that all subresources are involved.761762uint8_t subres_mask_full_qwords = num_subresources / 64;763for (uint32_t i = 0; i < subres_mask_full_qwords; i++) {764if (br.groups[0].subres_mask[i] != UINT64_MAX) {765may_do_single_barrier = false;766break;767}768}769if (may_do_single_barrier) {770if (num_subresources % 64) {771DEV_ASSERT(br.subres_mask_qwords == subres_mask_full_qwords + 1);772uint64_t mask_tail_qword = 0;773for (uint8_t i = 0; i < num_subresources % 64; i++) {774mask_tail_qword |= ((uint64_t)1 << i);775}776if ((br.groups[0].subres_mask[subres_mask_full_qwords] & mask_tail_qword) != mask_tail_qword) {777may_do_single_barrier = false;778}779}780}781}782783if (may_do_single_barrier) {784// Second requisite is that the source state is the same for all.785786for (uint32_t i = 1; i < num_subresources; i++) {787if (res_states->subresource_states[i] != res_states->subresource_states[0]) {788may_do_single_barrier = false;789break;790}791}792793if (may_do_single_barrier) {794// Hurray!, we can do a single barrier (plus maybe a UAV one, too).795796bool just_written = res_states->subresource_states[0] == D3D12_RESOURCE_STATE_UNORDERED_ACCESS;797bool needs_uav_barrier = just_written && res_states->last_batch_with_uav_barrier != p_command_buffer->res_barriers_batch;798799uint32_t needed_barriers = (needs_uav_barrier ? 1 : 0) + 1;800if (p_command_buffer->res_barriers.size() < p_command_buffer->res_barriers_count + needed_barriers) {801p_command_buffer->res_barriers.resize(p_command_buffer->res_barriers_count + needed_barriers);802}803804if (needs_uav_barrier) {805p_command_buffer->res_barriers[p_command_buffer->res_barriers_count] = CD3DX12_RESOURCE_BARRIER::UAV(br.dx_resource);806p_command_buffer->res_barriers_count++;807res_states->last_batch_with_uav_barrier = p_command_buffer->res_barriers_batch;808}809810if (res_states->subresource_states[0] != br.groups[0].states) {811p_command_buffer->res_barriers[p_command_buffer->res_barriers_count] = CD3DX12_RESOURCE_BARRIER::Transition(br.dx_resource, res_states->subresource_states[0], br.groups[0].states, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES);812p_command_buffer->res_barriers_count++;813}814815for (uint32_t i = 0; i < num_subresources; i++) {816res_states->subresource_states[i] = br.groups[0].states;817}818}819}820}821822if (!may_do_single_barrier) {823for (uint8_t i = 0; i < br.groups_count; i++) {824const BarrierRequest::Group &g = E.value.groups[i];825826if (unlikely(g.states == BarrierRequest::DELETED_GROUP)) {827continue;828}829830uint32_t subresource = 0;831do {832uint64_t subres_mask_piece = ((uint64_t)1 << (subresource % 64));833uint8_t subres_qword = subresource / 64;834835if (likely(g.subres_mask[subres_qword] == 0)) {836subresource += 64;837continue;838}839840if (likely(!(g.subres_mask[subres_qword] & subres_mask_piece))) {841subresource++;842continue;843}844845D3D12_RESOURCE_STATES *curr_state = &res_states->subresource_states[subresource];846847bool just_written = *curr_state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS;848bool needs_uav_barrier = just_written && res_states->last_batch_with_uav_barrier != p_command_buffer->res_barriers_batch;849850uint32_t needed_barriers = (needs_uav_barrier ? 1 : 0) + br.planes;851if (p_command_buffer->res_barriers.size() < p_command_buffer->res_barriers_count + needed_barriers) {852p_command_buffer->res_barriers.resize(p_command_buffer->res_barriers_count + needed_barriers);853}854855if (needs_uav_barrier) {856p_command_buffer->res_barriers[p_command_buffer->res_barriers_count] = CD3DX12_RESOURCE_BARRIER::UAV(br.dx_resource);857p_command_buffer->res_barriers_count++;858res_states->last_batch_with_uav_barrier = p_command_buffer->res_barriers_batch;859}860861if (*curr_state != g.states) {862for (uint8_t k = 0; k < br.planes; k++) {863p_command_buffer->res_barriers[p_command_buffer->res_barriers_count] = CD3DX12_RESOURCE_BARRIER::Transition(br.dx_resource, *curr_state, g.states, subresource + k * num_subresources);864p_command_buffer->res_barriers_count++;865}866}867868*curr_state = g.states;869870subresource++;871} while (subresource < num_subresources);872}873}874}875876if (p_command_buffer->res_barriers_count) {877p_command_buffer->cmd_list->ResourceBarrier(p_command_buffer->res_barriers_count, p_command_buffer->res_barriers.ptr());878p_command_buffer->res_barriers_requests.clear();879}880881p_command_buffer->res_barriers_count = 0;882p_command_buffer->res_barriers_batch++;883}884885/*****************/886/**** BUFFERS ****/887/*****************/888889RDD::BufferID RenderingDeviceDriverD3D12::buffer_create(uint64_t p_size, BitField<BufferUsageBits> p_usage, MemoryAllocationType p_allocation_type, uint64_t p_frames_drawn) {890uint32_t alignment = D3D12_RAW_UAV_SRV_BYTE_ALIGNMENT; // 16 bytes is reasonable.891if (p_usage.has_flag(BUFFER_USAGE_UNIFORM_BIT)) {892// 256 bytes is absurd. Only use it when required.893alignment = D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT;894}895896// We don't have VMA like in Vulkan, that takes care of the details. We must align the size.897p_size = STEPIFY(p_size, alignment);898899const size_t original_size = p_size;900if (p_usage.has_flag(BUFFER_USAGE_DYNAMIC_PERSISTENT_BIT)) {901p_size = p_size * frames.size();902}903904CD3DX12_RESOURCE_DESC1 resource_desc = CD3DX12_RESOURCE_DESC1::Buffer(p_size);905if (p_usage.has_flag(RDD::BUFFER_USAGE_STORAGE_BIT)) {906resource_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;907} else {908resource_desc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;909}910911D3D12MA::ALLOCATION_DESC allocation_desc = {};912allocation_desc.HeapType = D3D12_HEAP_TYPE_DEFAULT;913D3D12_RESOURCE_STATES initial_state = D3D12_RESOURCE_STATE_COMMON;914switch (p_allocation_type) {915case MEMORY_ALLOCATION_TYPE_CPU: {916bool is_src = p_usage.has_flag(BUFFER_USAGE_TRANSFER_FROM_BIT);917bool is_dst = p_usage.has_flag(BUFFER_USAGE_TRANSFER_TO_BIT);918if (is_src && !is_dst) {919// Looks like a staging buffer: CPU maps, writes sequentially, then GPU copies to VRAM.920allocation_desc.HeapType = D3D12_HEAP_TYPE_UPLOAD;921initial_state = D3D12_RESOURCE_STATE_GENERIC_READ;922}923if (is_dst && !is_src) {924// Looks like a readback buffer: GPU copies from VRAM, then CPU maps and reads.925allocation_desc.HeapType = D3D12_HEAP_TYPE_READBACK;926initial_state = D3D12_RESOURCE_STATE_COPY_DEST;927}928} break;929case MEMORY_ALLOCATION_TYPE_GPU: {930// Use default parameters.931if (p_usage.has_flag(BUFFER_USAGE_DYNAMIC_PERSISTENT_BIT)) {932allocation_desc.HeapType = dynamic_persistent_upload_heap;933934// D3D12_HEAP_TYPE_UPLOAD mandates D3D12_RESOURCE_STATE_GENERIC_READ.935if (dynamic_persistent_upload_heap == D3D12_HEAP_TYPE_UPLOAD) {936initial_state = D3D12_RESOURCE_STATE_GENERIC_READ;937}938939// We can't use STORAGE for write access, just for read.940resource_desc.Flags = resource_desc.Flags & ~D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;941}942} break;943}944945ComPtr<ID3D12Resource> buffer;946ComPtr<D3D12MA::Allocation> allocation;947HRESULT res;948if (barrier_capabilities.enhanced_barriers_supported) {949res = allocator->CreateResource3(950&allocation_desc,951&resource_desc,952D3D12_BARRIER_LAYOUT_UNDEFINED,953nullptr,9540,955nullptr,956allocation.GetAddressOf(),957IID_PPV_ARGS(buffer.GetAddressOf()));958} else {959res = allocator->CreateResource(960&allocation_desc,961reinterpret_cast<const D3D12_RESOURCE_DESC *>(&resource_desc),962initial_state,963nullptr,964allocation.GetAddressOf(),965IID_PPV_ARGS(buffer.GetAddressOf()));966}967968ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), BufferID(), "Can't create buffer of size: " + itos(p_size) + ", error " + vformat("0x%08ux", (uint64_t)res) + ".");969970// Bookkeep.971972BufferInfo *buf_info;973if (p_usage.has_flag(BUFFER_USAGE_DYNAMIC_PERSISTENT_BIT)) {974void *persistent_ptr = nullptr;975res = buffer->Map(0, &VOID_RANGE, &persistent_ptr);976ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), BufferID(), "Map failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");977978BufferDynamicInfo *dyn_buffer = VersatileResource::allocate<BufferDynamicInfo>(resources_allocator);979buf_info = dyn_buffer;980#ifdef DEBUG_ENABLED981dyn_buffer->last_frame_mapped = p_frames_drawn - 1ul;982#endif983dyn_buffer->frame_idx = 0u;984dyn_buffer->persistent_ptr = (uint8_t *)persistent_ptr;985} else {986buf_info = VersatileResource::allocate<BufferInfo>(resources_allocator);987}988buf_info->resource = buffer.Get();989buf_info->owner_info.resource = buffer;990buf_info->owner_info.allocation = allocation;991buf_info->owner_info.states.subresource_states.push_back(initial_state);992buf_info->states_ptr = &buf_info->owner_info.states;993buf_info->gpu_virtual_address = buffer->GetGPUVirtualAddress();994buf_info->size = original_size;995buf_info->flags.is_dynamic = p_usage.has_flag(BUFFER_USAGE_DYNAMIC_PERSISTENT_BIT);996997return BufferID(buf_info);998}9991000bool RenderingDeviceDriverD3D12::buffer_set_texel_format(BufferID p_buffer, DataFormat p_format) {1001BufferInfo *buf_info = (BufferInfo *)p_buffer.id;1002buf_info->texel_format = p_format;1003return true;1004}10051006void RenderingDeviceDriverD3D12::buffer_free(BufferID p_buffer) {1007BufferInfo *buf_info = (BufferInfo *)p_buffer.id;1008if (buf_info->is_dynamic()) {1009buf_info->resource->Unmap(0, &VOID_RANGE);1010VersatileResource::free(resources_allocator, (BufferDynamicInfo *)buf_info);1011} else {1012VersatileResource::free(resources_allocator, buf_info);1013}1014}10151016uint64_t RenderingDeviceDriverD3D12::buffer_get_allocation_size(BufferID p_buffer) {1017const BufferInfo *buf_info = (const BufferInfo *)p_buffer.id;1018return buf_info->owner_info.allocation ? buf_info->owner_info.allocation->GetSize() : 0;1019}10201021uint8_t *RenderingDeviceDriverD3D12::buffer_map(BufferID p_buffer) {1022const BufferInfo *buf_info = (const BufferInfo *)p_buffer.id;1023void *data_ptr = nullptr;1024HRESULT res = buf_info->resource->Map(0, &VOID_RANGE, &data_ptr);1025ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), nullptr, "Map failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");1026return (uint8_t *)data_ptr;1027}10281029void RenderingDeviceDriverD3D12::buffer_unmap(BufferID p_buffer) {1030const BufferInfo *buf_info = (const BufferInfo *)p_buffer.id;1031buf_info->resource->Unmap(0, &VOID_RANGE);1032}10331034uint8_t *RenderingDeviceDriverD3D12::buffer_persistent_map_advance(BufferID p_buffer, uint64_t p_frames_drawn) {1035BufferDynamicInfo *buf_info = (BufferDynamicInfo *)p_buffer.id;1036ERR_FAIL_COND_V_MSG(!buf_info->is_dynamic(), nullptr, "Buffer must have BUFFER_USAGE_DYNAMIC_PERSISTENT_BIT. Use buffer_map() instead.");1037#ifdef DEBUG_ENABLED1038ERR_FAIL_COND_V_MSG(buf_info->last_frame_mapped == p_frames_drawn, nullptr, "Buffers with BUFFER_USAGE_DYNAMIC_PERSISTENT_BIT must only be mapped once per frame. Otherwise there could be race conditions with the GPU. Amalgamate all data uploading into one map(), use an extra buffer or remove the bit.");1039buf_info->last_frame_mapped = p_frames_drawn;1040#endif1041buf_info->frame_idx = (buf_info->frame_idx + 1u) % frames.size();1042return buf_info->persistent_ptr + buf_info->frame_idx * buf_info->size;1043}10441045uint64_t RenderingDeviceDriverD3D12::buffer_get_dynamic_offsets(Span<BufferID> p_buffers) {1046uint64_t mask = 0u;1047uint64_t shift = 0u;10481049for (const BufferID &buf : p_buffers) {1050const BufferInfo *buf_info = (const BufferInfo *)buf.id;1051if (!buf_info->is_dynamic()) {1052continue;1053}1054const BufferDynamicInfo *dyn_buf = (const BufferDynamicInfo *)buf.id;1055mask |= dyn_buf->frame_idx << shift;1056// We can encode the frame index in 2 bits since frame_count won't be > 4.1057shift += 2UL;1058}10591060return mask;1061}10621063uint64_t RenderingDeviceDriverD3D12::buffer_get_device_address(BufferID p_buffer) {1064const BufferInfo *buf_info = (const BufferInfo *)p_buffer.id;1065return buf_info->gpu_virtual_address;1066}10671068/*****************/1069/**** TEXTURE ****/1070/*****************/10711072static const D3D12_SRV_DIMENSION RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_SRV[RD::TEXTURE_TYPE_MAX] = {1073D3D12_SRV_DIMENSION_TEXTURE1D,1074D3D12_SRV_DIMENSION_TEXTURE2D,1075D3D12_SRV_DIMENSION_TEXTURE3D,1076D3D12_SRV_DIMENSION_TEXTURECUBE,1077D3D12_SRV_DIMENSION_TEXTURE1DARRAY,1078D3D12_SRV_DIMENSION_TEXTURE2DARRAY,1079D3D12_SRV_DIMENSION_TEXTURECUBEARRAY,1080};10811082static const D3D12_SRV_DIMENSION RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_SRV_MS[RD::TEXTURE_TYPE_MAX] = {1083D3D12_SRV_DIMENSION_UNKNOWN,1084D3D12_SRV_DIMENSION_TEXTURE2DMS,1085D3D12_SRV_DIMENSION_UNKNOWN,1086D3D12_SRV_DIMENSION_UNKNOWN,1087D3D12_SRV_DIMENSION_UNKNOWN,1088D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY,1089D3D12_SRV_DIMENSION_UNKNOWN,1090};10911092static const D3D12_UAV_DIMENSION RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_UAV[RD::TEXTURE_TYPE_MAX] = {1093D3D12_UAV_DIMENSION_TEXTURE1D,1094D3D12_UAV_DIMENSION_TEXTURE2D,1095D3D12_UAV_DIMENSION_TEXTURE3D,1096D3D12_UAV_DIMENSION_TEXTURE2DARRAY,1097D3D12_UAV_DIMENSION_TEXTURE1DARRAY,1098D3D12_UAV_DIMENSION_TEXTURE2DARRAY,1099D3D12_UAV_DIMENSION_TEXTURE2DARRAY,1100};11011102uint32_t RenderingDeviceDriverD3D12::_find_max_common_supported_sample_count(VectorView<DXGI_FORMAT> p_formats) {1103uint32_t common = UINT32_MAX;11041105MutexLock lock(format_sample_counts_mask_cache_mutex);1106for (uint32_t i = 0; i < p_formats.size(); i++) {1107if (format_sample_counts_mask_cache.has(p_formats[i])) {1108common &= format_sample_counts_mask_cache[p_formats[i]];1109} else {1110D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msql = {};1111msql.Format = p_formats[i];1112uint32_t mask = 0;1113for (int samples = 1 << (TEXTURE_SAMPLES_MAX - 1); samples >= 1; samples /= 2) {1114msql.SampleCount = (UINT)samples;1115HRESULT res = device->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &msql, sizeof(msql));1116if (SUCCEEDED(res) && msql.NumQualityLevels) {1117int bit = get_shift_from_power_of_2((uint32_t)samples);1118ERR_FAIL_COND_V(bit == -1, 1);1119mask |= (uint32_t)(1 << bit);1120}1121}1122format_sample_counts_mask_cache.insert(p_formats[i], mask);1123common &= mask;1124}1125}1126if (common == UINT32_MAX) {1127return 1;1128} else {1129return ((uint32_t)1 << nearest_shift(common));1130}1131}11321133UINT RenderingDeviceDriverD3D12::_compute_component_mapping(const RDD::TextureView &p_view) {1134UINT base_swizzle = RD_TO_D3D12_FORMAT[p_view.format].swizzle;11351136D3D12_SHADER_COMPONENT_MAPPING component_swizzles[TEXTURE_SWIZZLE_MAX] = {1137D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0, // Unused.1138D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,1139D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1,1140// These will be D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_*.1141D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(0, base_swizzle),1142D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(1, base_swizzle),1143D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(2, base_swizzle),1144D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(3, base_swizzle),1145};11461147return D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(1148p_view.swizzle_r == TEXTURE_SWIZZLE_IDENTITY ? component_swizzles[TEXTURE_SWIZZLE_R] : component_swizzles[p_view.swizzle_r],1149p_view.swizzle_g == TEXTURE_SWIZZLE_IDENTITY ? component_swizzles[TEXTURE_SWIZZLE_G] : component_swizzles[p_view.swizzle_g],1150p_view.swizzle_b == TEXTURE_SWIZZLE_IDENTITY ? component_swizzles[TEXTURE_SWIZZLE_B] : component_swizzles[p_view.swizzle_b],1151p_view.swizzle_a == TEXTURE_SWIZZLE_IDENTITY ? component_swizzles[TEXTURE_SWIZZLE_A] : component_swizzles[p_view.swizzle_a]);1152}11531154UINT RenderingDeviceDriverD3D12::_compute_plane_slice(DataFormat p_format, BitField<TextureAspectBits> p_aspect_bits) {1155TextureAspect aspect = TEXTURE_ASPECT_MAX;11561157if (p_aspect_bits.has_flag(TEXTURE_ASPECT_COLOR_BIT)) {1158DEV_ASSERT(aspect == TEXTURE_ASPECT_MAX);1159aspect = TEXTURE_ASPECT_COLOR;1160}1161if (p_aspect_bits.has_flag(TEXTURE_ASPECT_DEPTH_BIT)) {1162DEV_ASSERT(aspect == TEXTURE_ASPECT_MAX);1163aspect = TEXTURE_ASPECT_DEPTH;1164} else if (p_aspect_bits.has_flag(TEXTURE_ASPECT_STENCIL_BIT)) {1165DEV_ASSERT(aspect == TEXTURE_ASPECT_MAX);1166aspect = TEXTURE_ASPECT_STENCIL;1167}11681169DEV_ASSERT(aspect != TEXTURE_ASPECT_MAX);11701171return _compute_plane_slice(p_format, aspect);1172}11731174UINT RenderingDeviceDriverD3D12::_compute_plane_slice(DataFormat p_format, TextureAspect p_aspect) {1175switch (p_aspect) {1176case TEXTURE_ASPECT_COLOR:1177// The plane must be 0 for the color aspect (assuming the format is a regular color one, which must be the case).1178return 0;1179case TEXTURE_ASPECT_DEPTH:1180// The plane must be 0 for the color or depth aspect1181return 0;1182case TEXTURE_ASPECT_STENCIL:1183// The plane may be 0 for the stencil aspect (if the format is stencil-only), or 1 (if the format is depth-stencil; other cases are ill).1184return format_get_plane_count(p_format) == 2 ? 1 : 0;1185default:1186DEV_ASSERT(false);1187return 0;1188}1189}11901191UINT RenderingDeviceDriverD3D12::_compute_subresource_from_layers(TextureInfo *p_texture, const TextureSubresourceLayers &p_layers, uint32_t p_layer_offset) {1192return D3D12CalcSubresource(p_layers.mipmap, p_layers.base_layer + p_layer_offset, _compute_plane_slice(p_texture->format, p_layers.aspect), p_texture->desc.MipLevels, p_texture->desc.ArraySize());1193}11941195void RenderingDeviceDriverD3D12::_discard_texture_subresources(const TextureInfo *p_tex_info, const CommandBufferInfo *p_cmd_buf_info) {1196uint32_t planes = 1;1197if ((p_tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {1198planes = format_get_plane_count(p_tex_info->format);1199}1200D3D12_DISCARD_REGION dr = {};1201dr.NumRects = p_cmd_buf_info->render_pass_state.region_is_all ? 0 : 1;1202dr.pRects = p_cmd_buf_info->render_pass_state.region_is_all ? nullptr : &p_cmd_buf_info->render_pass_state.region_rect;1203dr.FirstSubresource = UINT_MAX;1204dr.NumSubresources = 0;1205for (uint32_t u = 0; u < planes; u++) {1206for (uint32_t v = 0; v < p_tex_info->layers; v++) {1207for (uint32_t w = 0; w < p_tex_info->mipmaps; w++) {1208UINT subresource = D3D12CalcSubresource(1209p_tex_info->base_mip + w,1210p_tex_info->base_layer + v,1211u,1212p_tex_info->desc.MipLevels,1213p_tex_info->desc.ArraySize());1214if (dr.NumSubresources == 0) {1215dr.FirstSubresource = subresource;1216dr.NumSubresources = 1;1217} else if (dr.FirstSubresource + dr.NumSubresources == subresource) {1218dr.NumSubresources++;1219} else {1220p_cmd_buf_info->cmd_list->DiscardResource(p_tex_info->resource, &dr);1221dr.FirstSubresource = subresource;1222dr.NumSubresources = 1;1223}1224}1225}1226}1227if (dr.NumSubresources) {1228p_cmd_buf_info->cmd_list->DiscardResource(p_tex_info->resource, &dr);1229}1230}12311232bool RenderingDeviceDriverD3D12::_unordered_access_supported_by_format(DataFormat p_format) {1233switch (p_format) {1234case DATA_FORMAT_R4G4_UNORM_PACK8:1235case DATA_FORMAT_R4G4B4A4_UNORM_PACK16:1236case DATA_FORMAT_B4G4R4A4_UNORM_PACK16:1237case DATA_FORMAT_R5G6B5_UNORM_PACK16:1238case DATA_FORMAT_B5G6R5_UNORM_PACK16:1239case DATA_FORMAT_R5G5B5A1_UNORM_PACK16:1240case DATA_FORMAT_B5G5R5A1_UNORM_PACK16:1241case DATA_FORMAT_A1R5G5B5_UNORM_PACK16:1242case DATA_FORMAT_A8B8G8R8_UNORM_PACK32:1243case DATA_FORMAT_A8B8G8R8_SNORM_PACK32:1244case DATA_FORMAT_A8B8G8R8_USCALED_PACK32:1245case DATA_FORMAT_A8B8G8R8_SSCALED_PACK32:1246case DATA_FORMAT_A8B8G8R8_UINT_PACK32:1247case DATA_FORMAT_A8B8G8R8_SINT_PACK32:1248case DATA_FORMAT_A8B8G8R8_SRGB_PACK32:1249case DATA_FORMAT_A2R10G10B10_UNORM_PACK32:1250case DATA_FORMAT_A2R10G10B10_SNORM_PACK32:1251case DATA_FORMAT_A2R10G10B10_USCALED_PACK32:1252case DATA_FORMAT_A2R10G10B10_SSCALED_PACK32:1253case DATA_FORMAT_A2R10G10B10_UINT_PACK32:1254case DATA_FORMAT_A2R10G10B10_SINT_PACK32:1255case DATA_FORMAT_A2B10G10R10_UNORM_PACK32:1256case DATA_FORMAT_A2B10G10R10_SNORM_PACK32:1257case DATA_FORMAT_A2B10G10R10_USCALED_PACK32:1258case DATA_FORMAT_A2B10G10R10_SSCALED_PACK32:1259case DATA_FORMAT_A2B10G10R10_UINT_PACK32:1260case DATA_FORMAT_A2B10G10R10_SINT_PACK32:1261case DATA_FORMAT_B10G11R11_UFLOAT_PACK32:1262case DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32:1263case DATA_FORMAT_X8_D24_UNORM_PACK32:1264case DATA_FORMAT_R10X6_UNORM_PACK16:1265case DATA_FORMAT_R10X6G10X6_UNORM_2PACK16:1266case DATA_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:1267case DATA_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:1268case DATA_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:1269case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:1270case DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:1271case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:1272case DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:1273case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:1274case DATA_FORMAT_R12X4_UNORM_PACK16:1275case DATA_FORMAT_R12X4G12X4_UNORM_2PACK16:1276case DATA_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:1277case DATA_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:1278case DATA_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:1279case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:1280case DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:1281case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:1282case DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:1283case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:1284return false;1285default:1286return true;1287}1288}12891290RDD::TextureID RenderingDeviceDriverD3D12::texture_create(const TextureFormat &p_format, const TextureView &p_view) {1291// Using D3D12_RESOURCE_DESC1. Thanks to the layout, it's sliceable down to D3D12_RESOURCE_DESC if needed.1292CD3DX12_RESOURCE_DESC1 resource_desc = {};1293resource_desc.Dimension = RD_TEXTURE_TYPE_TO_D3D12_RESOURCE_DIMENSION[p_format.texture_type];1294resource_desc.Alignment = 0; // D3D12MA will override this to use a smaller alignment than the default if possible.12951296resource_desc.Width = p_format.width;1297resource_desc.Height = p_format.height;1298resource_desc.DepthOrArraySize = p_format.depth * p_format.array_layers;1299resource_desc.MipLevels = p_format.mipmaps;13001301// Format.1302bool cross_family_sharing = false;1303bool relaxed_casting_available = false;1304DXGI_FORMAT *relaxed_casting_formats = nullptr;1305uint32_t relaxed_casting_format_count = 0;1306{1307resource_desc.Format = RD_TO_D3D12_FORMAT[p_format.format].family;13081309// If views of different families are wanted, special setup is needed for proper sharing among them.1310// If the driver reports relaxed casting is, leverage its new extended resource creation API (via D3D12MA).1311if (p_format.shareable_formats.size() && format_capabilities.relaxed_casting_supported) {1312relaxed_casting_available = true;1313relaxed_casting_formats = ALLOCA_ARRAY(DXGI_FORMAT, p_format.shareable_formats.size() + 1);1314relaxed_casting_formats[0] = RD_TO_D3D12_FORMAT[p_format.format].general_format;1315relaxed_casting_format_count++;1316}13171318HashMap<DataFormat, D3D12_RESOURCE_FLAGS> aliases_forbidden_flags;1319for (int i = 0; i < p_format.shareable_formats.size(); i++) {1320DataFormat curr_format = p_format.shareable_formats[i];1321String format_text = "'" + String(FORMAT_NAMES[p_format.format]) + "'";13221323ERR_FAIL_COND_V_MSG(RD_TO_D3D12_FORMAT[curr_format].family == DXGI_FORMAT_UNKNOWN, TextureID(), "Format " + format_text + " is not supported.");13241325if (RD_TO_D3D12_FORMAT[curr_format].family != RD_TO_D3D12_FORMAT[p_format.format].family) {1326cross_family_sharing = true;1327}13281329if (relaxed_casting_available) {1330relaxed_casting_formats[relaxed_casting_format_count] = RD_TO_D3D12_FORMAT[curr_format].general_format;1331relaxed_casting_format_count++;1332}1333}13341335if (cross_family_sharing && !relaxed_casting_available) {1336// Per https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_texture_layout.1337if (p_format.texture_type == TEXTURE_TYPE_1D) {1338ERR_FAIL_V_MSG(TextureID(), "This texture's views require aliasing, but that's not supported for a 1D texture.");1339}1340if (p_format.samples != TEXTURE_SAMPLES_1) {1341ERR_FAIL_V_MSG(TextureID(), "This texture's views require aliasing, but that's not supported for a multi-sample texture.");1342}1343if ((p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {1344ERR_FAIL_V_MSG(TextureID(), "This texture's views require aliasing, but that's not supported for a depth-stencil texture.");1345}1346if (RD_TO_D3D12_FORMAT[p_format.format].family == DXGI_FORMAT_R32G32B32_TYPELESS) {1347ERR_FAIL_V_MSG(TextureID(), "This texture's views require aliasing, but that's not supported for an R32G32B32 texture.");1348}1349}1350}13511352// Usage.1353if ((p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {1354resource_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;1355} else {1356if ((p_format.usage_bits & TEXTURE_USAGE_CAN_COPY_TO_BIT) && _unordered_access_supported_by_format(p_format.format)) {1357resource_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; // For clearing via UAV.1358}1359}1360if ((p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {1361resource_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;1362}1363if ((p_format.usage_bits & TEXTURE_USAGE_STORAGE_BIT)) {1364resource_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;1365}1366if ((p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT)) {1367ERR_FAIL_V_MSG(TextureID(), "CPU readable textures are unsupported on D3D12.");1368}1369if ((p_format.usage_bits & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) && (p_format.usage_bits & TEXTURE_USAGE_VRS_FRAGMENT_SHADING_RATE_BIT)) {1370// For VRS images we can't use the typeless format.1371resource_desc.Format = DXGI_FORMAT_R8_UINT;1372}13731374resource_desc.SampleDesc = {};1375DXGI_FORMAT format_to_test = (resource_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) ? RD_TO_D3D12_FORMAT[p_format.format].dsv_format : RD_TO_D3D12_FORMAT[p_format.format].general_format;1376if (!(resource_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)) {1377resource_desc.SampleDesc.Count = MIN(1378_find_max_common_supported_sample_count(format_to_test),1379TEXTURE_SAMPLES_COUNT[p_format.samples]);1380} else {1381// No MSAA in D3D12 if storage. May have become possible recently where supported, though.1382resource_desc.SampleDesc.Count = 1;1383}1384resource_desc.SampleDesc.Quality = resource_desc.SampleDesc.Count == 1 ? 0 : DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN;13851386// Create.13871388D3D12MA::ALLOCATION_DESC allocation_desc = {};1389allocation_desc.HeapType = D3D12_HEAP_TYPE_DEFAULT;1390if ((resource_desc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL))) {1391allocation_desc.ExtraHeapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES;1392} else {1393allocation_desc.ExtraHeapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES;1394}1395if ((resource_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)) {1396allocation_desc.ExtraHeapFlags |= D3D12_HEAP_FLAG_ALLOW_SHADER_ATOMICS;1397}13981399D3D12_RESOURCE_STATES initial_state = {};1400ID3D12Resource *texture = nullptr;1401ComPtr<ID3D12Resource> main_texture;1402ComPtr<D3D12MA::Allocation> allocation;1403static const FLOAT black[4] = {};1404D3D12_CLEAR_VALUE clear_value = CD3DX12_CLEAR_VALUE(RD_TO_D3D12_FORMAT[p_format.format].general_format, black);1405D3D12_CLEAR_VALUE *clear_value_ptr = (resource_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) ? &clear_value : nullptr;1406{1407HRESULT res = E_FAIL;1408if (barrier_capabilities.enhanced_barriers_supported || (cross_family_sharing && relaxed_casting_available)) {1409// Create with undefined layout if enhanced barriers are supported. Leave as common otherwise for interop with legacy barriers.1410D3D12_BARRIER_LAYOUT initial_layout = barrier_capabilities.enhanced_barriers_supported ? D3D12_BARRIER_LAYOUT_UNDEFINED : D3D12_BARRIER_LAYOUT_COMMON;1411res = allocator->CreateResource3(1412&allocation_desc,1413&resource_desc,1414initial_layout,1415clear_value_ptr,1416relaxed_casting_format_count,1417relaxed_casting_formats,1418allocation.GetAddressOf(),1419IID_PPV_ARGS(main_texture.GetAddressOf()));1420initial_state = D3D12_RESOURCE_STATE_COMMON;1421} else {1422res = allocator->CreateResource(1423&allocation_desc,1424(D3D12_RESOURCE_DESC *)&resource_desc,1425D3D12_RESOURCE_STATE_COPY_DEST,1426clear_value_ptr,1427allocation.GetAddressOf(),1428IID_PPV_ARGS(main_texture.GetAddressOf()));1429initial_state = D3D12_RESOURCE_STATE_COPY_DEST;1430}1431ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), TextureID(), "CreateResource failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");1432texture = main_texture.Get();1433}14341435// Describe views.14361437D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {};1438{1439srv_desc.Format = RD_TO_D3D12_FORMAT[p_view.format].general_format;1440srv_desc.ViewDimension = p_format.samples == TEXTURE_SAMPLES_1 ? RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_SRV[p_format.texture_type] : RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_SRV_MS[p_format.texture_type];1441srv_desc.Shader4ComponentMapping = _compute_component_mapping(p_view);14421443switch (srv_desc.ViewDimension) {1444case D3D12_SRV_DIMENSION_TEXTURE1D: {1445srv_desc.Texture1D.MipLevels = p_format.mipmaps;1446} break;1447case D3D12_SRV_DIMENSION_TEXTURE1DARRAY: {1448srv_desc.Texture1DArray.MipLevels = p_format.mipmaps;1449srv_desc.Texture1DArray.ArraySize = p_format.array_layers;1450} break;1451case D3D12_SRV_DIMENSION_TEXTURE2D: {1452srv_desc.Texture2D.MipLevels = p_format.mipmaps;1453} break;1454case D3D12_SRV_DIMENSION_TEXTURE2DMS: {1455} break;1456case D3D12_SRV_DIMENSION_TEXTURE2DARRAY: {1457srv_desc.Texture2DArray.MipLevels = p_format.mipmaps;1458srv_desc.Texture2DArray.ArraySize = p_format.array_layers;1459} break;1460case D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY: {1461srv_desc.Texture2DMSArray.ArraySize = p_format.array_layers;1462} break;1463case D3D12_SRV_DIMENSION_TEXTURECUBEARRAY: {1464srv_desc.TextureCubeArray.MipLevels = p_format.mipmaps;1465srv_desc.TextureCubeArray.NumCubes = p_format.array_layers / 6;1466} break;1467case D3D12_SRV_DIMENSION_TEXTURE3D: {1468srv_desc.Texture3D.MipLevels = p_format.mipmaps;1469} break;1470case D3D12_SRV_DIMENSION_TEXTURECUBE: {1471srv_desc.TextureCube.MipLevels = p_format.mipmaps;1472} break;1473default: {1474}1475}1476}14771478D3D12_UNORDERED_ACCESS_VIEW_DESC main_uav_desc = {};1479{1480main_uav_desc.Format = RD_TO_D3D12_FORMAT[p_format.format].general_format;1481main_uav_desc.ViewDimension = p_format.samples == TEXTURE_SAMPLES_1 ? RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_UAV[p_format.texture_type] : D3D12_UAV_DIMENSION_UNKNOWN;14821483switch (main_uav_desc.ViewDimension) {1484case D3D12_UAV_DIMENSION_TEXTURE1DARRAY: {1485main_uav_desc.Texture1DArray.ArraySize = p_format.array_layers;1486} break;1487case D3D12_UAV_DIMENSION_TEXTURE2DARRAY: {1488// Either for an actual 2D texture array, cubemap or cubemap array.1489main_uav_desc.Texture2DArray.ArraySize = p_format.array_layers;1490} break;1491case D3D12_UAV_DIMENSION_TEXTURE3D: {1492main_uav_desc.Texture3D.WSize = p_format.depth;1493} break;1494default: {1495}1496}1497}14981499D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = main_uav_desc;1500uav_desc.Format = RD_TO_D3D12_FORMAT[p_view.format].general_format;15011502// Bookkeep.15031504TextureInfo *tex_info = VersatileResource::allocate<TextureInfo>(resources_allocator);1505tex_info->resource = texture;1506tex_info->owner_info.resource = main_texture;1507tex_info->owner_info.allocation = allocation;1508tex_info->owner_info.states.subresource_states.resize(p_format.mipmaps * p_format.array_layers);1509for (uint32_t i = 0; i < tex_info->owner_info.states.subresource_states.size(); i++) {1510tex_info->owner_info.states.subresource_states[i] = initial_state;1511}1512tex_info->states_ptr = &tex_info->owner_info.states;1513tex_info->format = p_format.format;1514GODOT_GCC_WARNING_PUSH_AND_IGNORE("-Wstrict-aliasing")1515tex_info->desc = *(CD3DX12_RESOURCE_DESC *)&resource_desc;1516GODOT_GCC_WARNING_POP1517tex_info->base_layer = 0;1518tex_info->layers = resource_desc.ArraySize();1519tex_info->base_mip = 0;1520tex_info->mipmaps = resource_desc.MipLevels;1521tex_info->view_descs.srv = srv_desc;1522tex_info->view_descs.uav = uav_desc;15231524return TextureID(tex_info);1525}15261527RDD::TextureID RenderingDeviceDriverD3D12::texture_create_from_extension(uint64_t p_native_texture, TextureType p_type, DataFormat p_format, uint32_t p_array_layers, bool p_depth_stencil, uint32_t p_mipmaps) {1528ID3D12Resource *texture = (ID3D12Resource *)p_native_texture;15291530#if defined(_MSC_VER) || !defined(_WIN32)1531const D3D12_RESOURCE_DESC base_resource_desc = texture->GetDesc();1532#else1533D3D12_RESOURCE_DESC base_resource_desc;1534texture->GetDesc(&base_resource_desc);1535#endif1536CD3DX12_RESOURCE_DESC resource_desc(base_resource_desc);1537D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {};1538{1539srv_desc.Format = RD_TO_D3D12_FORMAT[p_format].general_format;1540srv_desc.ViewDimension = resource_desc.SampleDesc.Count == 1 ? RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_SRV[p_type] : RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_SRV_MS[p_type];1541srv_desc.Shader4ComponentMapping = _compute_component_mapping(TextureView{ p_format });15421543switch (srv_desc.ViewDimension) {1544case D3D12_SRV_DIMENSION_TEXTURE1D: {1545srv_desc.Texture1D.MipLevels = resource_desc.MipLevels;1546} break;1547case D3D12_SRV_DIMENSION_TEXTURE1DARRAY: {1548srv_desc.Texture1DArray.MipLevels = resource_desc.MipLevels;1549srv_desc.Texture1DArray.ArraySize = p_array_layers;1550} break;1551case D3D12_SRV_DIMENSION_TEXTURE2D: {1552srv_desc.Texture2D.MipLevels = resource_desc.MipLevels;1553} break;1554case D3D12_SRV_DIMENSION_TEXTURE2DMS: {1555} break;1556case D3D12_SRV_DIMENSION_TEXTURE2DARRAY: {1557srv_desc.Texture2DArray.MipLevels = resource_desc.MipLevels;1558srv_desc.Texture2DArray.ArraySize = p_array_layers;1559} break;1560case D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY: {1561srv_desc.Texture2DMSArray.ArraySize = p_array_layers;1562} break;1563case D3D12_SRV_DIMENSION_TEXTURECUBEARRAY: {1564srv_desc.TextureCubeArray.MipLevels = resource_desc.MipLevels;1565srv_desc.TextureCubeArray.NumCubes = p_array_layers / 6;1566} break;1567case D3D12_SRV_DIMENSION_TEXTURE3D: {1568srv_desc.Texture3D.MipLevels = resource_desc.MipLevels;1569} break;1570case D3D12_SRV_DIMENSION_TEXTURECUBE: {1571srv_desc.TextureCube.MipLevels = resource_desc.MipLevels;1572} break;1573default: {1574}1575}1576}15771578D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = {};1579{1580uav_desc.Format = RD_TO_D3D12_FORMAT[p_format].general_format;1581uav_desc.ViewDimension = resource_desc.SampleDesc.Count == 1 ? RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_UAV[p_type] : D3D12_UAV_DIMENSION_UNKNOWN;15821583switch (uav_desc.ViewDimension) {1584case D3D12_UAV_DIMENSION_TEXTURE1DARRAY: {1585uav_desc.Texture1DArray.ArraySize = p_array_layers;1586} break;1587case D3D12_UAV_DIMENSION_TEXTURE2DARRAY: {1588// Either for an actual 2D texture array, cubemap or cubemap array.1589uav_desc.Texture2DArray.ArraySize = p_array_layers;1590} break;1591case D3D12_UAV_DIMENSION_TEXTURE3D: {1592uav_desc.Texture3D.WSize = resource_desc.Depth();1593} break;1594default: {1595}1596}1597}15981599TextureInfo *tex_info = VersatileResource::allocate<TextureInfo>(resources_allocator);1600tex_info->resource = texture;1601tex_info->owner_info.resource = nullptr; // Not allocated by us.1602tex_info->owner_info.allocation = nullptr; // Not allocated by us.1603tex_info->owner_info.states.subresource_states.resize(resource_desc.MipLevels * p_array_layers);1604for (uint32_t i = 0; i < tex_info->owner_info.states.subresource_states.size(); i++) {1605tex_info->owner_info.states.subresource_states[i] = !p_depth_stencil ? D3D12_RESOURCE_STATE_RENDER_TARGET : D3D12_RESOURCE_STATE_DEPTH_WRITE;1606}1607tex_info->states_ptr = &tex_info->owner_info.states;1608tex_info->format = p_format;1609#if defined(__GNUC__) && !defined(__clang__)1610#pragma GCC diagnostic push1611#pragma GCC diagnostic ignored "-Wstrict-aliasing"1612#endif1613tex_info->desc = *(CD3DX12_RESOURCE_DESC *)&resource_desc;1614#if defined(__GNUC__) && !defined(__clang__)1615#pragma GCC diagnostic pop1616#endif1617tex_info->base_layer = 0;1618tex_info->layers = p_array_layers;1619tex_info->base_mip = 0;1620tex_info->mipmaps = resource_desc.MipLevels;1621tex_info->view_descs.srv = srv_desc;1622tex_info->view_descs.uav = uav_desc;1623#ifdef DEBUG_ENABLED1624tex_info->created_from_extension = true;1625#endif1626return TextureID(tex_info);1627}16281629RDD::TextureID RenderingDeviceDriverD3D12::texture_create_shared(TextureID p_original_texture, const TextureView &p_view) {1630return _texture_create_shared_from_slice(p_original_texture, p_view, (TextureSliceType)-1, 0, 0, 0, 0);1631}16321633RDD::TextureID RenderingDeviceDriverD3D12::texture_create_shared_from_slice(TextureID p_original_texture, const TextureView &p_view, TextureSliceType p_slice_type, uint32_t p_layer, uint32_t p_layers, uint32_t p_mipmap, uint32_t p_mipmaps) {1634return _texture_create_shared_from_slice(p_original_texture, p_view, p_slice_type, p_layer, p_layers, p_mipmap, p_mipmaps);1635}16361637RDD::TextureID RenderingDeviceDriverD3D12::_texture_create_shared_from_slice(TextureID p_original_texture, const TextureView &p_view, TextureSliceType p_slice_type, uint32_t p_layer, uint32_t p_layers, uint32_t p_mipmap, uint32_t p_mipmaps) {1638TextureInfo *owner_tex_info = (TextureInfo *)p_original_texture.id;1639#ifdef DEBUG_ENABLED1640ERR_FAIL_COND_V(!owner_tex_info->owner_info.allocation, TextureID());1641#endif16421643ComPtr<ID3D12Resource> new_texture;1644ComPtr<D3D12MA::Allocation> new_allocation;1645ID3D12Resource *resource = owner_tex_info->resource;1646CD3DX12_RESOURCE_DESC new_tex_resource_desc = owner_tex_info->desc;16471648// Describe views.16491650D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = owner_tex_info->view_descs.srv;1651{1652srv_desc.Format = RD_TO_D3D12_FORMAT[p_view.format].general_format;1653srv_desc.Shader4ComponentMapping = _compute_component_mapping(p_view);1654}16551656D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = owner_tex_info->view_descs.uav;1657{1658uav_desc.Format = RD_TO_D3D12_FORMAT[p_view.format].general_format;1659}16601661if (p_slice_type != (TextureSliceType)-1) {1662// Complete description with slicing.16631664switch (p_slice_type) {1665case TEXTURE_SLICE_2D: {1666if (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2D && p_layer == 0) {1667srv_desc.Texture2D.MostDetailedMip = p_mipmap;1668srv_desc.Texture2D.MipLevels = p_mipmaps;16691670DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2D);1671uav_desc.Texture1D.MipSlice = p_mipmap;1672} else if (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMS && p_layer == 0) {1673DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_UNKNOWN);1674} else if ((srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DARRAY || (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2D && p_layer)) || srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBE || srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBEARRAY) {1675srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;1676srv_desc.Texture2DArray.MostDetailedMip = p_mipmap;1677srv_desc.Texture2DArray.MipLevels = p_mipmaps;1678srv_desc.Texture2DArray.FirstArraySlice = p_layer;1679srv_desc.Texture2DArray.ArraySize = 1;1680srv_desc.Texture2DArray.PlaneSlice = 0;1681srv_desc.Texture2DArray.ResourceMinLODClamp = 0.0f;16821683uav_desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;1684uav_desc.Texture2DArray.MipSlice = p_mipmap;1685uav_desc.Texture2DArray.FirstArraySlice = p_layer;1686uav_desc.Texture2DArray.ArraySize = 1;1687uav_desc.Texture2DArray.PlaneSlice = 0;1688} else if ((srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY || (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMS && p_layer))) {1689srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY;1690srv_desc.Texture2DMSArray.FirstArraySlice = p_layer;1691srv_desc.Texture2DMSArray.ArraySize = 1;16921693uav_desc.ViewDimension = D3D12_UAV_DIMENSION_UNKNOWN;1694} else {1695DEV_ASSERT(false);1696}1697} break;1698case TEXTURE_SLICE_CUBEMAP: {1699if (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBE || p_layer == 0) {1700srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;1701srv_desc.TextureCube.MostDetailedMip = p_mipmap;1702srv_desc.TextureCube.MipLevels = p_mipmaps;17031704DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2DARRAY);1705uav_desc.Texture2DArray.MipSlice = p_mipmap;1706uav_desc.Texture2DArray.FirstArraySlice = p_layer;1707uav_desc.Texture2DArray.ArraySize = 6;1708uav_desc.Texture2DArray.PlaneSlice = 0;1709} else if (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBEARRAY || p_layer != 0) {1710srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY;1711srv_desc.TextureCubeArray.MostDetailedMip = p_mipmap;1712srv_desc.TextureCubeArray.MipLevels = p_mipmaps;1713srv_desc.TextureCubeArray.First2DArrayFace = p_layer;1714srv_desc.TextureCubeArray.NumCubes = 1;1715srv_desc.TextureCubeArray.ResourceMinLODClamp = 0.0f;17161717DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2DARRAY);1718uav_desc.Texture2DArray.MipSlice = p_mipmap;1719uav_desc.Texture2DArray.FirstArraySlice = p_layer;1720uav_desc.Texture2DArray.ArraySize = 6;1721uav_desc.Texture2DArray.PlaneSlice = 0;1722} else {1723DEV_ASSERT(false);1724}1725} break;1726case TEXTURE_SLICE_3D: {1727DEV_ASSERT(srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE3D);1728srv_desc.Texture3D.MostDetailedMip = p_mipmap;1729srv_desc.Texture3D.MipLevels = p_mipmaps;17301731DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE3D);1732uav_desc.Texture3D.MipSlice = p_mipmap;1733uav_desc.Texture3D.WSize = -1;1734} break;1735case TEXTURE_SLICE_2D_ARRAY: {1736DEV_ASSERT(srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DARRAY);1737srv_desc.Texture2DArray.MostDetailedMip = p_mipmap;1738srv_desc.Texture2DArray.MipLevels = p_mipmaps;1739srv_desc.Texture2DArray.FirstArraySlice = p_layer;1740srv_desc.Texture2DArray.ArraySize = p_layers;17411742DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2DARRAY);1743uav_desc.Texture2DArray.MipSlice = p_mipmap;1744uav_desc.Texture2DArray.FirstArraySlice = p_layer;1745uav_desc.Texture2DArray.ArraySize = p_layers;1746} break;1747default:1748break;1749}1750}17511752// Bookkeep.17531754TextureInfo *tex_info = VersatileResource::allocate<TextureInfo>(resources_allocator);1755tex_info->resource = resource;1756tex_info->states_ptr = owner_tex_info->states_ptr;1757tex_info->format = p_view.format;1758tex_info->desc = new_tex_resource_desc;1759if (p_slice_type == (TextureSliceType)-1) {1760tex_info->base_layer = owner_tex_info->base_layer;1761tex_info->layers = owner_tex_info->layers;1762tex_info->base_mip = owner_tex_info->base_mip;1763tex_info->mipmaps = owner_tex_info->mipmaps;1764} else {1765tex_info->base_layer = p_layer;1766tex_info->layers = p_layers;1767tex_info->base_mip = p_mipmap;1768tex_info->mipmaps = p_mipmaps;1769}1770tex_info->view_descs.srv = srv_desc;1771tex_info->view_descs.uav = uav_desc;1772tex_info->main_texture = owner_tex_info;17731774return TextureID(tex_info);1775}17761777void RenderingDeviceDriverD3D12::texture_free(TextureID p_texture) {1778TextureInfo *tex_info = (TextureInfo *)p_texture.id;1779VersatileResource::free(resources_allocator, tex_info);1780}17811782uint64_t RenderingDeviceDriverD3D12::texture_get_allocation_size(TextureID p_texture) {1783const TextureInfo *tex_info = (const TextureInfo *)p_texture.id;1784return tex_info->owner_info.allocation ? tex_info->owner_info.allocation->GetSize() : 0;1785}17861787void RenderingDeviceDriverD3D12::texture_get_copyable_layout(TextureID p_texture, const TextureSubresource &p_subresource, TextureCopyableLayout *r_layout) {1788TextureInfo *tex_info = (TextureInfo *)p_texture.id;17891790UINT plane = _compute_plane_slice(tex_info->format, p_subresource.aspect);1791UINT subresource = tex_info->desc.CalcSubresource(p_subresource.mipmap, p_subresource.layer, plane);17921793D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint = {};1794UINT64 subresource_total_size = 0;1795device->GetCopyableFootprints(1796&tex_info->desc,1797subresource,17981,17990,1800&footprint,1801nullptr,1802nullptr,1803&subresource_total_size);18041805*r_layout = {};1806r_layout->size = subresource_total_size;1807r_layout->row_pitch = footprint.Footprint.RowPitch;1808}18091810Vector<uint8_t> RenderingDeviceDriverD3D12::texture_get_data(TextureID p_texture, uint32_t p_layer) {1811ERR_FAIL_V_MSG(Vector<uint8_t>(), "Cannot get texture data. CPU readable textures are unsupported on D3D12.");1812}18131814BitField<RDD::TextureUsageBits> RenderingDeviceDriverD3D12::texture_get_usages_supported_by_format(DataFormat p_format, bool p_cpu_readable) {1815if (p_cpu_readable) {1816// CPU readable textures are unsupported on D3D12.1817return 0;1818}18191820D3D12_FEATURE_DATA_FORMAT_SUPPORT srv_rtv_support = {};1821srv_rtv_support.Format = RD_TO_D3D12_FORMAT[p_format].general_format;1822if (srv_rtv_support.Format != DXGI_FORMAT_UNKNOWN) { // Some implementations (i.e., vkd3d-proton) error out instead of returning empty.1823HRESULT res = device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &srv_rtv_support, sizeof(srv_rtv_support));1824ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), false, "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");1825}18261827D3D12_FEATURE_DATA_FORMAT_SUPPORT &uav_support = srv_rtv_support; // Fine for now.18281829D3D12_FEATURE_DATA_FORMAT_SUPPORT dsv_support = {};1830dsv_support.Format = RD_TO_D3D12_FORMAT[p_format].dsv_format;1831if (dsv_support.Format != DXGI_FORMAT_UNKNOWN) { // See above.1832HRESULT res = device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &dsv_support, sizeof(dsv_support));1833ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), false, "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");1834}18351836// Everything supported by default makes an all-or-nothing check easier for the caller.1837BitField<RDD::TextureUsageBits> supported = INT64_MAX;18381839// Per https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_format_support1,1840// as long as the resource can be used as a texture, Sample() will work with point filter at least.1841// However, we've empirically found that checking for at least D3D12_FORMAT_SUPPORT1_SHADER_LOAD is needed.1842// That's almost good for integer formats. The problem is that theoretically there may be1843// float formats that support LOAD but not SAMPLE fully, so this check will not detect1844// such a flaw in the format. Linearly interpolated sampling would just not work on them.1845if (!(srv_rtv_support.Support1 & (D3D12_FORMAT_SUPPORT1_SHADER_LOAD | D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE)) ||1846RD_TO_D3D12_FORMAT[p_format].general_format == DXGI_FORMAT_UNKNOWN) {1847supported.clear_flag(TEXTURE_USAGE_SAMPLING_BIT);1848}18491850if (!(srv_rtv_support.Support1 & D3D12_FORMAT_SUPPORT1_RENDER_TARGET)) {1851supported.clear_flag(TEXTURE_USAGE_COLOR_ATTACHMENT_BIT);1852}1853if (!(dsv_support.Support1 & D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL)) {1854supported.clear_flag(TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);1855}1856if (!(uav_support.Support1 & D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW)) { // Maybe check LOAD/STORE, too?1857supported.clear_flag(TEXTURE_USAGE_STORAGE_BIT);1858}1859if (!(uav_support.Support2 & D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_ADD)) { // Check a basic atomic at least.1860supported.clear_flag(TEXTURE_USAGE_STORAGE_ATOMIC_BIT);1861}1862if (RD_TO_D3D12_FORMAT[p_format].general_format != DXGI_FORMAT_R8_UINT) {1863supported.clear_flag(TEXTURE_USAGE_VRS_ATTACHMENT_BIT);1864}18651866return supported;1867}18681869bool RenderingDeviceDriverD3D12::texture_can_make_shared_with_format(TextureID p_texture, DataFormat p_format, bool &r_raw_reinterpretation) {1870r_raw_reinterpretation = false;18711872if (format_capabilities.relaxed_casting_supported) {1873// Relaxed casting is supported, there should be no need to check for format family compatibility.1874return true;1875} else {1876TextureInfo *tex_info = (TextureInfo *)p_texture.id;1877if (tex_info->format == DATA_FORMAT_R16_UINT && p_format == DATA_FORMAT_R4G4B4A4_UNORM_PACK16) {1878// Specific cases that require buffer reinterpretation.1879r_raw_reinterpretation = true;1880return false;1881} else if (RD_TO_D3D12_FORMAT[tex_info->format].family != RD_TO_D3D12_FORMAT[p_format].family) {1882// Format family is different but copying resources directly is possible.1883return false;1884} else {1885// Format family is the same and the view can just cast the format.1886return true;1887}1888}1889}18901891/*****************/1892/**** SAMPLER ****/1893/*****************/18941895static const D3D12_TEXTURE_ADDRESS_MODE RD_REPEAT_MODE_TO_D3D12_ADDRESS_MODE[RDD::SAMPLER_REPEAT_MODE_MAX] = {1896D3D12_TEXTURE_ADDRESS_MODE_WRAP,1897D3D12_TEXTURE_ADDRESS_MODE_MIRROR,1898D3D12_TEXTURE_ADDRESS_MODE_CLAMP,1899D3D12_TEXTURE_ADDRESS_MODE_BORDER,1900D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE,1901};19021903static const FLOAT RD_TO_D3D12_SAMPLER_BORDER_COLOR[RDD::SAMPLER_BORDER_COLOR_MAX][4] = {1904{ 0, 0, 0, 0 },1905{ 0, 0, 0, 0 },1906{ 0, 0, 0, 1 },1907{ 0, 0, 0, 1 },1908{ 1, 1, 1, 1 },1909{ 1, 1, 1, 1 },1910};19111912RDD::SamplerID RenderingDeviceDriverD3D12::sampler_create(const SamplerState &p_state) {1913uint32_t slot = UINT32_MAX;19141915if (samplers.is_empty()) {1916// Adding a seemigly busy slot 0 makes things easier elsewhere.1917samplers.push_back({});1918samplers.push_back({});1919slot = 1;1920} else {1921for (uint32_t i = 1; i < samplers.size(); i++) {1922if ((int)samplers[i].Filter == INT_MAX) {1923slot = i;1924break;1925}1926}1927if (slot == UINT32_MAX) {1928slot = samplers.size();1929samplers.push_back({});1930}1931}19321933D3D12_SAMPLER_DESC &sampler_desc = samplers[slot];19341935// D3D12 does not support anisotropic nearest filtering.1936bool use_anisotropy = p_state.use_anisotropy && p_state.min_filter == RDD::SAMPLER_FILTER_LINEAR && p_state.mag_filter == RDD::SAMPLER_FILTER_LINEAR;19371938// Nearest mipmap is a separate D3D12 capability.1939if (!sampler_capabilities.aniso_filter_with_point_mip_supported && p_state.mip_filter == RDD::SAMPLER_FILTER_NEAREST) {1940use_anisotropy = false;1941}19421943D3D12_FILTER_REDUCTION_TYPE reduction_type = p_state.enable_compare ? D3D12_FILTER_REDUCTION_TYPE_COMPARISON : D3D12_FILTER_REDUCTION_TYPE_STANDARD;19441945if (use_anisotropy) {1946if (p_state.mip_filter == RDD::SAMPLER_FILTER_NEAREST) {1947// This path is never going to be taken if the capability is unsupported.1948sampler_desc.Filter = D3D12_ENCODE_MIN_MAG_ANISOTROPIC_MIP_POINT_FILTER(reduction_type);1949} else {1950sampler_desc.Filter = D3D12_ENCODE_ANISOTROPIC_FILTER(reduction_type);1951}1952sampler_desc.MaxAnisotropy = p_state.anisotropy_max;1953} else {1954static const D3D12_FILTER_TYPE RD_FILTER_TYPE_TO_D3D12[] = {1955D3D12_FILTER_TYPE_POINT, // SAMPLER_FILTER_NEAREST.1956D3D12_FILTER_TYPE_LINEAR, // SAMPLER_FILTER_LINEAR.1957};1958sampler_desc.Filter = D3D12_ENCODE_BASIC_FILTER(1959RD_FILTER_TYPE_TO_D3D12[p_state.min_filter],1960RD_FILTER_TYPE_TO_D3D12[p_state.mag_filter],1961RD_FILTER_TYPE_TO_D3D12[p_state.mip_filter],1962reduction_type);1963}19641965sampler_desc.AddressU = RD_REPEAT_MODE_TO_D3D12_ADDRESS_MODE[p_state.repeat_u];1966sampler_desc.AddressV = RD_REPEAT_MODE_TO_D3D12_ADDRESS_MODE[p_state.repeat_v];1967sampler_desc.AddressW = RD_REPEAT_MODE_TO_D3D12_ADDRESS_MODE[p_state.repeat_w];19681969for (int i = 0; i < 4; i++) {1970sampler_desc.BorderColor[i] = RD_TO_D3D12_SAMPLER_BORDER_COLOR[p_state.border_color][i];1971}19721973sampler_desc.MinLOD = p_state.min_lod;1974sampler_desc.MaxLOD = p_state.max_lod;1975sampler_desc.MipLODBias = p_state.lod_bias;19761977sampler_desc.ComparisonFunc = p_state.enable_compare ? RD_TO_D3D12_COMPARE_OP[p_state.compare_op] : D3D12_COMPARISON_FUNC_NEVER;19781979// TODO: Emulate somehow?1980if (p_state.unnormalized_uvw) {1981WARN_PRINT("Creating a sampler with unnormalized UVW, which is not supported.");1982}19831984return SamplerID(slot);1985}19861987void RenderingDeviceDriverD3D12::sampler_free(SamplerID p_sampler) {1988samplers[p_sampler.id].Filter = (D3D12_FILTER)INT_MAX;1989}19901991bool RenderingDeviceDriverD3D12::sampler_is_format_supported_for_filter(DataFormat p_format, SamplerFilter p_filter) {1992D3D12_FEATURE_DATA_FORMAT_SUPPORT srv_rtv_support = {};1993srv_rtv_support.Format = RD_TO_D3D12_FORMAT[p_format].general_format;1994HRESULT res = device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &srv_rtv_support, sizeof(srv_rtv_support));1995ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), false, "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");1996return (srv_rtv_support.Support1 & D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE);1997}19981999/**********************/2000/**** VERTEX ARRAY ****/2001/**********************/20022003RDD::VertexFormatID RenderingDeviceDriverD3D12::vertex_format_create(Span<VertexAttribute> p_vertex_attribs, const VertexAttributeBindingsMap &p_vertex_bindings) {2004VertexFormatInfo *vf_info = VersatileResource::allocate<VertexFormatInfo>(resources_allocator);2005vf_info->input_elem_descs.resize(p_vertex_attribs.size());20062007uint32_t max_binding = 0;2008for (uint32_t i = 0; i < p_vertex_attribs.size(); i++) {2009D3D12_INPUT_ELEMENT_DESC &input_element_desc = vf_info->input_elem_descs[i];2010const VertexAttribute &vertex_attrib = p_vertex_attribs[i];2011const VertexAttributeBinding &vertex_binding = p_vertex_bindings[vertex_attrib.binding];20122013input_element_desc = {};2014input_element_desc.SemanticName = "TEXCOORD";2015input_element_desc.SemanticIndex = vertex_attrib.location;2016input_element_desc.Format = RD_TO_D3D12_FORMAT[vertex_attrib.format].general_format;2017input_element_desc.InputSlot = vertex_attrib.binding;2018input_element_desc.AlignedByteOffset = vertex_attrib.offset;2019if (vertex_binding.frequency == VERTEX_FREQUENCY_INSTANCE) {2020input_element_desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;2021input_element_desc.InstanceDataStepRate = 1;2022} else {2023input_element_desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;2024input_element_desc.InstanceDataStepRate = 0;2025}20262027max_binding = MAX(max_binding, vertex_attrib.binding + 1);2028}20292030vf_info->vertex_buffer_strides.resize(max_binding);2031for (const VertexAttributeBindingsMap::KV &vertex_binding_pair : p_vertex_bindings) {2032vf_info->vertex_buffer_strides[vertex_binding_pair.key] = vertex_binding_pair.value.stride;2033}20342035return VertexFormatID(vf_info);2036}20372038void RenderingDeviceDriverD3D12::vertex_format_free(VertexFormatID p_vertex_format) {2039VertexFormatInfo *vf_info = (VertexFormatInfo *)p_vertex_format.id;2040VersatileResource::free(resources_allocator, vf_info);2041}20422043/******************/2044/**** BARRIERS ****/2045/******************/20462047static D3D12_BARRIER_ACCESS _rd_texture_layout_access_mask(RDD::TextureLayout p_texture_layout) {2048switch (p_texture_layout) {2049case RDD::TEXTURE_LAYOUT_STORAGE_OPTIMAL:2050return D3D12_BARRIER_ACCESS_UNORDERED_ACCESS;2051case RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:2052return D3D12_BARRIER_ACCESS_RENDER_TARGET;2053case RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:2054return D3D12_BARRIER_ACCESS_DEPTH_STENCIL_READ | D3D12_BARRIER_ACCESS_DEPTH_STENCIL_WRITE;2055case RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:2056return D3D12_BARRIER_ACCESS_DEPTH_STENCIL_READ;2057case RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:2058return D3D12_BARRIER_ACCESS_SHADER_RESOURCE;2059case RDD::TEXTURE_LAYOUT_COPY_SRC_OPTIMAL:2060return D3D12_BARRIER_ACCESS_COPY_SOURCE;2061case RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL:2062return D3D12_BARRIER_ACCESS_COPY_DEST;2063case RDD::TEXTURE_LAYOUT_RESOLVE_SRC_OPTIMAL:2064return D3D12_BARRIER_ACCESS_RESOLVE_SOURCE;2065case RDD::TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL:2066return D3D12_BARRIER_ACCESS_RESOLVE_DEST;2067case RDD::TEXTURE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL:2068return D3D12_BARRIER_ACCESS_SHADING_RATE_SOURCE;2069case RDD::TEXTURE_LAYOUT_FRAGMENT_DENSITY_MAP_ATTACHMENT_OPTIMAL:2070DEV_ASSERT(false && "Fragment density maps are not supported in D3D12.");2071return D3D12_BARRIER_ACCESS_NO_ACCESS;2072default:2073return D3D12_BARRIER_ACCESS_NO_ACCESS;2074}2075}20762077static void _rd_access_to_d3d12_and_mask(BitField<RDD::BarrierAccessBits> p_access, RDD::TextureLayout p_texture_layout, D3D12_BARRIER_ACCESS &r_access, D3D12_BARRIER_SYNC &r_sync_mask) {2078r_access = D3D12_BARRIER_ACCESS_COMMON;2079r_sync_mask = D3D12_BARRIER_SYNC_ALL;20802081if (p_access.has_flag(RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT)) {2082r_access |= D3D12_BARRIER_ACCESS_INDIRECT_ARGUMENT;2083r_sync_mask |= D3D12_BARRIER_SYNC_EXECUTE_INDIRECT;2084}20852086if (p_access.has_flag(RDD::BARRIER_ACCESS_INDEX_READ_BIT)) {2087r_access |= D3D12_BARRIER_ACCESS_INDEX_BUFFER;2088r_sync_mask |= D3D12_BARRIER_SYNC_INDEX_INPUT | D3D12_BARRIER_SYNC_DRAW;2089}20902091if (p_access.has_flag(RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT)) {2092r_access |= D3D12_BARRIER_ACCESS_VERTEX_BUFFER;2093r_sync_mask |= D3D12_BARRIER_SYNC_VERTEX_SHADING | D3D12_BARRIER_SYNC_DRAW | D3D12_BARRIER_SYNC_ALL_SHADING;2094}20952096if (p_access.has_flag(RDD::BARRIER_ACCESS_UNIFORM_READ_BIT)) {2097r_access |= D3D12_BARRIER_ACCESS_CONSTANT_BUFFER;2098r_sync_mask |= D3D12_BARRIER_SYNC_VERTEX_SHADING | D3D12_BARRIER_SYNC_PIXEL_SHADING | D3D12_BARRIER_SYNC_COMPUTE_SHADING |2099D3D12_BARRIER_SYNC_DRAW | D3D12_BARRIER_SYNC_ALL_SHADING;2100}21012102if (p_access.has_flag(RDD::BARRIER_ACCESS_INPUT_ATTACHMENT_READ_BIT)) {2103r_access |= D3D12_BARRIER_ACCESS_RENDER_TARGET;2104r_sync_mask |= D3D12_BARRIER_SYNC_DRAW | D3D12_BARRIER_SYNC_RENDER_TARGET;2105}21062107if (p_access.has_flag(RDD::BARRIER_ACCESS_COPY_READ_BIT)) {2108r_access |= D3D12_BARRIER_ACCESS_COPY_SOURCE;2109r_sync_mask |= D3D12_BARRIER_SYNC_COPY;2110}21112112if (p_access.has_flag(RDD::BARRIER_ACCESS_COPY_WRITE_BIT)) {2113r_access |= D3D12_BARRIER_ACCESS_COPY_DEST;2114r_sync_mask |= D3D12_BARRIER_SYNC_COPY;2115}21162117if (p_access.has_flag(RDD::BARRIER_ACCESS_RESOLVE_READ_BIT)) {2118r_access |= D3D12_BARRIER_ACCESS_RESOLVE_SOURCE;2119r_sync_mask |= D3D12_BARRIER_SYNC_RESOLVE;2120}21212122if (p_access.has_flag(RDD::BARRIER_ACCESS_RESOLVE_WRITE_BIT)) {2123r_access |= D3D12_BARRIER_ACCESS_RESOLVE_DEST;2124r_sync_mask |= D3D12_BARRIER_SYNC_RESOLVE;2125}21262127if (p_access.has_flag(RDD::BARRIER_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT)) {2128r_access |= D3D12_BARRIER_ACCESS_SHADING_RATE_SOURCE;2129r_sync_mask |= D3D12_BARRIER_SYNC_PIXEL_SHADING | D3D12_BARRIER_SYNC_ALL_SHADING;2130}21312132const D3D12_BARRIER_SYNC unordered_access_mask = D3D12_BARRIER_SYNC_VERTEX_SHADING | D3D12_BARRIER_SYNC_PIXEL_SHADING | D3D12_BARRIER_SYNC_COMPUTE_SHADING |2133D3D12_BARRIER_SYNC_VERTEX_SHADING | D3D12_BARRIER_SYNC_DRAW | D3D12_BARRIER_SYNC_ALL_SHADING | D3D12_BARRIER_SYNC_CLEAR_UNORDERED_ACCESS_VIEW;21342135if (p_access.has_flag(RDD::BARRIER_ACCESS_STORAGE_CLEAR_BIT)) {2136r_access |= D3D12_BARRIER_ACCESS_UNORDERED_ACCESS;2137r_sync_mask |= unordered_access_mask;2138}21392140// These access bits only have compatibility with certain layouts unlike in Vulkan where they imply specific operations in the same layout.2141if (p_access.has_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT)) {2142r_access |= D3D12_BARRIER_ACCESS_UNORDERED_ACCESS;2143r_sync_mask |= unordered_access_mask;2144} else if (p_access.has_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT)) {2145if (p_texture_layout == RDD::TEXTURE_LAYOUT_STORAGE_OPTIMAL) {2146// Unordered access must be enforced if the texture is using the storage layout.2147r_access |= D3D12_BARRIER_ACCESS_UNORDERED_ACCESS;2148r_sync_mask |= unordered_access_mask;2149} else {2150r_access |= D3D12_BARRIER_ACCESS_SHADER_RESOURCE;2151r_sync_mask |= D3D12_BARRIER_SYNC_VERTEX_SHADING | D3D12_BARRIER_SYNC_PIXEL_SHADING | D3D12_BARRIER_SYNC_COMPUTE_SHADING | D3D12_BARRIER_SYNC_DRAW | D3D12_BARRIER_SYNC_ALL_SHADING;2152}2153}21542155if (p_access.has_flag(RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT) || p_access.has_flag(RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT)) {2156r_access |= D3D12_BARRIER_ACCESS_RENDER_TARGET;2157r_sync_mask |= D3D12_BARRIER_SYNC_DRAW | D3D12_BARRIER_SYNC_RENDER_TARGET;2158}21592160if (p_access.has_flag(RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT)) {2161r_access |= D3D12_BARRIER_ACCESS_DEPTH_STENCIL_WRITE;2162r_sync_mask |= D3D12_BARRIER_SYNC_DRAW | D3D12_BARRIER_SYNC_DEPTH_STENCIL;2163} else if (p_access.has_flag(RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT)) {2164r_access |= D3D12_BARRIER_ACCESS_DEPTH_STENCIL_READ;2165r_sync_mask |= D3D12_BARRIER_SYNC_DRAW | D3D12_BARRIER_SYNC_DEPTH_STENCIL;2166}2167}21682169static void _rd_stages_to_d3d12(BitField<RDD::PipelineStageBits> p_stages, D3D12_BARRIER_SYNC &r_sync) {2170if (p_stages.has_flag(RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT)) {2171r_sync = D3D12_BARRIER_SYNC_ALL;2172} else {2173if (p_stages.has_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT)) {2174r_sync |= D3D12_BARRIER_SYNC_EXECUTE_INDIRECT;2175}21762177if (p_stages.has_flag(RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT)) {2178r_sync |= D3D12_BARRIER_SYNC_INDEX_INPUT;2179}21802181if (p_stages.has_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT)) {2182r_sync |= D3D12_BARRIER_SYNC_VERTEX_SHADING;2183}21842185if (p_stages.has_flag(RDD::PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT) || p_stages.has_flag(RDD::PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT) || p_stages.has_flag(RDD::PIPELINE_STAGE_GEOMETRY_SHADER_BIT)) {2186// There's no granularity for tessellation or geometry stages. The specification defines it as part of vertex shading.2187r_sync |= D3D12_BARRIER_SYNC_VERTEX_SHADING;2188}21892190if (p_stages.has_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT) || p_stages.has_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT)) {2191r_sync |= D3D12_BARRIER_SYNC_PIXEL_SHADING;2192}21932194if (p_stages.has_flag(RDD::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT) || p_stages.has_flag(RDD::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT)) {2195// Covers both read and write operations for depth stencil.2196r_sync |= D3D12_BARRIER_SYNC_DEPTH_STENCIL;2197}21982199if (p_stages.has_flag(RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)) {2200r_sync |= D3D12_BARRIER_SYNC_RENDER_TARGET;2201}22022203if (p_stages.has_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT)) {2204r_sync |= D3D12_BARRIER_SYNC_COMPUTE_SHADING;2205}22062207if (p_stages.has_flag(RDD::PIPELINE_STAGE_COPY_BIT)) {2208r_sync |= D3D12_BARRIER_SYNC_COPY;2209}22102211if (p_stages.has_flag(RDD::PIPELINE_STAGE_RESOLVE_BIT)) {2212r_sync |= D3D12_BARRIER_SYNC_RESOLVE;2213}22142215if (p_stages.has_flag(RDD::PIPELINE_STAGE_CLEAR_STORAGE_BIT)) {2216r_sync |= D3D12_BARRIER_SYNC_CLEAR_UNORDERED_ACCESS_VIEW;2217}22182219if (p_stages.has_flag(RDD::PIPELINE_STAGE_ALL_GRAPHICS_BIT)) {2220r_sync |= D3D12_BARRIER_SYNC_DRAW;2221}2222}2223}22242225static void _rd_stages_and_access_to_d3d12(BitField<RDD::PipelineStageBits> p_stages, RDD::TextureLayout p_texture_layout, BitField<RDD::BarrierAccessBits> p_access, D3D12_BARRIER_SYNC &r_sync, D3D12_BARRIER_ACCESS &r_access) {2226D3D12_BARRIER_SYNC sync_mask;2227r_sync = D3D12_BARRIER_SYNC_NONE;22282229if (p_texture_layout == RDD::TEXTURE_LAYOUT_UNDEFINED) {2230// Undefined texture layouts are a special case where no access bits or synchronization scopes are allowed.2231r_access = D3D12_BARRIER_ACCESS_NO_ACCESS;2232return;2233}22342235// Convert access bits to the D3D12 barrier access bits.2236_rd_access_to_d3d12_and_mask(p_access, p_texture_layout, r_access, sync_mask);22372238if (p_texture_layout != RDD::TEXTURE_LAYOUT_MAX) {2239// Only allow the access bits compatible with the texture layout.2240r_access &= _rd_texture_layout_access_mask(p_texture_layout);2241}22422243// Convert stage bits to the D3D12 synchronization scope bits.2244_rd_stages_to_d3d12(p_stages, r_sync);22452246// Only enable synchronization stages compatible with the access bits that were used.2247r_sync &= sync_mask;22482249if (r_sync == D3D12_BARRIER_SYNC_NONE) {2250if (p_access.is_empty()) {2251// No valid synchronization scope was defined and no access in particular is required.2252r_access = D3D12_BARRIER_ACCESS_NO_ACCESS;2253} else {2254// Access is required but the synchronization scope wasn't compatible. We fall back to the global synchronization scope and access.2255r_sync = D3D12_BARRIER_SYNC_ALL;2256r_access = D3D12_BARRIER_ACCESS_COMMON;2257}2258}2259}22602261static D3D12_BARRIER_LAYOUT _rd_texture_layout_to_d3d12_barrier_layout(RDD::TextureLayout p_texture_layout) {2262switch (p_texture_layout) {2263case RDD::TEXTURE_LAYOUT_UNDEFINED:2264return D3D12_BARRIER_LAYOUT_UNDEFINED;2265case RDD::TEXTURE_LAYOUT_GENERAL:2266return D3D12_BARRIER_LAYOUT_COMMON;2267case RDD::TEXTURE_LAYOUT_STORAGE_OPTIMAL:2268return D3D12_BARRIER_LAYOUT_UNORDERED_ACCESS;2269case RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:2270return D3D12_BARRIER_LAYOUT_RENDER_TARGET;2271case RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:2272return D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_WRITE;2273case RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:2274return D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_READ;2275case RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:2276return D3D12_BARRIER_LAYOUT_SHADER_RESOURCE;2277case RDD::TEXTURE_LAYOUT_COPY_SRC_OPTIMAL:2278return D3D12_BARRIER_LAYOUT_COPY_SOURCE;2279case RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL:2280return D3D12_BARRIER_LAYOUT_COPY_DEST;2281case RDD::TEXTURE_LAYOUT_RESOLVE_SRC_OPTIMAL:2282return D3D12_BARRIER_LAYOUT_RESOLVE_SOURCE;2283case RDD::TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL:2284return D3D12_BARRIER_LAYOUT_RESOLVE_DEST;2285case RDD::TEXTURE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL:2286return D3D12_BARRIER_LAYOUT_SHADING_RATE_SOURCE;2287case RDD::TEXTURE_LAYOUT_FRAGMENT_DENSITY_MAP_ATTACHMENT_OPTIMAL:2288DEV_ASSERT(false && "Fragment density maps are not supported in D3D12.");2289return D3D12_BARRIER_LAYOUT_UNDEFINED;2290default:2291DEV_ASSERT(false && "Unknown texture layout.");2292return D3D12_BARRIER_LAYOUT_UNDEFINED;2293}2294}22952296void RenderingDeviceDriverD3D12::command_pipeline_barrier(CommandBufferID p_cmd_buffer,2297BitField<PipelineStageBits> p_src_stages,2298BitField<PipelineStageBits> p_dst_stages,2299VectorView<RDD::MemoryAccessBarrier> p_memory_barriers,2300VectorView<RDD::BufferBarrier> p_buffer_barriers,2301VectorView<RDD::TextureBarrier> p_texture_barriers,2302VectorView<AccelerationStructureBarrier> p_acceleration_structure_barriers) {2303if (!barrier_capabilities.enhanced_barriers_supported) {2304// Enhanced barriers are a requirement for this function.2305return;2306}23072308if (p_memory_barriers.size() == 0 && p_buffer_barriers.size() == 0 && p_texture_barriers.size() == 0) {2309// At least one barrier must be present in the arguments.2310return;2311}23122313// Convert the RDD barriers to D3D12 enhanced barriers.2314thread_local LocalVector<D3D12_GLOBAL_BARRIER> global_barriers;2315thread_local LocalVector<D3D12_BUFFER_BARRIER> buffer_barriers;2316thread_local LocalVector<D3D12_TEXTURE_BARRIER> texture_barriers;2317global_barriers.clear();2318buffer_barriers.clear();2319texture_barriers.clear();23202321D3D12_GLOBAL_BARRIER global_barrier = {};2322for (uint32_t i = 0; i < p_memory_barriers.size(); i++) {2323const MemoryAccessBarrier &memory_barrier = p_memory_barriers[i];2324_rd_stages_and_access_to_d3d12(p_src_stages, RDD::TEXTURE_LAYOUT_MAX, memory_barrier.src_access, global_barrier.SyncBefore, global_barrier.AccessBefore);2325_rd_stages_and_access_to_d3d12(p_dst_stages, RDD::TEXTURE_LAYOUT_MAX, memory_barrier.dst_access, global_barrier.SyncAfter, global_barrier.AccessAfter);2326global_barriers.push_back(global_barrier);2327}23282329D3D12_BUFFER_BARRIER buffer_barrier_d3d12 = {};2330buffer_barrier_d3d12.Offset = 0;2331buffer_barrier_d3d12.Size = UINT64_MAX; // The specification says this must be the size of the buffer barrier.2332for (uint32_t i = 0; i < p_buffer_barriers.size(); i++) {2333const BufferBarrier &buffer_barrier_rd = p_buffer_barriers[i];2334const BufferInfo *buffer_info = (const BufferInfo *)(buffer_barrier_rd.buffer.id);2335_rd_stages_and_access_to_d3d12(p_src_stages, RDD::TEXTURE_LAYOUT_MAX, buffer_barrier_rd.src_access, buffer_barrier_d3d12.SyncBefore, buffer_barrier_d3d12.AccessBefore);2336_rd_stages_and_access_to_d3d12(p_dst_stages, RDD::TEXTURE_LAYOUT_MAX, buffer_barrier_rd.dst_access, buffer_barrier_d3d12.SyncAfter, buffer_barrier_d3d12.AccessAfter);2337buffer_barrier_d3d12.pResource = buffer_info->resource;2338buffer_barriers.push_back(buffer_barrier_d3d12);2339}23402341D3D12_TEXTURE_BARRIER texture_barrier_d3d12 = {};2342for (uint32_t i = 0; i < p_texture_barriers.size(); i++) {2343const TextureBarrier &texture_barrier_rd = p_texture_barriers[i];2344const TextureInfo *texture_info = (const TextureInfo *)(texture_barrier_rd.texture.id);2345if (texture_info->main_texture) {2346texture_info = texture_info->main_texture;2347}2348// Textures created for simultaneous access do not need explicit transitions.2349if (texture_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS) {2350continue;2351}2352_rd_stages_and_access_to_d3d12(p_src_stages, texture_barrier_rd.prev_layout, texture_barrier_rd.src_access, texture_barrier_d3d12.SyncBefore, texture_barrier_d3d12.AccessBefore);2353_rd_stages_and_access_to_d3d12(p_dst_stages, texture_barrier_rd.next_layout, texture_barrier_rd.dst_access, texture_barrier_d3d12.SyncAfter, texture_barrier_d3d12.AccessAfter);2354texture_barrier_d3d12.LayoutBefore = _rd_texture_layout_to_d3d12_barrier_layout(texture_barrier_rd.prev_layout);2355texture_barrier_d3d12.LayoutAfter = _rd_texture_layout_to_d3d12_barrier_layout(texture_barrier_rd.next_layout);2356texture_barrier_d3d12.pResource = texture_info->resource;2357if (texture_barrier_rd.subresources.mipmap_count == texture_info->mipmaps && texture_barrier_rd.subresources.layer_count == texture_info->layers) {2358// So, all resources. Then, let's be explicit about it so D3D12 doesn't think2359// we are dealing with a subset of subresources.2360texture_barrier_d3d12.Subresources.IndexOrFirstMipLevel = 0xffffffff;2361texture_barrier_d3d12.Subresources.NumMipLevels = 0;2362// Because NumMipLevels == 0, all the other fields are ignored by D3D12.2363} else {2364texture_barrier_d3d12.Subresources.IndexOrFirstMipLevel = texture_barrier_rd.subresources.base_mipmap;2365texture_barrier_d3d12.Subresources.NumMipLevels = texture_barrier_rd.subresources.mipmap_count;2366texture_barrier_d3d12.Subresources.FirstArraySlice = texture_barrier_rd.subresources.base_layer;2367texture_barrier_d3d12.Subresources.NumArraySlices = texture_barrier_rd.subresources.layer_count;2368texture_barrier_d3d12.Subresources.FirstPlane = _compute_plane_slice(texture_info->format, texture_barrier_rd.subresources.aspect);2369texture_barrier_d3d12.Subresources.NumPlanes = format_get_plane_count(texture_info->format);2370}2371texture_barrier_d3d12.Flags = (texture_barrier_rd.prev_layout == RDD::TEXTURE_LAYOUT_UNDEFINED) ? D3D12_TEXTURE_BARRIER_FLAG_DISCARD : D3D12_TEXTURE_BARRIER_FLAG_NONE;2372texture_barriers.push_back(texture_barrier_d3d12);2373}23742375// Define the barrier groups and execute.23762377D3D12_BARRIER_GROUP barrier_groups[3] = {};2378uint32_t barrier_groups_count = 0;23792380if (!global_barriers.is_empty()) {2381D3D12_BARRIER_GROUP &barrier_group = barrier_groups[barrier_groups_count++];2382barrier_group.Type = D3D12_BARRIER_TYPE_GLOBAL;2383barrier_group.NumBarriers = global_barriers.size();2384barrier_group.pGlobalBarriers = global_barriers.ptr();2385}23862387if (!buffer_barriers.is_empty()) {2388D3D12_BARRIER_GROUP &barrier_group = barrier_groups[barrier_groups_count++];2389barrier_group.Type = D3D12_BARRIER_TYPE_BUFFER;2390barrier_group.NumBarriers = buffer_barriers.size();2391barrier_group.pBufferBarriers = buffer_barriers.ptr();2392}23932394if (!texture_barriers.is_empty()) {2395D3D12_BARRIER_GROUP &barrier_group = barrier_groups[barrier_groups_count++];2396barrier_group.Type = D3D12_BARRIER_TYPE_TEXTURE;2397barrier_group.NumBarriers = texture_barriers.size();2398barrier_group.pTextureBarriers = texture_barriers.ptr();2399}24002401if (barrier_groups_count) {2402const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)(p_cmd_buffer.id);2403cmd_buf_info->cmd_list_7->Barrier(barrier_groups_count, barrier_groups);2404}2405}24062407/****************/2408/**** FENCES ****/2409/****************/24102411RDD::FenceID RenderingDeviceDriverD3D12::fence_create() {2412ComPtr<ID3D12Fence> d3d_fence;2413HRESULT res = device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(d3d_fence.GetAddressOf()));2414ERR_FAIL_COND_V(!SUCCEEDED(res), FenceID());24152416HANDLE event_handle = CreateEvent(nullptr, FALSE, FALSE, nullptr);2417ERR_FAIL_NULL_V(event_handle, FenceID());24182419FenceInfo *fence = memnew(FenceInfo);2420fence->d3d_fence = d3d_fence;2421fence->event_handle = event_handle;2422return FenceID(fence);2423}24242425Error RenderingDeviceDriverD3D12::fence_wait(FenceID p_fence) {2426FenceInfo *fence = (FenceInfo *)(p_fence.id);2427fence->d3d_fence->SetEventOnCompletion(fence->fence_value, fence->event_handle);2428DWORD res = WaitForSingleObjectEx(fence->event_handle, INFINITE, FALSE);2429#ifdef PIX_ENABLED2430PIXNotifyWakeFromFenceSignal(fence->event_handle);2431#endif24322433return (res == WAIT_FAILED) ? FAILED : OK;2434}24352436void RenderingDeviceDriverD3D12::fence_free(FenceID p_fence) {2437FenceInfo *fence = (FenceInfo *)(p_fence.id);2438CloseHandle(fence->event_handle);2439memdelete(fence);2440}24412442/********************/2443/**** SEMAPHORES ****/2444/********************/24452446RDD::SemaphoreID RenderingDeviceDriverD3D12::semaphore_create() {2447ComPtr<ID3D12Fence> d3d_fence;2448HRESULT res = device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(d3d_fence.GetAddressOf()));2449ERR_FAIL_COND_V(!SUCCEEDED(res), SemaphoreID());24502451SemaphoreInfo *semaphore = memnew(SemaphoreInfo);2452semaphore->d3d_fence = d3d_fence;2453return SemaphoreID(semaphore);2454}24552456void RenderingDeviceDriverD3D12::semaphore_free(SemaphoreID p_semaphore) {2457SemaphoreInfo *semaphore = (SemaphoreInfo *)(p_semaphore.id);2458memdelete(semaphore);2459}24602461/******************/2462/**** COMMANDS ****/2463/******************/24642465// ----- QUEUE FAMILY -----24662467RDD::CommandQueueFamilyID RenderingDeviceDriverD3D12::command_queue_family_get(BitField<CommandQueueFamilyBits> p_cmd_queue_family_bits, RenderingContextDriver::SurfaceID p_surface) {2468// Return the command list type encoded plus one so zero is an invalid value.2469// The only ones that support presenting to a surface are direct queues.2470if (p_cmd_queue_family_bits.has_flag(COMMAND_QUEUE_FAMILY_GRAPHICS_BIT) || (p_surface != 0)) {2471return CommandQueueFamilyID(D3D12_COMMAND_LIST_TYPE_DIRECT + 1);2472} else if (p_cmd_queue_family_bits.has_flag(COMMAND_QUEUE_FAMILY_COMPUTE_BIT)) {2473return CommandQueueFamilyID(D3D12_COMMAND_LIST_TYPE_COMPUTE + 1);2474} else if (p_cmd_queue_family_bits.has_flag(COMMAND_QUEUE_FAMILY_TRANSFER_BIT)) {2475return CommandQueueFamilyID(D3D12_COMMAND_LIST_TYPE_COPY + 1);2476} else {2477return CommandQueueFamilyID();2478}2479}24802481// ----- QUEUE -----24822483RDD::CommandQueueID RenderingDeviceDriverD3D12::command_queue_create(CommandQueueFamilyID p_cmd_queue_family, bool p_identify_as_main_queue) {2484ComPtr<ID3D12CommandQueue> d3d_queue;2485D3D12_COMMAND_QUEUE_DESC queue_desc = {};2486queue_desc.Type = (D3D12_COMMAND_LIST_TYPE)(p_cmd_queue_family.id - 1);2487HRESULT res = device->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(d3d_queue.GetAddressOf()));2488ERR_FAIL_COND_V(!SUCCEEDED(res), CommandQueueID());24892490if (p_identify_as_main_queue && D3D12Hooks::get_singleton() != nullptr) {2491D3D12Hooks::get_singleton()->set_command_queue(d3d_queue.Get());2492}24932494CommandQueueInfo *command_queue = memnew(CommandQueueInfo);2495command_queue->d3d_queue = d3d_queue;2496return CommandQueueID(command_queue);2497}24982499Error RenderingDeviceDriverD3D12::command_queue_execute_and_present(CommandQueueID p_cmd_queue, VectorView<SemaphoreID> p_wait_semaphores, VectorView<CommandBufferID> p_cmd_buffers, VectorView<SemaphoreID> p_cmd_semaphores, FenceID p_cmd_fence, VectorView<SwapChainID> p_swap_chains) {2500CommandQueueInfo *command_queue = (CommandQueueInfo *)(p_cmd_queue.id);2501for (uint32_t i = 0; i < p_wait_semaphores.size(); i++) {2502const SemaphoreInfo *semaphore = (const SemaphoreInfo *)(p_wait_semaphores[i].id);2503command_queue->d3d_queue->Wait(semaphore->d3d_fence.Get(), semaphore->fence_value);2504}25052506if (p_cmd_buffers.size() > 0) {2507thread_local LocalVector<ID3D12CommandList *> command_lists;2508command_lists.resize(p_cmd_buffers.size());2509for (uint32_t i = 0; i < p_cmd_buffers.size(); i++) {2510const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)(p_cmd_buffers[i].id);2511command_lists[i] = cmd_buf_info->cmd_list.Get();2512}25132514command_queue->d3d_queue->ExecuteCommandLists(command_lists.size(), command_lists.ptr());25152516for (uint32_t i = 0; i < p_cmd_semaphores.size(); i++) {2517SemaphoreInfo *semaphore = (SemaphoreInfo *)(p_cmd_semaphores[i].id);2518semaphore->fence_value++;2519command_queue->d3d_queue->Signal(semaphore->d3d_fence.Get(), semaphore->fence_value);2520}25212522if (p_cmd_fence) {2523FenceInfo *fence = (FenceInfo *)(p_cmd_fence.id);2524fence->fence_value++;2525command_queue->d3d_queue->Signal(fence->d3d_fence.Get(), fence->fence_value);2526}2527}25282529HRESULT res;2530bool any_present_failed = false;2531for (uint32_t i = 0; i < p_swap_chains.size(); i++) {2532SwapChain *swap_chain = (SwapChain *)(p_swap_chains[i].id);2533res = swap_chain->d3d_swap_chain->Present(swap_chain->sync_interval, swap_chain->present_flags);2534if (!SUCCEEDED(res)) {2535print_verbose(vformat("D3D12: Presenting swapchain failed with error 0x%08ux.", (uint64_t)res));2536any_present_failed = true;2537}2538}25392540return any_present_failed ? FAILED : OK;2541}25422543void RenderingDeviceDriverD3D12::command_queue_free(CommandQueueID p_cmd_queue) {2544CommandQueueInfo *command_queue = (CommandQueueInfo *)(p_cmd_queue.id);2545memdelete(command_queue);2546}25472548// ----- POOL -----25492550RDD::CommandPoolID RenderingDeviceDriverD3D12::command_pool_create(CommandQueueFamilyID p_cmd_queue_family, CommandBufferType p_cmd_buffer_type) {2551CommandPoolInfo *command_pool = memnew(CommandPoolInfo);2552command_pool->queue_family = p_cmd_queue_family;2553command_pool->buffer_type = p_cmd_buffer_type;2554return CommandPoolID(command_pool);2555}25562557bool RenderingDeviceDriverD3D12::command_pool_reset(CommandPoolID p_cmd_pool) {2558return true;2559}25602561void RenderingDeviceDriverD3D12::command_pool_free(CommandPoolID p_cmd_pool) {2562CommandPoolInfo *command_pool = (CommandPoolInfo *)(p_cmd_pool.id);25632564// Destroy all command buffers associated with this command pool, mirroring Vulkan's behavior.2565SelfList<CommandBufferInfo> *cmd_buf_elem = command_pool->command_buffers.first();2566while (cmd_buf_elem != nullptr) {2567CommandBufferInfo *cmd_buf_info = cmd_buf_elem->self();2568cmd_buf_elem = cmd_buf_elem->next();25692570cmd_buf_info->cmd_list.Reset();2571cmd_buf_info->cmd_list_1.Reset();2572cmd_buf_info->cmd_list_5.Reset();2573cmd_buf_info->cmd_list_7.Reset();2574cmd_buf_info->cmd_allocator.Reset();25752576resource_descriptor_heap_pool.free(cmd_buf_info->uav_alloc);2577rtv_descriptor_heap_pool.free(cmd_buf_info->rtv_alloc);2578dsv_descriptor_heap_pool.free(cmd_buf_info->dsv_alloc);25792580VersatileResource::free(resources_allocator, cmd_buf_info);2581}25822583memdelete(command_pool);2584}25852586// ----- BUFFER -----25872588RDD::CommandBufferID RenderingDeviceDriverD3D12::command_buffer_create(CommandPoolID p_cmd_pool) {2589DEV_ASSERT(p_cmd_pool);25902591CommandPoolInfo *command_pool = (CommandPoolInfo *)(p_cmd_pool.id);2592D3D12_COMMAND_LIST_TYPE list_type;2593if (command_pool->buffer_type == COMMAND_BUFFER_TYPE_SECONDARY) {2594list_type = D3D12_COMMAND_LIST_TYPE_BUNDLE;2595} else {2596list_type = D3D12_COMMAND_LIST_TYPE(command_pool->queue_family.id - 1);2597}25982599ComPtr<ID3D12CommandAllocator> cmd_allocator;2600{2601HRESULT res = device->CreateCommandAllocator(list_type, IID_PPV_ARGS(cmd_allocator.GetAddressOf()));2602ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), CommandBufferID(), "CreateCommandAllocator failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");2603}26042605ComPtr<ID3D12GraphicsCommandList> cmd_list;2606{2607ComPtr<ID3D12Device4> device_4;2608device->QueryInterface(device_4.GetAddressOf());2609HRESULT res = E_FAIL;2610if (device_4) {2611res = device_4->CreateCommandList1(0, list_type, D3D12_COMMAND_LIST_FLAG_NONE, IID_PPV_ARGS(cmd_list.GetAddressOf()));2612} else {2613res = device->CreateCommandList(0, list_type, cmd_allocator.Get(), nullptr, IID_PPV_ARGS(cmd_list.GetAddressOf()));2614}2615ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), CommandBufferID(), "CreateCommandList failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");2616if (!device_4) {2617cmd_list->Close();2618}2619}26202621CPUDescriptorHeapPool::Allocation uav_alloc;2622CPUDescriptorHeapPool::Allocation rtv_alloc;2623CPUDescriptorHeapPool::Allocation dsv_alloc;26242625if (list_type != D3D12_COMMAND_LIST_TYPE_COPY) {2626Error err = resource_descriptor_heap_pool.allocate(1, device.Get(), uav_alloc);2627ERR_FAIL_COND_V(err != OK, CommandBufferID());26282629err = rtv_descriptor_heap_pool.allocate(1, device.Get(), rtv_alloc);2630if (unlikely(err != OK)) {2631resource_descriptor_heap_pool.free(uav_alloc);2632ERR_FAIL_V(CommandBufferID());2633}26342635err = dsv_descriptor_heap_pool.allocate(1, device.Get(), dsv_alloc);2636if (unlikely(err != OK)) {2637resource_descriptor_heap_pool.free(uav_alloc);2638rtv_descriptor_heap_pool.free(rtv_alloc);2639ERR_FAIL_V(CommandBufferID());2640}2641}26422643// Bookkeep26442645CommandBufferInfo *cmd_buf_info = VersatileResource::allocate<CommandBufferInfo>(resources_allocator);2646cmd_buf_info->cmd_allocator = cmd_allocator;2647cmd_buf_info->cmd_list = cmd_list;26482649cmd_list->QueryInterface(cmd_buf_info->cmd_list_1.GetAddressOf());2650cmd_list->QueryInterface(cmd_buf_info->cmd_list_5.GetAddressOf());2651cmd_list->QueryInterface(cmd_buf_info->cmd_list_7.GetAddressOf());26522653cmd_buf_info->uav_alloc = uav_alloc;2654cmd_buf_info->rtv_alloc = rtv_alloc;2655cmd_buf_info->dsv_alloc = dsv_alloc;26562657// Add this command buffer to the command pool's list of command buffers.2658command_pool->command_buffers.add(&cmd_buf_info->command_buffer_info_elem);26592660return CommandBufferID(cmd_buf_info);2661}26622663bool RenderingDeviceDriverD3D12::command_buffer_begin(CommandBufferID p_cmd_buffer) {2664const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;2665HRESULT res = cmd_buf_info->cmd_allocator->Reset();2666ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), false, "Reset failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");2667res = cmd_buf_info->cmd_list->Reset(cmd_buf_info->cmd_allocator.Get(), nullptr);2668ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), false, "Reset failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");2669return true;2670}26712672bool RenderingDeviceDriverD3D12::command_buffer_begin_secondary(CommandBufferID p_cmd_buffer, RenderPassID p_render_pass, uint32_t p_subpass, FramebufferID p_framebuffer) {2673const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;2674HRESULT res = cmd_buf_info->cmd_allocator->Reset();2675ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), false, "Reset failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");2676res = cmd_buf_info->cmd_list->Reset(cmd_buf_info->cmd_allocator.Get(), nullptr);2677ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), false, "Reset failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");2678return true;2679}26802681void RenderingDeviceDriverD3D12::command_buffer_end(CommandBufferID p_cmd_buffer) {2682CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;2683HRESULT res = cmd_buf_info->cmd_list->Close();26842685ERR_FAIL_COND_MSG(!SUCCEEDED(res), "Close failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");2686cmd_buf_info->graphics_pso = nullptr;2687cmd_buf_info->graphics_root_signature_crc = 0;2688cmd_buf_info->compute_pso = nullptr;2689cmd_buf_info->compute_root_signature_crc = 0;2690cmd_buf_info->pending_dyn_params = true;2691cmd_buf_info->descriptor_heaps_set = false;2692}26932694void RenderingDeviceDriverD3D12::command_buffer_execute_secondary(CommandBufferID p_cmd_buffer, VectorView<CommandBufferID> p_secondary_cmd_buffers) {2695const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;2696for (uint32_t i = 0; i < p_secondary_cmd_buffers.size(); i++) {2697const CommandBufferInfo *secondary_cb_info = (const CommandBufferInfo *)p_secondary_cmd_buffers[i].id;2698cmd_buf_info->cmd_list->ExecuteBundle(secondary_cb_info->cmd_list.Get());2699}2700}27012702/********************/2703/**** SWAP CHAIN ****/2704/********************/27052706void RenderingDeviceDriverD3D12::_swap_chain_release(SwapChain *p_swap_chain) {2707_swap_chain_release_buffers(p_swap_chain);27082709p_swap_chain->d3d_swap_chain.Reset();2710}27112712void RenderingDeviceDriverD3D12::_swap_chain_release_buffers(SwapChain *p_swap_chain) {2713for (ID3D12Resource *render_target : p_swap_chain->render_targets) {2714render_target->Release();2715}27162717p_swap_chain->render_targets.clear();2718p_swap_chain->render_targets_info.clear();27192720for (RDD::FramebufferID framebuffer : p_swap_chain->framebuffers) {2721framebuffer_free(framebuffer);2722}27232724p_swap_chain->framebuffers.clear();2725}27262727RDD::SwapChainID RenderingDeviceDriverD3D12::swap_chain_create(RenderingContextDriver::SurfaceID p_surface) {2728// Create the render pass that will be used to draw to the swap chain's framebuffers.2729RDD::Attachment attachment;2730attachment.format = DATA_FORMAT_R8G8B8A8_UNORM;2731attachment.samples = RDD::TEXTURE_SAMPLES_1;2732attachment.load_op = RDD::ATTACHMENT_LOAD_OP_CLEAR;2733attachment.store_op = RDD::ATTACHMENT_STORE_OP_STORE;27342735RDD::Subpass subpass;2736RDD::AttachmentReference color_ref;2737color_ref.attachment = 0;2738color_ref.aspect.set_flag(RDD::TEXTURE_ASPECT_COLOR_BIT);2739subpass.color_references.push_back(color_ref);27402741RenderPassID render_pass = render_pass_create(attachment, subpass, {}, 1, AttachmentReference());2742ERR_FAIL_COND_V(!render_pass, SwapChainID());27432744// Create the empty swap chain until it is resized.2745SwapChain *swap_chain = memnew(SwapChain);2746swap_chain->surface = p_surface;2747swap_chain->data_format = attachment.format;2748swap_chain->render_pass = render_pass;2749return SwapChainID(swap_chain);2750}27512752Error RenderingDeviceDriverD3D12::swap_chain_resize(CommandQueueID p_cmd_queue, SwapChainID p_swap_chain, uint32_t p_desired_framebuffer_count) {2753DEV_ASSERT(p_cmd_queue.id != 0);2754DEV_ASSERT(p_swap_chain.id != 0);27552756CommandQueueInfo *command_queue = (CommandQueueInfo *)(p_cmd_queue.id);2757SwapChain *swap_chain = (SwapChain *)(p_swap_chain.id);2758RenderingContextDriverD3D12::Surface *surface = (RenderingContextDriverD3D12::Surface *)(swap_chain->surface);2759if (surface->width == 0 || surface->height == 0) {2760// Very likely the window is minimized, don't create a swap chain.2761return ERR_SKIP;2762}27632764HRESULT res;2765const bool is_tearing_supported = context_driver->get_tearing_supported();2766UINT sync_interval = 0;2767UINT present_flags = 0;2768UINT creation_flags = 0;2769switch (surface->vsync_mode) {2770case DisplayServer::VSYNC_MAILBOX: {2771sync_interval = 1;2772present_flags = DXGI_PRESENT_RESTART;2773} break;2774case DisplayServer::VSYNC_ENABLED: {2775sync_interval = 1;2776present_flags = 0;2777} break;2778case DisplayServer::VSYNC_DISABLED: {2779sync_interval = 0;2780present_flags = is_tearing_supported ? DXGI_PRESENT_ALLOW_TEARING : 0;2781creation_flags = is_tearing_supported ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;2782} break;2783case DisplayServer::VSYNC_ADAPTIVE: // Unsupported.2784default:2785sync_interval = 1;2786present_flags = 0;2787break;2788}27892790if (swap_chain->d3d_swap_chain != nullptr && creation_flags != swap_chain->creation_flags) {2791// The swap chain must be recreated if the creation flags are different.2792_swap_chain_release(swap_chain);2793}27942795#ifdef DCOMP_ENABLED2796bool create_for_composition = OS::get_singleton()->is_layered_allowed();2797#else2798if (OS::get_singleton()->is_layered_allowed()) {2799WARN_PRINT_ONCE("Window transparency is not supported without DirectComposition on D3D12.");2800}2801bool create_for_composition = false;2802#endif28032804DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = {};2805if (swap_chain->d3d_swap_chain != nullptr) {2806_swap_chain_release_buffers(swap_chain);2807res = swap_chain->d3d_swap_chain->ResizeBuffers(p_desired_framebuffer_count, surface->width, surface->height, DXGI_FORMAT_UNKNOWN, creation_flags);2808ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_UNAVAILABLE);2809} else {2810swap_chain_desc.BufferCount = p_desired_framebuffer_count;2811swap_chain_desc.Format = RD_TO_D3D12_FORMAT[swap_chain->data_format].general_format;2812swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;2813swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;2814swap_chain_desc.SampleDesc.Count = 1;2815swap_chain_desc.Flags = creation_flags;2816swap_chain_desc.Scaling = DXGI_SCALING_STRETCH;2817if (create_for_composition) {2818swap_chain_desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;2819has_comp_alpha[(uint64_t)p_cmd_queue.id] = true;2820} else {2821swap_chain_desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;2822has_comp_alpha[(uint64_t)p_cmd_queue.id] = false;2823}2824swap_chain_desc.Width = surface->width;2825swap_chain_desc.Height = surface->height;28262827ComPtr<IDXGISwapChain1> swap_chain_1;2828if (create_for_composition) {2829res = context_driver->dxgi_factory_get()->CreateSwapChainForComposition(command_queue->d3d_queue.Get(), &swap_chain_desc, nullptr, swap_chain_1.GetAddressOf());2830if (!SUCCEEDED(res)) {2831WARN_PRINT_ONCE("Window transparency is not supported without DirectComposition on D3D12.");2832swap_chain_desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;2833has_comp_alpha[(uint64_t)p_cmd_queue.id] = false;2834create_for_composition = false;28352836res = context_driver->dxgi_factory_get()->CreateSwapChainForHwnd(command_queue->d3d_queue.Get(), surface->hwnd, &swap_chain_desc, nullptr, nullptr, swap_chain_1.GetAddressOf());2837}2838} else {2839res = context_driver->dxgi_factory_get()->CreateSwapChainForHwnd(command_queue->d3d_queue.Get(), surface->hwnd, &swap_chain_desc, nullptr, nullptr, swap_chain_1.GetAddressOf());2840}28412842ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);28432844swap_chain_1.As(&swap_chain->d3d_swap_chain);2845ERR_FAIL_NULL_V(swap_chain->d3d_swap_chain, ERR_CANT_CREATE);28462847res = context_driver->dxgi_factory_get()->MakeWindowAssociation(surface->hwnd, DXGI_MWA_NO_ALT_ENTER | DXGI_MWA_NO_WINDOW_CHANGES);2848ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);2849}28502851#ifdef DCOMP_ENABLED2852if (create_for_composition) {2853if (surface->composition_device.Get() == nullptr) {2854using PFN_DCompositionCreateDevice = HRESULT(WINAPI *)(IDXGIDevice *, REFIID, void **);2855PFN_DCompositionCreateDevice pfn_DCompositionCreateDevice = (PFN_DCompositionCreateDevice)(void *)GetProcAddress(context_driver->lib_dcomp, "DCompositionCreateDevice");2856ERR_FAIL_NULL_V(pfn_DCompositionCreateDevice, ERR_CANT_CREATE);28572858res = pfn_DCompositionCreateDevice(nullptr, IID_PPV_ARGS(surface->composition_device.GetAddressOf()));2859ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);28602861res = surface->composition_device->CreateTargetForHwnd(surface->hwnd, TRUE, surface->composition_target.GetAddressOf());2862ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);28632864res = surface->composition_device->CreateVisual(surface->composition_visual.GetAddressOf());2865ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);28662867res = surface->composition_visual->SetContent(swap_chain->d3d_swap_chain.Get());2868ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);28692870res = surface->composition_target->SetRoot(surface->composition_visual.Get());2871ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);28722873res = surface->composition_device->Commit();2874ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);2875} else {2876res = surface->composition_visual->SetContent(swap_chain->d3d_swap_chain.Get());2877ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);28782879res = surface->composition_device->Commit();2880ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);2881}2882}2883#endif28842885res = swap_chain->d3d_swap_chain->GetDesc1(&swap_chain_desc);2886ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);2887ERR_FAIL_COND_V(swap_chain_desc.BufferCount == 0, ERR_CANT_CREATE);28882889surface->width = swap_chain_desc.Width;2890surface->height = swap_chain_desc.Height;28912892swap_chain->creation_flags = creation_flags;2893swap_chain->sync_interval = sync_interval;2894swap_chain->present_flags = present_flags;28952896// Retrieve the render targets associated to the swap chain and recreate the framebuffers. The following code2897// relies on the address of the elements remaining static when new elements are inserted, so the container must2898// follow this restriction when reserving the right amount of elements beforehand.2899swap_chain->render_targets.reserve(swap_chain_desc.BufferCount);2900swap_chain->render_targets_info.reserve(swap_chain_desc.BufferCount);2901swap_chain->framebuffers.reserve(swap_chain_desc.BufferCount);29022903for (uint32_t i = 0; i < swap_chain_desc.BufferCount; i++) {2904// Retrieve the resource corresponding to the swap chain's buffer.2905ID3D12Resource *render_target = nullptr;2906res = swap_chain->d3d_swap_chain->GetBuffer(i, IID_PPV_ARGS(&render_target));2907ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);2908swap_chain->render_targets.push_back(render_target);29092910// Create texture information for the framebuffer to reference the resource. Since the states pointer must2911// reference an address of the element itself, we must insert it first and then modify it.2912swap_chain->render_targets_info.push_back(TextureInfo());2913TextureInfo &texture_info = swap_chain->render_targets_info[i];2914texture_info.owner_info.states.subresource_states.push_back(D3D12_RESOURCE_STATE_PRESENT);2915texture_info.states_ptr = &texture_info.owner_info.states;2916texture_info.format = swap_chain->data_format;2917#if defined(_MSC_VER) || !defined(_WIN32)2918texture_info.desc = CD3DX12_RESOURCE_DESC(render_target->GetDesc());2919#else2920render_target->GetDesc(&texture_info.desc);2921#endif2922texture_info.layers = 1;2923texture_info.mipmaps = 1;2924texture_info.resource = render_target;2925texture_info.view_descs.srv.Format = texture_info.desc.Format;2926texture_info.view_descs.srv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;29272928// Create the framebuffer for this buffer.2929FramebufferID framebuffer = _framebuffer_create(swap_chain->render_pass, TextureID(&swap_chain->render_targets_info[i]), swap_chain_desc.Width, swap_chain_desc.Height, true);2930ERR_FAIL_COND_V(!framebuffer, ERR_CANT_CREATE);2931swap_chain->framebuffers.push_back(framebuffer);2932}29332934// Once everything's been created correctly, indicate the surface no longer needs to be resized.2935context_driver->surface_set_needs_resize(swap_chain->surface, false);29362937return OK;2938}29392940RDD::FramebufferID RenderingDeviceDriverD3D12::swap_chain_acquire_framebuffer(CommandQueueID p_cmd_queue, SwapChainID p_swap_chain, bool &r_resize_required) {2941DEV_ASSERT(p_swap_chain.id != 0);29422943const SwapChain *swap_chain = (const SwapChain *)(p_swap_chain.id);2944if (context_driver->surface_get_needs_resize(swap_chain->surface)) {2945r_resize_required = true;2946return FramebufferID();2947}29482949const uint32_t buffer_index = swap_chain->d3d_swap_chain->GetCurrentBackBufferIndex();2950DEV_ASSERT(buffer_index < swap_chain->framebuffers.size());2951return swap_chain->framebuffers[buffer_index];2952}29532954RDD::RenderPassID RenderingDeviceDriverD3D12::swap_chain_get_render_pass(SwapChainID p_swap_chain) {2955const SwapChain *swap_chain = (const SwapChain *)(p_swap_chain.id);2956return swap_chain->render_pass;2957}29582959RDD::DataFormat RenderingDeviceDriverD3D12::swap_chain_get_format(SwapChainID p_swap_chain) {2960const SwapChain *swap_chain = (const SwapChain *)(p_swap_chain.id);2961return swap_chain->data_format;2962}29632964void RenderingDeviceDriverD3D12::swap_chain_free(SwapChainID p_swap_chain) {2965SwapChain *swap_chain = (SwapChain *)(p_swap_chain.id);2966_swap_chain_release(swap_chain);2967render_pass_free(swap_chain->render_pass);2968memdelete(swap_chain);2969}29702971/*********************/2972/**** FRAMEBUFFER ****/2973/*********************/29742975D3D12_RENDER_TARGET_VIEW_DESC RenderingDeviceDriverD3D12::_make_rtv_for_texture(const TextureInfo *p_texture_info, uint32_t p_mipmap_offset, uint32_t p_layer_offset, uint32_t p_layers, bool p_add_bases) {2976D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = {};2977rtv_desc.Format = p_texture_info->view_descs.srv.Format;29782979switch (p_texture_info->view_descs.srv.ViewDimension) {2980case D3D12_SRV_DIMENSION_TEXTURE1D: {2981rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1D;2982rtv_desc.Texture1D.MipSlice = p_texture_info->base_mip + p_mipmap_offset;2983} break;2984case D3D12_SRV_DIMENSION_TEXTURE1DARRAY: {2985rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1DARRAY;2986rtv_desc.Texture1DArray.MipSlice = (p_add_bases ? p_texture_info->base_mip : 0) + p_mipmap_offset;2987rtv_desc.Texture1DArray.FirstArraySlice = (p_add_bases ? p_texture_info->base_layer : 0) + p_layer_offset;2988rtv_desc.Texture1DArray.ArraySize = p_layers == UINT32_MAX ? p_texture_info->view_descs.srv.Texture1DArray.ArraySize : p_layers;2989} break;2990case D3D12_SRV_DIMENSION_TEXTURE2D: {2991rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;2992rtv_desc.Texture2D.MipSlice = (p_add_bases ? p_texture_info->base_mip : 0) + p_mipmap_offset;2993rtv_desc.Texture2D.PlaneSlice = p_texture_info->view_descs.srv.Texture2D.PlaneSlice;2994} break;2995case D3D12_SRV_DIMENSION_TEXTURE2DARRAY: {2996rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;2997rtv_desc.Texture2DArray.MipSlice = (p_add_bases ? p_texture_info->base_mip : 0) + p_mipmap_offset;2998rtv_desc.Texture2DArray.FirstArraySlice = (p_add_bases ? p_texture_info->base_layer : 0) + p_layer_offset;2999rtv_desc.Texture2DArray.ArraySize = p_layers == UINT32_MAX ? p_texture_info->view_descs.srv.Texture2DArray.ArraySize : p_layers;3000rtv_desc.Texture2DArray.PlaneSlice = p_texture_info->view_descs.srv.Texture2DArray.PlaneSlice;3001} break;3002case D3D12_SRV_DIMENSION_TEXTURE2DMS: {3003rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;3004} break;3005case D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY: {3006rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;3007rtv_desc.Texture2DMSArray.FirstArraySlice = (p_add_bases ? p_texture_info->base_layer : 0) + p_layer_offset;3008rtv_desc.Texture2DMSArray.ArraySize = p_layers == UINT32_MAX ? p_texture_info->view_descs.srv.Texture2DMSArray.ArraySize : p_layers;3009} break;3010case D3D12_SRV_DIMENSION_TEXTURE3D: {3011rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;3012rtv_desc.Texture3D.MipSlice = p_texture_info->view_descs.srv.Texture3D.MostDetailedMip + p_mipmap_offset;3013rtv_desc.Texture3D.FirstWSlice = 0;3014rtv_desc.Texture3D.WSize = -1;3015} break;3016case D3D12_SRV_DIMENSION_TEXTURECUBE:3017case D3D12_SRV_DIMENSION_TEXTURECUBEARRAY: {3018rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;3019rtv_desc.Texture2DArray.MipSlice = (p_add_bases ? p_texture_info->base_mip : 0) + p_mipmap_offset;3020rtv_desc.Texture2DArray.FirstArraySlice = (p_add_bases ? p_texture_info->base_layer : 0) + p_layer_offset;3021rtv_desc.Texture2DArray.ArraySize = p_layers == UINT32_MAX ? p_texture_info->layers : p_layers;3022rtv_desc.Texture2DArray.PlaneSlice = 0;3023} break;3024default: {3025DEV_ASSERT(false);3026}3027}30283029return rtv_desc;3030}30313032D3D12_UNORDERED_ACCESS_VIEW_DESC RenderingDeviceDriverD3D12::_make_ranged_uav_for_texture(const TextureInfo *p_texture_info, uint32_t p_mipmap_offset, uint32_t p_layer_offset, uint32_t p_layers, bool p_add_bases) {3033D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = p_texture_info->view_descs.uav;30343035uint32_t mip = (p_add_bases ? p_texture_info->base_mip : 0) + p_mipmap_offset;3036switch (p_texture_info->view_descs.uav.ViewDimension) {3037case D3D12_UAV_DIMENSION_TEXTURE1D: {3038uav_desc.Texture1DArray.MipSlice = mip;3039} break;3040case D3D12_UAV_DIMENSION_TEXTURE1DARRAY: {3041uav_desc.Texture1DArray.MipSlice = mip;3042uav_desc.Texture1DArray.FirstArraySlice = mip;3043uav_desc.Texture1DArray.ArraySize = p_layers;3044} break;3045case D3D12_UAV_DIMENSION_TEXTURE2D: {3046uav_desc.Texture2D.MipSlice = mip;3047} break;3048case D3D12_UAV_DIMENSION_TEXTURE2DARRAY: {3049uav_desc.Texture2DArray.MipSlice = mip;3050uav_desc.Texture2DArray.FirstArraySlice = (p_add_bases ? p_texture_info->base_layer : 0) + p_layer_offset;3051uav_desc.Texture2DArray.ArraySize = p_layers;3052} break;3053case D3D12_UAV_DIMENSION_TEXTURE3D: {3054uav_desc.Texture3D.MipSlice = mip;3055uav_desc.Texture3D.WSize = MAX(uav_desc.Texture3D.WSize >> p_mipmap_offset, 1U);3056} break;3057default:3058break;3059}30603061return uav_desc;3062}30633064D3D12_DEPTH_STENCIL_VIEW_DESC RenderingDeviceDriverD3D12::_make_dsv_for_texture(const TextureInfo *p_texture_info, uint32_t p_mipmap_offset, uint32_t p_layer_offset, uint32_t p_layers, bool p_add_bases) {3065D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc = {};3066dsv_desc.Format = RD_TO_D3D12_FORMAT[p_texture_info->format].dsv_format;3067dsv_desc.Flags = D3D12_DSV_FLAG_NONE;30683069switch (p_texture_info->view_descs.srv.ViewDimension) {3070case D3D12_SRV_DIMENSION_TEXTURE1D: {3071dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE1D;3072dsv_desc.Texture1D.MipSlice = p_texture_info->base_mip + p_mipmap_offset;3073} break;3074case D3D12_SRV_DIMENSION_TEXTURE1DARRAY: {3075dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE1DARRAY;3076dsv_desc.Texture1DArray.MipSlice = (p_add_bases ? p_texture_info->base_mip : 0) + p_mipmap_offset;3077dsv_desc.Texture1DArray.FirstArraySlice = (p_add_bases ? p_texture_info->base_layer : 0) + p_layer_offset;3078dsv_desc.Texture1DArray.ArraySize = p_layers == UINT32_MAX ? p_texture_info->view_descs.srv.Texture1DArray.ArraySize : p_layers;3079} break;3080case D3D12_SRV_DIMENSION_TEXTURE2D: {3081dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;3082dsv_desc.Texture2D.MipSlice = (p_add_bases ? p_texture_info->base_mip : 0) + p_mipmap_offset;3083} break;3084case D3D12_SRV_DIMENSION_TEXTURE2DARRAY: {3085dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY;3086dsv_desc.Texture2DArray.MipSlice = (p_add_bases ? p_texture_info->base_mip : 0) + p_mipmap_offset;3087dsv_desc.Texture2DArray.FirstArraySlice = (p_add_bases ? p_texture_info->base_layer : 0) + p_layer_offset;3088dsv_desc.Texture2DArray.ArraySize = p_layers == UINT32_MAX ? p_texture_info->view_descs.srv.Texture2DArray.ArraySize : p_layers;3089} break;3090case D3D12_SRV_DIMENSION_TEXTURE2DMS: {3091dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMS;3092dsv_desc.Texture2DMS.UnusedField_NothingToDefine = p_texture_info->view_descs.srv.Texture2DMS.UnusedField_NothingToDefine;3093} break;3094case D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY: {3095dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY;3096dsv_desc.Texture2DMSArray.FirstArraySlice = (p_add_bases ? p_texture_info->base_layer : 0) + p_layer_offset;3097dsv_desc.Texture2DMSArray.ArraySize = p_layers == UINT32_MAX ? p_texture_info->view_descs.srv.Texture2DMSArray.ArraySize : p_layers;3098} break;3099case D3D12_SRV_DIMENSION_TEXTURECUBE: {3100dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY;3101dsv_desc.Texture2DArray.MipSlice = (p_add_bases ? p_texture_info->base_mip : 0) + p_mipmap_offset;3102dsv_desc.Texture2DArray.FirstArraySlice = (p_add_bases ? p_texture_info->base_layer : 0) + p_layer_offset;3103dsv_desc.Texture2DArray.ArraySize = p_layers == UINT32_MAX ? 6 : p_layers;3104} break;3105case D3D12_SRV_DIMENSION_TEXTURECUBEARRAY: {3106dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY;3107dsv_desc.Texture2DArray.MipSlice = (p_add_bases ? p_texture_info->base_mip : 0) + p_mipmap_offset;3108dsv_desc.Texture2DArray.FirstArraySlice = (p_add_bases ? p_texture_info->base_layer : 0) + p_layer_offset;3109dsv_desc.Texture2DArray.ArraySize = p_layers == UINT32_MAX ? (p_texture_info->view_descs.srv.TextureCubeArray.NumCubes * 6) : p_layers;3110} break;3111default: {3112DEV_ASSERT(false);3113}3114}31153116return dsv_desc;3117}31183119RDD::FramebufferID RenderingDeviceDriverD3D12::_framebuffer_create(RenderPassID p_render_pass, VectorView<TextureID> p_attachments, uint32_t p_width, uint32_t p_height, bool p_is_screen) {3120const RenderPassInfo *pass_info = (const RenderPassInfo *)p_render_pass.id;31213122uint32_t num_color = 0;3123uint32_t num_depth_stencil = 0;3124for (uint32_t i = 0; i < p_attachments.size(); i++) {3125const TextureInfo *tex_info = (const TextureInfo *)p_attachments[i].id;3126if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)) {3127num_color++;3128} else if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {3129num_depth_stencil++;3130}3131}31323133uint32_t vrs_index = UINT32_MAX;3134for (const Subpass &E : pass_info->subpasses) {3135if (E.fragment_shading_rate_reference.attachment != AttachmentReference::UNUSED) {3136vrs_index = E.fragment_shading_rate_reference.attachment;3137}3138}31393140CPUDescriptorHeapPool::Allocation rtv_alloc;3141if (num_color) {3142Error err = rtv_descriptor_heap_pool.allocate(num_color, device.Get(), rtv_alloc);3143ERR_FAIL_COND_V(err != OK, FramebufferID());3144}31453146CPUDescriptorHeapPool::Allocation dsv_alloc;3147if (num_depth_stencil) {3148Error err = dsv_descriptor_heap_pool.allocate(num_depth_stencil, device.Get(), dsv_alloc);3149if (unlikely(err != OK)) {3150rtv_descriptor_heap_pool.free(rtv_alloc);3151ERR_FAIL_V(FramebufferID());3152}3153}31543155// Bookkeep.3156FramebufferInfo *fb_info = VersatileResource::allocate<FramebufferInfo>(resources_allocator);3157fb_info->is_screen = p_is_screen;31583159fb_info->rtv_alloc = rtv_alloc;3160fb_info->dsv_alloc = dsv_alloc;31613162fb_info->attachments_handle_inds.resize(p_attachments.size());3163fb_info->attachments.reserve(num_color + num_depth_stencil);31643165uint32_t color_idx = 0;3166uint32_t depth_stencil_idx = 0;3167for (uint32_t i = 0; i < p_attachments.size(); i++) {3168const TextureInfo *tex_info = (const TextureInfo *)p_attachments[i].id;31693170if (fb_info->size.x == 0) {3171fb_info->size = Size2i(tex_info->desc.Width, tex_info->desc.Height);3172}31733174if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)) {3175D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = _make_rtv_for_texture(tex_info, 0, 0, UINT32_MAX);3176device->CreateRenderTargetView(tex_info->resource, &rtv_desc, get_cpu_handle(fb_info->rtv_alloc.cpu_handle, color_idx, rtv_descriptor_heap_pool.increment_size));31773178fb_info->attachments_handle_inds[i] = color_idx;3179fb_info->attachments.push_back(p_attachments[i]);3180color_idx++;3181} else if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {3182D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc = _make_dsv_for_texture(tex_info, 0, 0, UINT32_MAX);3183device->CreateDepthStencilView(tex_info->resource, &dsv_desc, get_cpu_handle(fb_info->dsv_alloc.cpu_handle, depth_stencil_idx, dsv_descriptor_heap_pool.increment_size));31843185fb_info->attachments_handle_inds[i] = depth_stencil_idx;3186fb_info->attachments.push_back(p_attachments[i]);3187depth_stencil_idx++;3188} else if (i == vrs_index) {3189fb_info->vrs_attachment = p_attachments[i];3190} else {3191DEV_ASSERT(false);3192}3193}31943195DEV_ASSERT(fb_info->attachments.size() == color_idx + depth_stencil_idx);3196DEV_ASSERT((fb_info->vrs_attachment.id != 0) == (vrs_index != UINT32_MAX));31973198return FramebufferID(fb_info);3199}32003201RDD::FramebufferID RenderingDeviceDriverD3D12::framebuffer_create(RenderPassID p_render_pass, VectorView<TextureID> p_attachments, uint32_t p_width, uint32_t p_height) {3202return _framebuffer_create(p_render_pass, p_attachments, p_width, p_height, false);3203}32043205void RenderingDeviceDriverD3D12::framebuffer_free(FramebufferID p_framebuffer) {3206FramebufferInfo *fb_info = (FramebufferInfo *)p_framebuffer.id;32073208rtv_descriptor_heap_pool.free(fb_info->rtv_alloc);3209dsv_descriptor_heap_pool.free(fb_info->dsv_alloc);32103211VersatileResource::free(resources_allocator, fb_info);3212}32133214/****************/3215/**** SHADER ****/3216/****************/32173218bool RenderingDeviceDriverD3D12::_shader_apply_specialization_constants(3219const ShaderInfo *p_shader_info,3220VectorView<PipelineSpecializationConstant> p_specialization_constants,3221HashMap<ShaderStage, Vector<uint8_t>> &r_final_stages_bytecode) {3222// If something needs to be patched, COW will do the trick.3223r_final_stages_bytecode = p_shader_info->stages_bytecode;3224uint32_t stages_re_sign_mask = 0;3225for (uint32_t i = 0; i < p_specialization_constants.size(); i++) {3226const PipelineSpecializationConstant &psc = p_specialization_constants[i];3227if (!(p_shader_info->spirv_specialization_constants_ids_mask & (1 << psc.constant_id))) {3228// This SC wasn't even in the original SPIR-V shader.3229continue;3230}3231for (const ShaderInfo::SpecializationConstant &sc : p_shader_info->specialization_constants) {3232if (psc.constant_id == sc.constant_id) {3233if (psc.int_value != sc.int_value) {3234stages_re_sign_mask |= RenderingDXIL::patch_specialization_constant(psc.type, &psc.int_value, sc.stages_bit_offsets, r_final_stages_bytecode, false);3235}3236break;3237}3238}3239}3240// Re-sign patched stages.3241for (KeyValue<ShaderStage, Vector<uint8_t>> &E : r_final_stages_bytecode) {3242ShaderStage stage = E.key;3243if ((stages_re_sign_mask & (1 << stage))) {3244Vector<uint8_t> &bytecode = E.value;3245RenderingDXIL::sign_bytecode(stage, bytecode);3246}3247}32483249return true;3250}32513252RDD::ShaderID RenderingDeviceDriverD3D12::shader_create_from_container(const Ref<RenderingShaderContainer> &p_shader_container, const Vector<ImmutableSampler> &p_immutable_samplers) {3253ShaderReflection shader_refl = p_shader_container->get_shader_reflection();3254ShaderInfo shader_info_in;3255const RenderingShaderContainerD3D12 *shader_container_d3d12 = Object::cast_to<RenderingShaderContainerD3D12>(p_shader_container.ptr());3256ERR_FAIL_NULL_V_MSG(shader_container_d3d12, ShaderID(), "Shader container is not a recognized format.");32573258RenderingShaderContainerD3D12::ShaderReflectionD3D12 shader_refl_d3d12 = shader_container_d3d12->get_shader_reflection_d3d12();3259if (shader_refl_d3d12.dxil_push_constant_stages != 0) {3260shader_info_in.dxil_push_constant_size = shader_refl.push_constant_size;3261}32623263shader_info_in.spirv_specialization_constants_ids_mask = shader_refl_d3d12.spirv_specialization_constants_ids_mask;3264shader_info_in.nir_runtime_data_root_param_idx = shader_refl_d3d12.nir_runtime_data_root_param_idx;3265shader_info_in.pipeline_type = shader_refl.pipeline_type;32663267shader_info_in.sets.resize(shader_refl.uniform_sets.size());3268for (uint32_t i = 0; i < shader_info_in.sets.size(); i++) {3269const RenderingShaderContainerD3D12::ReflectionBindingSetDataD3D12 &set_d3d12 = shader_refl_d3d12.reflection_binding_sets_d3d12[i];32703271ShaderInfo::UniformSet &set = shader_info_in.sets[i];3272set.resource_root_param_idx = set_d3d12.resource_root_param_idx;3273set.resource_descriptor_count = set_d3d12.resource_descriptor_count;3274set.sampler_root_param_idx = set_d3d12.sampler_root_param_idx;3275set.sampler_descriptor_count = set_d3d12.sampler_descriptor_count;32763277set.bindings.resize(shader_refl.uniform_sets[i].size());3278for (uint32_t j = 0; j < set.bindings.size(); j++) {3279const ShaderUniform &uniform = shader_refl.uniform_sets[i][j];3280const RenderingShaderContainerD3D12::ReflectionBindingDataD3D12 &uniform_d3d12 = shader_refl_d3d12.reflection_binding_set_uniforms_d3d12[i][j];3281ShaderInfo::UniformBindingInfo &binding = set.bindings[j];3282binding.stages = uniform_d3d12.dxil_stages;3283binding.res_class = (ResourceClass)(uniform_d3d12.resource_class);3284binding.type = UniformType(uniform.type);3285binding.length = uniform.length;3286binding.writable = uniform.writable;3287binding.resource_descriptor_offset = uniform_d3d12.resource_descriptor_offset;3288binding.sampler_descriptor_offset = uniform_d3d12.sampler_descriptor_offset;3289binding.root_param_idx = uniform_d3d12.root_param_idx;3290}3291}32923293shader_info_in.specialization_constants.resize(shader_refl.specialization_constants.size());3294for (uint32_t i = 0; i < shader_info_in.specialization_constants.size(); i++) {3295ShaderInfo::SpecializationConstant &sc = shader_info_in.specialization_constants[i];3296const ShaderSpecializationConstant &src_sc = shader_refl.specialization_constants[i];3297const RenderingShaderContainerD3D12::ReflectionSpecializationDataD3D12 &src_sc_d3d12 = shader_refl_d3d12.reflection_specialization_data_d3d12[i];3298sc.constant_id = src_sc.constant_id;3299sc.int_value = src_sc.int_value;3300memcpy(sc.stages_bit_offsets, src_sc_d3d12.stages_bit_offsets, sizeof(sc.stages_bit_offsets));3301}33023303Vector<uint8_t> decompressed_code;3304for (uint32_t i = 0; i < shader_refl.stages_vector.size(); i++) {3305const RenderingShaderContainer::Shader &shader = p_shader_container->shaders[i];3306bool requires_decompression = (shader.code_decompressed_size > 0);3307if (requires_decompression) {3308decompressed_code.resize(shader.code_decompressed_size);3309bool decompressed = p_shader_container->decompress_code(shader.code_compressed_bytes.ptr(), shader.code_compressed_bytes.size(), shader.code_compression_flags, decompressed_code.ptrw(), decompressed_code.size());3310ERR_FAIL_COND_V_MSG(!decompressed, ShaderID(), vformat("Failed to decompress code on shader stage %s.", String(SHADER_STAGE_NAMES[shader_refl.stages_vector[i]])));3311}33123313if (requires_decompression) {3314shader_info_in.stages_bytecode[shader.shader_stage] = decompressed_code;3315} else {3316shader_info_in.stages_bytecode[shader.shader_stage] = shader.code_compressed_bytes;3317}3318}33193320PFN_D3D12_CREATE_ROOT_SIGNATURE_DESERIALIZER d3d_D3D12CreateRootSignatureDeserializer = (PFN_D3D12_CREATE_ROOT_SIGNATURE_DESERIALIZER)(void *)GetProcAddress(context_driver->lib_d3d12, "D3D12CreateRootSignatureDeserializer");3321ERR_FAIL_NULL_V(d3d_D3D12CreateRootSignatureDeserializer, ShaderID());33223323HRESULT res = d3d_D3D12CreateRootSignatureDeserializer(shader_refl_d3d12.root_signature_bytes.ptr(), shader_refl_d3d12.root_signature_bytes.size(), IID_PPV_ARGS(shader_info_in.root_signature_deserializer.GetAddressOf()));3324ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ShaderID(), "D3D12CreateRootSignatureDeserializer failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");33253326ComPtr<ID3D12RootSignature> root_signature;3327res = device->CreateRootSignature(0, shader_refl_d3d12.root_signature_bytes.ptr(), shader_refl_d3d12.root_signature_bytes.size(), IID_PPV_ARGS(shader_info_in.root_signature.GetAddressOf()));3328ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ShaderID(), "CreateRootSignature failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");33293330shader_info_in.root_signature_desc = shader_info_in.root_signature_deserializer->GetRootSignatureDesc();3331shader_info_in.root_signature_crc = shader_refl_d3d12.root_signature_crc;33323333// Bookkeep.3334ShaderInfo *shader_info_ptr = VersatileResource::allocate<ShaderInfo>(resources_allocator);3335*shader_info_ptr = shader_info_in;3336return ShaderID(shader_info_ptr);3337}33383339uint32_t RenderingDeviceDriverD3D12::shader_get_layout_hash(ShaderID p_shader) {3340const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;3341return shader_info_in->root_signature_crc;3342}33433344void RenderingDeviceDriverD3D12::shader_free(ShaderID p_shader) {3345ShaderInfo *shader_info_in = (ShaderInfo *)p_shader.id;3346VersatileResource::free(resources_allocator, shader_info_in);3347}33483349void RenderingDeviceDriverD3D12::shader_destroy_modules(ShaderID p_shader) {3350ShaderInfo *shader_info_in = (ShaderInfo *)p_shader.id;3351shader_info_in->stages_bytecode.clear();3352}33533354/*********************/3355/**** UNIFORM SET ****/3356/*********************/33573358RDD::UniformSetID RenderingDeviceDriverD3D12::uniform_set_create(VectorView<BoundUniform> p_uniforms, ShaderID p_shader, uint32_t p_set_index, int p_linear_pool_index) {3359// Pre-bookkeep.3360UniformSetInfo *uniform_set_info = VersatileResource::allocate<UniformSetInfo>(resources_allocator);33613362const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;3363const ShaderInfo::UniformSet &uniform_set = shader_info_in->sets[p_set_index];33643365// We first gather dynamic arrays in a local array because TightLocalVector's3366// growth is not efficient when the number of elements is unknown.3367UniformSetInfo::DynamicBuffer dynamic_buffers[MAX_DYNAMIC_BUFFERS];3368uint32_t num_dynamic_buffers = 0u;33693370// Allocate range for resource descriptors.3371if (uniform_set.resource_descriptor_count > 0) {3372Error err = resource_descriptor_heap.allocate(uniform_set.resource_descriptor_count, uniform_set_info->resource_descriptor_heap_alloc);3373if (unlikely(err != OK)) {3374VersatileResource::free(resources_allocator, uniform_set_info);33753376ERR_FAIL_COND_V_MSG(err == ERR_OUT_OF_MEMORY, UniformSetID(), "Cannot create uniform set because there's not enough room in the RESOURCES descriptor heap.\n"3377"Please increase the value of the rendering/rendering_device/d3d12/max_resource_descriptors project setting.");33783379ERR_FAIL_V_MSG(UniformSetID(), "Failed to allocate resource descriptors.");3380}3381}33823383// Allocate range for sampler descriptors. Since we do not have much space for samplers, and many uniform sets use identical ones, it's very beneficial to cache and reuse them.3384bool create_samplers = false;3385if (uniform_set.sampler_descriptor_count > 0) {3386uint32_t sampler_key = HASH_MURMUR3_SEED;3387for (uint32_t i = 0; i < p_uniforms.size(); i++) {3388const BoundUniform &uniform = p_uniforms[i];33893390switch (uniform.type) {3391case UNIFORM_TYPE_SAMPLER: {3392for (uint32_t j = 0; j < uniform.ids.size(); j++) {3393sampler_key = hash_murmur3_one_64(uniform.ids[j].id, sampler_key);3394}3395} break;3396case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE: {3397for (uint32_t j = 0; j < uniform.ids.size(); j += 2) {3398sampler_key = hash_murmur3_one_64(uniform.ids[j].id, sampler_key);3399}3400} break;3401default: {3402} break;3403}3404}3405sampler_key = hash_fmix32(sampler_key);34063407RBMap<uint32_t, SamplerDescriptorHeapAllocation>::Iterator find_result = sampler_descriptor_heap_allocations.find(sampler_key);3408if (find_result != sampler_descriptor_heap_allocations.end()) {3409uniform_set_info->sampler_descriptor_heap_alloc = &find_result->value;3410++uniform_set_info->sampler_descriptor_heap_alloc->use_count;3411} else {3412uniform_set_info->sampler_descriptor_heap_alloc = &sampler_descriptor_heap_allocations.insert(sampler_key, SamplerDescriptorHeapAllocation())->get();3413uniform_set_info->sampler_descriptor_heap_alloc->key = sampler_key;34143415Error err = sampler_descriptor_heap.allocate(uniform_set.sampler_descriptor_count, *uniform_set_info->sampler_descriptor_heap_alloc);3416if (unlikely(err != OK)) {3417resource_descriptor_heap.free(uniform_set_info->resource_descriptor_heap_alloc);3418VersatileResource::free(resources_allocator, uniform_set_info);34193420ERR_FAIL_COND_V_MSG(err == ERR_OUT_OF_MEMORY, UniformSetID(), "Cannot create uniform set because there's not enough room in the SAMPLERS descriptors heap.\n"3421"Please increase the value of the rendering/rendering_device/d3d12/max_sampler_descriptors project setting.");34223423ERR_FAIL_V_MSG(UniformSetID(), "Failed to allocate sampler descriptors.");3424}34253426create_samplers = true;3427}3428}34293430struct NeededState {3431bool is_buffer = false;3432uint64_t shader_uniform_idx_mask = 0;3433D3D12_RESOURCE_STATES states = {};3434};3435HashMap<ResourceInfo *, NeededState> resource_states;34363437for (uint32_t i = 0; i < p_uniforms.size(); i++) {3438const BoundUniform &uniform = p_uniforms[i];3439const ShaderInfo::UniformBindingInfo &binding = uniform_set.bindings[i];34403441switch (uniform.type) {3442case UNIFORM_TYPE_SAMPLER: {3443if (create_samplers) {3444for (uint32_t j = 0; j < uniform.ids.size(); j++) {3445const D3D12_SAMPLER_DESC &sampler_desc = samplers[uniform.ids[j].id];3446device->CreateSampler(&sampler_desc, get_cpu_handle(uniform_set_info->sampler_descriptor_heap_alloc->cpu_handle, binding.sampler_descriptor_offset + j, sampler_descriptor_heap.increment_size));3447}3448}3449} break;3450case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE: {3451for (uint32_t j = 0; j < uniform.ids.size(); j += 2) {3452if (create_samplers) {3453const D3D12_SAMPLER_DESC &sampler_desc = samplers[uniform.ids[j].id];3454device->CreateSampler(&sampler_desc, get_cpu_handle(uniform_set_info->sampler_descriptor_heap_alloc->cpu_handle, binding.sampler_descriptor_offset + (j / 2), sampler_descriptor_heap.increment_size));3455}34563457TextureInfo *texture_info = (TextureInfo *)uniform.ids[j + 1].id;3458device->CreateShaderResourceView(texture_info->resource, &texture_info->view_descs.srv, get_cpu_handle(uniform_set_info->resource_descriptor_heap_alloc.cpu_handle, binding.resource_descriptor_offset + (j / 2), resource_descriptor_heap.increment_size));34593460NeededState &ns = resource_states[texture_info];3461ns.shader_uniform_idx_mask |= ((uint64_t)1 << i);3462ns.states |= D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE;3463}3464} break;3465case UNIFORM_TYPE_TEXTURE: {3466for (uint32_t j = 0; j < uniform.ids.size(); j++) {3467TextureInfo *texture_info = (TextureInfo *)uniform.ids[j].id;3468device->CreateShaderResourceView(texture_info->resource, &texture_info->view_descs.srv, get_cpu_handle(uniform_set_info->resource_descriptor_heap_alloc.cpu_handle, binding.resource_descriptor_offset + j, resource_descriptor_heap.increment_size));34693470NeededState &ns = resource_states[texture_info];3471ns.shader_uniform_idx_mask |= ((uint64_t)1 << i);3472ns.states |= D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE;3473}3474} break;3475case UNIFORM_TYPE_IMAGE: {3476for (uint32_t j = 0; j < uniform.ids.size(); j++) {3477TextureInfo *texture_info = (TextureInfo *)uniform.ids[j].id;3478device->CreateUnorderedAccessView(texture_info->resource, nullptr, &texture_info->view_descs.uav, get_cpu_handle(uniform_set_info->resource_descriptor_heap_alloc.cpu_handle, binding.resource_descriptor_offset + j, resource_descriptor_heap.increment_size));34793480NeededState &ns = resource_states[texture_info];3481ns.shader_uniform_idx_mask |= ((uint64_t)1 << i);3482ns.states |= D3D12_RESOURCE_STATE_UNORDERED_ACCESS;3483}3484} break;3485case UNIFORM_TYPE_TEXTURE_BUFFER:3486case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER: {3487CRASH_NOW_MSG("Unimplemented!");3488} break;3489case UNIFORM_TYPE_IMAGE_BUFFER: {3490CRASH_NOW_MSG("Unimplemented!");3491} break;3492case UNIFORM_TYPE_UNIFORM_BUFFER:3493case UNIFORM_TYPE_UNIFORM_BUFFER_DYNAMIC: {3494BufferInfo *buf_info = (BufferInfo *)uniform.ids[0].id;34953496if (uniform.type == UNIFORM_TYPE_UNIFORM_BUFFER) {3497ERR_FAIL_COND_V_MSG(buf_info->is_dynamic(), UniformSetID(),3498"Sent a buffer with BUFFER_USAGE_DYNAMIC_PERSISTENT_BIT but binding (" + itos(uniform.binding) + "), set (" + itos(p_set_index) + ") is UNIFORM_TYPE_UNIFORM_BUFFER instead of UNIFORM_TYPE_UNIFORM_BUFFER_DYNAMIC.");34993500D3D12_CONSTANT_BUFFER_VIEW_DESC cbv_desc = {};3501cbv_desc.BufferLocation = buf_info->gpu_virtual_address;3502cbv_desc.SizeInBytes = STEPIFY(buf_info->size, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT);35033504device->CreateConstantBufferView(&cbv_desc, get_cpu_handle(uniform_set_info->resource_descriptor_heap_alloc.cpu_handle, binding.resource_descriptor_offset, resource_descriptor_heap.increment_size));3505} else {3506ERR_FAIL_COND_V_MSG(!buf_info->is_dynamic(), UniformSetID(),3507"Sent a buffer without BUFFER_USAGE_DYNAMIC_PERSISTENT_BIT but binding (" + itos(uniform.binding) + "), set (" + itos(p_set_index) + ") is UNIFORM_TYPE_UNIFORM_BUFFER_DYNAMIC instead of UNIFORM_TYPE_UNIFORM_BUFFER.");3508ERR_FAIL_COND_V_MSG(num_dynamic_buffers >= MAX_DYNAMIC_BUFFERS, UniformSetID(),3509"Uniform set exceeded the limit of dynamic/persistent buffers. (" + itos(MAX_DYNAMIC_BUFFERS) + ").");35103511UniformSetInfo::DynamicBuffer &dynamic_buffer = dynamic_buffers[num_dynamic_buffers++];3512dynamic_buffer.info = (const BufferDynamicInfo *)buf_info;3513dynamic_buffer.binding = i;3514}35153516NeededState &ns = resource_states[buf_info];3517ns.is_buffer = true;3518ns.shader_uniform_idx_mask |= ((uint64_t)1 << i);3519ns.states |= D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;3520} break;3521case UNIFORM_TYPE_STORAGE_BUFFER:3522case UNIFORM_TYPE_STORAGE_BUFFER_DYNAMIC: {3523BufferInfo *buf_info = (BufferInfo *)uniform.ids[0].id;35243525if (uniform.type == UNIFORM_TYPE_STORAGE_BUFFER) {3526ERR_FAIL_COND_V_MSG(buf_info->is_dynamic(), UniformSetID(),3527"Sent a buffer with BUFFER_USAGE_DYNAMIC_PERSISTENT_BIT but binding (" + itos(uniform.binding) + "), set (" + itos(p_set_index) + ") is UNIFORM_TYPE_STORAGE_BUFFER instead of UNIFORM_TYPE_STORAGE_BUFFER_DYNAMIC.");35283529// Create UAV or SRV depending on whether the uniform is writable.3530if (binding.writable) {3531D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = {};3532uav_desc.Format = DXGI_FORMAT_R32_TYPELESS;3533uav_desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;3534uav_desc.Buffer.FirstElement = 0;3535uav_desc.Buffer.NumElements = (buf_info->size + 3u) / 4u;3536uav_desc.Buffer.StructureByteStride = 0;3537uav_desc.Buffer.CounterOffsetInBytes = 0;3538uav_desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;3539device->CreateUnorderedAccessView(buf_info->resource, nullptr, &uav_desc, get_cpu_handle(uniform_set_info->resource_descriptor_heap_alloc.cpu_handle, binding.resource_descriptor_offset, resource_descriptor_heap.increment_size));3540} else {3541D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {};3542srv_desc.Format = DXGI_FORMAT_R32_TYPELESS;3543srv_desc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;3544srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;3545srv_desc.Buffer.FirstElement = 0;3546srv_desc.Buffer.NumElements = (buf_info->size + 3u) / 4u;3547srv_desc.Buffer.StructureByteStride = 0;3548srv_desc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW;3549device->CreateShaderResourceView(buf_info->resource, &srv_desc, get_cpu_handle(uniform_set_info->resource_descriptor_heap_alloc.cpu_handle, binding.resource_descriptor_offset, resource_descriptor_heap.increment_size));3550}35513552} else {3553ERR_FAIL_COND_V_MSG(!buf_info->is_dynamic(), UniformSetID(),3554"Sent a buffer without BUFFER_USAGE_DYNAMIC_PERSISTENT_BIT but binding (" + itos(uniform.binding) + "), set (" + itos(p_set_index) + ") is UNIFORM_TYPE_STORAGE_BUFFER_DYNAMIC instead of UNIFORM_TYPE_STORAGE_BUFFER.");3555ERR_FAIL_COND_V_MSG(num_dynamic_buffers >= MAX_DYNAMIC_BUFFERS, UniformSetID(),3556"Uniform set exceeded the limit of dynamic/persistent buffers. (" + itos(MAX_DYNAMIC_BUFFERS) + ").");35573558UniformSetInfo::DynamicBuffer &dynamic_buffer = dynamic_buffers[num_dynamic_buffers++];3559dynamic_buffer.info = (const BufferDynamicInfo *)buf_info;3560dynamic_buffer.binding = i;3561}35623563NeededState &ns = resource_states[buf_info];3564ns.shader_uniform_idx_mask |= ((uint64_t)1 << i);3565ns.is_buffer = true;3566ns.states |= (binding.writable ? D3D12_RESOURCE_STATE_UNORDERED_ACCESS : D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);3567} break;3568case UNIFORM_TYPE_INPUT_ATTACHMENT: {3569for (uint32_t j = 0; j < uniform.ids.size(); j++) {3570TextureInfo *texture_info = (TextureInfo *)uniform.ids[j].id;35713572device->CreateShaderResourceView(texture_info->resource, &texture_info->view_descs.srv, get_cpu_handle(uniform_set_info->resource_descriptor_heap_alloc.cpu_handle, binding.resource_descriptor_offset + j, resource_descriptor_heap.increment_size));35733574NeededState &ns = resource_states[texture_info];3575ns.shader_uniform_idx_mask |= ((uint64_t)1 << i);3576ns.states |= D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;3577}3578} break;3579default: {3580DEV_ASSERT(false);3581}3582}3583}35843585uniform_set_info->dynamic_buffers.resize(num_dynamic_buffers);3586for (size_t i = 0u; i < num_dynamic_buffers; ++i) {3587uniform_set_info->dynamic_buffers[i] = dynamic_buffers[i];3588}35893590{3591uniform_set_info->resource_states.reserve(resource_states.size());3592for (const KeyValue<ResourceInfo *, NeededState> &E : resource_states) {3593UniformSetInfo::StateRequirement sr;3594sr.resource = E.key;3595sr.is_buffer = E.value.is_buffer;3596sr.states = E.value.states;3597sr.shader_uniform_idx_mask = E.value.shader_uniform_idx_mask;3598uniform_set_info->resource_states.push_back(sr);3599}3600}36013602return UniformSetID(uniform_set_info);3603}36043605void RenderingDeviceDriverD3D12::uniform_set_free(UniformSetID p_uniform_set) {3606UniformSetInfo *uniform_set_info = (UniformSetInfo *)p_uniform_set.id;36073608resource_descriptor_heap.free(uniform_set_info->resource_descriptor_heap_alloc);36093610if (uniform_set_info->sampler_descriptor_heap_alloc != nullptr) {3611if ((--uniform_set_info->sampler_descriptor_heap_alloc->use_count) == 0) {3612sampler_descriptor_heap.free(*uniform_set_info->sampler_descriptor_heap_alloc);3613sampler_descriptor_heap_allocations.erase(uniform_set_info->sampler_descriptor_heap_alloc->key);3614}3615}36163617VersatileResource::free(resources_allocator, uniform_set_info);3618}36193620uint32_t RenderingDeviceDriverD3D12::uniform_sets_get_dynamic_offsets(VectorView<UniformSetID> p_uniform_sets, ShaderID p_shader, uint32_t p_first_set_index, uint32_t p_set_count) const {3621uint32_t mask = 0u;3622uint32_t shift = 0u;3623#ifdef DEV_ENABLED3624uint32_t curr_dynamic_offset = 0u;3625#endif36263627for (uint32_t i = 0; i < p_set_count; i++) {3628const UniformSetInfo *usi = (const UniformSetInfo *)p_uniform_sets[i].id;3629// At this point this assert should already have been validated.3630DEV_ASSERT(curr_dynamic_offset + usi->dynamic_buffers.size() <= MAX_DYNAMIC_BUFFERS);36313632for (const UniformSetInfo::DynamicBuffer &dynamic_buffer : usi->dynamic_buffers) {3633DEV_ASSERT(dynamic_buffer.info->frame_idx < 16u);3634mask |= dynamic_buffer.info->frame_idx << shift;3635shift += 4u;3636}3637#ifdef DEV_ENABLED3638curr_dynamic_offset += usi->dynamic_buffers.size();3639#endif3640}36413642return mask;3643}36443645// ----- COMMANDS -----36463647void RenderingDeviceDriverD3D12::command_uniform_set_prepare_for_use(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) {3648if (barrier_capabilities.enhanced_barriers_supported) {3649return;3650}36513652CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;3653const UniformSetInfo *uniform_set_info = (const UniformSetInfo *)p_uniform_set.id;3654const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;3655const ShaderInfo::UniformSet &shader_set = shader_info_in->sets[p_set_index];36563657for (const UniformSetInfo::StateRequirement &sr : uniform_set_info->resource_states) {3658#ifdef DEV_ENABLED3659{3660uint32_t stages = 0;3661D3D12_RESOURCE_STATES wanted_state = {};3662bool writable = false;3663// Doing the full loop for debugging since the real one below may break early,3664// but we want an exhaustive check3665uint64_t inv_uniforms_mask = ~sr.shader_uniform_idx_mask; // Inverting the mask saves operations.3666for (uint8_t bit = 0; inv_uniforms_mask != UINT64_MAX; bit++) {3667uint64_t bit_mask = ((uint64_t)1 << bit);3668if (likely((inv_uniforms_mask & bit_mask))) {3669continue;3670}3671inv_uniforms_mask |= bit_mask;36723673const ShaderInfo::UniformBindingInfo &binding = shader_set.bindings[bit];3674if (unlikely(!binding.stages)) {3675continue;3676}36773678if (stages) { // Second occurrence at least?3679CRASH_COND_MSG(binding.writable != writable, "A resource is used in the same uniform set both as R/O and R/W. That's not supported and shouldn't happen.");3680CRASH_COND_MSG(sr.states != wanted_state, "A resource is used in the same uniform set with different resource states. The code needs to be enhanced to support that.");3681} else {3682wanted_state = sr.states;3683stages |= binding.stages;3684writable = binding.writable;3685}36863687DEV_ASSERT((wanted_state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS) == (bool)(wanted_state & D3D12_RESOURCE_STATE_UNORDERED_ACCESS));3688}3689}3690#endif36913692// We may have assumed D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE for a resource,3693// because at uniform set creation time we couldn't know for sure which stages3694// it would be used in (due to the fact that a set can be created against a different,3695// albeit compatible, shader, which may make a different usage in the end).3696// However, now we know and can exclude up to one unneeded states.36973698// TODO: If subresources involved already in the needed states, or scheduled for it,3699// maybe it's more optimal not to do anything here37003701uint32_t stages = 0;3702D3D12_RESOURCE_STATES wanted_state = {};3703uint64_t inv_uniforms_mask = ~sr.shader_uniform_idx_mask; // Inverting the mask saves operations.3704for (uint8_t bit = 0; inv_uniforms_mask != UINT64_MAX; bit++) {3705uint64_t bit_mask = ((uint64_t)1 << bit);3706if (likely((inv_uniforms_mask & bit_mask))) {3707continue;3708}3709inv_uniforms_mask |= bit_mask;37103711const ShaderInfo::UniformBindingInfo &binding = shader_set.bindings[bit];3712if (unlikely(!binding.stages)) {3713continue;3714}37153716if (!stages) {3717wanted_state = sr.states;37183719if (!(wanted_state & D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE)) {3720// By now, we already know the resource is used, and with no PS/NON_PS disjuntive; no need to check further.3721break;3722}3723}37243725stages |= binding.stages;37263727if (stages == (SHADER_STAGE_VERTEX_BIT | SHADER_STAGE_FRAGMENT_BIT) || stages == SHADER_STAGE_COMPUTE_BIT) {3728// By now, we already know the resource is used, and as both PS/NON_PS; no need to check further.3729break;3730}3731}37323733if (likely(wanted_state)) {3734if ((wanted_state & D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE)) {3735if (stages == SHADER_STAGE_VERTEX_BIT || stages == SHADER_STAGE_COMPUTE_BIT) {3736D3D12_RESOURCE_STATES unneeded_states = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;3737wanted_state &= ~unneeded_states;3738} else if (stages == SHADER_STAGE_FRAGMENT_BIT) {3739D3D12_RESOURCE_STATES unneeded_states = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;3740wanted_state &= ~unneeded_states;3741}3742}37433744if (likely(wanted_state)) {3745if (sr.is_buffer) {3746_resource_transition_batch(cmd_buf_info, sr.resource, 0, 1, wanted_state);3747} else {3748TextureInfo *tex_info = (TextureInfo *)sr.resource;3749uint32_t planes = 1;3750if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {3751planes = format_get_plane_count(tex_info->format);3752}3753for (uint32_t i = 0; i < tex_info->layers; i++) {3754for (uint32_t j = 0; j < tex_info->mipmaps; j++) {3755uint32_t subresource = D3D12CalcSubresource(tex_info->base_mip + j, tex_info->base_layer + i, 0, tex_info->desc.MipLevels, tex_info->desc.ArraySize());3756_resource_transition_batch(cmd_buf_info, tex_info, subresource, planes, wanted_state);3757}3758}3759}3760}3761}3762}37633764if (p_set_index == shader_info_in->sets.size() - 1) {3765_resource_transitions_flush(cmd_buf_info);3766}3767}37683769void RenderingDeviceDriverD3D12::_command_check_descriptor_sets(CommandBufferID p_cmd_buffer) {3770DEV_ASSERT(segment_begun && "Unable to use commands that rely on descriptors because a segment was never begun.");37713772CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;3773if (!cmd_buf_info->descriptor_heaps_set) {3774// Set descriptor heaps for the command buffer if they haven't been set yet.3775ID3D12DescriptorHeap *heaps[] = {3776resource_descriptor_heap.heap.Get(),3777sampler_descriptor_heap.heap.Get(),3778};37793780cmd_buf_info->cmd_list->SetDescriptorHeaps(2, heaps);3781cmd_buf_info->descriptor_heaps_set = true;3782}3783}37843785/******************/3786/**** TRANSFER ****/3787/******************/37883789RenderingDeviceDriverD3D12::DescriptorHeap::Allocation RenderingDeviceDriverD3D12::_command_allocate_per_frame_descriptor() {3790FrameInfo &f = frames[frame_idx];3791if (f.descriptor_allocation_count < f.descriptor_allocations.size()) {3792uint32_t allocation_index = f.descriptor_allocation_count;3793++f.descriptor_allocation_count;3794return f.descriptor_allocations[allocation_index];3795} else {3796DescriptorHeap::Allocation descriptor_allocation = {};37973798Error err = resource_descriptor_heap.allocate(1, descriptor_allocation);3799ERR_FAIL_COND_V_MSG(err == ERR_OUT_OF_MEMORY, DescriptorHeap::Allocation(), "Cannot allocate per frame descriptor because there's not enough room in the RESOURCES descriptor heap.\n"3800"Please increase the value of the rendering/rendering_device/d3d12/max_resource_descriptors project setting.");38013802ERR_FAIL_COND_V_MSG(err != OK, DescriptorHeap::Allocation(), "Failed to allocate per frame descriptor.");38033804f.descriptor_allocations.push_back(descriptor_allocation);3805f.descriptor_allocation_count = f.descriptor_allocations.size();38063807return descriptor_allocation;3808}3809}38103811void RenderingDeviceDriverD3D12::command_clear_buffer(CommandBufferID p_cmd_buffer, BufferID p_buffer, uint64_t p_offset, uint64_t p_size) {3812_command_check_descriptor_sets(p_cmd_buffer);38133814CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;3815BufferInfo *buf_info = (BufferInfo *)p_buffer.id;38163817if (!barrier_capabilities.enhanced_barriers_supported) {3818_resource_transition_batch(cmd_buf_info, buf_info, 0, 1, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);3819_resource_transitions_flush(cmd_buf_info);3820}38213822D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = {};3823uav_desc.Format = DXGI_FORMAT_R32_TYPELESS;3824uav_desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;3825uav_desc.Buffer.FirstElement = p_offset / 4;3826uav_desc.Buffer.NumElements = p_size / 4;3827uav_desc.Buffer.StructureByteStride = 0;3828uav_desc.Buffer.CounterOffsetInBytes = 0;3829uav_desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;3830device->CreateUnorderedAccessView(3831buf_info->resource,3832nullptr,3833&uav_desc,3834cmd_buf_info->uav_alloc.cpu_handle);38353836DescriptorHeap::Allocation shader_visible_descriptor_allocation = _command_allocate_per_frame_descriptor();3837ERR_FAIL_COND(shader_visible_descriptor_allocation.virtual_alloc_handle == 0);38383839device->CopyDescriptorsSimple(38401,3841shader_visible_descriptor_allocation.cpu_handle,3842cmd_buf_info->uav_alloc.cpu_handle,3843D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);38443845static const UINT values[4] = {};3846cmd_buf_info->cmd_list->ClearUnorderedAccessViewUint(3847shader_visible_descriptor_allocation.gpu_handle,3848cmd_buf_info->uav_alloc.cpu_handle,3849buf_info->resource,3850values,38510,3852nullptr);3853}38543855void RenderingDeviceDriverD3D12::command_copy_buffer(CommandBufferID p_cmd_buffer, BufferID p_src_buffer, BufferID p_buf_locfer, VectorView<BufferCopyRegion> p_regions) {3856CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;3857BufferInfo *src_buf_info = (BufferInfo *)p_src_buffer.id;3858BufferInfo *buf_loc_info = (BufferInfo *)p_buf_locfer.id;38593860if (!barrier_capabilities.enhanced_barriers_supported) {3861_resource_transition_batch(cmd_buf_info, src_buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_SOURCE);3862_resource_transition_batch(cmd_buf_info, buf_loc_info, 0, 1, D3D12_RESOURCE_STATE_COPY_DEST);3863_resource_transitions_flush(cmd_buf_info);3864}38653866for (uint32_t i = 0; i < p_regions.size(); i++) {3867cmd_buf_info->cmd_list->CopyBufferRegion(buf_loc_info->resource, p_regions[i].dst_offset, src_buf_info->resource, p_regions[i].src_offset, p_regions[i].size);3868}3869}38703871void RenderingDeviceDriverD3D12::command_copy_texture(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, VectorView<TextureCopyRegion> p_regions) {3872CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;3873TextureInfo *src_tex_info = (TextureInfo *)p_src_texture.id;3874TextureInfo *dst_tex_info = (TextureInfo *)p_dst_texture.id;38753876if (!barrier_capabilities.enhanced_barriers_supported) {3877// Batch all barrier transitions for the textures before performing the copies.3878for (uint32_t i = 0; i < p_regions.size(); i++) {3879uint32_t layer_count = MIN(p_regions[i].src_subresources.layer_count, p_regions[i].dst_subresources.layer_count);3880for (uint32_t j = 0; j < layer_count; j++) {3881UINT src_subresource = _compute_subresource_from_layers(src_tex_info, p_regions[i].src_subresources, j);3882UINT dst_subresource = _compute_subresource_from_layers(dst_tex_info, p_regions[i].dst_subresources, j);3883_resource_transition_batch(cmd_buf_info, src_tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_COPY_SOURCE);3884_resource_transition_batch(cmd_buf_info, dst_tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_COPY_DEST);3885}3886}38873888_resource_transitions_flush(cmd_buf_info);3889}38903891CD3DX12_BOX src_box;3892for (uint32_t i = 0; i < p_regions.size(); i++) {3893uint32_t layer_count = MIN(p_regions[i].src_subresources.layer_count, p_regions[i].dst_subresources.layer_count);3894for (uint32_t j = 0; j < layer_count; j++) {3895UINT src_subresource = _compute_subresource_from_layers(src_tex_info, p_regions[i].src_subresources, j);3896UINT dst_subresource = _compute_subresource_from_layers(dst_tex_info, p_regions[i].dst_subresources, j);3897CD3DX12_TEXTURE_COPY_LOCATION src_location(src_tex_info->resource, src_subresource);3898CD3DX12_TEXTURE_COPY_LOCATION dst_location(dst_tex_info->resource, dst_subresource);3899src_box.left = p_regions[i].src_offset.x;3900src_box.top = p_regions[i].src_offset.y;3901src_box.front = p_regions[i].src_offset.z;3902src_box.right = p_regions[i].src_offset.x + p_regions[i].size.x;3903src_box.bottom = p_regions[i].src_offset.y + p_regions[i].size.y;3904src_box.back = p_regions[i].src_offset.z + p_regions[i].size.z;3905cmd_buf_info->cmd_list->CopyTextureRegion(&dst_location, p_regions[i].dst_offset.x, p_regions[i].dst_offset.y, p_regions[i].dst_offset.z, &src_location, &src_box);3906}3907}3908}39093910void RenderingDeviceDriverD3D12::command_resolve_texture(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, uint32_t p_src_layer, uint32_t p_src_mipmap, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, uint32_t p_dst_layer, uint32_t p_dst_mipmap) {3911CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;3912TextureInfo *src_tex_info = (TextureInfo *)p_src_texture.id;3913TextureInfo *dst_tex_info = (TextureInfo *)p_dst_texture.id;39143915UINT src_subresource = D3D12CalcSubresource(p_src_mipmap, p_src_layer, 0, src_tex_info->desc.MipLevels, src_tex_info->desc.ArraySize());3916UINT dst_subresource = D3D12CalcSubresource(p_dst_mipmap, p_dst_layer, 0, dst_tex_info->desc.MipLevels, dst_tex_info->desc.ArraySize());3917if (!barrier_capabilities.enhanced_barriers_supported) {3918_resource_transition_batch(cmd_buf_info, src_tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);3919_resource_transition_batch(cmd_buf_info, dst_tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_RESOLVE_DEST);3920_resource_transitions_flush(cmd_buf_info);3921}39223923cmd_buf_info->cmd_list->ResolveSubresource(dst_tex_info->resource, dst_subresource, src_tex_info->resource, src_subresource, RD_TO_D3D12_FORMAT[src_tex_info->format].general_format);3924}39253926void RenderingDeviceDriverD3D12::command_clear_color_texture(CommandBufferID p_cmd_buffer, TextureID p_texture, TextureLayout p_texture_layout, const Color &p_color, const TextureSubresourceRange &p_subresources) {3927CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;3928TextureInfo *tex_info = (TextureInfo *)p_texture.id;3929if (tex_info->main_texture) {3930tex_info = tex_info->main_texture;3931}39323933auto _transition_subresources = [&](D3D12_RESOURCE_STATES p_new_state) {3934for (uint32_t i = 0; i < p_subresources.layer_count; i++) {3935for (uint32_t j = 0; j < p_subresources.mipmap_count; j++) {3936UINT subresource = D3D12CalcSubresource(3937p_subresources.base_mipmap + j,3938p_subresources.base_layer + i,39390,3940tex_info->desc.MipLevels,3941tex_info->desc.ArraySize());3942_resource_transition_batch(cmd_buf_info, tex_info, subresource, 1, p_new_state);3943}3944}3945_resource_transitions_flush(cmd_buf_info);3946};39473948if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)) {3949if (!barrier_capabilities.enhanced_barriers_supported) {3950_transition_subresources(D3D12_RESOURCE_STATE_RENDER_TARGET);3951}39523953for (uint32_t i = 0; i < p_subresources.mipmap_count; i++) {3954D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = _make_rtv_for_texture(tex_info, p_subresources.base_mipmap + i, p_subresources.base_layer, p_subresources.layer_count, false);3955rtv_desc.Format = tex_info->view_descs.uav.Format;3956device->CreateRenderTargetView(3957tex_info->resource,3958&rtv_desc,3959cmd_buf_info->rtv_alloc.cpu_handle);39603961cmd_buf_info->cmd_list->ClearRenderTargetView(3962cmd_buf_info->rtv_alloc.cpu_handle,3963p_color.components,39640,3965nullptr);3966}3967} else if (tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS) {3968// Clear via UAV.3969_command_check_descriptor_sets(p_cmd_buffer);39703971if (!barrier_capabilities.enhanced_barriers_supported) {3972_transition_subresources(D3D12_RESOURCE_STATE_UNORDERED_ACCESS);3973}39743975for (uint32_t i = 0; i < p_subresources.mipmap_count; i++) {3976D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = _make_ranged_uav_for_texture(tex_info, p_subresources.base_mipmap + i, p_subresources.base_layer, p_subresources.layer_count, false);3977device->CreateUnorderedAccessView(3978tex_info->resource,3979nullptr,3980&uav_desc,3981cmd_buf_info->uav_alloc.cpu_handle);39823983DescriptorHeap::Allocation shader_visible_descriptor_allocation = _command_allocate_per_frame_descriptor();3984ERR_FAIL_COND(shader_visible_descriptor_allocation.virtual_alloc_handle == 0);39853986device->CopyDescriptorsSimple(39871,3988shader_visible_descriptor_allocation.cpu_handle,3989cmd_buf_info->uav_alloc.cpu_handle,3990D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);39913992UINT values[4] = {3993(UINT)p_color.get_r8(),3994(UINT)p_color.get_g8(),3995(UINT)p_color.get_b8(),3996(UINT)p_color.get_a8(),3997};39983999cmd_buf_info->cmd_list->ClearUnorderedAccessViewUint(4000shader_visible_descriptor_allocation.gpu_handle,4001cmd_buf_info->uav_alloc.cpu_handle,4002tex_info->resource,4003values,40040,4005nullptr);4006}4007} else {4008ERR_FAIL_MSG("Cannot clear texture because its format does not support UAV writes. You'll need to update its contents through another method.");4009}4010}40114012void RenderingDeviceDriverD3D12::command_clear_depth_stencil_texture(CommandBufferID p_cmd_buffer, TextureID p_texture, TextureLayout p_texture_layout, float p_depth, uint8_t p_stencil, const TextureSubresourceRange &p_subresources) {4013CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;4014TextureInfo *tex_info = (TextureInfo *)p_texture.id;4015if (tex_info->main_texture) {4016tex_info = tex_info->main_texture;4017}40184019if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {4020if (!barrier_capabilities.enhanced_barriers_supported) {4021uint32_t num_planes = format_get_plane_count(tex_info->format);40224023for (uint32_t i = 0; i < p_subresources.layer_count; i++) {4024for (uint32_t j = 0; j < p_subresources.mipmap_count; j++) {4025UINT subresource = D3D12CalcSubresource(4026p_subresources.base_mipmap + j,4027p_subresources.base_layer + i,40280,4029tex_info->desc.MipLevels,4030tex_info->desc.ArraySize());4031_resource_transition_batch(cmd_buf_info, tex_info, subresource, num_planes, D3D12_RESOURCE_STATE_DEPTH_WRITE);4032}4033}4034_resource_transitions_flush(cmd_buf_info);4035}40364037D3D12_CLEAR_FLAGS clear_flags = {};4038if (p_subresources.aspect.has_flag(RDD::TEXTURE_ASPECT_DEPTH_BIT)) {4039clear_flags |= D3D12_CLEAR_FLAG_DEPTH;4040}4041if (p_subresources.aspect.has_flag(RDD::TEXTURE_ASPECT_STENCIL_BIT)) {4042clear_flags |= D3D12_CLEAR_FLAG_STENCIL;4043}40444045for (uint32_t i = 0; i < p_subresources.mipmap_count; i++) {4046D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc = _make_dsv_for_texture(tex_info, p_subresources.base_mipmap + i, p_subresources.base_layer, p_subresources.layer_count, false);4047device->CreateDepthStencilView(4048tex_info->resource,4049&dsv_desc,4050cmd_buf_info->dsv_alloc.cpu_handle);40514052cmd_buf_info->cmd_list->ClearDepthStencilView(4053cmd_buf_info->dsv_alloc.cpu_handle,4054clear_flags,4055p_depth,4056p_stencil,40570,4058nullptr);4059}4060} else {4061ERR_FAIL_MSG("Cannot clear depth because the texture was not created with the depth attachment bit. You'll need to update its contents through another method.");4062}4063}40644065void RenderingDeviceDriverD3D12::command_copy_buffer_to_texture(CommandBufferID p_cmd_buffer, BufferID p_src_buffer, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, VectorView<BufferTextureCopyRegion> p_regions) {4066CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;4067BufferInfo *buf_info = (BufferInfo *)p_src_buffer.id;4068TextureInfo *tex_info = (TextureInfo *)p_dst_texture.id;40694070if (!barrier_capabilities.enhanced_barriers_supported) {4071_resource_transition_batch(cmd_buf_info, buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_SOURCE);4072}40734074uint32_t block_w = 0, block_h = 0;4075get_compressed_image_format_block_dimensions(tex_info->format, block_w, block_h);40764077for (uint32_t i = 0; i < p_regions.size(); i++) {4078DEV_ASSERT((p_regions[i].buffer_offset & (D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT - 1)) == 0 && "Buffer offset must be aligned to 512 bytes. See API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT.");4079DEV_ASSERT((p_regions[i].row_pitch & (D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1)) == 0 && "Row pitch must be aligned to 256 bytes. See API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP.");40804081D3D12_PLACED_SUBRESOURCE_FOOTPRINT src_footprint = {};4082src_footprint.Offset = p_regions[i].buffer_offset;4083src_footprint.Footprint = CD3DX12_SUBRESOURCE_FOOTPRINT(4084RD_TO_D3D12_FORMAT[tex_info->format].family,4085STEPIFY(p_regions[i].texture_region_size.x, block_w),4086STEPIFY(p_regions[i].texture_region_size.y, block_h),4087p_regions[i].texture_region_size.z,4088p_regions[i].row_pitch);40894090CD3DX12_TEXTURE_COPY_LOCATION copy_src(buf_info->resource, src_footprint);40914092UINT dst_subresource = D3D12CalcSubresource(4093p_regions[i].texture_subresource.mipmap,4094p_regions[i].texture_subresource.layer,4095_compute_plane_slice(tex_info->format, p_regions[i].texture_subresource.aspect),4096tex_info->desc.MipLevels,4097tex_info->desc.ArraySize());40984099if (!barrier_capabilities.enhanced_barriers_supported) {4100_resource_transition_batch(cmd_buf_info, tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_COPY_DEST);4101_resource_transitions_flush(cmd_buf_info);4102}41034104CD3DX12_TEXTURE_COPY_LOCATION copy_dst(tex_info->resource, dst_subresource);41054106cmd_buf_info->cmd_list->CopyTextureRegion(4107©_dst,4108p_regions[i].texture_offset.x,4109p_regions[i].texture_offset.y,4110p_regions[i].texture_offset.z,4111©_src,4112nullptr);4113}4114}41154116void RenderingDeviceDriverD3D12::command_copy_texture_to_buffer(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, BufferID p_buf_locfer, VectorView<BufferTextureCopyRegion> p_regions) {4117CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;4118TextureInfo *tex_info = (TextureInfo *)p_src_texture.id;4119BufferInfo *buf_info = (BufferInfo *)p_buf_locfer.id;41204121if (!barrier_capabilities.enhanced_barriers_supported) {4122_resource_transition_batch(cmd_buf_info, buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_DEST);4123}41244125uint32_t block_w = 0, block_h = 0;4126get_compressed_image_format_block_dimensions(tex_info->format, block_w, block_h);41274128for (uint32_t i = 0; i < p_regions.size(); i++) {4129DEV_ASSERT((p_regions[i].buffer_offset & (D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT - 1)) == 0 && "Buffer offset must be aligned to 512 bytes. See API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT.");4130DEV_ASSERT((p_regions[i].row_pitch & (D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1)) == 0 && "Row pitch must be aligned to 256 bytes. See API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP.");41314132UINT src_subresource = D3D12CalcSubresource(4133p_regions[i].texture_subresource.mipmap,4134p_regions[i].texture_subresource.layer,4135_compute_plane_slice(tex_info->format, p_regions[i].texture_subresource.aspect),4136tex_info->desc.MipLevels,4137tex_info->desc.ArraySize());41384139if (!barrier_capabilities.enhanced_barriers_supported) {4140_resource_transition_batch(cmd_buf_info, tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_COPY_SOURCE);4141_resource_transitions_flush(cmd_buf_info);4142}41434144CD3DX12_TEXTURE_COPY_LOCATION copy_src(tex_info->resource, src_subresource);41454146CD3DX12_BOX src_box(4147p_regions[i].texture_offset.x,4148p_regions[i].texture_offset.y,4149p_regions[i].texture_offset.z,4150p_regions[i].texture_offset.x + STEPIFY(p_regions[i].texture_region_size.x, block_w),4151p_regions[i].texture_offset.y + STEPIFY(p_regions[i].texture_region_size.y, block_h),4152p_regions[i].texture_offset.z + p_regions[i].texture_region_size.z);41534154bool full_box =4155src_box.left == 0 &&4156src_box.top == 0 &&4157src_box.front == 0 &&4158src_box.right == tex_info->desc.Width &&4159src_box.bottom == tex_info->desc.Height &&4160src_box.back == tex_info->desc.Depth();41614162D3D12_PLACED_SUBRESOURCE_FOOTPRINT dst_footprint = {};4163dst_footprint.Offset = p_regions[i].buffer_offset;4164dst_footprint.Footprint.Format = RD_TO_D3D12_FORMAT[tex_info->format].family;4165dst_footprint.Footprint.Width = STEPIFY(p_regions[i].texture_region_size.x, block_w);4166dst_footprint.Footprint.Height = STEPIFY(p_regions[i].texture_region_size.y, block_h);4167dst_footprint.Footprint.Depth = p_regions[i].texture_region_size.z;4168dst_footprint.Footprint.RowPitch = p_regions[i].row_pitch;41694170CD3DX12_TEXTURE_COPY_LOCATION copy_dst(buf_info->resource, dst_footprint);41714172cmd_buf_info->cmd_list->CopyTextureRegion(4173©_dst,41740,41750,41760,4177©_src,4178full_box ? nullptr : &src_box);4179}4180}41814182/******************/4183/**** PIPELINE ****/4184/******************/41854186void RenderingDeviceDriverD3D12::pipeline_free(PipelineID p_pipeline) {4187PipelineInfo *pipeline_info = (PipelineInfo *)(p_pipeline.id);4188memdelete(pipeline_info);4189}41904191// ----- BINDING -----41924193void RenderingDeviceDriverD3D12::command_bind_push_constants(CommandBufferID p_cmd_buffer, ShaderID p_shader, uint32_t p_dst_first_index, VectorView<uint32_t> p_data) {4194const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;4195const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;4196if (!shader_info_in->dxil_push_constant_size) {4197return;4198}4199if (shader_info_in->pipeline_type == PIPELINE_TYPE_COMPUTE) {4200cmd_buf_info->cmd_list->SetComputeRoot32BitConstants(0, p_data.size(), p_data.ptr(), p_dst_first_index);4201} else if (shader_info_in->pipeline_type == PIPELINE_TYPE_RASTERIZATION) {4202cmd_buf_info->cmd_list->SetGraphicsRoot32BitConstants(0, p_data.size(), p_data.ptr(), p_dst_first_index);4203} else if (shader_info_in->pipeline_type == PIPELINE_TYPE_RAYTRACING) {4204ERR_FAIL_MSG("Ray tracing is not currently supported by the D3D12 driver.");4205} else {4206ERR_FAIL_MSG("This pipeline type is not currently supported by the D3D12 driver.");4207}4208}42094210// ----- CACHE -----42114212bool RenderingDeviceDriverD3D12::pipeline_cache_create(const Vector<uint8_t> &p_data) {4213return false;4214}42154216void RenderingDeviceDriverD3D12::pipeline_cache_free() {4217ERR_FAIL_MSG("Not implemented.");4218}42194220size_t RenderingDeviceDriverD3D12::pipeline_cache_query_size() {4221ERR_FAIL_V_MSG(0, "Not implemented.");4222}42234224Vector<uint8_t> RenderingDeviceDriverD3D12::pipeline_cache_serialize() {4225ERR_FAIL_V_MSG(Vector<uint8_t>(), "Not implemented.");4226}42274228/*******************/4229/**** RENDERING ****/4230/*******************/42314232// ----- SUBPASS -----42334234RDD::RenderPassID RenderingDeviceDriverD3D12::render_pass_create(VectorView<Attachment> p_attachments, VectorView<Subpass> p_subpasses, VectorView<SubpassDependency> p_subpass_dependencies, uint32_t p_view_count, AttachmentReference p_fragment_density_map_attachment) {4235ERR_FAIL_COND_V_MSG(p_fragment_density_map_attachment.attachment != AttachmentReference::UNUSED, RenderPassID(), "Fragment density maps are not supported in D3D12.");42364237// Pre-bookkeep.4238RenderPassInfo *pass_info = VersatileResource::allocate<RenderPassInfo>(resources_allocator);42394240pass_info->attachments.resize(p_attachments.size());4241for (uint32_t i = 0; i < p_attachments.size(); i++) {4242pass_info->attachments[i] = p_attachments[i];4243}42444245pass_info->subpasses.resize(p_subpasses.size());4246for (uint32_t i = 0; i < p_subpasses.size(); i++) {4247pass_info->subpasses[i] = p_subpasses[i];4248}42494250pass_info->view_count = p_view_count;42514252DXGI_FORMAT *formats = ALLOCA_ARRAY(DXGI_FORMAT, p_attachments.size());4253for (uint32_t i = 0; i < p_attachments.size(); i++) {4254const D3D12Format &format = RD_TO_D3D12_FORMAT[p_attachments[i].format];4255if (format.dsv_format != DXGI_FORMAT_UNKNOWN) {4256formats[i] = format.dsv_format;4257} else {4258formats[i] = format.general_format;4259}4260}4261pass_info->max_supported_sample_count = _find_max_common_supported_sample_count(VectorView(formats, p_attachments.size()));42624263return RenderPassID(pass_info);4264}42654266void RenderingDeviceDriverD3D12::render_pass_free(RenderPassID p_render_pass) {4267RenderPassInfo *pass_info = (RenderPassInfo *)p_render_pass.id;4268VersatileResource::free(resources_allocator, pass_info);4269}42704271// ----- COMMANDS -----42724273void RenderingDeviceDriverD3D12::command_begin_render_pass(CommandBufferID p_cmd_buffer, RenderPassID p_render_pass, FramebufferID p_framebuffer, CommandBufferType p_cmd_buffer_type, const Rect2i &p_rect, VectorView<RenderPassClearValue> p_attachment_clears) {4274CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;4275const RenderPassInfo *pass_info = (const RenderPassInfo *)p_render_pass.id;4276const FramebufferInfo *fb_info = (const FramebufferInfo *)p_framebuffer.id;42774278DEV_ASSERT(cmd_buf_info->render_pass_state.current_subpass == UINT32_MAX);42794280auto _transition_subresources = [&](TextureInfo *p_texture_info, D3D12_RESOURCE_STATES p_states) {4281uint32_t planes = 1;4282if ((p_texture_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {4283planes = format_get_plane_count(p_texture_info->format);4284}4285for (uint32_t i = 0; i < p_texture_info->layers; i++) {4286for (uint32_t j = 0; j < p_texture_info->mipmaps; j++) {4287uint32_t subresource = D3D12CalcSubresource(4288p_texture_info->base_mip + j,4289p_texture_info->base_layer + i,42900,4291p_texture_info->desc.MipLevels,4292p_texture_info->desc.ArraySize());42934294_resource_transition_batch(cmd_buf_info, p_texture_info, subresource, planes, p_states);4295}4296}4297};42984299if (fb_info->is_screen || !barrier_capabilities.enhanced_barriers_supported) {4300// Screen framebuffers must perform this transition even if enhanced barriers are supported.4301for (uint32_t i = 0; i < fb_info->attachments.size(); i++) {4302TextureInfo *tex_info = (TextureInfo *)fb_info->attachments[i].id;4303if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)) {4304_transition_subresources(tex_info, D3D12_RESOURCE_STATE_RENDER_TARGET);4305} else if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {4306_transition_subresources(tex_info, D3D12_RESOURCE_STATE_DEPTH_WRITE);4307} else {4308DEV_ASSERT(false);4309}4310}4311if (fb_info->vrs_attachment) {4312TextureInfo *tex_info = (TextureInfo *)fb_info->vrs_attachment.id;4313_transition_subresources(tex_info, D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE);4314}43154316_resource_transitions_flush(cmd_buf_info);4317}43184319cmd_buf_info->render_pass_state.region_rect = CD3DX12_RECT(4320p_rect.position.x,4321p_rect.position.y,4322p_rect.position.x + p_rect.size.x,4323p_rect.position.y + p_rect.size.y);4324cmd_buf_info->render_pass_state.region_is_all = (cmd_buf_info->render_pass_state.region_rect.left == 0 &&4325cmd_buf_info->render_pass_state.region_rect.top == 0 &&4326cmd_buf_info->render_pass_state.region_rect.right == fb_info->size.x &&4327cmd_buf_info->render_pass_state.region_rect.bottom == fb_info->size.y);43284329cmd_buf_info->render_pass_state.attachment_layouts.resize(pass_info->attachments.size());43304331for (uint32_t i = 0; i < pass_info->attachments.size(); i++) {4332const Attachment &attachment = pass_info->attachments[i];43334334for (RenderPassState::AttachmentLayout::AspectLayout &aspect_layout : cmd_buf_info->render_pass_state.attachment_layouts[i].aspect_layouts) {4335aspect_layout.cur_layout = attachment.initial_layout;4336aspect_layout.expected_layout = attachment.initial_layout;4337}43384339if (attachment.load_op == ATTACHMENT_LOAD_OP_DONT_CARE) {4340const TextureInfo *tex_info = (const TextureInfo *)fb_info->attachments[i].id;4341_discard_texture_subresources(tex_info, cmd_buf_info);4342}4343}43444345if (fb_info->vrs_attachment && fsr_capabilities.attachment_supported) {4346static const D3D12_SHADING_RATE_COMBINER COMBINERS[D3D12_RS_SET_SHADING_RATE_COMBINER_COUNT] = {4347D3D12_SHADING_RATE_COMBINER_PASSTHROUGH,4348D3D12_SHADING_RATE_COMBINER_OVERRIDE,4349};4350cmd_buf_info->cmd_list_5->RSSetShadingRate(D3D12_SHADING_RATE_1X1, COMBINERS);4351}43524353cmd_buf_info->render_pass_state.current_subpass = UINT32_MAX;4354cmd_buf_info->render_pass_state.fb_info = fb_info;4355cmd_buf_info->render_pass_state.pass_info = pass_info;4356command_next_render_subpass(p_cmd_buffer, p_cmd_buffer_type);43574358AttachmentClear *clears = ALLOCA_ARRAY(AttachmentClear, pass_info->attachments.size());4359uint32_t num_clears = 0;43604361for (uint32_t i = 0; i < pass_info->attachments.size(); i++) {4362TextureInfo *tex_info = (TextureInfo *)fb_info->attachments[i].id;4363if (!tex_info) {4364continue;4365}43664367AttachmentClear clear;4368if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)) {4369if (pass_info->attachments[i].load_op == ATTACHMENT_LOAD_OP_CLEAR) {4370clear.aspect.set_flag(TEXTURE_ASPECT_COLOR_BIT);4371clear.color_attachment = i;4372}4373} else if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {4374if (pass_info->attachments[i].load_op == ATTACHMENT_LOAD_OP_CLEAR) {4375clear.aspect.set_flag(TEXTURE_ASPECT_DEPTH_BIT);4376}4377if (pass_info->attachments[i].stencil_load_op == ATTACHMENT_LOAD_OP_CLEAR) {4378clear.aspect.set_flag(TEXTURE_ASPECT_STENCIL_BIT);4379}4380}4381if (!clear.aspect.is_empty()) {4382clear.value = p_attachment_clears[i];4383clears[num_clears] = clear;4384num_clears++;4385}4386}43874388if (num_clears) {4389command_render_clear_attachments(p_cmd_buffer, VectorView(clears, num_clears), VectorView(p_rect));4390}4391}43924393// Subpass dependencies cannot be specified by the end user, and by default they are very aggressive.4394// We can be more lenient by just looking at the texture layout and specifying appropriate access and stage bits.43954396// We specify full barrier for layouts we don't expect to see as fallback.4397static const BitField<RDD::BarrierAccessBits> RD_RENDER_PASS_LAYOUT_TO_ACCESS_BITS[RDD::TEXTURE_LAYOUT_MAX] = {4398RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT, // TEXTURE_LAYOUT_UNDEFINED4399RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT, // TEXTURE_LAYOUT_GENERAL4400RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT, // TEXTURE_LAYOUT_STORAGE_OPTIMAL4401RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL4402RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL4403RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT, // TEXTURE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL4404RDD::BARRIER_ACCESS_SHADER_READ_BIT, // TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL4405RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT, // TEXTURE_LAYOUT_COPY_SRC_OPTIMAL4406RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT, // TEXTURE_LAYOUT_COPY_DST_OPTIMAL4407RDD::BARRIER_ACCESS_RESOLVE_READ_BIT, // TEXTURE_LAYOUT_RESOLVE_SRC_OPTIMAL4408RDD::BARRIER_ACCESS_RESOLVE_WRITE_BIT, // TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL4409RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT, // TEXTURE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL4410RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT // TEXTURE_LAYOUT_FRAGMENT_DENSITY_MAP_ATTACHMENT_OPTIMAL4411};44124413// We specify all commands for layouts we don't expect to see as fallback.4414static const BitField<RDD::PipelineStageBits> RD_RENDER_PASS_LAYOUT_TO_STAGE_BITS[RDD::TEXTURE_LAYOUT_MAX] = {4415RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, // TEXTURE_LAYOUT_UNDEFINED4416RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, // TEXTURE_LAYOUT_GENERAL4417RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, // TEXTURE_LAYOUT_STORAGE_OPTIMAL4418RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL4419RDD::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | RDD::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, // TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL4420RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, // TEXTURE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL4421RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL4422RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, // TEXTURE_LAYOUT_COPY_SRC_OPTIMAL4423RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, // TEXTURE_LAYOUT_COPY_DST_OPTIMAL4424RDD::PIPELINE_STAGE_RESOLVE_BIT, // TEXTURE_LAYOUT_RESOLVE_SRC_OPTIMAL4425RDD::PIPELINE_STAGE_RESOLVE_BIT, // TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL4426RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, // TEXTURE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL4427RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT // TEXTURE_LAYOUT_FRAGMENT_DENSITY_MAP_ATTACHMENT_OPTIMAL4428};44294430void RenderingDeviceDriverD3D12::_render_pass_enhanced_barriers_flush(CommandBufferID p_cmd_buffer) {4431if (!barrier_capabilities.enhanced_barriers_supported) {4432return;4433}44344435BitField<PipelineStageBits> src_stages = {};4436BitField<PipelineStageBits> dst_stages = {};44374438thread_local LocalVector<TextureBarrier> texture_barriers;4439texture_barriers.clear();44404441CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;44424443for (uint32_t i = 0; i < cmd_buf_info->render_pass_state.attachment_layouts.size(); i++) {4444RenderPassState::AttachmentLayout &attachment_layout = cmd_buf_info->render_pass_state.attachment_layouts[i];4445TextureID tex = cmd_buf_info->render_pass_state.fb_info->attachments[i];4446TextureInfo *tex_info = (TextureInfo *)tex.id;44474448for (uint32_t j = 0; j < TEXTURE_ASPECT_MAX; j++) {4449RenderPassState::AttachmentLayout::AspectLayout &aspect_layout = attachment_layout.aspect_layouts[j];44504451if (aspect_layout.cur_layout != aspect_layout.expected_layout) {4452src_stages = src_stages | RD_RENDER_PASS_LAYOUT_TO_STAGE_BITS[aspect_layout.cur_layout];4453dst_stages = dst_stages | RD_RENDER_PASS_LAYOUT_TO_STAGE_BITS[aspect_layout.expected_layout];44544455TextureBarrier texture_barrier;4456texture_barrier.texture = tex;4457texture_barrier.src_access = RD_RENDER_PASS_LAYOUT_TO_ACCESS_BITS[aspect_layout.cur_layout];4458texture_barrier.dst_access = RD_RENDER_PASS_LAYOUT_TO_ACCESS_BITS[aspect_layout.expected_layout];4459texture_barrier.prev_layout = aspect_layout.cur_layout;4460texture_barrier.next_layout = aspect_layout.expected_layout;4461texture_barrier.subresources.aspect = (TextureAspectBits)(1 << j);4462texture_barrier.subresources.base_mipmap = tex_info->base_mip;4463texture_barrier.subresources.mipmap_count = tex_info->mipmaps;4464texture_barrier.subresources.base_layer = tex_info->base_layer;4465texture_barrier.subresources.layer_count = tex_info->layers;4466texture_barriers.push_back(texture_barrier);44674468aspect_layout.cur_layout = aspect_layout.expected_layout;4469}4470}4471}44724473if (!texture_barriers.is_empty()) {4474command_pipeline_barrier(p_cmd_buffer, src_stages, dst_stages, VectorView<MemoryAccessBarrier>(), VectorView<BufferBarrier>(), texture_barriers, VectorView<AccelerationStructureBarrier>());4475}4476}44774478void RenderingDeviceDriverD3D12::_end_render_pass(CommandBufferID p_cmd_buffer) {4479CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;44804481DEV_ASSERT(cmd_buf_info->render_pass_state.current_subpass != UINT32_MAX);44824483const FramebufferInfo *fb_info = cmd_buf_info->render_pass_state.fb_info;4484const RenderPassInfo *pass_info = cmd_buf_info->render_pass_state.pass_info;4485const Subpass &subpass = pass_info->subpasses[cmd_buf_info->render_pass_state.current_subpass];44864487if (fb_info->is_screen) {4488// Screen framebuffers must transition back to present state when the render pass is finished.4489for (uint32_t i = 0; i < fb_info->attachments.size(); i++) {4490TextureInfo *src_tex_info = (TextureInfo *)(fb_info->attachments[i].id);4491uint32_t src_subresource = D3D12CalcSubresource(src_tex_info->base_mip, src_tex_info->base_layer, 0, src_tex_info->desc.MipLevels, src_tex_info->desc.ArraySize());4492_resource_transition_batch(cmd_buf_info, src_tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_PRESENT);4493}4494}44954496struct Resolve {4497ID3D12Resource *src_res = nullptr;4498uint32_t src_subres = 0;4499ID3D12Resource *dst_res = nullptr;4500uint32_t dst_subres = 0;4501DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;4502};4503Resolve *resolves = ALLOCA_ARRAY(Resolve, subpass.resolve_references.size());4504uint32_t num_resolves = 0;45054506for (uint32_t i = 0; i < subpass.resolve_references.size(); i++) {4507uint32_t color_index = subpass.color_references[i].attachment;4508uint32_t resolve_index = subpass.resolve_references[i].attachment;4509DEV_ASSERT((color_index == AttachmentReference::UNUSED) == (resolve_index == AttachmentReference::UNUSED));4510if (color_index == AttachmentReference::UNUSED || !fb_info->attachments[color_index]) {4511continue;4512}45134514TextureInfo *src_tex_info = (TextureInfo *)fb_info->attachments[color_index].id;4515uint32_t src_subresource = D3D12CalcSubresource(src_tex_info->base_mip, src_tex_info->base_layer, 0, src_tex_info->desc.MipLevels, src_tex_info->desc.ArraySize());45164517if (barrier_capabilities.enhanced_barriers_supported) {4518cmd_buf_info->render_pass_state.attachment_layouts[color_index].aspect_layouts[TEXTURE_ASPECT_COLOR].expected_layout = TEXTURE_LAYOUT_RESOLVE_SRC_OPTIMAL;4519} else {4520_resource_transition_batch(cmd_buf_info, src_tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);4521}45224523TextureInfo *dst_tex_info = (TextureInfo *)fb_info->attachments[resolve_index].id;4524uint32_t dst_subresource = D3D12CalcSubresource(dst_tex_info->base_mip, dst_tex_info->base_layer, 0, dst_tex_info->desc.MipLevels, dst_tex_info->desc.ArraySize());45254526if (barrier_capabilities.enhanced_barriers_supported) {4527// This should have already been done when beginning the subpass.4528DEV_ASSERT(cmd_buf_info->render_pass_state.attachment_layouts[resolve_index].aspect_layouts[TEXTURE_ASPECT_COLOR].expected_layout == TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL);4529} else {4530_resource_transition_batch(cmd_buf_info, dst_tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_RESOLVE_DEST);4531}45324533resolves[num_resolves].src_res = src_tex_info->resource;4534resolves[num_resolves].src_subres = src_subresource;4535resolves[num_resolves].dst_res = dst_tex_info->resource;4536resolves[num_resolves].dst_subres = dst_subresource;4537resolves[num_resolves].format = RD_TO_D3D12_FORMAT[src_tex_info->format].general_format;4538num_resolves++;4539}45404541_resource_transitions_flush(cmd_buf_info);45424543// There can be enhanced barriers to flush only when we need to resolve textures.4544if (num_resolves != 0) {4545_render_pass_enhanced_barriers_flush(p_cmd_buffer);4546}45474548for (uint32_t i = 0; i < num_resolves; i++) {4549cmd_buf_info->cmd_list->ResolveSubresource(resolves[i].dst_res, resolves[i].dst_subres, resolves[i].src_res, resolves[i].src_subres, resolves[i].format);4550}4551}45524553void RenderingDeviceDriverD3D12::command_end_render_pass(CommandBufferID p_cmd_buffer) {4554_end_render_pass(p_cmd_buffer);45554556CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;4557DEV_ASSERT(cmd_buf_info->render_pass_state.current_subpass != UINT32_MAX);45584559const FramebufferInfo *fb_info = cmd_buf_info->render_pass_state.fb_info;4560const RenderPassInfo *pass_info = cmd_buf_info->render_pass_state.pass_info;45614562if (fb_info->vrs_attachment && fsr_capabilities.attachment_supported) {4563cmd_buf_info->cmd_list_5->RSSetShadingRateImage(nullptr);4564}45654566auto _transition_subresources = [&](TextureInfo *p_texture_info, D3D12_RESOURCE_STATES p_states) {4567uint32_t planes = 1;4568if ((p_texture_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {4569planes = format_get_plane_count(p_texture_info->format);4570}4571for (uint32_t i = 0; i < p_texture_info->layers; i++) {4572for (uint32_t j = 0; j < p_texture_info->mipmaps; j++) {4573uint32_t subresource = D3D12CalcSubresource(4574p_texture_info->base_mip + j,4575p_texture_info->base_layer + i,45760,4577p_texture_info->desc.MipLevels,4578p_texture_info->desc.ArraySize());45794580_resource_transition_batch(cmd_buf_info, p_texture_info, subresource, planes, p_states);4581}4582}4583};45844585if (!barrier_capabilities.enhanced_barriers_supported) {4586for (uint32_t i = 0; i < pass_info->attachments.size(); i++) {4587if (pass_info->attachments[i].store_op == ATTACHMENT_STORE_OP_DONT_CARE) {4588TextureInfo *tex_info = (TextureInfo *)fb_info->attachments[i].id;4589if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)) {4590_transition_subresources(tex_info, D3D12_RESOURCE_STATE_RENDER_TARGET);4591} else if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {4592_transition_subresources(tex_info, D3D12_RESOURCE_STATE_DEPTH_WRITE);4593} else {4594DEV_ASSERT(false);4595}4596}4597}45984599_resource_transitions_flush(cmd_buf_info);4600}46014602for (uint32_t i = 0; i < pass_info->attachments.size(); i++) {4603const Attachment &attachment = pass_info->attachments[i];46044605for (RenderPassState::AttachmentLayout::AspectLayout &aspect_layout : cmd_buf_info->render_pass_state.attachment_layouts[i].aspect_layouts) {4606aspect_layout.expected_layout = attachment.final_layout;4607}4608}46094610_render_pass_enhanced_barriers_flush(p_cmd_buffer);46114612for (uint32_t i = 0; i < pass_info->attachments.size(); i++) {4613if (pass_info->attachments[i].store_op == ATTACHMENT_STORE_OP_DONT_CARE) {4614const TextureInfo *tex_info = (const TextureInfo *)fb_info->attachments[i].id;4615_discard_texture_subresources(tex_info, cmd_buf_info);4616}4617}46184619cmd_buf_info->render_pass_state.current_subpass = UINT32_MAX;4620}46214622void RenderingDeviceDriverD3D12::command_next_render_subpass(CommandBufferID p_cmd_buffer, CommandBufferType p_cmd_buffer_type) {4623CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;46244625if (cmd_buf_info->render_pass_state.current_subpass == UINT32_MAX) {4626cmd_buf_info->render_pass_state.current_subpass = 0;4627} else {4628_end_render_pass(p_cmd_buffer);4629cmd_buf_info->render_pass_state.current_subpass++;4630}46314632const FramebufferInfo *fb_info = cmd_buf_info->render_pass_state.fb_info;4633const RenderPassInfo *pass_info = cmd_buf_info->render_pass_state.pass_info;4634const Subpass &subpass = pass_info->subpasses[cmd_buf_info->render_pass_state.current_subpass];46354636for (uint32_t i = 0; i < subpass.input_references.size(); i++) {4637const AttachmentReference &input_reference = subpass.input_references[i];4638uint32_t attachment = input_reference.attachment;46394640if (attachment != AttachmentReference::UNUSED) {4641RenderPassState::AttachmentLayout &attachment_layout = cmd_buf_info->render_pass_state.attachment_layouts[attachment];46424643// Vulkan cares about aspect bits only for input attachments.4644for (uint32_t j = 0; j < TEXTURE_ASPECT_MAX; j++) {4645if (input_reference.aspect & (1 << j)) {4646attachment_layout.aspect_layouts[j].expected_layout = input_reference.layout;4647}4648}4649}4650}46514652D3D12_CPU_DESCRIPTOR_HANDLE *rtv_handles = ALLOCA_ARRAY(D3D12_CPU_DESCRIPTOR_HANDLE, subpass.color_references.size());4653for (uint32_t i = 0; i < subpass.color_references.size(); i++) {4654const AttachmentReference &color_reference = subpass.color_references[i];4655uint32_t attachment = color_reference.attachment;4656if (attachment == AttachmentReference::UNUSED) {4657rtv_handles[i] = null_rtv_alloc.cpu_handle;4658} else {4659uint32_t rt_index = fb_info->attachments_handle_inds[attachment];4660rtv_handles[i] = get_cpu_handle(fb_info->rtv_alloc.cpu_handle, rt_index, rtv_descriptor_heap_pool.increment_size);46614662cmd_buf_info->render_pass_state.attachment_layouts[attachment].aspect_layouts[TEXTURE_ASPECT_COLOR].expected_layout = color_reference.layout;4663}4664}46654666D3D12_CPU_DESCRIPTOR_HANDLE dsv_handle = {};4667{4668if (subpass.depth_stencil_reference.attachment != AttachmentReference::UNUSED) {4669uint32_t ds_index = fb_info->attachments_handle_inds[subpass.depth_stencil_reference.attachment];4670dsv_handle = get_cpu_handle(fb_info->dsv_alloc.cpu_handle, ds_index, dsv_descriptor_heap_pool.increment_size);46714672RenderPassState::AttachmentLayout &attachment_layout = cmd_buf_info->render_pass_state.attachment_layouts[subpass.depth_stencil_reference.attachment];4673attachment_layout.aspect_layouts[TEXTURE_ASPECT_DEPTH].expected_layout = subpass.depth_stencil_reference.layout;4674attachment_layout.aspect_layouts[TEXTURE_ASPECT_STENCIL].expected_layout = subpass.depth_stencil_reference.layout;4675}4676}46774678for (uint32_t i = 0; i < subpass.resolve_references.size(); i++) {4679const AttachmentReference &resolve_reference = subpass.resolve_references[i];4680uint32_t attachment = resolve_reference.attachment;46814682if (attachment != AttachmentReference::UNUSED) {4683// Vulkan expects the layout to be in color attachment layout, but D3D12 wants resolve destination.4684DEV_ASSERT(resolve_reference.layout == TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);4685cmd_buf_info->render_pass_state.attachment_layouts[attachment].aspect_layouts[TEXTURE_ASPECT_COLOR].expected_layout = TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL;4686}4687}46884689_render_pass_enhanced_barriers_flush(p_cmd_buffer);46904691cmd_buf_info->cmd_list->OMSetRenderTargets(subpass.color_references.size(), rtv_handles, false, dsv_handle.ptr ? &dsv_handle : nullptr);4692}46934694void RenderingDeviceDriverD3D12::command_render_set_viewport(CommandBufferID p_cmd_buffer, VectorView<Rect2i> p_viewports) {4695const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;46964697D3D12_VIEWPORT *d3d12_viewports = ALLOCA_ARRAY(D3D12_VIEWPORT, p_viewports.size());4698for (uint32_t i = 0; i < p_viewports.size(); i++) {4699d3d12_viewports[i] = CD3DX12_VIEWPORT(4700p_viewports[i].position.x,4701p_viewports[i].position.y,4702p_viewports[i].size.x,4703p_viewports[i].size.y);4704}47054706cmd_buf_info->cmd_list->RSSetViewports(p_viewports.size(), d3d12_viewports);4707}47084709void RenderingDeviceDriverD3D12::command_render_set_scissor(CommandBufferID p_cmd_buffer, VectorView<Rect2i> p_scissors) {4710const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;47114712D3D12_RECT *d3d12_scissors = ALLOCA_ARRAY(D3D12_RECT, p_scissors.size());4713for (uint32_t i = 0; i < p_scissors.size(); i++) {4714d3d12_scissors[i] = CD3DX12_RECT(4715p_scissors[i].position.x,4716p_scissors[i].position.y,4717p_scissors[i].position.x + p_scissors[i].size.x,4718p_scissors[i].position.y + p_scissors[i].size.y);4719}47204721cmd_buf_info->cmd_list->RSSetScissorRects(p_scissors.size(), d3d12_scissors);4722}47234724void RenderingDeviceDriverD3D12::command_render_clear_attachments(CommandBufferID p_cmd_buffer, VectorView<AttachmentClear> p_attachment_clears, VectorView<Rect2i> p_rects) {4725const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;47264727DEV_ASSERT(cmd_buf_info->render_pass_state.current_subpass != UINT32_MAX);4728const FramebufferInfo *fb_info = cmd_buf_info->render_pass_state.fb_info;4729const RenderPassInfo *pass_info = cmd_buf_info->render_pass_state.pass_info;47304731for (uint32_t i = 0; i < p_attachment_clears.size(); i++) {4732uint32_t attachment = UINT32_MAX;4733bool is_render_target = false;4734if (p_attachment_clears[i].aspect.has_flag(TEXTURE_ASPECT_COLOR_BIT)) {4735attachment = p_attachment_clears[i].color_attachment;4736is_render_target = true;4737} else {4738attachment = pass_info->subpasses[cmd_buf_info->render_pass_state.current_subpass].depth_stencil_reference.attachment;4739}47404741for (uint32_t j = 0; j < p_rects.size(); j++) {4742D3D12_RECT rect = CD3DX12_RECT(4743p_rects[j].position.x,4744p_rects[j].position.y,4745p_rects[j].position.x + p_rects[j].size.x,4746p_rects[j].position.y + p_rects[j].size.y);4747const D3D12_RECT *rect_ptr = cmd_buf_info->render_pass_state.region_is_all ? nullptr : ▭47484749if (is_render_target) {4750uint32_t color_idx = fb_info->attachments_handle_inds[attachment];4751cmd_buf_info->cmd_list->ClearRenderTargetView(4752get_cpu_handle(fb_info->rtv_alloc.cpu_handle, color_idx, rtv_descriptor_heap_pool.increment_size),4753p_attachment_clears[i].value.color.components,4754rect_ptr ? 1 : 0,4755rect_ptr);4756} else {4757uint32_t depth_stencil_idx = fb_info->attachments_handle_inds[attachment];4758D3D12_CLEAR_FLAGS flags = {};4759if (p_attachment_clears[i].aspect.has_flag(TEXTURE_ASPECT_DEPTH_BIT)) {4760flags |= D3D12_CLEAR_FLAG_DEPTH;4761}4762if (p_attachment_clears[i].aspect.has_flag(TEXTURE_ASPECT_STENCIL_BIT)) {4763flags |= D3D12_CLEAR_FLAG_STENCIL;4764}4765cmd_buf_info->cmd_list->ClearDepthStencilView(4766get_cpu_handle(fb_info->dsv_alloc.cpu_handle, depth_stencil_idx, dsv_descriptor_heap_pool.increment_size),4767flags,4768p_attachment_clears[i].value.depth,4769p_attachment_clears[i].value.stencil,4770rect_ptr ? 1 : 0,4771rect_ptr);4772}4773}4774}4775}47764777void RenderingDeviceDriverD3D12::command_bind_render_pipeline(CommandBufferID p_cmd_buffer, PipelineID p_pipeline) {4778CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;47794780const PipelineInfo *pipeline_info = (const PipelineInfo *)p_pipeline.id;4781const ShaderInfo *shader_info_in = pipeline_info->shader_info;4782const RenderPipelineInfo &render_info = pipeline_info->render_info;47834784if (cmd_buf_info->graphics_pso != pipeline_info->pso.Get()) {4785cmd_buf_info->cmd_list->SetPipelineState(pipeline_info->pso.Get());47864787cmd_buf_info->graphics_pso = pipeline_info->pso.Get();4788cmd_buf_info->compute_pso = nullptr;4789}47904791if (cmd_buf_info->graphics_root_signature_crc != shader_info_in->root_signature_crc) {4792cmd_buf_info->cmd_list->SetGraphicsRootSignature(shader_info_in->root_signature.Get());4793cmd_buf_info->graphics_root_signature_crc = shader_info_in->root_signature_crc;4794}47954796if (cmd_buf_info->pending_dyn_params || (cmd_buf_info->dyn_params.primitive_topology != render_info.dyn_params.primitive_topology)) {4797cmd_buf_info->cmd_list->IASetPrimitiveTopology(render_info.dyn_params.primitive_topology);4798cmd_buf_info->dyn_params.primitive_topology = render_info.dyn_params.primitive_topology;4799}48004801if (cmd_buf_info->pending_dyn_params || (cmd_buf_info->dyn_params.blend_constant != render_info.dyn_params.blend_constant)) {4802cmd_buf_info->cmd_list->OMSetBlendFactor(render_info.dyn_params.blend_constant.components);4803cmd_buf_info->dyn_params.blend_constant = render_info.dyn_params.blend_constant;4804}48054806if (cmd_buf_info->pending_dyn_params || (cmd_buf_info->dyn_params.stencil_reference != render_info.dyn_params.stencil_reference)) {4807cmd_buf_info->cmd_list->OMSetStencilRef(render_info.dyn_params.stencil_reference);4808cmd_buf_info->dyn_params.stencil_reference = render_info.dyn_params.stencil_reference;4809}48104811if (misc_features_support.depth_bounds_supported && (cmd_buf_info->pending_dyn_params || (cmd_buf_info->dyn_params.depth_bounds_min != render_info.dyn_params.depth_bounds_min) || (cmd_buf_info->dyn_params.depth_bounds_max != render_info.dyn_params.depth_bounds_max))) {4812cmd_buf_info->cmd_list_1->OMSetDepthBounds(render_info.dyn_params.depth_bounds_min, render_info.dyn_params.depth_bounds_max);4813cmd_buf_info->dyn_params.depth_bounds_min = render_info.dyn_params.depth_bounds_min;4814cmd_buf_info->dyn_params.depth_bounds_max = render_info.dyn_params.depth_bounds_max;4815}48164817cmd_buf_info->pending_dyn_params = false;4818cmd_buf_info->render_pass_state.vf_info = render_info.vf_info;4819}48204821void RenderingDeviceDriverD3D12::command_bind_render_uniform_sets(CommandBufferID p_cmd_buffer, VectorView<UniformSetID> p_uniform_sets, ShaderID p_shader, uint32_t p_first_set_index, uint32_t p_set_count, uint32_t p_dynamic_offsets) {4822_command_check_descriptor_sets(p_cmd_buffer);48234824const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;4825const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;48264827for (uint32_t i = 0u; i < p_set_count; ++i) {4828UniformSetInfo *uniform_set_info = (UniformSetInfo *)p_uniform_sets[i].id;4829const ShaderInfo::UniformSet &uniform_set_shader_info = shader_info_in->sets[p_first_set_index + i];48304831for (const UniformSetInfo::DynamicBuffer &dynamic_buffer : uniform_set_info->dynamic_buffers) {4832uint32_t frame_index = p_dynamic_offsets & 0xF;4833p_dynamic_offsets >>= 4;48344835const ShaderInfo::UniformBindingInfo &binding = uniform_set_shader_info.bindings[dynamic_buffer.binding];4836if (binding.root_param_idx != UINT_MAX) {4837D3D12_GPU_VIRTUAL_ADDRESS buffer_location = dynamic_buffer.info->gpu_virtual_address + (dynamic_buffer.info->size * frame_index);4838switch (binding.res_class) {4839case RES_CLASS_INVALID: {4840} break;4841case RES_CLASS_CBV: {4842cmd_buf_info->cmd_list->SetGraphicsRootConstantBufferView(binding.root_param_idx, buffer_location);4843} break;4844case RES_CLASS_SRV: {4845cmd_buf_info->cmd_list->SetGraphicsRootShaderResourceView(binding.root_param_idx, buffer_location);4846} break;4847case RES_CLASS_UAV: {4848cmd_buf_info->cmd_list->SetGraphicsRootUnorderedAccessView(binding.root_param_idx, buffer_location);4849} break;4850}4851}4852}48534854if (uniform_set_shader_info.resource_root_param_idx != UINT_MAX) {4855cmd_buf_info->cmd_list->SetGraphicsRootDescriptorTable(uniform_set_shader_info.resource_root_param_idx, uniform_set_info->resource_descriptor_heap_alloc.gpu_handle);4856}4857if (uniform_set_shader_info.sampler_root_param_idx != UINT_MAX) {4858cmd_buf_info->cmd_list->SetGraphicsRootDescriptorTable(uniform_set_shader_info.sampler_root_param_idx, uniform_set_info->sampler_descriptor_heap_alloc->gpu_handle);4859}4860}4861}48624863void RenderingDeviceDriverD3D12::command_render_draw(CommandBufferID p_cmd_buffer, uint32_t p_vertex_count, uint32_t p_instance_count, uint32_t p_base_vertex, uint32_t p_first_instance) {4864CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;4865_bind_vertex_buffers(cmd_buf_info);4866cmd_buf_info->cmd_list->DrawInstanced(p_vertex_count, p_instance_count, p_base_vertex, p_first_instance);4867}48684869void RenderingDeviceDriverD3D12::command_render_draw_indexed(CommandBufferID p_cmd_buffer, uint32_t p_index_count, uint32_t p_instance_count, uint32_t p_first_index, int32_t p_vertex_offset, uint32_t p_first_instance) {4870CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;4871_bind_vertex_buffers(cmd_buf_info);4872cmd_buf_info->cmd_list->DrawIndexedInstanced(p_index_count, p_instance_count, p_first_index, p_vertex_offset, p_first_instance);4873}48744875void RenderingDeviceDriverD3D12::command_render_draw_indexed_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, uint32_t p_draw_count, uint32_t p_stride) {4876CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;4877_bind_vertex_buffers(cmd_buf_info);4878BufferInfo *indirect_buf_info = (BufferInfo *)p_indirect_buffer.id;4879if (!barrier_capabilities.enhanced_barriers_supported) {4880_resource_transition_batch(cmd_buf_info, indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);4881_resource_transitions_flush(cmd_buf_info);4882}48834884cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.draw_indexed.Get(), p_draw_count, indirect_buf_info->resource, p_offset, nullptr, 0);4885}48864887void RenderingDeviceDriverD3D12::command_render_draw_indexed_indirect_count(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, BufferID p_count_buffer, uint64_t p_count_buffer_offset, uint32_t p_max_draw_count, uint32_t p_stride) {4888CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;4889_bind_vertex_buffers(cmd_buf_info);4890BufferInfo *indirect_buf_info = (BufferInfo *)p_indirect_buffer.id;4891BufferInfo *count_buf_info = (BufferInfo *)p_count_buffer.id;4892if (!barrier_capabilities.enhanced_barriers_supported) {4893_resource_transition_batch(cmd_buf_info, indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);4894_resource_transition_batch(cmd_buf_info, count_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);4895_resource_transitions_flush(cmd_buf_info);4896}48974898cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.draw_indexed.Get(), p_max_draw_count, indirect_buf_info->resource, p_offset, count_buf_info->resource, p_count_buffer_offset);4899}49004901void RenderingDeviceDriverD3D12::command_render_draw_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, uint32_t p_draw_count, uint32_t p_stride) {4902CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;4903_bind_vertex_buffers(cmd_buf_info);4904BufferInfo *indirect_buf_info = (BufferInfo *)p_indirect_buffer.id;4905if (!barrier_capabilities.enhanced_barriers_supported) {4906_resource_transition_batch(cmd_buf_info, indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);4907_resource_transitions_flush(cmd_buf_info);4908}49094910cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.draw.Get(), p_draw_count, indirect_buf_info->resource, p_offset, nullptr, 0);4911}49124913void RenderingDeviceDriverD3D12::command_render_draw_indirect_count(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, BufferID p_count_buffer, uint64_t p_count_buffer_offset, uint32_t p_max_draw_count, uint32_t p_stride) {4914CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;4915_bind_vertex_buffers(cmd_buf_info);4916BufferInfo *indirect_buf_info = (BufferInfo *)p_indirect_buffer.id;4917BufferInfo *count_buf_info = (BufferInfo *)p_count_buffer.id;4918if (!barrier_capabilities.enhanced_barriers_supported) {4919_resource_transition_batch(cmd_buf_info, indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);4920_resource_transition_batch(cmd_buf_info, count_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);4921_resource_transitions_flush(cmd_buf_info);4922}49234924cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.draw.Get(), p_max_draw_count, indirect_buf_info->resource, p_offset, count_buf_info->resource, p_count_buffer_offset);4925}49264927void RenderingDeviceDriverD3D12::command_render_bind_vertex_buffers(CommandBufferID p_cmd_buffer, uint32_t p_binding_count, const BufferID *p_buffers, const uint64_t *p_offsets, uint64_t p_dynamic_offsets) {4928CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;49294930DEV_ASSERT(cmd_buf_info->render_pass_state.current_subpass != UINT32_MAX);49314932// Vertex buffer views are set deferredly, to be sure we already know the strides by then,4933// which is only true once the pipeline has been bound. Otherwise, we'd need that the pipeline4934// is always bound first, which would be not kind of us. [[DEFERRED_VERTEX_BUFFERS]]4935DEV_ASSERT(p_binding_count <= ARRAY_SIZE(cmd_buf_info->render_pass_state.vertex_buffer_views));4936for (uint32_t i = 0; i < p_binding_count; i++) {4937BufferInfo *buffer_info = (BufferInfo *)p_buffers[i].id;49384939uint32_t dynamic_offset = 0;4940if (buffer_info->is_dynamic()) {4941uint64_t buffer_frame_idx = p_dynamic_offsets & 0x3; // Assuming max 4 frames.4942p_dynamic_offsets >>= 2;4943dynamic_offset = buffer_frame_idx * buffer_info->size;4944}49454946cmd_buf_info->render_pass_state.vertex_buffer_views[i] = {};4947cmd_buf_info->render_pass_state.vertex_buffer_views[i].BufferLocation = buffer_info->gpu_virtual_address + dynamic_offset + p_offsets[i];4948cmd_buf_info->render_pass_state.vertex_buffer_views[i].SizeInBytes = buffer_info->size - p_offsets[i];4949if (!barrier_capabilities.enhanced_barriers_supported) {4950_resource_transition_batch(cmd_buf_info, buffer_info, 0, 1, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);4951}4952}49534954if (!barrier_capabilities.enhanced_barriers_supported) {4955_resource_transitions_flush(cmd_buf_info);4956}49574958cmd_buf_info->render_pass_state.vertex_buffer_count = p_binding_count;4959}49604961void RenderingDeviceDriverD3D12::command_render_bind_index_buffer(CommandBufferID p_cmd_buffer, BufferID p_buffer, IndexBufferFormat p_format, uint64_t p_offset) {4962CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;4963BufferInfo *buffer_info = (BufferInfo *)p_buffer.id;49644965D3D12_INDEX_BUFFER_VIEW d3d12_ib_view = {};4966d3d12_ib_view.BufferLocation = buffer_info->gpu_virtual_address + p_offset;4967d3d12_ib_view.SizeInBytes = buffer_info->size - p_offset;4968d3d12_ib_view.Format = p_format == INDEX_BUFFER_FORMAT_UINT16 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT;49694970if (!barrier_capabilities.enhanced_barriers_supported) {4971_resource_transition_batch(cmd_buf_info, buffer_info, 0, 1, D3D12_RESOURCE_STATE_INDEX_BUFFER);4972_resource_transitions_flush(cmd_buf_info);4973}49744975cmd_buf_info->cmd_list->IASetIndexBuffer(&d3d12_ib_view);4976}49774978// [[DEFERRED_VERTEX_BUFFERS]]4979void RenderingDeviceDriverD3D12::_bind_vertex_buffers(CommandBufferInfo *p_cmd_buf_info) {4980RenderPassState &render_pass_state = p_cmd_buf_info->render_pass_state;4981if (render_pass_state.vertex_buffer_count && render_pass_state.vf_info) {4982for (uint32_t i = 0; i < render_pass_state.vertex_buffer_count; i++) {4983render_pass_state.vertex_buffer_views[i].StrideInBytes = render_pass_state.vf_info->vertex_buffer_strides[i];4984}4985p_cmd_buf_info->cmd_list->IASetVertexBuffers(0, render_pass_state.vertex_buffer_count, render_pass_state.vertex_buffer_views);4986render_pass_state.vertex_buffer_count = 0;4987}4988}49894990void RenderingDeviceDriverD3D12::command_render_set_blend_constants(CommandBufferID p_cmd_buffer, const Color &p_constants) {4991const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;4992cmd_buf_info->cmd_list->OMSetBlendFactor(p_constants.components);4993}49944995void RenderingDeviceDriverD3D12::command_render_set_line_width(CommandBufferID p_cmd_buffer, float p_width) {4996if (!Math::is_equal_approx(p_width, 1.0f)) {4997ERR_FAIL_MSG("Setting line widths other than 1.0 is not supported by the Direct3D 12 rendering driver.");4998}4999}50005001// ----- PIPELINE -----50025003static const D3D12_PRIMITIVE_TOPOLOGY_TYPE RD_PRIMITIVE_TO_D3D12_TOPOLOGY_TYPE[RDD::RENDER_PRIMITIVE_MAX] = {5004D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT,5005D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,5006D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,5007D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,5008D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,5009D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,5010D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,5011D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,5012D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,5013D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,5014D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH,5015};50165017static const D3D12_PRIMITIVE_TOPOLOGY RD_PRIMITIVE_TO_D3D12_TOPOLOGY[RDD::RENDER_PRIMITIVE_MAX] = {5018D3D_PRIMITIVE_TOPOLOGY_POINTLIST,5019D3D_PRIMITIVE_TOPOLOGY_LINELIST,5020D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ,5021D3D_PRIMITIVE_TOPOLOGY_LINESTRIP,5022D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ,5023D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST,5024D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ,5025D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,5026D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ,5027D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,5028D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST,5029};50305031static const D3D12_CULL_MODE RD_POLYGON_CULL_TO_D3D12_CULL_MODE[RDD::POLYGON_CULL_MAX] = {5032D3D12_CULL_MODE_NONE,5033D3D12_CULL_MODE_FRONT,5034D3D12_CULL_MODE_BACK,5035};50365037static const D3D12_STENCIL_OP RD_TO_D3D12_STENCIL_OP[RDD::STENCIL_OP_MAX] = {5038D3D12_STENCIL_OP_KEEP,5039D3D12_STENCIL_OP_ZERO,5040D3D12_STENCIL_OP_REPLACE,5041D3D12_STENCIL_OP_INCR_SAT,5042D3D12_STENCIL_OP_DECR_SAT,5043D3D12_STENCIL_OP_INVERT,5044D3D12_STENCIL_OP_INCR,5045D3D12_STENCIL_OP_DECR,5046};50475048static const D3D12_LOGIC_OP RD_TO_D3D12_LOGIC_OP[RDD::LOGIC_OP_MAX] = {5049D3D12_LOGIC_OP_CLEAR,5050D3D12_LOGIC_OP_AND,5051D3D12_LOGIC_OP_AND_REVERSE,5052D3D12_LOGIC_OP_COPY,5053D3D12_LOGIC_OP_AND_INVERTED,5054D3D12_LOGIC_OP_NOOP,5055D3D12_LOGIC_OP_XOR,5056D3D12_LOGIC_OP_OR,5057D3D12_LOGIC_OP_NOR,5058D3D12_LOGIC_OP_EQUIV,5059D3D12_LOGIC_OP_INVERT,5060D3D12_LOGIC_OP_OR_REVERSE,5061D3D12_LOGIC_OP_COPY_INVERTED,5062D3D12_LOGIC_OP_OR_INVERTED,5063D3D12_LOGIC_OP_NAND,5064D3D12_LOGIC_OP_SET,5065};50665067static const D3D12_BLEND RD_TO_D3D12_BLEND_FACTOR[RDD::BLEND_FACTOR_MAX] = {5068D3D12_BLEND_ZERO,5069D3D12_BLEND_ONE,5070D3D12_BLEND_SRC_COLOR,5071D3D12_BLEND_INV_SRC_COLOR,5072D3D12_BLEND_DEST_COLOR,5073D3D12_BLEND_INV_DEST_COLOR,5074D3D12_BLEND_SRC_ALPHA,5075D3D12_BLEND_INV_SRC_ALPHA,5076D3D12_BLEND_DEST_ALPHA,5077D3D12_BLEND_INV_DEST_ALPHA,5078D3D12_BLEND_BLEND_FACTOR,5079D3D12_BLEND_INV_BLEND_FACTOR,5080D3D12_BLEND_BLEND_FACTOR,5081D3D12_BLEND_INV_BLEND_FACTOR,5082D3D12_BLEND_SRC_ALPHA_SAT,5083D3D12_BLEND_SRC1_COLOR,5084D3D12_BLEND_INV_SRC1_COLOR,5085D3D12_BLEND_SRC1_ALPHA,5086D3D12_BLEND_INV_SRC1_ALPHA,5087};50885089static const D3D12_BLEND_OP RD_TO_D3D12_BLEND_OP[RDD::BLEND_OP_MAX] = {5090D3D12_BLEND_OP_ADD,5091D3D12_BLEND_OP_SUBTRACT,5092D3D12_BLEND_OP_REV_SUBTRACT,5093D3D12_BLEND_OP_MIN,5094D3D12_BLEND_OP_MAX,5095};50965097RDD::PipelineID RenderingDeviceDriverD3D12::render_pipeline_create(5098ShaderID p_shader,5099VertexFormatID p_vertex_format,5100RenderPrimitive p_render_primitive,5101PipelineRasterizationState p_rasterization_state,5102PipelineMultisampleState p_multisample_state,5103PipelineDepthStencilState p_depth_stencil_state,5104PipelineColorBlendState p_blend_state,5105VectorView<int32_t> p_color_attachments,5106BitField<PipelineDynamicStateFlags> p_dynamic_state,5107RenderPassID p_render_pass,5108uint32_t p_render_subpass,5109VectorView<PipelineSpecializationConstant> p_specialization_constants) {5110const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;51115112CD3DX12_PIPELINE_STATE_STREAM1 pipeline_desc = {};51135114const RenderPassInfo *pass_info = (const RenderPassInfo *)p_render_pass.id;5115RenderPipelineInfo render_info;51165117// Attachments.5118LocalVector<uint32_t> color_attachments;5119{5120const Subpass &subpass = pass_info->subpasses[p_render_subpass];51215122for (uint32_t i = 0; i < ARRAY_SIZE((&pipeline_desc.RTVFormats)->RTFormats); i++) {5123(&pipeline_desc.RTVFormats)->RTFormats[i] = DXGI_FORMAT_UNKNOWN;5124}51255126for (uint32_t i = 0; i < subpass.color_references.size(); i++) {5127const AttachmentReference &ref = subpass.color_references[i];5128if (ref.attachment != AttachmentReference::UNUSED) {5129const Attachment &attachment = pass_info->attachments[ref.attachment];5130DEV_ASSERT((&pipeline_desc.RTVFormats)->RTFormats[i] == DXGI_FORMAT_UNKNOWN);5131(&pipeline_desc.RTVFormats)->RTFormats[i] = RD_TO_D3D12_FORMAT[attachment.format].general_format;5132}5133}5134(&pipeline_desc.RTVFormats)->NumRenderTargets = p_color_attachments.size();51355136if (subpass.depth_stencil_reference.attachment != AttachmentReference::UNUSED) {5137const Attachment &attachment = pass_info->attachments[subpass.depth_stencil_reference.attachment];5138pipeline_desc.DSVFormat = RD_TO_D3D12_FORMAT[attachment.format].dsv_format;5139} else {5140pipeline_desc.DSVFormat = DXGI_FORMAT_UNKNOWN;5141}5142}51435144// Vertex.5145if (p_vertex_format) {5146const VertexFormatInfo *vf_info = (const VertexFormatInfo *)p_vertex_format.id;5147(&pipeline_desc.InputLayout)->pInputElementDescs = vf_info->input_elem_descs.ptr();5148(&pipeline_desc.InputLayout)->NumElements = vf_info->input_elem_descs.size();5149render_info.vf_info = vf_info;5150}51515152// Input assembly & tessellation.51535154pipeline_desc.PrimitiveTopologyType = RD_PRIMITIVE_TO_D3D12_TOPOLOGY_TYPE[p_render_primitive];5155if (p_render_primitive == RENDER_PRIMITIVE_TESSELATION_PATCH) {5156// Is there any way to get the true point count limit?5157ERR_FAIL_COND_V(p_rasterization_state.patch_control_points < 1 || p_rasterization_state.patch_control_points > 32, PipelineID());5158render_info.dyn_params.primitive_topology = (D3D12_PRIMITIVE_TOPOLOGY)((int)D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + p_rasterization_state.patch_control_points);5159} else {5160render_info.dyn_params.primitive_topology = RD_PRIMITIVE_TO_D3D12_TOPOLOGY[p_render_primitive];5161}5162if (p_render_primitive == RENDER_PRIMITIVE_TRIANGLE_STRIPS_WITH_RESTART_INDEX) {5163// TODO: This is right for 16-bit indices; for 32-bit there's a different enum value to set, but we don't know at this point.5164pipeline_desc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF;5165} else {5166pipeline_desc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;5167}51685169// Rasterization.5170(&pipeline_desc.RasterizerState)->DepthClipEnable = !p_rasterization_state.enable_depth_clamp;5171// In D3D12, discard can be supported with some extra effort (empty pixel shader + disable depth/stencil test); that said, unsupported by now.5172ERR_FAIL_COND_V(p_rasterization_state.discard_primitives, PipelineID());5173(&pipeline_desc.RasterizerState)->FillMode = p_rasterization_state.wireframe ? D3D12_FILL_MODE_WIREFRAME : D3D12_FILL_MODE_SOLID;5174(&pipeline_desc.RasterizerState)->CullMode = RD_POLYGON_CULL_TO_D3D12_CULL_MODE[p_rasterization_state.cull_mode];5175(&pipeline_desc.RasterizerState)->FrontCounterClockwise = p_rasterization_state.front_face == POLYGON_FRONT_FACE_COUNTER_CLOCKWISE;5176// In D3D12, there's still a point in setting up depth bias with no depth buffer, but just zeroing (disabling) it all in such case is closer to Vulkan.5177if (p_rasterization_state.depth_bias_enabled && pipeline_desc.DSVFormat != DXGI_FORMAT_UNKNOWN) {5178(&pipeline_desc.RasterizerState)->DepthBias = p_rasterization_state.depth_bias_constant_factor;5179(&pipeline_desc.RasterizerState)->DepthBiasClamp = p_rasterization_state.depth_bias_clamp;5180(&pipeline_desc.RasterizerState)->SlopeScaledDepthBias = p_rasterization_state.depth_bias_slope_factor;5181(&pipeline_desc.RasterizerState)->DepthBias = 0;5182(&pipeline_desc.RasterizerState)->DepthBiasClamp = 0.0f;5183(&pipeline_desc.RasterizerState)->SlopeScaledDepthBias = 0.0f;5184}5185(&pipeline_desc.RasterizerState)->ForcedSampleCount = 0;5186(&pipeline_desc.RasterizerState)->ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;5187(&pipeline_desc.RasterizerState)->MultisampleEnable = TEXTURE_SAMPLES_COUNT[p_multisample_state.sample_count] != 1;5188(&pipeline_desc.RasterizerState)->AntialiasedLineEnable = true;51895190// In D3D12, there's no line width.5191ERR_FAIL_COND_V(!Math::is_equal_approx(p_rasterization_state.line_width, 1.0f), PipelineID());51925193// Multisample.5194ERR_FAIL_COND_V(p_multisample_state.enable_sample_shading, PipelineID()); // How one enables this in D3D12?5195if ((&pipeline_desc.RTVFormats)->NumRenderTargets || pipeline_desc.DSVFormat != DXGI_FORMAT_UNKNOWN) {5196uint32_t sample_count = MIN(5197pass_info->max_supported_sample_count,5198TEXTURE_SAMPLES_COUNT[p_multisample_state.sample_count]);5199(&pipeline_desc.SampleDesc)->Count = sample_count;5200} else {5201(&pipeline_desc.SampleDesc)->Count = 1;5202}5203if ((&pipeline_desc.SampleDesc)->Count > 1) {5204(&pipeline_desc.SampleDesc)->Quality = DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN;5205} else {5206(&pipeline_desc.SampleDesc)->Quality = 0;5207}5208if (p_multisample_state.sample_mask.size()) {5209for (int i = 1; i < p_multisample_state.sample_mask.size(); i++) {5210// In D3D12 there's a single sample mask for every pixel.5211ERR_FAIL_COND_V(p_multisample_state.sample_mask[i] != p_multisample_state.sample_mask[0], PipelineID());5212}5213pipeline_desc.SampleMask = p_multisample_state.sample_mask[0];5214} else {5215pipeline_desc.SampleMask = 0xffffffff;5216}52175218// Depth stencil.52195220if (pipeline_desc.DSVFormat == DXGI_FORMAT_UNKNOWN) {5221(&pipeline_desc.DepthStencilState)->DepthEnable = false;5222(&pipeline_desc.DepthStencilState)->StencilEnable = false;5223} else {5224(&pipeline_desc.DepthStencilState)->DepthEnable = p_depth_stencil_state.enable_depth_test;5225(&pipeline_desc.DepthStencilState)->DepthWriteMask = p_depth_stencil_state.enable_depth_write ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;5226(&pipeline_desc.DepthStencilState)->DepthFunc = RD_TO_D3D12_COMPARE_OP[p_depth_stencil_state.depth_compare_operator];5227(&pipeline_desc.DepthStencilState)->DepthBoundsTestEnable = p_depth_stencil_state.enable_depth_range;5228(&pipeline_desc.DepthStencilState)->StencilEnable = p_depth_stencil_state.enable_stencil;52295230// In D3D12 some elements can't be different across front and back.5231ERR_FAIL_COND_V(p_depth_stencil_state.front_op.compare_mask != p_depth_stencil_state.back_op.compare_mask, PipelineID());5232ERR_FAIL_COND_V(p_depth_stencil_state.front_op.write_mask != p_depth_stencil_state.back_op.write_mask, PipelineID());5233ERR_FAIL_COND_V(p_depth_stencil_state.front_op.reference != p_depth_stencil_state.back_op.reference, PipelineID());5234(&pipeline_desc.DepthStencilState)->StencilReadMask = p_depth_stencil_state.front_op.compare_mask;5235(&pipeline_desc.DepthStencilState)->StencilWriteMask = p_depth_stencil_state.front_op.write_mask;52365237(&pipeline_desc.DepthStencilState)->FrontFace.StencilFailOp = RD_TO_D3D12_STENCIL_OP[p_depth_stencil_state.front_op.fail];5238(&pipeline_desc.DepthStencilState)->FrontFace.StencilPassOp = RD_TO_D3D12_STENCIL_OP[p_depth_stencil_state.front_op.pass];5239(&pipeline_desc.DepthStencilState)->FrontFace.StencilDepthFailOp = RD_TO_D3D12_STENCIL_OP[p_depth_stencil_state.front_op.depth_fail];5240(&pipeline_desc.DepthStencilState)->FrontFace.StencilFunc = RD_TO_D3D12_COMPARE_OP[p_depth_stencil_state.front_op.compare];52415242(&pipeline_desc.DepthStencilState)->BackFace.StencilFailOp = RD_TO_D3D12_STENCIL_OP[p_depth_stencil_state.back_op.fail];5243(&pipeline_desc.DepthStencilState)->BackFace.StencilPassOp = RD_TO_D3D12_STENCIL_OP[p_depth_stencil_state.back_op.pass];5244(&pipeline_desc.DepthStencilState)->BackFace.StencilDepthFailOp = RD_TO_D3D12_STENCIL_OP[p_depth_stencil_state.back_op.depth_fail];5245(&pipeline_desc.DepthStencilState)->BackFace.StencilFunc = RD_TO_D3D12_COMPARE_OP[p_depth_stencil_state.back_op.compare];52465247if (misc_features_support.depth_bounds_supported) {5248render_info.dyn_params.depth_bounds_min = p_depth_stencil_state.enable_depth_range ? p_depth_stencil_state.depth_range_min : 0.0f;5249render_info.dyn_params.depth_bounds_max = p_depth_stencil_state.enable_depth_range ? p_depth_stencil_state.depth_range_max : 1.0f;5250} else {5251if (p_depth_stencil_state.enable_depth_range) {5252WARN_PRINT_ONCE("Depth bounds test is not supported by the GPU driver.");5253}5254}52555256render_info.dyn_params.stencil_reference = p_depth_stencil_state.front_op.reference;5257}52585259// Blend states.5260(&pipeline_desc.BlendState)->AlphaToCoverageEnable = p_multisample_state.enable_alpha_to_coverage;5261{5262bool all_attachments_same_blend = true;5263for (int i = 0; i < p_blend_state.attachments.size(); i++) {5264const PipelineColorBlendState::Attachment &bs = p_blend_state.attachments[i];5265D3D12_RENDER_TARGET_BLEND_DESC &bd = (&pipeline_desc.BlendState)->RenderTarget[i];52665267bd.BlendEnable = bs.enable_blend;5268bd.LogicOpEnable = p_blend_state.enable_logic_op;5269bd.LogicOp = RD_TO_D3D12_LOGIC_OP[p_blend_state.logic_op];52705271bd.SrcBlend = RD_TO_D3D12_BLEND_FACTOR[bs.src_color_blend_factor];5272bd.DestBlend = RD_TO_D3D12_BLEND_FACTOR[bs.dst_color_blend_factor];5273bd.BlendOp = RD_TO_D3D12_BLEND_OP[bs.color_blend_op];52745275bd.SrcBlendAlpha = RD_TO_D3D12_BLEND_FACTOR[bs.src_alpha_blend_factor];5276bd.DestBlendAlpha = RD_TO_D3D12_BLEND_FACTOR[bs.dst_alpha_blend_factor];5277bd.BlendOpAlpha = RD_TO_D3D12_BLEND_OP[bs.alpha_blend_op];52785279if (bs.write_r) {5280bd.RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_RED;5281}5282if (bs.write_g) {5283bd.RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_GREEN;5284}5285if (bs.write_b) {5286bd.RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_BLUE;5287}5288if (bs.write_a) {5289bd.RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_ALPHA;5290}52915292if (i > 0 && all_attachments_same_blend) {5293all_attachments_same_blend = &(&pipeline_desc.BlendState)->RenderTarget[i] == &(&pipeline_desc.BlendState)->RenderTarget[0];5294}5295}52965297// Per D3D12 docs, if logic op used, independent blending is not supported.5298ERR_FAIL_COND_V(p_blend_state.enable_logic_op && !all_attachments_same_blend, PipelineID());52995300(&pipeline_desc.BlendState)->IndependentBlendEnable = !all_attachments_same_blend;5301}53025303render_info.dyn_params.blend_constant = p_blend_state.blend_constant;53045305// Multiview5306// We are using render target slices for each view.5307const D3D12_VIEW_INSTANCE_LOCATION viewInstanceLocations[D3D12_MAX_VIEW_INSTANCE_COUNT] = { { 0, 0 }, { 0, 1 }, { 0, 2 }, { 0, 3 } };5308if (pass_info->view_count > 1) {5309(&pipeline_desc.ViewInstancingDesc)->ViewInstanceCount = pass_info->view_count;5310(&pipeline_desc.ViewInstancingDesc)->Flags = D3D12_VIEW_INSTANCING_FLAG_NONE;5311(&pipeline_desc.ViewInstancingDesc)->pViewInstanceLocations = viewInstanceLocations;5312}53135314// Stages bytecodes + specialization constants.53155316pipeline_desc.pRootSignature = shader_info_in->root_signature.Get();53175318HashMap<ShaderStage, Vector<uint8_t>> final_stages_bytecode;5319bool ok = _shader_apply_specialization_constants(shader_info_in, p_specialization_constants, final_stages_bytecode);5320ERR_FAIL_COND_V(!ok, PipelineID());53215322pipeline_desc.VS = D3D12_SHADER_BYTECODE{5323final_stages_bytecode[SHADER_STAGE_VERTEX].ptr(),5324(SIZE_T)final_stages_bytecode[SHADER_STAGE_VERTEX].size()5325};5326pipeline_desc.PS = D3D12_SHADER_BYTECODE{5327final_stages_bytecode[SHADER_STAGE_FRAGMENT].ptr(),5328(SIZE_T)final_stages_bytecode[SHADER_STAGE_FRAGMENT].size()5329};53305331ComPtr<ID3D12Device2> device_2;5332device->QueryInterface(device_2.GetAddressOf());5333ComPtr<ID3D12PipelineState> pso;5334HRESULT res = E_FAIL;5335if (device_2) {5336D3D12_PIPELINE_STATE_STREAM_DESC pssd = {};5337pssd.pPipelineStateSubobjectStream = &pipeline_desc;5338pssd.SizeInBytes = sizeof(pipeline_desc);5339res = device_2->CreatePipelineState(&pssd, IID_PPV_ARGS(pso.GetAddressOf()));5340} else {5341D3D12_GRAPHICS_PIPELINE_STATE_DESC desc = pipeline_desc.GraphicsDescV0();5342res = device->CreateGraphicsPipelineState(&desc, IID_PPV_ARGS(pso.GetAddressOf()));5343}5344ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), PipelineID(), "Create(Graphics)PipelineState failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");53455346PipelineInfo *pipeline_info = memnew(PipelineInfo);5347pipeline_info->pso = pso;5348pipeline_info->shader_info = shader_info_in;5349pipeline_info->render_info = render_info;53505351return PipelineID(pipeline_info);5352}53535354/*****************/5355/**** COMPUTE ****/5356/*****************/53575358// ----- COMMANDS -----53595360void RenderingDeviceDriverD3D12::command_bind_compute_pipeline(CommandBufferID p_cmd_buffer, PipelineID p_pipeline) {5361CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;53625363const PipelineInfo *pipeline_info = (const PipelineInfo *)p_pipeline.id;5364const ShaderInfo *shader_info_in = pipeline_info->shader_info;53655366if (cmd_buf_info->compute_pso != pipeline_info->pso.Get()) {5367cmd_buf_info->cmd_list->SetPipelineState(pipeline_info->pso.Get());53685369cmd_buf_info->compute_pso = pipeline_info->pso.Get();5370cmd_buf_info->graphics_pso = nullptr;5371}53725373if (cmd_buf_info->compute_root_signature_crc != shader_info_in->root_signature_crc) {5374cmd_buf_info->cmd_list->SetComputeRootSignature(shader_info_in->root_signature.Get());5375cmd_buf_info->compute_root_signature_crc = shader_info_in->root_signature_crc;5376}5377}53785379void RenderingDeviceDriverD3D12::command_bind_compute_uniform_sets(CommandBufferID p_cmd_buffer, VectorView<UniformSetID> p_uniform_sets, ShaderID p_shader, uint32_t p_first_set_index, uint32_t p_set_count, uint32_t p_dynamic_offsets) {5380_command_check_descriptor_sets(p_cmd_buffer);53815382const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;5383const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;53845385for (uint32_t i = 0u; i < p_set_count; ++i) {5386UniformSetInfo *uniform_set_info = (UniformSetInfo *)p_uniform_sets[i].id;5387const ShaderInfo::UniformSet &uniform_set_shader_info = shader_info_in->sets[p_first_set_index + i];53885389for (const UniformSetInfo::DynamicBuffer &dynamic_buffer : uniform_set_info->dynamic_buffers) {5390uint32_t frame_index = p_dynamic_offsets & 0xF;5391p_dynamic_offsets >>= 4;53925393const ShaderInfo::UniformBindingInfo &binding = uniform_set_shader_info.bindings[dynamic_buffer.binding];5394if (binding.root_param_idx != UINT_MAX) {5395D3D12_GPU_VIRTUAL_ADDRESS buffer_location = dynamic_buffer.info->gpu_virtual_address + (dynamic_buffer.info->size * frame_index);5396switch (binding.res_class) {5397case RES_CLASS_INVALID: {5398} break;5399case RES_CLASS_CBV: {5400cmd_buf_info->cmd_list->SetComputeRootConstantBufferView(binding.root_param_idx, buffer_location);5401} break;5402case RES_CLASS_SRV: {5403cmd_buf_info->cmd_list->SetComputeRootShaderResourceView(binding.root_param_idx, buffer_location);5404} break;5405case RES_CLASS_UAV: {5406cmd_buf_info->cmd_list->SetComputeRootUnorderedAccessView(binding.root_param_idx, buffer_location);5407} break;5408}5409}5410}54115412if (uniform_set_shader_info.resource_root_param_idx != UINT_MAX) {5413cmd_buf_info->cmd_list->SetComputeRootDescriptorTable(uniform_set_shader_info.resource_root_param_idx, uniform_set_info->resource_descriptor_heap_alloc.gpu_handle);5414}5415if (uniform_set_shader_info.sampler_root_param_idx != UINT_MAX) {5416cmd_buf_info->cmd_list->SetComputeRootDescriptorTable(uniform_set_shader_info.sampler_root_param_idx, uniform_set_info->sampler_descriptor_heap_alloc->gpu_handle);5417}5418}5419}54205421void RenderingDeviceDriverD3D12::command_compute_dispatch(CommandBufferID p_cmd_buffer, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) {5422CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;5423if (!barrier_capabilities.enhanced_barriers_supported) {5424_resource_transitions_flush(cmd_buf_info);5425}54265427cmd_buf_info->cmd_list->Dispatch(p_x_groups, p_y_groups, p_z_groups);5428}54295430void RenderingDeviceDriverD3D12::command_compute_dispatch_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset) {5431CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;5432BufferInfo *indirect_buf_info = (BufferInfo *)p_indirect_buffer.id;5433if (!barrier_capabilities.enhanced_barriers_supported) {5434_resource_transition_batch(cmd_buf_info, indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);5435_resource_transitions_flush(cmd_buf_info);5436}54375438cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.dispatch.Get(), 1, indirect_buf_info->resource, p_offset, nullptr, 0);5439}54405441// ----- PIPELINE -----54425443RDD::PipelineID RenderingDeviceDriverD3D12::compute_pipeline_create(ShaderID p_shader, VectorView<PipelineSpecializationConstant> p_specialization_constants) {5444const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;54455446CD3DX12_PIPELINE_STATE_STREAM pipeline_desc = {};54475448// Stages bytecodes + specialization constants.54495450pipeline_desc.pRootSignature = shader_info_in->root_signature.Get();54515452HashMap<ShaderStage, Vector<uint8_t>> final_stages_bytecode;5453bool ok = _shader_apply_specialization_constants(shader_info_in, p_specialization_constants, final_stages_bytecode);5454ERR_FAIL_COND_V(!ok, PipelineID());54555456pipeline_desc.CS = D3D12_SHADER_BYTECODE{5457final_stages_bytecode[SHADER_STAGE_COMPUTE].ptr(),5458(SIZE_T)final_stages_bytecode[SHADER_STAGE_COMPUTE].size()5459};54605461ComPtr<ID3D12Device2> device_2;5462device->QueryInterface(device_2.GetAddressOf());5463ComPtr<ID3D12PipelineState> pso;5464HRESULT res = E_FAIL;5465if (device_2) {5466D3D12_PIPELINE_STATE_STREAM_DESC pssd = {};5467pssd.pPipelineStateSubobjectStream = &pipeline_desc;5468pssd.SizeInBytes = sizeof(pipeline_desc);5469res = device_2->CreatePipelineState(&pssd, IID_PPV_ARGS(pso.GetAddressOf()));5470} else {5471D3D12_COMPUTE_PIPELINE_STATE_DESC desc = pipeline_desc.ComputeDescV0();5472res = device->CreateComputePipelineState(&desc, IID_PPV_ARGS(pso.GetAddressOf()));5473}5474ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), PipelineID(), "Create(Compute)PipelineState failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");54755476PipelineInfo *pipeline_info = memnew(PipelineInfo);5477pipeline_info->pso = pso;5478pipeline_info->shader_info = shader_info_in;54795480return PipelineID(pipeline_info);5481}54825483/********************/5484/**** RAYTRACING ****/5485/********************/54865487// ---- ACCELERATION STRUCTURES ----54885489RDD::AccelerationStructureID RenderingDeviceDriverD3D12::blas_create(BufferID p_vertex_buffer, uint64_t p_vertex_offset, VertexFormatID p_vertex_format, uint32_t p_vertex_count, uint32_t p_position_attribute_location, BufferID p_index_buffer, IndexBufferFormat p_index_format, uint64_t p_index_offset, uint32_t p_index_count, BitField<AccelerationStructureGeometryBits> p_geometry_bits) {5490ERR_FAIL_V_MSG(AccelerationStructureID(), "Ray tracing is not currently supported by the D3D12 driver.");5491}54925493uint32_t RenderingDeviceDriverD3D12::tlas_instances_buffer_get_size_bytes(uint32_t p_instance_count) {5494ERR_FAIL_V_MSG(0, "Ray tracing is not currently supported by the D3D12 driver.");5495}54965497void RenderingDeviceDriverD3D12::tlas_instances_buffer_fill(BufferID p_instances_buffer, VectorView<AccelerationStructureID> p_blases, VectorView<Transform3D> p_transforms) {5498ERR_FAIL_MSG("Ray tracing is not currently supported by the D3D12 driver.");5499}55005501RDD::AccelerationStructureID RenderingDeviceDriverD3D12::tlas_create(BufferID p_instance_buffer) {5502ERR_FAIL_V_MSG(AccelerationStructureID(), "Ray tracing is not currently supported by the D3D12 driver.");5503}55045505void RenderingDeviceDriverD3D12::acceleration_structure_free(AccelerationStructureID p_acceleration_structure) {5506ERR_FAIL_MSG("Ray tracing is not currently supported by the D3D12 driver.");5507}55085509uint32_t RenderingDeviceDriverD3D12::acceleration_structure_get_scratch_size_bytes(AccelerationStructureID p_acceleration_structure) {5510ERR_FAIL_V_MSG(0, "Ray tracing is not currently supported by the D3D12 driver.");5511}55125513// ----- PIPELINE -----55145515RDD::RaytracingPipelineID RenderingDeviceDriverD3D12::raytracing_pipeline_create(ShaderID p_shader, VectorView<PipelineSpecializationConstant> p_specialization_constants) {5516ERR_FAIL_V_MSG(RaytracingPipelineID(), "Ray tracing is not currently supported by the D3D12 driver.");5517}55185519void RenderingDeviceDriverD3D12::raytracing_pipeline_free(RDD::RaytracingPipelineID p_pipeline) {5520ERR_FAIL_MSG("Ray tracing is not currently supported by the D3D12 driver.");5521}55225523// ----- COMMANDS -----55245525void RenderingDeviceDriverD3D12::command_build_acceleration_structure(CommandBufferID p_cmd_buffer, AccelerationStructureID p_acceleration_structure, BufferID p_scratch_buffer) {5526ERR_FAIL_MSG("Ray tracing is not currently supported by the D3D12 driver.");5527}55285529void RenderingDeviceDriverD3D12::command_bind_raytracing_pipeline(CommandBufferID p_cmd_buffer, RaytracingPipelineID p_pipeline) {5530ERR_FAIL_MSG("Ray tracing is not currently supported by the D3D12 driver.");5531}55325533void RenderingDeviceDriverD3D12::command_bind_raytracing_uniform_set(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) {5534ERR_FAIL_MSG("Ray tracing is not currently supported by the D3D12 driver.");5535}55365537void RenderingDeviceDriverD3D12::command_trace_rays(CommandBufferID p_cmd_buffer, uint32_t p_width, uint32_t p_height) {5538ERR_FAIL_MSG("Ray tracing is not currently supported by the D3D12 driver.");5539}55405541/*****************/5542/**** QUERIES ****/5543/*****************/55445545// ----- TIMESTAMP -----55465547RDD::QueryPoolID RenderingDeviceDriverD3D12::timestamp_query_pool_create(uint32_t p_query_count) {5548ComPtr<ID3D12QueryHeap> query_heap;5549{5550D3D12_QUERY_HEAP_DESC qh_desc = {};5551qh_desc.Type = D3D12_QUERY_HEAP_TYPE_TIMESTAMP;5552qh_desc.Count = p_query_count;5553qh_desc.NodeMask = 0;5554HRESULT res = device->CreateQueryHeap(&qh_desc, IID_PPV_ARGS(query_heap.GetAddressOf()));5555ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), QueryPoolID(), "CreateQueryHeap failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");5556}55575558ComPtr<D3D12MA::Allocation> results_buffer_allocation;5559{5560D3D12MA::ALLOCATION_DESC allocation_desc = {};5561allocation_desc.HeapType = D3D12_HEAP_TYPE_READBACK;55625563CD3DX12_RESOURCE_DESC resource_desc = CD3DX12_RESOURCE_DESC::Buffer(sizeof(uint64_t) * p_query_count);55645565ComPtr<ID3D12Resource> results_buffer;5566HRESULT res = allocator->CreateResource(5567&allocation_desc,5568&resource_desc,5569D3D12_RESOURCE_STATE_COPY_DEST,5570nullptr,5571results_buffer_allocation.GetAddressOf(),5572IID_PPV_ARGS(results_buffer.GetAddressOf()));5573ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), QueryPoolID(), "D3D12MA::CreateResource failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");5574}55755576// Bookkeep.55775578TimestampQueryPoolInfo *tqp_info = VersatileResource::allocate<TimestampQueryPoolInfo>(resources_allocator);5579tqp_info->query_heap = query_heap;5580tqp_info->query_count = p_query_count;5581tqp_info->results_buffer_allocation = results_buffer_allocation;55825583return RDD::QueryPoolID(tqp_info);5584}55855586void RenderingDeviceDriverD3D12::timestamp_query_pool_free(QueryPoolID p_pool_id) {5587TimestampQueryPoolInfo *tqp_info = (TimestampQueryPoolInfo *)p_pool_id.id;5588VersatileResource::free(resources_allocator, tqp_info);5589}55905591void RenderingDeviceDriverD3D12::timestamp_query_pool_get_results(QueryPoolID p_pool_id, uint32_t p_query_count, uint64_t *r_results) {5592TimestampQueryPoolInfo *tqp_info = (TimestampQueryPoolInfo *)p_pool_id.id;55935594ID3D12Resource *results_buffer = tqp_info->results_buffer_allocation->GetResource();55955596void *results_buffer_data = nullptr;5597results_buffer->Map(0, &VOID_RANGE, &results_buffer_data);5598memcpy(r_results, results_buffer_data, sizeof(uint64_t) * p_query_count);5599results_buffer->Unmap(0, &VOID_RANGE);5600}56015602uint64_t RenderingDeviceDriverD3D12::timestamp_query_result_to_time(uint64_t p_result) {5603return p_result / (double)device_limits.timestamp_frequency * 1000000000.0;5604}56055606void RenderingDeviceDriverD3D12::command_timestamp_query_pool_reset(CommandBufferID p_cmd_buffer, QueryPoolID p_pool_id, uint32_t p_query_count) {5607}56085609void RenderingDeviceDriverD3D12::command_timestamp_write(CommandBufferID p_cmd_buffer, QueryPoolID p_pool_id, uint32_t p_index) {5610const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;5611TimestampQueryPoolInfo *tqp_info = (TimestampQueryPoolInfo *)p_pool_id.id;5612ID3D12Resource *results_buffer = tqp_info->results_buffer_allocation->GetResource();5613cmd_buf_info->cmd_list->EndQuery(tqp_info->query_heap.Get(), D3D12_QUERY_TYPE_TIMESTAMP, p_index);5614cmd_buf_info->cmd_list->ResolveQueryData(tqp_info->query_heap.Get(), D3D12_QUERY_TYPE_TIMESTAMP, p_index, 1, results_buffer, p_index * sizeof(uint64_t));5615}56165617void RenderingDeviceDriverD3D12::command_begin_label(CommandBufferID p_cmd_buffer, const char *p_label_name, const Color &p_color) {5618#ifdef PIX_ENABLED5619const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;5620PIXBeginEvent(cmd_buf_info->cmd_list.Get(), p_color.to_argb32(), p_label_name);5621#endif5622}56235624void RenderingDeviceDriverD3D12::command_end_label(CommandBufferID p_cmd_buffer) {5625#ifdef PIX_ENABLED5626const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;5627PIXEndEvent(cmd_buf_info->cmd_list.Get());5628#endif5629}56305631void RenderingDeviceDriverD3D12::command_insert_breadcrumb(CommandBufferID p_cmd_buffer, uint32_t p_data) {5632// TODO: Implement via DRED.5633}56345635/********************/5636/**** SUBMISSION ****/5637/********************/56385639void RenderingDeviceDriverD3D12::begin_segment(uint32_t p_frame_index, uint32_t p_frames_drawn) {5640frame_idx = p_frame_index;5641frames[frame_idx].descriptor_allocation_count = 0;56425643frames_drawn = p_frames_drawn;5644allocator->SetCurrentFrameIndex(p_frames_drawn);56455646segment_begun = true;5647}56485649void RenderingDeviceDriverD3D12::end_segment() {5650FrameInfo &f = frames[frame_idx];56515652// Free leftover descriptors.5653for (uint32_t i = f.descriptor_allocation_count; i < f.descriptor_allocations.size(); i++) {5654resource_descriptor_heap.free(f.descriptor_allocations[i]);5655}5656f.descriptor_allocations.resize(f.descriptor_allocation_count);56575658segment_begun = false;5659}56605661/**************/5662/**** MISC ****/5663/**************/56645665void RenderingDeviceDriverD3D12::_set_object_name(ID3D12Object *p_object, String p_object_name) {5666ERR_FAIL_NULL(p_object);5667int name_len = p_object_name.size();5668WCHAR *name_w = (WCHAR *)alloca(sizeof(WCHAR) * (name_len + 1));5669MultiByteToWideChar(CP_UTF8, 0, p_object_name.utf8().get_data(), -1, name_w, name_len);5670p_object->SetName(name_w);5671}56725673void RenderingDeviceDriverD3D12::set_object_name(ObjectType p_type, ID p_driver_id, const String &p_name) {5674switch (p_type) {5675case OBJECT_TYPE_TEXTURE: {5676const TextureInfo *tex_info = (const TextureInfo *)p_driver_id.id;5677if (tex_info->owner_info.allocation) {5678_set_object_name(tex_info->resource, p_name);5679}5680} break;5681case OBJECT_TYPE_SAMPLER: {5682} break;5683case OBJECT_TYPE_BUFFER: {5684const BufferInfo *buf_info = (const BufferInfo *)p_driver_id.id;5685_set_object_name(buf_info->resource, p_name);5686} break;5687case OBJECT_TYPE_SHADER: {5688const ShaderInfo *shader_info_in = (const ShaderInfo *)p_driver_id.id;5689_set_object_name(shader_info_in->root_signature.Get(), p_name);5690} break;5691case OBJECT_TYPE_UNIFORM_SET: {5692// Descriptor heaps are suballocated from bigger heaps and can therefore not be given unique names.5693} break;5694case OBJECT_TYPE_PIPELINE: {5695const PipelineInfo *pipeline_info = (const PipelineInfo *)p_driver_id.id;5696_set_object_name(pipeline_info->pso.Get(), p_name);5697} break;5698default: {5699DEV_ASSERT(false);5700}5701}5702}57035704uint64_t RenderingDeviceDriverD3D12::get_resource_native_handle(DriverResource p_type, ID p_driver_id) {5705switch (p_type) {5706case DRIVER_RESOURCE_LOGICAL_DEVICE: {5707return (uint64_t)device.Get();5708}5709case DRIVER_RESOURCE_PHYSICAL_DEVICE: {5710return (uint64_t)adapter.Get();5711}5712case DRIVER_RESOURCE_TOPMOST_OBJECT: {5713return 0;5714}5715case DRIVER_RESOURCE_COMMAND_QUEUE: {5716const CommandQueueInfo *cmd_queue_info = (const CommandQueueInfo *)p_driver_id.id;5717return (uint64_t)cmd_queue_info->d3d_queue.Get();5718}5719case DRIVER_RESOURCE_QUEUE_FAMILY: {5720return 0;5721}5722case DRIVER_RESOURCE_TEXTURE: {5723const TextureInfo *tex_info = (const TextureInfo *)p_driver_id.id;5724if (tex_info->main_texture) {5725tex_info = tex_info->main_texture;5726}5727return (uint64_t)tex_info->resource;5728} break;5729case DRIVER_RESOURCE_TEXTURE_VIEW: {5730const TextureInfo *tex_info = (const TextureInfo *)p_driver_id.id;5731return (uint64_t)tex_info->resource;5732}5733case DRIVER_RESOURCE_TEXTURE_DATA_FORMAT: {5734const TextureInfo *tex_info = (const TextureInfo *)p_driver_id.id;5735return (uint64_t)tex_info->desc.Format;5736}5737case DRIVER_RESOURCE_SAMPLER:5738case DRIVER_RESOURCE_UNIFORM_SET:5739return 0;5740case DRIVER_RESOURCE_BUFFER: {5741const TextureInfo *tex_info = (const TextureInfo *)p_driver_id.id;5742return (uint64_t)tex_info->resource;5743} break;5744case DRIVER_RESOURCE_COMPUTE_PIPELINE:5745case DRIVER_RESOURCE_RENDER_PIPELINE: {5746return p_driver_id.id;5747}5748default: {5749return 0;5750}5751}5752}57535754uint64_t RenderingDeviceDriverD3D12::get_total_memory_used() {5755D3D12MA::TotalStatistics stats;5756allocator->CalculateStatistics(&stats);5757return stats.Total.Stats.BlockBytes;5758}57595760uint64_t RenderingDeviceDriverD3D12::get_lazily_memory_used() {5761return 0;5762}57635764uint64_t RenderingDeviceDriverD3D12::limit_get(Limit p_limit) {5765uint64_t safe_unbounded = ((uint64_t)1 << 30);5766switch (p_limit) {5767case LIMIT_MAX_BOUND_UNIFORM_SETS:5768return safe_unbounded;5769case LIMIT_MAX_TEXTURE_ARRAY_LAYERS:5770return D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION;5771case LIMIT_MAX_TEXTURE_SIZE_1D:5772return D3D12_REQ_TEXTURE1D_U_DIMENSION;5773case LIMIT_MAX_TEXTURE_SIZE_2D:5774return D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION;5775case LIMIT_MAX_TEXTURE_SIZE_3D:5776return D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION;5777case LIMIT_MAX_TEXTURE_SIZE_CUBE:5778return D3D12_REQ_TEXTURECUBE_DIMENSION;5779case LIMIT_MAX_TEXTURES_PER_SHADER_STAGE:5780return device_limits.max_srvs_per_shader_stage;5781case LIMIT_MAX_UNIFORM_BUFFER_SIZE:5782return 65536;5783case LIMIT_MAX_VIEWPORT_DIMENSIONS_X:5784case LIMIT_MAX_VIEWPORT_DIMENSIONS_Y:5785return 16384; // Based on max. texture size. Maybe not correct.5786case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X:5787return D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION;5788case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Y:5789return D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION;5790case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Z:5791return D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION;5792case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_X:5793return D3D12_CS_THREAD_GROUP_MAX_X;5794case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Y:5795return D3D12_CS_THREAD_GROUP_MAX_Y;5796case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z:5797return D3D12_CS_THREAD_GROUP_MAX_Z;5798case LIMIT_MAX_COMPUTE_SHARED_MEMORY_SIZE:5799return D3D12_CS_TGSM_REGISTER_COUNT * sizeof(float);5800case LIMIT_SUBGROUP_SIZE:5801// Note in min/max. Shader model 6.6 supports it (see https://microsoft.github.io/DirectX-Specs/d3d/HLSL_SM_6_6_WaveSize.html),5802// but at this time I don't know the implications on the transpilation to DXIL, etc.5803case LIMIT_SUBGROUP_MIN_SIZE:5804case LIMIT_SUBGROUP_MAX_SIZE:5805return subgroup_capabilities.size;5806case LIMIT_SUBGROUP_IN_SHADERS:5807return subgroup_capabilities.supported_stages_flags_rd();5808case LIMIT_SUBGROUP_OPERATIONS:5809return subgroup_capabilities.supported_operations_flags_rd();5810case LIMIT_MAX_SHADER_VARYINGS:5811return MIN(D3D12_VS_OUTPUT_REGISTER_COUNT, D3D12_PS_INPUT_REGISTER_COUNT);5812default: {5813#ifdef DEV_ENABLED5814WARN_PRINT("Returning maximum value for unknown limit " + itos(p_limit) + ".");5815#endif5816return safe_unbounded;5817}5818}5819}58205821uint64_t RenderingDeviceDriverD3D12::api_trait_get(ApiTrait p_trait) {5822switch (p_trait) {5823case API_TRAIT_HONORS_PIPELINE_BARRIERS:5824return barrier_capabilities.enhanced_barriers_supported;5825case API_TRAIT_SHADER_CHANGE_INVALIDATION:5826return (uint64_t)SHADER_CHANGE_INVALIDATION_ALL_OR_NONE_ACCORDING_TO_LAYOUT_HASH;5827case API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT:5828return D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT;5829case API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP:5830return D3D12_TEXTURE_DATA_PITCH_ALIGNMENT;5831case API_TRAIT_SECONDARY_VIEWPORT_SCISSOR:5832return false;5833case API_TRAIT_CLEARS_WITH_COPY_ENGINE:5834return false;5835case API_TRAIT_USE_GENERAL_IN_COPY_QUEUES:5836return true;5837case API_TRAIT_BUFFERS_REQUIRE_TRANSITIONS:5838return !barrier_capabilities.enhanced_barriers_supported;5839case API_TRAIT_TEXTURE_OUTPUTS_REQUIRE_CLEARS:5840return true;5841default:5842return RenderingDeviceDriver::api_trait_get(p_trait);5843}5844}58455846bool RenderingDeviceDriverD3D12::has_feature(Features p_feature) {5847switch (p_feature) {5848case SUPPORTS_HALF_FLOAT:5849return shader_capabilities.native_16bit_ops;5850case SUPPORTS_FRAGMENT_SHADER_WITH_ONLY_SIDE_EFFECTS:5851return true;5852case SUPPORTS_BUFFER_DEVICE_ADDRESS:5853return true;5854case SUPPORTS_IMAGE_ATOMIC_32_BIT:5855return true;5856case SUPPORTS_VULKAN_MEMORY_MODEL:5857return false;5858case SUPPORTS_POINT_SIZE:5859return false;5860default:5861return false;5862}5863}58645865const RDD::MultiviewCapabilities &RenderingDeviceDriverD3D12::get_multiview_capabilities() {5866return multiview_capabilities;5867}58685869const RDD::FragmentShadingRateCapabilities &RenderingDeviceDriverD3D12::get_fragment_shading_rate_capabilities() {5870return fsr_capabilities;5871}58725873const RDD::FragmentDensityMapCapabilities &RenderingDeviceDriverD3D12::get_fragment_density_map_capabilities() {5874return fdm_capabilities;5875}58765877String RenderingDeviceDriverD3D12::get_api_name() const {5878return "D3D12";5879}58805881String RenderingDeviceDriverD3D12::get_api_version() const {5882return vformat("%d_%d", feature_level / 10, feature_level % 10);5883}58845885String RenderingDeviceDriverD3D12::get_pipeline_cache_uuid() const {5886return pipeline_cache_id;5887}58885889const RDD::Capabilities &RenderingDeviceDriverD3D12::get_capabilities() const {5890return device_capabilities;5891}58925893const RenderingShaderContainerFormat &RenderingDeviceDriverD3D12::get_shader_container_format() const {5894return shader_container_format;5895}58965897bool RenderingDeviceDriverD3D12::is_composite_alpha_supported(CommandQueueID p_queue) const {5898if (has_comp_alpha.has((uint64_t)p_queue.id)) {5899return has_comp_alpha[(uint64_t)p_queue.id];5900}5901return false;5902}59035904/******************/59055906RenderingDeviceDriverD3D12::RenderingDeviceDriverD3D12(RenderingContextDriverD3D12 *p_context_driver) {5907DEV_ASSERT(p_context_driver != nullptr);59085909this->context_driver = p_context_driver;5910}59115912RenderingDeviceDriverD3D12::~RenderingDeviceDriverD3D12() {5913rtv_descriptor_heap_pool.free(null_rtv_alloc);59145915for (FrameInfo &f : frames) {5916for (DescriptorHeap::Allocation &alloc : f.descriptor_allocations) {5917resource_descriptor_heap.free(alloc);5918}5919}59205921if (D3D12Hooks::get_singleton() != nullptr) {5922D3D12Hooks::get_singleton()->cleanup_device();5923}59245925glsl_type_singleton_decref();5926}59275928bool RenderingDeviceDriverD3D12::is_in_developer_mode() {5929HKEY hkey = nullptr;5930LSTATUS result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AppModelUnlock", 0, KEY_READ, &hkey);5931if (result != ERROR_SUCCESS) {5932return false;5933}59345935DWORD value = 0;5936DWORD dword_size = sizeof(DWORD);5937result = RegQueryValueExW(hkey, L"AllowDevelopmentWithoutDevLicense", nullptr, nullptr, (PBYTE)&value, &dword_size);5938RegCloseKey(hkey);59395940if (result != ERROR_SUCCESS) {5941return false;5942}59435944return (value != 0);5945}59465947Error RenderingDeviceDriverD3D12::_initialize_device() {5948HRESULT res;59495950if (is_in_developer_mode()) {5951typedef HRESULT(WINAPI * PFN_D3D12_ENABLE_EXPERIMENTAL_FEATURES)(_In_ UINT, _In_count_(NumFeatures) const IID *, _In_opt_count_(NumFeatures) void *, _In_opt_count_(NumFeatures) UINT *);5952PFN_D3D12_ENABLE_EXPERIMENTAL_FEATURES d3d_D3D12EnableExperimentalFeatures = (PFN_D3D12_ENABLE_EXPERIMENTAL_FEATURES)(void *)GetProcAddress(context_driver->lib_d3d12, "D3D12EnableExperimentalFeatures");5953ERR_FAIL_NULL_V(d3d_D3D12EnableExperimentalFeatures, ERR_CANT_CREATE);59545955UUID experimental_features[] = { D3D12ExperimentalShaderModels };5956d3d_D3D12EnableExperimentalFeatures(1, experimental_features, nullptr, nullptr);5957}59585959D3D_FEATURE_LEVEL requested_feature_level = D3D_FEATURE_LEVEL_11_0;5960// Override the adapter and feature level if needed by the XR backend.5961if (D3D12Hooks::get_singleton() != nullptr) {5962const LUID adapter_luid = D3D12Hooks::get_singleton()->get_adapter_luid();5963requested_feature_level = D3D12Hooks::get_singleton()->get_feature_level();5964ComPtr<IDXGIAdapter1> desired_adapter;5965for (UINT adapter_index = 0;; adapter_index++) {5966// EnumAdapters1 will fail with DXGI_ERROR_NOT_FOUND when there are no more adapters to5967// enumerate.5968if (context_driver->dxgi_factory_get()->EnumAdapters1(adapter_index, desired_adapter.ReleaseAndGetAddressOf()) == DXGI_ERROR_NOT_FOUND) {5969break;5970}5971DXGI_ADAPTER_DESC1 desc;5972desired_adapter->GetDesc1(&desc);5973if (!memcmp(&desc.AdapterLuid, &adapter_luid, sizeof(LUID))) {5974break;5975}5976}5977ERR_FAIL_NULL_V(desired_adapter, ERR_CANT_CREATE);5978adapter = desired_adapter;5979}59805981ID3D12DeviceFactory *device_factory = context_driver->device_factory_get();5982if (device_factory != nullptr) {5983res = device_factory->CreateDevice(adapter.Get(), requested_feature_level, IID_PPV_ARGS(device.GetAddressOf()));5984} else {5985PFN_D3D12_CREATE_DEVICE d3d_D3D12CreateDevice = (PFN_D3D12_CREATE_DEVICE)(void *)GetProcAddress(context_driver->lib_d3d12, "D3D12CreateDevice");5986ERR_FAIL_NULL_V(d3d_D3D12CreateDevice, ERR_CANT_CREATE);59875988res = d3d_D3D12CreateDevice(adapter.Get(), requested_feature_level, IID_PPV_ARGS(device.GetAddressOf()));5989}5990ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_CANT_CREATE, "D3D12CreateDevice failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");59915992if (D3D12Hooks::get_singleton() != nullptr) {5993D3D12Hooks::get_singleton()->set_device(device.Get());5994}59955996if (context_driver->use_validation_layers()) {5997ComPtr<ID3D12InfoQueue> info_queue;5998res = device.As(&info_queue);5999ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);60006001#if CUSTOM_INFO_QUEUE_ENABLED6002ComPtr<ID3D12InfoQueue1> info_queue_1;6003device.As(&info_queue_1);6004if (info_queue_1) {6005// Custom printing supported (added in Windows 10 Release Preview build 20236). Even if the callback cookie is unused, it seems the6006// argument is not optional and the function will fail if it's not specified.6007DWORD callback_cookie;6008info_queue_1->SetMuteDebugOutput(TRUE);6009res = info_queue_1->RegisterMessageCallback(&_debug_message_func, D3D12_MESSAGE_CALLBACK_IGNORE_FILTERS, nullptr, &callback_cookie);6010ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);6011} else6012#endif6013{6014// Rely on D3D12's own debug printing.6015if (Engine::get_singleton()->is_abort_on_gpu_errors_enabled()) {6016res = info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, TRUE);6017ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);6018res = info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, TRUE);6019ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);6020res = info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, TRUE);6021ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);6022}6023}60246025D3D12_MESSAGE_SEVERITY severities_to_mute[] = {6026D3D12_MESSAGE_SEVERITY_INFO,6027};60286029D3D12_MESSAGE_ID messages_to_mute[] = {6030D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE,6031D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_MISMATCHINGCLEARVALUE,6032// These happen due to how D3D12MA manages buffers; seems benign.6033D3D12_MESSAGE_ID_HEAP_ADDRESS_RANGE_HAS_NO_RESOURCE,6034D3D12_MESSAGE_ID_HEAP_ADDRESS_RANGE_INTERSECTS_MULTIPLE_BUFFERS,6035// Seemingly a false positive.6036D3D12_MESSAGE_ID_DATA_STATIC_WHILE_SET_AT_EXECUTE_DESCRIPTOR_INVALID_DATA_CHANGE,6037};60386039D3D12_INFO_QUEUE_FILTER filter = {};6040filter.DenyList.NumSeverities = ARRAY_SIZE(severities_to_mute);6041filter.DenyList.pSeverityList = severities_to_mute;6042filter.DenyList.NumIDs = ARRAY_SIZE(messages_to_mute);6043filter.DenyList.pIDList = messages_to_mute;60446045res = info_queue->PushStorageFilter(&filter);6046ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);6047}60486049return OK;6050}60516052Error RenderingDeviceDriverD3D12::_check_capabilities() {6053// Check feature levels.6054const D3D_FEATURE_LEVEL FEATURE_LEVELS[] = {6055D3D_FEATURE_LEVEL_11_0,6056D3D_FEATURE_LEVEL_11_1,6057D3D_FEATURE_LEVEL_12_0,6058D3D_FEATURE_LEVEL_12_1,6059D3D_FEATURE_LEVEL_12_2,6060};60616062D3D12_FEATURE_DATA_FEATURE_LEVELS feat_levels = {};6063feat_levels.NumFeatureLevels = ARRAY_SIZE(FEATURE_LEVELS);6064feat_levels.pFeatureLevelsRequested = FEATURE_LEVELS;60656066HRESULT res = device->CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS, &feat_levels, sizeof(feat_levels));6067ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_UNAVAILABLE, "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");60686069// Example: D3D_FEATURE_LEVEL_12_1 = 0xc100.6070uint32_t feat_level_major = feat_levels.MaxSupportedFeatureLevel >> 12;6071uint32_t feat_level_minor = (feat_levels.MaxSupportedFeatureLevel >> 16) & 0xff;6072feature_level = feat_level_major * 10 + feat_level_minor;60736074// Fill device capabilities.6075device_capabilities.device_family = DEVICE_DIRECTX;6076device_capabilities.version_major = feature_level / 10;6077device_capabilities.version_minor = feature_level % 10;60786079// Assume not supported until proven otherwise.6080multiview_capabilities.is_supported = false;6081multiview_capabilities.geometry_shader_is_supported = false;6082multiview_capabilities.tessellation_shader_is_supported = false;6083multiview_capabilities.max_view_count = 0;6084multiview_capabilities.max_instance_count = 0;6085multiview_capabilities.is_supported = false;6086subgroup_capabilities.size = 0;6087subgroup_capabilities.wave_ops_supported = false;6088shader_capabilities.shader_model = (D3D_SHADER_MODEL)0;6089shader_capabilities.native_16bit_ops = false;6090format_capabilities.relaxed_casting_supported = false;60916092{6093static const D3D_SHADER_MODEL SMS_TO_CHECK[] = {6094D3D_SHADER_MODEL_6_6,6095D3D_SHADER_MODEL_6_5,6096D3D_SHADER_MODEL_6_4,6097D3D_SHADER_MODEL_6_3,6098D3D_SHADER_MODEL_6_2,6099D3D_SHADER_MODEL_6_1,6100D3D_SHADER_MODEL_6_0, // Determined by NIR (dxil_min_shader_model).6101};61026103D3D12_FEATURE_DATA_SHADER_MODEL shader_model = {};6104for (uint32_t i = 0; i < ARRAY_SIZE(SMS_TO_CHECK); i++) {6105shader_model.HighestShaderModel = SMS_TO_CHECK[i];6106res = device->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &shader_model, sizeof(shader_model));6107if (SUCCEEDED(res)) {6108shader_capabilities.shader_model = shader_model.HighestShaderModel;6109break;6110}6111if (res == E_INVALIDARG) {6112continue; // Must assume the device doesn't know about the SM just checked.6113}6114ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_CANT_CREATE, "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");6115}61166117#define D3D_SHADER_MODEL_TO_STRING(m_sm) vformat("%d.%d", (m_sm >> 4), (m_sm & 0xf))61186119ERR_FAIL_COND_V_MSG(shader_capabilities.shader_model < SMS_TO_CHECK[ARRAY_SIZE(SMS_TO_CHECK) - 1], ERR_UNAVAILABLE,6120vformat("No support for any of the suitable shader models (%s-%s) has been found.", D3D_SHADER_MODEL_TO_STRING(SMS_TO_CHECK[ARRAY_SIZE(SMS_TO_CHECK) - 1]), D3D_SHADER_MODEL_TO_STRING(SMS_TO_CHECK[0])));61216122print_verbose("- Shader:");6123print_verbose(" model: " + D3D_SHADER_MODEL_TO_STRING(shader_capabilities.shader_model));6124}61256126shader_container_format.set_lib_d3d12(context_driver->lib_d3d12);61276128D3D12_FEATURE_DATA_D3D12_OPTIONS options = {};6129res = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options));6130ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_UNAVAILABLE, "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");6131ERR_FAIL_COND_V_MSG(!options.TypedUAVLoadAdditionalFormats, ERR_UNAVAILABLE, "No support for Typed UAV Load Additional Formats has been found.");61326133D3D12_FEATURE_DATA_D3D12_OPTIONS1 options1 = {};6134res = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS1, &options1, sizeof(options1));6135if (SUCCEEDED(res)) {6136subgroup_capabilities.size = options1.WaveLaneCountMin;6137subgroup_capabilities.wave_ops_supported = options1.WaveOps;6138}61396140D3D12_FEATURE_DATA_D3D12_OPTIONS2 options2 = {};6141res = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS2, &options2, sizeof(options2));6142if (SUCCEEDED(res)) {6143misc_features_support.depth_bounds_supported = options2.DepthBoundsTestSupported;6144}61456146D3D12_FEATURE_DATA_D3D12_OPTIONS3 options3 = {};6147res = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &options3, sizeof(options3));6148if (SUCCEEDED(res)) {6149// https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_view_instancing_tier6150// https://microsoft.github.io/DirectX-Specs/d3d/ViewInstancing.html#sv_viewid6151if (options3.ViewInstancingTier >= D3D12_VIEW_INSTANCING_TIER_1) {6152multiview_capabilities.is_supported = true;6153multiview_capabilities.geometry_shader_is_supported = options3.ViewInstancingTier >= D3D12_VIEW_INSTANCING_TIER_3;6154multiview_capabilities.tessellation_shader_is_supported = options3.ViewInstancingTier >= D3D12_VIEW_INSTANCING_TIER_3;6155multiview_capabilities.max_view_count = D3D12_MAX_VIEW_INSTANCE_COUNT;6156multiview_capabilities.max_instance_count = UINT32_MAX;6157}6158}61596160D3D12_FEATURE_DATA_D3D12_OPTIONS4 options4 = {};6161res = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS4, &options4, sizeof(options4));6162if (SUCCEEDED(res)) {6163shader_capabilities.native_16bit_ops = options4.Native16BitShaderOpsSupported;6164}61656166D3D12_FEATURE_DATA_D3D12_OPTIONS6 options6 = {};6167res = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS6, &options6, sizeof(options6));6168if (SUCCEEDED(res)) {6169if (options6.VariableShadingRateTier >= D3D12_VARIABLE_SHADING_RATE_TIER_1) {6170fsr_capabilities.pipeline_supported = true;6171if (options6.VariableShadingRateTier >= D3D12_VARIABLE_SHADING_RATE_TIER_2) {6172fsr_capabilities.primitive_supported = true;6173fsr_capabilities.attachment_supported = true;6174fsr_capabilities.min_texel_size = Size2i(options6.ShadingRateImageTileSize, options6.ShadingRateImageTileSize);6175fsr_capabilities.max_texel_size = Size2i(8, 8);6176}6177}6178}61796180D3D12_FEATURE_DATA_D3D12_OPTIONS12 options12 = {};6181res = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS12, &options12, sizeof(options12));6182if (SUCCEEDED(res)) {6183format_capabilities.relaxed_casting_supported = options12.RelaxedFormatCastingSupported;6184barrier_capabilities.enhanced_barriers_supported = options12.EnhancedBarriersSupported;6185}61866187D3D12_FEATURE_DATA_D3D12_OPTIONS19 options19 = {};6188res = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS19, &options19, sizeof(options19));6189if (SUCCEEDED(res)) {6190sampler_capabilities.aniso_filter_with_point_mip_supported = options19.AnisoFilterWithPointMipSupported;6191}61926193if (fsr_capabilities.pipeline_supported || fsr_capabilities.primitive_supported || fsr_capabilities.attachment_supported) {6194print_verbose("- D3D12 Variable Rate Shading supported:");6195if (fsr_capabilities.pipeline_supported) {6196print_verbose(" Draw call");6197}6198if (fsr_capabilities.primitive_supported) {6199print_verbose(" Primitive");6200}6201if (fsr_capabilities.attachment_supported) {6202print_verbose(String(" Screen-space image (tile size: ") + itos(fsr_capabilities.min_texel_size.x) + ")");6203}6204} else {6205print_verbose("- D3D12 Variable Rate Shading not supported");6206}62076208if (multiview_capabilities.is_supported) {6209print_verbose("- D3D12 multiview supported:");6210print_verbose(" max view count: " + itos(multiview_capabilities.max_view_count));6211//print_verbose(" max instances: " + itos(multiview_capabilities.max_instance_count)); // Hardcoded; not very useful at the moment.6212} else {6213print_verbose("- D3D12 multiview not supported");6214}62156216if (format_capabilities.relaxed_casting_supported) {6217#if 06218print_verbose("- Relaxed casting supported");6219#else6220// Certain configurations (Windows 11 with an updated NVIDIA driver) crash when using relaxed casting.6221// Therefore, we disable it temporarily until we can assure that it's reliable.6222// There are fallbacks in place that work in every case, if less efficient.6223format_capabilities.relaxed_casting_supported = false;6224print_verbose("- Relaxed casting supported (but disabled for now)");6225#endif6226} else {6227print_verbose("- Relaxed casting not supported");6228}62296230print_verbose(String("- D3D12 16-bit ops supported: ") + (shader_capabilities.native_16bit_ops ? "yes" : "no"));62316232if (misc_features_support.depth_bounds_supported) {6233print_verbose("- Depth bounds test supported");6234} else {6235print_verbose("- Depth bounds test not supported");6236}62376238return OK;6239}62406241Error RenderingDeviceDriverD3D12::_get_device_limits() {6242D3D12_FEATURE_DATA_D3D12_OPTIONS options = {};6243HRESULT res = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options));6244ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_UNAVAILABLE, "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");62456246// https://docs.microsoft.com/en-us/windows/win32/direct3d12/hardware-support6247device_limits.max_srvs_per_shader_stage = options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1 ? 128 : UINT64_MAX;6248device_limits.max_cbvs_per_shader_stage = options.ResourceBindingTier <= D3D12_RESOURCE_BINDING_TIER_2 ? 14 : UINT64_MAX;6249device_limits.max_samplers_across_all_stages = options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1 ? 16 : 2048;6250if (options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1) {6251device_limits.max_uavs_across_all_stages = feature_level <= 110 ? 8 : 64;6252} else if (options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_2) {6253device_limits.max_uavs_across_all_stages = 64;6254} else {6255device_limits.max_uavs_across_all_stages = UINT64_MAX;6256}62576258// Retrieving the timestamp frequency requires creating a command queue that will be discarded immediately.6259ComPtr<ID3D12CommandQueue> unused_command_queue;6260D3D12_COMMAND_QUEUE_DESC queue_desc = {};6261queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;6262res = device->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(unused_command_queue.GetAddressOf()));6263ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);62646265res = unused_command_queue->GetTimestampFrequency(&device_limits.timestamp_frequency);6266if (!SUCCEEDED(res)) {6267print_verbose("D3D12: GetTimestampFrequency failed with error " + vformat("0x%08ux", (uint64_t)res) + ". Timestamps will be inaccurate.");6268}62696270return OK;6271}62726273Error RenderingDeviceDriverD3D12::_initialize_allocator() {6274D3D12MA::ALLOCATOR_DESC allocator_desc = {};6275allocator_desc.pDevice = device.Get();6276allocator_desc.pAdapter = adapter.Get();6277allocator_desc.Flags = D3D12MA::ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED | D3D12MA::ALLOCATOR_FLAG_DONT_PREFER_SMALL_BUFFERS_COMMITTED;62786279HRESULT res = D3D12MA::CreateAllocator(&allocator_desc, &allocator);6280ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_CANT_CREATE, "D3D12MA::CreateAllocator failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");62816282if (allocator->IsGPUUploadHeapSupported()) {6283dynamic_persistent_upload_heap = D3D12_HEAP_TYPE_GPU_UPLOAD;6284print_verbose("D3D12: Device supports GPU UPLOAD heap.");6285} else {6286dynamic_persistent_upload_heap = D3D12_HEAP_TYPE_UPLOAD;6287// Print it as a warning (instead of verbose) because in the rare chance this lesser-used code path6288// causes bugs, we get an inkling of what's going on (i.e. in order to repro bugs locally).6289print_verbose("D3D12: Device does NOT support GPU UPLOAD heap. ReBAR must be enabled for this feature. Regular UPLOAD heaps will be used as fallback.");6290}62916292return OK;6293}62946295static Error create_command_signature(ID3D12Device *device, D3D12_INDIRECT_ARGUMENT_TYPE p_type, uint32_t p_stride, ComPtr<ID3D12CommandSignature> *r_cmd_sig) {6296D3D12_INDIRECT_ARGUMENT_DESC iarg_desc = {};6297iarg_desc.Type = p_type;6298D3D12_COMMAND_SIGNATURE_DESC cs_desc = {};6299cs_desc.ByteStride = p_stride;6300cs_desc.NumArgumentDescs = 1;6301cs_desc.pArgumentDescs = &iarg_desc;6302cs_desc.NodeMask = 0;6303HRESULT res = device->CreateCommandSignature(&cs_desc, nullptr, IID_PPV_ARGS(r_cmd_sig->GetAddressOf()));6304ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_CANT_CREATE, "CreateCommandSignature failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");6305return OK;6306}63076308Error RenderingDeviceDriverD3D12::_initialize_frames(uint32_t p_frame_count) {6309uint32_t num_resource_descriptors = GLOBAL_GET("rendering/rendering_device/d3d12/max_resource_descriptors");6310uint32_t num_sampler_descriptors = GLOBAL_GET("rendering/rendering_device/d3d12/max_sampler_descriptors");63116312Error err = resource_descriptor_heap.initialize(device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, num_resource_descriptors, true);6313ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);63146315err = sampler_descriptor_heap.initialize(device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, num_sampler_descriptors, true);6316ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);63176318resource_descriptor_heap_pool.initialize(device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);6319rtv_descriptor_heap_pool.initialize(device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_RTV);6320dsv_descriptor_heap_pool.initialize(device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_DSV);63216322err = rtv_descriptor_heap_pool.allocate(1, device.Get(), null_rtv_alloc);6323ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);63246325D3D12_RENDER_TARGET_VIEW_DESC rtv_desc_null = {};6326rtv_desc_null.Format = DXGI_FORMAT_R8_UINT;6327rtv_desc_null.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;6328device->CreateRenderTargetView(nullptr, &rtv_desc_null, null_rtv_alloc.cpu_handle);63296330frames.resize(p_frame_count);63316332return OK;6333}63346335Error RenderingDeviceDriverD3D12::_initialize_command_signatures() {6336Error err = create_command_signature(device.Get(), D3D12_INDIRECT_ARGUMENT_TYPE_DRAW, sizeof(D3D12_DRAW_ARGUMENTS), &indirect_cmd_signatures.draw);6337ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);63386339err = create_command_signature(device.Get(), D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED, sizeof(D3D12_DRAW_INDEXED_ARGUMENTS), &indirect_cmd_signatures.draw_indexed);6340ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);63416342err = create_command_signature(device.Get(), D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH, sizeof(D3D12_DISPATCH_ARGUMENTS), &indirect_cmd_signatures.dispatch);6343ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);63446345return OK;6346}63476348Error RenderingDeviceDriverD3D12::initialize(uint32_t p_device_index, uint32_t p_frame_count) {6349glsl_type_singleton_init_or_ref();63506351context_device = context_driver->device_get(p_device_index);6352adapter.Attach(context_driver->create_adapter(p_device_index));6353ERR_FAIL_NULL_V(adapter, ERR_CANT_CREATE);63546355DXGI_ADAPTER_DESC adapter_desc;6356HRESULT res = adapter->GetDesc(&adapter_desc);6357ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);63586359// Set the pipeline cache ID based on the adapter information.6360pipeline_cache_id = String::hex_encode_buffer((uint8_t *)&adapter_desc.AdapterLuid, sizeof(LUID));6361pipeline_cache_id += "-driver-" + itos(adapter_desc.Revision);63626363Error err = _initialize_device();6364ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);63656366err = _check_capabilities();6367ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);63686369err = _get_device_limits();6370ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);63716372err = _initialize_allocator();6373ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);63746375err = _initialize_frames(p_frame_count);6376ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);63776378err = _initialize_command_signatures();6379ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);63806381return OK;6382}638363846385