/* * Copyright © Microsoft Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #include "d3d12_screen.h" #include "d3d12_bufmgr.h" #include "d3d12_compiler.h" #include "d3d12_context.h" #include "d3d12_debug.h" #include "d3d12_fence.h" #ifdef HAVE_GALLIUM_D3D12_VIDEO #include "d3d12_video_screen.h" #endif #include "d3d12_format.h" #include "d3d12_interop_public.h" #include "d3d12_residency.h" #include "d3d12_resource.h" #include "d3d12_nir_passes.h" #include "pipebuffer/pb_bufmgr.h" #include "util/u_debug.h" #include "util/u_math.h" #include "util/u_memory.h" #include "util/u_screen.h" #include "util/u_dl.h" #include "util/mesa-sha1.h" #include "nir.h" #include "frontend/sw_winsys.h" #include "nir_to_dxil.h" #include "git_sha1.h" #ifndef _GAMING_XBOX #include #endif #if defined(_WIN32) && defined(_WIN64) && !defined(_GAMING_XBOX) #include #include #endif #include static GUID OpenGLOn12CreatorID = { 0x6bb3cd34, 0x0d19, 0x45ab, { 0x97, 0xed, 0xd7, 0x20, 0xba, 0x3d, 0xfc, 0x80 } }; static const struct debug_named_value d3d12_debug_options[] = { { "verbose", D3D12_DEBUG_VERBOSE, NULL }, { "blit", D3D12_DEBUG_BLIT, "Trace blit and copy resource calls" }, { "experimental", D3D12_DEBUG_EXPERIMENTAL, "Enable experimental shader models feature" }, { "dxil", D3D12_DEBUG_DXIL, "Dump DXIL during program compile" }, { "disass", D3D12_DEBUG_DISASS, "Dump disassambly of created DXIL shader" }, { "res", D3D12_DEBUG_RESOURCE, "Debug resources" }, { "debuglayer", D3D12_DEBUG_DEBUG_LAYER, "Enable debug layer" }, { "gpuvalidator", D3D12_DEBUG_GPU_VALIDATOR, "Enable GPU validator" }, { "singleton", D3D12_DEBUG_SINGLETON, "Disallow use of device factory" }, { "pix", D3D12_DEBUG_PIX, "Load WinPixGpuCaptuerer.dll" }, DEBUG_NAMED_VALUE_END }; DEBUG_GET_ONCE_FLAGS_OPTION(d3d12_debug, "D3D12_DEBUG", d3d12_debug_options, 0) uint32_t d3d12_debug; enum { HW_VENDOR_AMD = 0x1002, HW_VENDOR_INTEL = 0x8086, HW_VENDOR_MICROSOFT = 0x1414, HW_VENDOR_NVIDIA = 0x10de, }; static const char * d3d12_get_vendor(struct pipe_screen *pscreen) { return "Microsoft Corporation"; } static const char * d3d12_get_device_vendor(struct pipe_screen *pscreen) { struct d3d12_screen* screen = d3d12_screen(pscreen); switch (screen->vendor_id) { case HW_VENDOR_MICROSOFT: return "Microsoft"; case HW_VENDOR_AMD: return "AMD"; case HW_VENDOR_NVIDIA: return "NVIDIA"; case HW_VENDOR_INTEL: return "Intel"; default: return "Unknown"; } } static int d3d12_get_video_mem(struct pipe_screen *pscreen) { struct d3d12_screen* screen = d3d12_screen(pscreen); return screen->memory_size_megabytes; } static int d3d12_get_param_default(struct pipe_screen *pscreen, enum pipe_cap param) { struct d3d12_screen *screen = d3d12_screen(pscreen); switch (param) { case PIPE_CAP_NPOT_TEXTURES: return 1; case PIPE_CAP_MAX_DUAL_SOURCE_RENDER_TARGETS: /* D3D12 only supports dual-source blending for a single * render-target. From the D3D11 functional spec (which also defines * this for D3D12): * * "When Dual Source Color Blending is enabled, the Pixel Shader must * have only a single RenderTarget bound, at slot 0, and must output * both o0 and o1. Writing to other outputs (o2, o3 etc.) produces * undefined results for the corresponding RenderTargets, if bound * illegally." * * Source: https://microsoft.github.io/DirectX-Specs/d3d/archive/D3D11_3_FunctionalSpec.htm#17.6%20Dual%20Source%20Color%20Blending */ return 1; case PIPE_CAP_ANISOTROPIC_FILTER: return 1; case PIPE_CAP_MAX_RENDER_TARGETS: return D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; case PIPE_CAP_TEXTURE_SWIZZLE: return 1; case PIPE_CAP_MAX_TEXEL_BUFFER_ELEMENTS_UINT: return 1 << D3D12_REQ_BUFFER_RESOURCE_TEXEL_COUNT_2_TO_EXP; case PIPE_CAP_MAX_TEXTURE_2D_SIZE: return D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; case PIPE_CAP_MAX_TEXTURE_3D_LEVELS: static_assert(D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION == (1 << 11), "D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION"); return 12; case PIPE_CAP_MAX_TEXTURE_CUBE_LEVELS: return D3D12_REQ_MIP_LEVELS; case PIPE_CAP_PRIMITIVE_RESTART: case PIPE_CAP_INDEP_BLEND_ENABLE: case PIPE_CAP_INDEP_BLEND_FUNC: case PIPE_CAP_FRAGMENT_SHADER_TEXTURE_LOD: case PIPE_CAP_FRAGMENT_SHADER_DERIVATIVES: case PIPE_CAP_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION: case PIPE_CAP_VERTEX_BUFFER_STRIDE_4BYTE_ALIGNED_ONLY: case PIPE_CAP_MIXED_COLOR_DEPTH_BITS: return 1; /* We need to do some lowering that requires a link to the sampler */ case PIPE_CAP_NIR_SAMPLERS_AS_DEREF: return 1; case PIPE_CAP_NIR_IMAGES_AS_DEREF: return 1; case PIPE_CAP_MAX_TEXTURE_ARRAY_LAYERS: return D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; case PIPE_CAP_DEPTH_CLIP_DISABLE: return 1; case PIPE_CAP_TGSI_TEXCOORD: return 1; case PIPE_CAP_VERTEX_COLOR_UNCLAMPED: return 1; case PIPE_CAP_GLSL_FEATURE_LEVEL: return 460; case PIPE_CAP_GLSL_FEATURE_LEVEL_COMPATIBILITY: return 460; case PIPE_CAP_ESSL_FEATURE_LEVEL: return 310; case PIPE_CAP_COMPUTE: return 1; case PIPE_CAP_TEXTURE_MULTISAMPLE: return 1; case PIPE_CAP_CUBE_MAP_ARRAY: return 1; case PIPE_CAP_TEXTURE_BUFFER_OBJECTS: return 1; case PIPE_CAP_TEXTURE_TRANSFER_MODES: return PIPE_TEXTURE_TRANSFER_BLIT; case PIPE_CAP_ENDIANNESS: return PIPE_ENDIAN_NATIVE; /* unsure */ case PIPE_CAP_MAX_VIEWPORTS: return D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; case PIPE_CAP_MIXED_FRAMEBUFFER_SIZES: return 1; case PIPE_CAP_MAX_TEXTURE_GATHER_COMPONENTS: return 4; case PIPE_CAP_FS_COORD_PIXEL_CENTER_HALF_INTEGER: case PIPE_CAP_FS_COORD_ORIGIN_UPPER_LEFT: return 1; case PIPE_CAP_ACCELERATED: return screen->vendor_id != HW_VENDOR_MICROSOFT; case PIPE_CAP_VIDEO_MEMORY: return d3d12_get_video_mem(pscreen); case PIPE_CAP_UMA: return screen->architecture.UMA; case PIPE_CAP_MAX_VERTEX_ATTRIB_STRIDE: return 2048; /* FIXME: no clue how to query this */ case PIPE_CAP_TEXTURE_FLOAT_LINEAR: case PIPE_CAP_TEXTURE_HALF_FLOAT_LINEAR: return 1; case PIPE_CAP_SHADER_BUFFER_OFFSET_ALIGNMENT: return D3D12_RAW_UAV_SRV_BYTE_ALIGNMENT; case PIPE_CAP_CONSTANT_BUFFER_OFFSET_ALIGNMENT: return D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT; case PIPE_CAP_PCI_GROUP: case PIPE_CAP_PCI_BUS: case PIPE_CAP_PCI_DEVICE: case PIPE_CAP_PCI_FUNCTION: return 0; /* TODO: figure these out */ case PIPE_CAP_FLATSHADE: case PIPE_CAP_ALPHA_TEST: case PIPE_CAP_TWO_SIDED_COLOR: case PIPE_CAP_CLIP_PLANES: return 0; case PIPE_CAP_SHADER_STENCIL_EXPORT: return screen->opts.PSSpecifiedStencilRefSupported; case PIPE_CAP_SEAMLESS_CUBE_MAP: case PIPE_CAP_TEXTURE_QUERY_LOD: case PIPE_CAP_VS_INSTANCEID: case PIPE_CAP_TGSI_TEX_TXF_LZ: case PIPE_CAP_OCCLUSION_QUERY: case PIPE_CAP_VIEWPORT_TRANSFORM_LOWERED: case PIPE_CAP_PSIZ_CLAMPED: case PIPE_CAP_BLEND_EQUATION_SEPARATE: case PIPE_CAP_CONDITIONAL_RENDER: case PIPE_CAP_CONDITIONAL_RENDER_INVERTED: case PIPE_CAP_QUERY_TIMESTAMP: case PIPE_CAP_VERTEX_ELEMENT_INSTANCE_DIVISOR: case PIPE_CAP_VERTEX_ELEMENT_SRC_OFFSET_4BYTE_ALIGNED_ONLY: case PIPE_CAP_IMAGE_STORE_FORMATTED: case PIPE_CAP_GLSL_TESS_LEVELS_AS_INPUTS: return 1; case PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS: return D3D12_SO_BUFFER_SLOT_COUNT; case PIPE_CAP_MAX_STREAM_OUTPUT_SEPARATE_COMPONENTS: case PIPE_CAP_MAX_STREAM_OUTPUT_INTERLEAVED_COMPONENTS: return D3D12_SO_OUTPUT_COMPONENT_COUNT; /* Geometry shader output. */ case PIPE_CAP_MAX_GEOMETRY_OUTPUT_VERTICES: return D3D12_GS_MAX_OUTPUT_VERTEX_COUNT_ACROSS_INSTANCES; case PIPE_CAP_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS: return D3D12_REQ_GS_INVOCATION_32BIT_OUTPUT_COMPONENT_LIMIT; case PIPE_CAP_MAX_VARYINGS: /* Subtract one so that implicit position can be added */ return D3D12_PS_INPUT_REGISTER_COUNT - 1; case PIPE_CAP_MAX_COMBINED_SHADER_OUTPUT_RESOURCES: if (screen->max_feature_level <= D3D_FEATURE_LEVEL_11_0) return D3D12_PS_CS_UAV_REGISTER_COUNT; if (screen->opts.ResourceBindingTier <= D3D12_RESOURCE_BINDING_TIER_2) return D3D12_UAV_SLOT_COUNT; return 0; case PIPE_CAP_START_INSTANCE: case PIPE_CAP_DRAW_PARAMETERS: case PIPE_CAP_DRAW_INDIRECT: case PIPE_CAP_MULTI_DRAW_INDIRECT: case PIPE_CAP_MULTI_DRAW_INDIRECT_PARAMS: case PIPE_CAP_FRAMEBUFFER_NO_ATTACHMENT: case PIPE_CAP_SAMPLE_SHADING: case PIPE_CAP_STREAM_OUTPUT_PAUSE_RESUME: case PIPE_CAP_STREAM_OUTPUT_INTERLEAVE_BUFFERS: case PIPE_CAP_INT64: case PIPE_CAP_DOUBLES: case PIPE_CAP_DEVICE_RESET_STATUS_QUERY: case PIPE_CAP_ROBUST_BUFFER_ACCESS_BEHAVIOR: case PIPE_CAP_MEMOBJ: case PIPE_CAP_FENCE_SIGNAL: case PIPE_CAP_TIMELINE_SEMAPHORE_IMPORT: case PIPE_CAP_CLIP_HALFZ: case PIPE_CAP_VS_LAYER_VIEWPORT: case PIPE_CAP_COPY_BETWEEN_COMPRESSED_AND_PLAIN_FORMATS: case PIPE_CAP_SHADER_ARRAY_COMPONENTS: case PIPE_CAP_TEXTURE_MIRROR_CLAMP_TO_EDGE: case PIPE_CAP_QUERY_TIME_ELAPSED: case PIPE_CAP_FS_FINE_DERIVATIVE: case PIPE_CAP_CULL_DISTANCE: case PIPE_CAP_TEXTURE_QUERY_SAMPLES: case PIPE_CAP_TEXTURE_BARRIER: case PIPE_CAP_GL_SPIRV: case PIPE_CAP_POLYGON_OFFSET_CLAMP: case PIPE_CAP_SHADER_GROUP_VOTE: case PIPE_CAP_SHADER_BALLOT: case PIPE_CAP_QUERY_PIPELINE_STATISTICS: case PIPE_CAP_QUERY_SO_OVERFLOW: return 1; case PIPE_CAP_QUERY_BUFFER_OBJECT: return (screen->opts3.WriteBufferImmediateSupportFlags & D3D12_COMMAND_LIST_SUPPORT_FLAG_DIRECT) != 0; case PIPE_CAP_MAX_VERTEX_STREAMS: return D3D12_SO_BUFFER_SLOT_COUNT; case PIPE_CAP_MAX_SHADER_PATCH_VARYINGS: /* This is asking about varyings, not total registers, so remove the 2 tess factor registers. */ return D3D12_HS_OUTPUT_PATCH_CONSTANT_REGISTER_COUNT - 2; case PIPE_CAP_MAX_TEXTURE_UPLOAD_MEMORY_BUDGET: /* Picking a value in line with other drivers. Without this, we can end up easily hitting OOM * if an app just creates, initializes, and destroys resources without explicitly flushing. */ return 64 * 1024 * 1024; case PIPE_CAP_SAMPLER_VIEW_TARGET: return screen->opts12.RelaxedFormatCastingSupported; default: return u_pipe_screen_get_param_defaults(pscreen, param); } } static int d3d12_get_generic_param(struct pipe_screen *pscreen, enum pipe_cap param) { struct d3d12_screen *screen = d3d12_screen(pscreen); switch (param) { case PIPE_CAP_ACCELERATED: return screen->vendor_id != HW_VENDOR_MICROSOFT; case PIPE_CAP_VIDEO_MEMORY: return d3d12_get_video_mem(pscreen); case PIPE_CAP_UMA: return screen->architecture.UMA; default: return 0; } } static int d3d12_get_param(struct pipe_screen *pscreen, enum pipe_cap param) { struct d3d12_screen *screen = d3d12_screen(pscreen); if (screen->max_feature_level < D3D_FEATURE_LEVEL_11_0) return d3d12_get_generic_param(pscreen, param); return d3d12_get_param_default(pscreen, param); } static float d3d12_get_paramf(struct pipe_screen *pscreen, enum pipe_capf param) { switch (param) { case PIPE_CAPF_MIN_LINE_WIDTH: case PIPE_CAPF_MIN_LINE_WIDTH_AA: case PIPE_CAPF_MIN_POINT_SIZE: case PIPE_CAPF_MIN_POINT_SIZE_AA: return 1; case PIPE_CAPF_POINT_SIZE_GRANULARITY: case PIPE_CAPF_LINE_WIDTH_GRANULARITY: return 0.1; case PIPE_CAPF_MAX_LINE_WIDTH: case PIPE_CAPF_MAX_LINE_WIDTH_AA: return 1.0f; /* no clue */ case PIPE_CAPF_MAX_POINT_SIZE: case PIPE_CAPF_MAX_POINT_SIZE_AA: return D3D12_MAX_POINT_SIZE; case PIPE_CAPF_MAX_TEXTURE_ANISOTROPY: return D3D12_MAX_MAXANISOTROPY; case PIPE_CAPF_MAX_TEXTURE_LOD_BIAS: return 15.99f; case PIPE_CAPF_MIN_CONSERVATIVE_RASTER_DILATE: case PIPE_CAPF_MAX_CONSERVATIVE_RASTER_DILATE: case PIPE_CAPF_CONSERVATIVE_RASTER_DILATE_GRANULARITY: return 0.0f; /* not implemented */ default: unreachable("unknown pipe_capf"); } return 0.0; } static int d3d12_get_shader_param(struct pipe_screen *pscreen, enum pipe_shader_type shader, enum pipe_shader_cap param) { struct d3d12_screen *screen = d3d12_screen(pscreen); if (shader == PIPE_SHADER_TASK || shader == PIPE_SHADER_MESH) return 0; switch (param) { case PIPE_SHADER_CAP_MAX_INSTRUCTIONS: case PIPE_SHADER_CAP_MAX_ALU_INSTRUCTIONS: case PIPE_SHADER_CAP_MAX_TEX_INSTRUCTIONS: case PIPE_SHADER_CAP_MAX_TEX_INDIRECTIONS: case PIPE_SHADER_CAP_MAX_CONTROL_FLOW_DEPTH: return INT_MAX; return 0; case PIPE_SHADER_CAP_MAX_INPUTS: switch (shader) { case PIPE_SHADER_VERTEX: return D3D12_VS_INPUT_REGISTER_COUNT; case PIPE_SHADER_FRAGMENT: return D3D12_PS_INPUT_REGISTER_COUNT; case PIPE_SHADER_GEOMETRY: return D3D12_GS_INPUT_REGISTER_COUNT; case PIPE_SHADER_TESS_CTRL: return D3D12_HS_CONTROL_POINT_PHASE_INPUT_REGISTER_COUNT; case PIPE_SHADER_TESS_EVAL: return D3D12_DS_INPUT_CONTROL_POINT_REGISTER_COUNT; case PIPE_SHADER_COMPUTE: return 0; default: unreachable("Unexpected shader"); } break; case PIPE_SHADER_CAP_MAX_OUTPUTS: switch (shader) { case PIPE_SHADER_VERTEX: return D3D12_VS_OUTPUT_REGISTER_COUNT; case PIPE_SHADER_FRAGMENT: return D3D12_PS_OUTPUT_REGISTER_COUNT; case PIPE_SHADER_GEOMETRY: return D3D12_GS_OUTPUT_REGISTER_COUNT; case PIPE_SHADER_TESS_CTRL: return D3D12_HS_CONTROL_POINT_PHASE_OUTPUT_REGISTER_COUNT; case PIPE_SHADER_TESS_EVAL: return D3D12_DS_OUTPUT_REGISTER_COUNT; case PIPE_SHADER_COMPUTE: return 0; default: unreachable("Unexpected shader"); } break; case PIPE_SHADER_CAP_MAX_TEXTURE_SAMPLERS: if (screen->opts.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1) return 16; return PIPE_MAX_SAMPLERS; case PIPE_SHADER_CAP_MAX_CONST_BUFFER0_SIZE: return 65536; case PIPE_SHADER_CAP_MAX_CONST_BUFFERS: if (screen->opts.ResourceBindingTier < D3D12_RESOURCE_BINDING_TIER_3) return 13; /* 15 - 2 for lowered uniforms and state vars*/ return 15; case PIPE_SHADER_CAP_MAX_TEMPS: return INT_MAX; case PIPE_SHADER_CAP_INDIRECT_INPUT_ADDR: case PIPE_SHADER_CAP_INDIRECT_OUTPUT_ADDR: case PIPE_SHADER_CAP_INDIRECT_TEMP_ADDR: case PIPE_SHADER_CAP_SUBROUTINES: return 0; /* not implemented */ case PIPE_SHADER_CAP_INDIRECT_CONST_ADDR: case PIPE_SHADER_CAP_INTEGERS: return 1; case PIPE_SHADER_CAP_INT64_ATOMICS: case PIPE_SHADER_CAP_FP16: return 0; /* not implemented */ case PIPE_SHADER_CAP_TGSI_SQRT_SUPPORTED: return 0; /* not implemented */ case PIPE_SHADER_CAP_MAX_SAMPLER_VIEWS: /* Note: This is wrong, but this is the max value that * TC can support to avoid overflowing an array. */ return PIPE_MAX_SAMPLERS; case PIPE_SHADER_CAP_TGSI_ANY_INOUT_DECL_RANGE: return 0; /* no idea */ case PIPE_SHADER_CAP_MAX_SHADER_BUFFERS: return (screen->max_feature_level >= D3D_FEATURE_LEVEL_11_1 || screen->opts.ResourceBindingTier >= D3D12_RESOURCE_BINDING_TIER_3) ? PIPE_MAX_SHADER_BUFFERS : D3D12_PS_CS_UAV_REGISTER_COUNT; case PIPE_SHADER_CAP_SUPPORTED_IRS: return 1 << PIPE_SHADER_IR_NIR; case PIPE_SHADER_CAP_MAX_SHADER_IMAGES: if (!screen->support_shader_images) return 0; return (screen->max_feature_level >= D3D_FEATURE_LEVEL_11_1 || screen->opts.ResourceBindingTier >= D3D12_RESOURCE_BINDING_TIER_3) ? PIPE_MAX_SHADER_IMAGES : D3D12_PS_CS_UAV_REGISTER_COUNT; case PIPE_SHADER_CAP_MAX_HW_ATOMIC_COUNTERS: case PIPE_SHADER_CAP_MAX_HW_ATOMIC_COUNTER_BUFFERS: case PIPE_SHADER_CAP_CONT_SUPPORTED: return 0; /* not implemented */ /* should only get here on unhandled cases */ default: return 0; } } static int d3d12_get_compute_param(struct pipe_screen *pscreen, enum pipe_shader_ir ir, enum pipe_compute_cap cap, void *ret) { switch (cap) { case PIPE_COMPUTE_CAP_MAX_GRID_SIZE: { uint64_t *grid = (uint64_t *)ret; grid[0] = grid[1] = grid[2] = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; return sizeof(uint64_t) * 3; } case PIPE_COMPUTE_CAP_MAX_BLOCK_SIZE: { uint64_t *block = (uint64_t *)ret; block[0] = D3D12_CS_THREAD_GROUP_MAX_X; block[1] = D3D12_CS_THREAD_GROUP_MAX_Y; block[2] = D3D12_CS_THREAD_GROUP_MAX_Z; return sizeof(uint64_t) * 3; } case PIPE_COMPUTE_CAP_MAX_VARIABLE_THREADS_PER_BLOCK: case PIPE_COMPUTE_CAP_MAX_THREADS_PER_BLOCK: *(uint64_t *)ret = D3D12_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP; return sizeof(uint64_t); case PIPE_COMPUTE_CAP_MAX_LOCAL_SIZE: *(uint64_t *)ret = D3D12_CS_TGSM_REGISTER_COUNT /*DWORDs*/ * 4; return sizeof(uint64_t); default: return 0; } } static bool d3d12_is_format_supported(struct pipe_screen *pscreen, enum pipe_format format, enum pipe_texture_target target, unsigned sample_count, unsigned storage_sample_count, unsigned bind) { struct d3d12_screen *screen = d3d12_screen(pscreen); if (MAX2(1, sample_count) != MAX2(1, storage_sample_count)) return false; if (target == PIPE_BUFFER) { /* Replace emulated vertex element formats for the tests */ format = d3d12_emulated_vtx_format(format); } else { /* Allow 3-comp 32 bit formats only for BOs (needed for ARB_tbo_rgb32) */ if ((format == PIPE_FORMAT_R32G32B32_FLOAT || format == PIPE_FORMAT_R32G32B32_SINT || format == PIPE_FORMAT_R32G32B32_UINT)) return false; } /* Don't advertise alpha/luminance_alpha formats because they can't be used * for render targets (except A8_UNORM) and can't be emulated by R/RG formats. * Let the state tracker choose an RGBA format instead. For YUV formats, we * want the state tracker to lower these to individual planes. */ if (format != PIPE_FORMAT_A8_UNORM && (util_format_is_alpha(format) || util_format_is_luminance_alpha(format) || util_format_is_yuv(format))) return false; if (format == PIPE_FORMAT_NONE) { /* For UAV-only rendering, aka ARB_framebuffer_no_attachments */ switch (sample_count) { case 0: case 1: case 4: case 8: case 16: return true; default: return false; } } DXGI_FORMAT dxgi_format = d3d12_get_format(format); if (dxgi_format == DXGI_FORMAT_UNKNOWN) return false; enum D3D12_FORMAT_SUPPORT1 dim_support = D3D12_FORMAT_SUPPORT1_NONE; switch (target) { case PIPE_TEXTURE_1D: case PIPE_TEXTURE_1D_ARRAY: dim_support = D3D12_FORMAT_SUPPORT1_TEXTURE1D; break; case PIPE_TEXTURE_2D: case PIPE_TEXTURE_RECT: case PIPE_TEXTURE_2D_ARRAY: dim_support = D3D12_FORMAT_SUPPORT1_TEXTURE2D; break; case PIPE_TEXTURE_3D: dim_support = D3D12_FORMAT_SUPPORT1_TEXTURE3D; break; case PIPE_TEXTURE_CUBE: case PIPE_TEXTURE_CUBE_ARRAY: dim_support = D3D12_FORMAT_SUPPORT1_TEXTURECUBE; break; case PIPE_BUFFER: dim_support = D3D12_FORMAT_SUPPORT1_BUFFER; break; default: unreachable("Unknown target"); } if (bind & PIPE_BIND_DISPLAY_TARGET) { enum pipe_format dt_format = format == PIPE_FORMAT_R16G16B16A16_FLOAT ? PIPE_FORMAT_R8G8B8A8_UNORM : format; if (!screen->winsys->is_displaytarget_format_supported(screen->winsys, bind, dt_format)) return false; } D3D12_FEATURE_DATA_FORMAT_SUPPORT fmt_info; fmt_info.Format = d3d12_get_resource_rt_format(format); if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &fmt_info, sizeof(fmt_info)))) return false; if (!(fmt_info.Support1 & dim_support)) return false; if (target == PIPE_BUFFER) { if (bind & PIPE_BIND_VERTEX_BUFFER && !(fmt_info.Support1 & D3D12_FORMAT_SUPPORT1_IA_VERTEX_BUFFER)) return false; if (bind & PIPE_BIND_INDEX_BUFFER) { if (format != PIPE_FORMAT_R16_UINT && format != PIPE_FORMAT_R32_UINT) return false; } if (sample_count > 0) return false; } else { /* all other targets are texture-targets */ if (bind & PIPE_BIND_RENDER_TARGET && !(fmt_info.Support1 & D3D12_FORMAT_SUPPORT1_RENDER_TARGET)) return false; if (bind & PIPE_BIND_BLENDABLE && !(fmt_info.Support1 & D3D12_FORMAT_SUPPORT1_BLENDABLE)) return false; if (bind & PIPE_BIND_SHADER_IMAGE && (fmt_info.Support2 & (D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD | D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE)) != (D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD | D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE)) return false; D3D12_FEATURE_DATA_FORMAT_SUPPORT fmt_info_sv; if (util_format_is_depth_or_stencil(format)) { fmt_info_sv.Format = d3d12_get_resource_srv_format(format, target); if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &fmt_info_sv, sizeof(fmt_info_sv)))) return false; } else fmt_info_sv = fmt_info; if (bind & PIPE_BIND_DEPTH_STENCIL && !(fmt_info.Support1 & D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL)) return false; if (sample_count > 0) { if (!(fmt_info_sv.Support1 & D3D12_FORMAT_SUPPORT1_MULTISAMPLE_LOAD)) return false; if (!util_is_power_of_two_nonzero(sample_count)) return false; if (bind & PIPE_BIND_SHADER_IMAGE) return false; D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS ms_info = {}; ms_info.Format = dxgi_format; ms_info.SampleCount = sample_count; if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &ms_info, sizeof(ms_info))) || !ms_info.NumQualityLevels) return false; } } return true; } void d3d12_deinit_screen(struct d3d12_screen *screen) { #ifdef HAVE_GALLIUM_D3D12_GRAPHICS if (screen->max_feature_level >= D3D_FEATURE_LEVEL_11_0) { if (screen->rtv_pool) { d3d12_descriptor_pool_free(screen->rtv_pool); screen->rtv_pool = nullptr; } if (screen->dsv_pool) { d3d12_descriptor_pool_free(screen->dsv_pool); screen->dsv_pool = nullptr; } if (screen->view_pool) { d3d12_descriptor_pool_free(screen->view_pool); screen->view_pool = nullptr; } } #endif // HAVE_GALLIUM_D3D12_GRAPHICS if (screen->readback_slab_bufmgr) { screen->readback_slab_bufmgr->destroy(screen->readback_slab_bufmgr); screen->readback_slab_bufmgr = nullptr; } if (screen->slab_bufmgr) { screen->slab_bufmgr->destroy(screen->slab_bufmgr); screen->slab_bufmgr = nullptr; } if (screen->cache_bufmgr) { screen->cache_bufmgr->destroy(screen->cache_bufmgr); screen->cache_bufmgr = nullptr; } if (screen->slab_cache_bufmgr) { screen->slab_cache_bufmgr->destroy(screen->slab_cache_bufmgr); screen->slab_cache_bufmgr = nullptr; } if (screen->readback_slab_cache_bufmgr) { screen->readback_slab_cache_bufmgr->destroy(screen->readback_slab_cache_bufmgr); screen->readback_slab_cache_bufmgr = nullptr; } if (screen->bufmgr) { screen->bufmgr->destroy(screen->bufmgr); screen->bufmgr = nullptr; } d3d12_deinit_residency(screen); if (screen->fence) { screen->fence->Release(); screen->fence = nullptr; } if (screen->cmdqueue) { screen->cmdqueue->Release(); screen->cmdqueue = nullptr; } if (screen->dev10) { screen->dev10->Release(); screen->dev10 = nullptr; } if (screen->dev) { screen->dev->Release(); screen->dev = nullptr; } } void d3d12_destroy_screen(struct d3d12_screen *screen) { slab_destroy_parent(&screen->transfer_pool); mtx_destroy(&screen->submit_mutex); mtx_destroy(&screen->descriptor_pool_mutex); #ifdef HAVE_GALLIUM_D3D12_GRAPHICS d3d12_varying_cache_destroy(screen); mtx_destroy(&screen->varying_info_mutex); #endif // HAVE_GALLIUM_D3D12_GRAPHICS if (screen->d3d12_mod) util_dl_close(screen->d3d12_mod); glsl_type_singleton_decref(); FREE(screen); } static void d3d12_flush_frontbuffer(struct pipe_screen * pscreen, struct pipe_context *pctx, struct pipe_resource *pres, unsigned level, unsigned layer, void *winsys_drawable_handle, unsigned nboxes, struct pipe_box *sub_box) { struct d3d12_screen *screen = d3d12_screen(pscreen); struct sw_winsys *winsys = screen->winsys; struct d3d12_resource *res = d3d12_resource(pres); if (!winsys || !pctx) return; assert(res->dt || res->dt_proxy); if (res->dt_proxy) { struct pipe_blit_info blit; memset(&blit, 0, sizeof(blit)); blit.dst.resource = res->dt_proxy; blit.dst.box.width = blit.dst.resource->width0; blit.dst.box.height = blit.dst.resource->height0; blit.dst.box.depth = 1; blit.dst.format = blit.dst.resource->format; blit.src.resource = pres; blit.src.box.width = blit.src.resource->width0; blit.src.box.height = blit.src.resource->height0; blit.src.box.depth = 1; blit.src.format = blit.src.resource->format; blit.mask = PIPE_MASK_RGBA; blit.filter = PIPE_TEX_FILTER_NEAREST; pctx->blit(pctx, &blit); pres = res->dt_proxy; res = d3d12_resource(pres); } assert(res->dt); void *map = winsys->displaytarget_map(winsys, res->dt, 0); if (map) { pctx = threaded_context_unwrap_sync(pctx); pipe_transfer *transfer = nullptr; void *res_map = pipe_texture_map(pctx, pres, level, layer, PIPE_MAP_READ, 0, 0, u_minify(pres->width0, level), u_minify(pres->height0, level), &transfer); if (res_map) { util_copy_rect((uint8_t*)map, pres->format, res->dt_stride, 0, 0, transfer->box.width, transfer->box.height, (const uint8_t*)res_map, transfer->stride, 0, 0); pipe_texture_unmap(pctx, transfer); } winsys->displaytarget_unmap(winsys, res->dt); } #if defined(_WIN32) && !defined(_GAMING_XBOX) // WindowFromDC is Windows-only, and this method requires an HWND, so only use it on Windows ID3D12SharingContract *sharing_contract; if (SUCCEEDED(screen->cmdqueue->QueryInterface(IID_PPV_ARGS(&sharing_contract)))) { ID3D12Resource *d3d12_res = d3d12_resource_resource(res); sharing_contract->Present(d3d12_res, 0, WindowFromDC((HDC)winsys_drawable_handle)); sharing_contract->Release(); } #endif winsys->displaytarget_display(winsys, res->dt, winsys_drawable_handle, nboxes, sub_box); } #ifndef _GAMING_XBOX static ID3D12Debug * get_debug_interface(util_dl_library *d3d12_mod, ID3D12DeviceFactory *factory) { ID3D12Debug *debug = nullptr; if (factory) { factory->GetConfigurationInterface(CLSID_D3D12Debug, IID_PPV_ARGS(&debug)); return debug; } typedef HRESULT(WINAPI *PFN_D3D12_GET_DEBUG_INTERFACE)(REFIID riid, void **ppFactory); PFN_D3D12_GET_DEBUG_INTERFACE D3D12GetDebugInterface; D3D12GetDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)util_dl_get_proc_address(d3d12_mod, "D3D12GetDebugInterface"); if (!D3D12GetDebugInterface) { debug_printf("D3D12: failed to load D3D12GetDebugInterface from D3D12.DLL\n"); return NULL; } if (FAILED(D3D12GetDebugInterface(IID_PPV_ARGS(&debug)))) { debug_printf("D3D12: D3D12GetDebugInterface failed\n"); return NULL; } return debug; } static void enable_d3d12_debug_layer(util_dl_library *d3d12_mod, ID3D12DeviceFactory *factory) { ID3D12Debug *debug = get_debug_interface(d3d12_mod, factory); if (debug) { debug->EnableDebugLayer(); debug->Release(); } } static void enable_gpu_validation(util_dl_library *d3d12_mod, ID3D12DeviceFactory *factory) { ID3D12Debug *debug = get_debug_interface(d3d12_mod, factory); ID3D12Debug3 *debug3; if (debug) { if (SUCCEEDED(debug->QueryInterface(IID_PPV_ARGS(&debug3)))) { debug3->SetEnableGPUBasedValidation(true); debug3->Release(); } debug->Release(); } } #endif #ifdef _GAMING_XBOX static ID3D12Device3 * create_device(util_dl_library *d3d12_mod, IUnknown *adapter) { D3D12XBOX_PROCESS_DEBUG_FLAGS debugFlags = D3D12XBOX_PROCESS_DEBUG_FLAG_ENABLE_COMMON_STATE_PROMOTION; /* For compatibility with desktop D3D12 */ if (d3d12_debug & D3D12_DEBUG_EXPERIMENTAL) { debug_printf("D3D12: experimental shader models are not supported on GDKX\n"); return nullptr; } if (d3d12_debug & D3D12_DEBUG_GPU_VALIDATOR) { debug_printf("D3D12: gpu validation is not supported on GDKX\n"); /* FIXME: Is this right? */ return nullptr; } if (d3d12_debug & D3D12_DEBUG_DEBUG_LAYER) debugFlags |= D3D12XBOX_PROCESS_DEBUG_FLAG_DEBUG; D3D12XBOX_CREATE_DEVICE_PARAMETERS params = {}; params.Version = D3D12_SDK_VERSION; params.ProcessDebugFlags = debugFlags; params.GraphicsCommandQueueRingSizeBytes = D3D12XBOX_DEFAULT_SIZE_BYTES; params.GraphicsScratchMemorySizeBytes = D3D12XBOX_DEFAULT_SIZE_BYTES; params.ComputeScratchMemorySizeBytes = D3D12XBOX_DEFAULT_SIZE_BYTES; ID3D12Device3 *dev = nullptr; typedef HRESULT(WINAPI * PFN_D3D12XBOXCREATEDEVICE)(IGraphicsUnknown *, const D3D12XBOX_CREATE_DEVICE_PARAMETERS *, REFIID, void **); PFN_D3D12XBOXCREATEDEVICE D3D12XboxCreateDevice = (PFN_D3D12XBOXCREATEDEVICE) util_dl_get_proc_address(d3d12_mod, "D3D12XboxCreateDevice"); if (!D3D12XboxCreateDevice) { debug_printf("D3D12: failed to load D3D12XboxCreateDevice from D3D12 DLL\n"); return NULL; } if (FAILED(D3D12XboxCreateDevice((IGraphicsUnknown*) adapter, ¶ms, IID_PPV_ARGS(&dev)))) debug_printf("D3D12: D3D12XboxCreateDevice failed\n"); return dev; } #else static ID3D12Device3 * create_device(util_dl_library *d3d12_mod, IUnknown *adapter, ID3D12DeviceFactory *factory) { #ifdef _WIN32 if (d3d12_debug & D3D12_DEBUG_EXPERIMENTAL) #endif { if (factory) { if (FAILED(factory->EnableExperimentalFeatures(1, &D3D12ExperimentalShaderModels, nullptr, nullptr))) { debug_printf("D3D12: failed to enable experimental shader models\n"); return nullptr; } } else { typedef HRESULT(WINAPI *PFN_D3D12ENABLEEXPERIMENTALFEATURES)(UINT, const IID*, void*, UINT*); PFN_D3D12ENABLEEXPERIMENTALFEATURES D3D12EnableExperimentalFeatures = (PFN_D3D12ENABLEEXPERIMENTALFEATURES)util_dl_get_proc_address(d3d12_mod, "D3D12EnableExperimentalFeatures"); if (!D3D12EnableExperimentalFeatures || FAILED(D3D12EnableExperimentalFeatures(1, &D3D12ExperimentalShaderModels, NULL, NULL))) { debug_printf("D3D12: failed to enable experimental shader models\n"); return nullptr; } } } ID3D12Device3 *dev = nullptr; if (factory) { factory->SetFlags(D3D12_DEVICE_FACTORY_FLAG_ALLOW_RETURNING_EXISTING_DEVICE | D3D12_DEVICE_FACTORY_FLAG_ALLOW_RETURNING_INCOMPATIBLE_EXISTING_DEVICE); /* Fallback to D3D_FEATURE_LEVEL_11_0 for D3D12 versions without generic support */ if (FAILED(factory->CreateDevice(adapter, D3D_FEATURE_LEVEL_1_0_GENERIC, IID_PPV_ARGS(&dev)))) if (FAILED(factory->CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&dev)))) debug_printf("D3D12: D3D12CreateDevice failed\n"); } else { typedef HRESULT(WINAPI *PFN_D3D12CREATEDEVICE)(IUnknown*, D3D_FEATURE_LEVEL, REFIID, void**); PFN_D3D12CREATEDEVICE D3D12CreateDevice = (PFN_D3D12CREATEDEVICE)util_dl_get_proc_address(d3d12_mod, "D3D12CreateDevice"); if (!D3D12CreateDevice) { debug_printf("D3D12: failed to load D3D12CreateDevice from D3D12.DLL\n"); return NULL; } /* Fallback to D3D_FEATURE_LEVEL_11_0 for D3D12 versions without generic support */ if (FAILED(D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_1_0_GENERIC, IID_PPV_ARGS(&dev)))) if (FAILED(D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&dev)))) debug_printf("D3D12: D3D12CreateDevice failed\n"); } return dev; } #endif /* _GAMING_XBOX */ static bool can_attribute_at_vertex(struct d3d12_screen *screen) { switch (screen->vendor_id) { case HW_VENDOR_MICROSOFT: return true; default: return screen->opts3.BarycentricsSupported; } } static bool can_shader_image_load_all_formats(struct d3d12_screen *screen) { if (!screen->opts.TypedUAVLoadAdditionalFormats) return false; /* All of these are required by ARB_shader_image_load_store */ static const DXGI_FORMAT additional_formats[] = { DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_SNORM, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32_UINT, DXGI_FORMAT_R32G32_SINT, DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_R10G10B10A2_UINT, DXGI_FORMAT_R11G11B10_FLOAT, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_R16G16_UNORM, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_R16G16_SNORM, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_SNORM, DXGI_FORMAT_R8_SNORM, }; for (unsigned i = 0; i < ARRAY_SIZE(additional_formats); ++i) { D3D12_FEATURE_DATA_FORMAT_SUPPORT support = { additional_formats[i] }; if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &support, sizeof(support))) || (support.Support1 & D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW) == D3D12_FORMAT_SUPPORT1_NONE || (support.Support2 & (D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD | D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE)) != (D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD | D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE)) return false; } return true; } static void d3d12_init_null_srvs(struct d3d12_screen *screen) { for (unsigned i = 0; i < RESOURCE_DIMENSION_COUNT; ++i) { D3D12_SHADER_RESOURCE_VIEW_DESC srv = {}; srv.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; srv.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; switch (i) { case RESOURCE_DIMENSION_BUFFER: case RESOURCE_DIMENSION_UNKNOWN: srv.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; srv.Buffer.FirstElement = 0; srv.Buffer.NumElements = 0; srv.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE; srv.Buffer.StructureByteStride = 0; break; case RESOURCE_DIMENSION_TEXTURE1D: srv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D; srv.Texture1D.MipLevels = 1; srv.Texture1D.MostDetailedMip = 0; srv.Texture1D.ResourceMinLODClamp = 0.0f; break; case RESOURCE_DIMENSION_TEXTURE1DARRAY: srv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY; srv.Texture1DArray.MipLevels = 1; srv.Texture1DArray.ArraySize = 1; srv.Texture1DArray.MostDetailedMip = 0; srv.Texture1DArray.FirstArraySlice = 0; srv.Texture1DArray.ResourceMinLODClamp = 0.0f; break; case RESOURCE_DIMENSION_TEXTURE2D: srv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; srv.Texture2D.MipLevels = 1; srv.Texture2D.MostDetailedMip = 0; srv.Texture2D.PlaneSlice = 0; srv.Texture2D.ResourceMinLODClamp = 0.0f; break; case RESOURCE_DIMENSION_TEXTURE2DARRAY: srv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; srv.Texture2DArray.MipLevels = 1; srv.Texture2DArray.ArraySize = 1; srv.Texture2DArray.MostDetailedMip = 0; srv.Texture2DArray.FirstArraySlice = 0; srv.Texture2DArray.PlaneSlice = 0; srv.Texture2DArray.ResourceMinLODClamp = 0.0f; break; case RESOURCE_DIMENSION_TEXTURE2DMS: srv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS; break; case RESOURCE_DIMENSION_TEXTURE2DMSARRAY: srv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY; srv.Texture2DMSArray.ArraySize = 1; srv.Texture2DMSArray.FirstArraySlice = 0; break; case RESOURCE_DIMENSION_TEXTURE3D: srv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D; srv.Texture3D.MipLevels = 1; srv.Texture3D.MostDetailedMip = 0; srv.Texture3D.ResourceMinLODClamp = 0.0f; break; case RESOURCE_DIMENSION_TEXTURECUBE: srv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE; srv.TextureCube.MipLevels = 1; srv.TextureCube.MostDetailedMip = 0; srv.TextureCube.ResourceMinLODClamp = 0.0f; break; case RESOURCE_DIMENSION_TEXTURECUBEARRAY: srv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY; srv.TextureCubeArray.MipLevels = 1; srv.TextureCubeArray.NumCubes = 1; srv.TextureCubeArray.MostDetailedMip = 0; srv.TextureCubeArray.First2DArrayFace = 0; srv.TextureCubeArray.ResourceMinLODClamp = 0.0f; break; } if (srv.ViewDimension != D3D12_SRV_DIMENSION_UNKNOWN) { d3d12_descriptor_pool_alloc_handle(screen->view_pool, &screen->null_srvs[i]); screen->dev->CreateShaderResourceView(NULL, &srv, screen->null_srvs[i].cpu_handle); } } } static void d3d12_init_null_uavs(struct d3d12_screen *screen) { for (unsigned i = 0; i < RESOURCE_DIMENSION_COUNT; ++i) { D3D12_UNORDERED_ACCESS_VIEW_DESC uav = {}; uav.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; switch (i) { case RESOURCE_DIMENSION_BUFFER: case RESOURCE_DIMENSION_UNKNOWN: uav.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; uav.Buffer.FirstElement = 0; uav.Buffer.NumElements = 0; uav.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE; uav.Buffer.StructureByteStride = 0; uav.Buffer.CounterOffsetInBytes = 0; break; case RESOURCE_DIMENSION_TEXTURE1D: uav.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE1D; uav.Texture1D.MipSlice = 0; break; case RESOURCE_DIMENSION_TEXTURE1DARRAY: uav.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE1DARRAY; uav.Texture1DArray.MipSlice = 0; uav.Texture1DArray.ArraySize = 1; uav.Texture1DArray.FirstArraySlice = 0; break; case RESOURCE_DIMENSION_TEXTURE2D: uav.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D; uav.Texture2D.MipSlice = 0; uav.Texture2D.PlaneSlice = 0; break; case RESOURCE_DIMENSION_TEXTURE2DARRAY: case RESOURCE_DIMENSION_TEXTURECUBE: case RESOURCE_DIMENSION_TEXTURECUBEARRAY: uav.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY; uav.Texture2DArray.MipSlice = 0; uav.Texture2DArray.ArraySize = 1; uav.Texture2DArray.FirstArraySlice = 0; uav.Texture2DArray.PlaneSlice = 0; break; case RESOURCE_DIMENSION_TEXTURE2DMS: case RESOURCE_DIMENSION_TEXTURE2DMSARRAY: break; case RESOURCE_DIMENSION_TEXTURE3D: uav.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D; uav.Texture3D.MipSlice = 0; uav.Texture3D.FirstWSlice = 0; uav.Texture3D.WSize = 1; break; } if (uav.ViewDimension != D3D12_UAV_DIMENSION_UNKNOWN) { d3d12_descriptor_pool_alloc_handle(screen->view_pool, &screen->null_uavs[i]); screen->dev->CreateUnorderedAccessView(NULL, NULL, &uav, screen->null_uavs[i].cpu_handle); } } } static void d3d12_init_null_rtv(struct d3d12_screen *screen) { D3D12_RENDER_TARGET_VIEW_DESC rtv = {}; rtv.Format = DXGI_FORMAT_R8G8B8A8_UNORM; rtv.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; rtv.Texture2D.MipSlice = 0; rtv.Texture2D.PlaneSlice = 0; d3d12_descriptor_pool_alloc_handle(screen->rtv_pool, &screen->null_rtv); screen->dev->CreateRenderTargetView(NULL, &rtv, screen->null_rtv.cpu_handle); } static void d3d12_get_adapter_luid(struct pipe_screen *pscreen, char *luid) { struct d3d12_screen *screen = d3d12_screen(pscreen); memcpy(luid, &screen->adapter_luid, PIPE_LUID_SIZE); } static void d3d12_get_device_uuid(struct pipe_screen *pscreen, char *uuid) { struct d3d12_screen *screen = d3d12_screen(pscreen); memcpy(uuid, &screen->device_uuid, PIPE_UUID_SIZE); } static void d3d12_get_driver_uuid(struct pipe_screen *pscreen, char *uuid) { struct d3d12_screen *screen = d3d12_screen(pscreen); memcpy(uuid, &screen->driver_uuid, PIPE_UUID_SIZE); } static uint32_t d3d12_get_node_mask(struct pipe_screen *pscreen) { /* This implementation doesn't support linked adapters */ return 1; } static void d3d12_create_fence_win32(struct pipe_screen *pscreen, struct pipe_fence_handle **pfence, void *handle, const void *name, enum pipe_fd_type type) { d3d12_fence_reference((struct d3d12_fence **)pfence, nullptr); if(type == PIPE_FD_TYPE_TIMELINE_SEMAPHORE) *pfence = (struct pipe_fence_handle*) d3d12_open_fence(d3d12_screen(pscreen), handle, name); } static void d3d12_set_fence_timeline_value(struct pipe_screen *pscreen, struct pipe_fence_handle *pfence, uint64_t value) { d3d12_fence(pfence)->value = value; } static uint32_t d3d12_interop_query_device_info(struct pipe_screen *pscreen, uint32_t data_size, void *data) { if (data_size < sizeof(d3d12_interop_device_info) || !data) return 0; d3d12_interop_device_info *info = (d3d12_interop_device_info *)data; struct d3d12_screen *screen = d3d12_screen(pscreen); static_assert(sizeof(info->adapter_luid) == sizeof(screen->adapter_luid), "Using uint64_t instead of Windows-specific type"); memcpy(&info->adapter_luid, &screen->adapter_luid, sizeof(screen->adapter_luid)); info->device = screen->dev; info->queue = screen->cmdqueue; return sizeof(*info); } static uint32_t d3d12_interop_export_object(struct pipe_screen *pscreen, struct pipe_resource *res, uint32_t data_size, void *data, bool *need_export_dmabuf) { if (data_size < sizeof(d3d12_interop_resource_info) || !data) return 0; d3d12_interop_resource_info *info = (d3d12_interop_resource_info *)data; info->resource = d3d12_resource_underlying(d3d12_resource(res), &info->buffer_offset); *need_export_dmabuf = false; return sizeof(*info); } static int d3d12_screen_get_fd(struct pipe_screen *pscreen) { struct d3d12_screen *screen = d3d12_screen(pscreen); struct sw_winsys *winsys = screen->winsys; if (winsys->get_fd) return winsys->get_fd(winsys); else return -1; } #ifdef _WIN32 static void* d3d12_fence_get_win32_handle(struct pipe_screen *pscreen, struct pipe_fence_handle *fence_handle, uint64_t *fence_value) { struct d3d12_screen *screen = d3d12_screen(pscreen); struct d3d12_fence* fence = (struct d3d12_fence*) fence_handle; HANDLE shared_handle = nullptr; screen->dev->CreateSharedHandle(fence->cmdqueue_fence, NULL, GENERIC_ALL, NULL, &shared_handle); if(shared_handle) *fence_value = fence->value; return (void*) shared_handle; } #endif bool d3d12_init_screen_base(struct d3d12_screen *screen, struct sw_winsys *winsys, LUID *adapter_luid) { glsl_type_singleton_init_or_ref(); d3d12_debug = debug_get_option_d3d12_debug(); screen->winsys = winsys; if (adapter_luid) screen->adapter_luid = *adapter_luid; mtx_init(&screen->descriptor_pool_mutex, mtx_plain); mtx_init(&screen->submit_mutex, mtx_plain); list_inithead(&screen->context_list); screen->context_id_count = 16; // Fill the array backwards, because we'll pop off the back to assign ids for (unsigned i = 0; i < 16; ++i) screen->context_id_list[i] = 15 - i; #ifdef HAVE_GALLIUM_D3D12_GRAPHICS d3d12_varying_cache_init(screen); mtx_init(&screen->varying_info_mutex, mtx_plain); screen->base.get_compiler_options = d3d12_get_compiler_options; #endif // HAVE_GALLIUM_D3D12_GRAPHICS slab_create_parent(&screen->transfer_pool, sizeof(struct d3d12_transfer), 16); screen->base.get_vendor = d3d12_get_vendor; screen->base.get_device_vendor = d3d12_get_device_vendor; screen->base.get_screen_fd = d3d12_screen_get_fd; screen->base.get_param = d3d12_get_param; screen->base.get_paramf = d3d12_get_paramf; screen->base.get_shader_param = d3d12_get_shader_param; screen->base.get_compute_param = d3d12_get_compute_param; screen->base.is_format_supported = d3d12_is_format_supported; screen->base.context_create = d3d12_context_create; screen->base.flush_frontbuffer = d3d12_flush_frontbuffer; screen->base.get_device_luid = d3d12_get_adapter_luid; screen->base.get_device_uuid = d3d12_get_device_uuid; screen->base.get_driver_uuid = d3d12_get_driver_uuid; screen->base.get_device_node_mask = d3d12_get_node_mask; screen->base.create_fence_win32 = d3d12_create_fence_win32; screen->base.set_fence_timeline_value = d3d12_set_fence_timeline_value; screen->base.interop_query_device_info = d3d12_interop_query_device_info; screen->base.interop_export_object = d3d12_interop_export_object; #ifdef _WIN32 screen->base.fence_get_win32_handle = d3d12_fence_get_win32_handle; #endif screen->d3d12_mod = util_dl_open( UTIL_DL_PREFIX #ifdef _GAMING_XBOX_SCARLETT "d3d12_xs" #elif defined(_GAMING_XBOX) "d3d12_x" #else "d3d12" #endif UTIL_DL_EXT ); if (!screen->d3d12_mod) { debug_printf("D3D12: failed to load D3D12.DLL\n"); return false; } return true; } #ifdef _WIN32 extern "C" IMAGE_DOS_HEADER __ImageBase; static const char * try_find_d3d12core_next_to_self(char *path, size_t path_arr_size) { uint32_t path_size = GetModuleFileNameA((HINSTANCE)&__ImageBase, path, path_arr_size); if (!path_arr_size || path_size == path_arr_size) { debug_printf("Unable to get path to self\n"); return nullptr; } auto last_slash = strrchr(path, '\\'); if (!last_slash) { debug_printf("Unable to get path to self\n"); return nullptr; } *(last_slash + 1) = '\0'; if (strcat_s(path, path_arr_size, "D3D12Core.dll") != 0) { debug_printf("Unable to get path to D3D12Core.dll next to self\n"); return nullptr; } if (GetFileAttributesA(path) == INVALID_FILE_ATTRIBUTES) { debug_printf("No D3D12Core.dll exists next to self\n"); return nullptr; } *(last_slash + 1) = '\0'; return path; } #endif #ifndef _GAMING_XBOX static ID3D12DeviceFactory * try_create_device_factory(util_dl_library *d3d12_mod) { #if defined(_WIN32) && defined(_WIN64) if (d3d12_debug & D3D12_DEBUG_PIX) { if (GetModuleHandleW(L"WinPixGpuCapturer.dll") == nullptr) { LPWSTR program_files_path = nullptr; SHGetKnownFolderPath(FOLDERID_ProgramFiles, KF_FLAG_DEFAULT, NULL, &program_files_path); auto pix_installation_path = std::filesystem::path(program_files_path) / "Microsoft PIX"; std::wstring newest_version; for (auto const &directory : std::filesystem::directory_iterator(pix_installation_path)) { if (directory.is_directory() && (newest_version.empty() || newest_version < directory.path().filename().c_str())) newest_version = directory.path().filename().wstring(); } if (newest_version.empty()) { debug_printf("D3D12: Failed to find any PIX installations\n"); } else if (!LoadLibraryW((pix_installation_path / newest_version / L"WinPixGpuCapturer.dll").c_str()) && // Try the x64 subdirectory for x64-on-arm64 !LoadLibraryW((pix_installation_path / newest_version / L"x64/WinPixGpuCapturer.dll").c_str())) { debug_printf("D3D12: Failed to load WinPixGpuCapturer.dll from %S\n", newest_version.c_str()); } } } #endif if (d3d12_debug & D3D12_DEBUG_SINGLETON) return nullptr; /* A device factory allows us to isolate things like debug layer enablement from other callers, * and can potentially even refer to a different D3D12 redist implementation from others. */ ID3D12DeviceFactory *factory = nullptr; typedef HRESULT(WINAPI *PFN_D3D12_GET_INTERFACE)(REFCLSID clsid, REFIID riid, void **ppFactory); PFN_D3D12_GET_INTERFACE D3D12GetInterface = (PFN_D3D12_GET_INTERFACE)util_dl_get_proc_address(d3d12_mod, "D3D12GetInterface"); if (!D3D12GetInterface) { debug_printf("D3D12: Failed to retrieve D3D12GetInterface"); return nullptr; } #ifdef _WIN32 /* First, try to create a device factory from a DLL-parallel D3D12Core.dll */ ID3D12SDKConfiguration *sdk_config = nullptr; if (SUCCEEDED(D3D12GetInterface(CLSID_D3D12SDKConfiguration, IID_PPV_ARGS(&sdk_config)))) { ID3D12SDKConfiguration1 *sdk_config1 = nullptr; if (SUCCEEDED(sdk_config->QueryInterface(&sdk_config1))) { char self_path[MAX_PATH]; const char *d3d12core_path = try_find_d3d12core_next_to_self(self_path, sizeof(self_path)); if (d3d12core_path) { if (SUCCEEDED(sdk_config1->CreateDeviceFactory(D3D12_PREVIEW_SDK_VERSION, d3d12core_path, IID_PPV_ARGS(&factory))) || SUCCEEDED(sdk_config1->CreateDeviceFactory(D3D12_SDK_VERSION, d3d12core_path, IID_PPV_ARGS(&factory)))) { sdk_config->Release(); sdk_config1->Release(); return factory; } } /* Nope, seems we don't have a matching D3D12Core.dll next to ourselves */ sdk_config1->Release(); } /* It's possible there's a D3D12Core.dll next to the .exe, for development/testing purposes. If so, we'll be notified * by environment variables what the relative path is and the version to use. */ const char *d3d12core_relative_path = getenv("D3D12_AGILITY_RELATIVE_PATH"); const char *d3d12core_sdk_version = getenv("D3D12_AGILITY_SDK_VERSION"); if (d3d12core_relative_path && d3d12core_sdk_version) { (void)sdk_config->SetSDKVersion(atoi(d3d12core_sdk_version), d3d12core_relative_path); } sdk_config->Release(); } #endif (void)D3D12GetInterface(CLSID_D3D12DeviceFactory, IID_PPV_ARGS(&factory)); return factory; } #endif bool d3d12_init_screen(struct d3d12_screen *screen, IUnknown *adapter) { assert(screen->base.destroy != nullptr); // Device can be imported with d3d12_create_dxcore_screen_from_d3d12_device if (!screen->dev) { #ifndef _GAMING_XBOX ID3D12DeviceFactory *factory = try_create_device_factory(screen->d3d12_mod); #if !MESA_DEBUG if (d3d12_debug & D3D12_DEBUG_DEBUG_LAYER) #endif enable_d3d12_debug_layer(screen->d3d12_mod, factory); if (d3d12_debug & D3D12_DEBUG_GPU_VALIDATOR) enable_gpu_validation(screen->d3d12_mod, factory); screen->dev = create_device(screen->d3d12_mod, adapter, factory); if (factory) factory->Release(); #else screen->dev = create_device(screen->d3d12_mod, adapter); #endif if (!screen->dev) { debug_printf("D3D12: failed to create device\n"); return false; } } screen->adapter_luid = GetAdapterLuid(screen->dev); #ifndef _GAMING_XBOX ID3D12InfoQueue *info_queue; if (SUCCEEDED(screen->dev->QueryInterface(IID_PPV_ARGS(&info_queue)))) { D3D12_MESSAGE_SEVERITY severities[] = { D3D12_MESSAGE_SEVERITY_INFO, D3D12_MESSAGE_SEVERITY_WARNING, }; D3D12_MESSAGE_ID msg_ids[] = { D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE, }; D3D12_INFO_QUEUE_FILTER NewFilter = {}; NewFilter.DenyList.NumSeverities = ARRAY_SIZE(severities); NewFilter.DenyList.pSeverityList = severities; NewFilter.DenyList.NumIDs = ARRAY_SIZE(msg_ids); NewFilter.DenyList.pIDList = msg_ids; info_queue->PushStorageFilter(&NewFilter); info_queue->Release(); } #endif /* !_GAMING_XBOX */ if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &screen->opts, sizeof(screen->opts)))) { debug_printf("D3D12: failed to get device options\n"); return false; } if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS1, &screen->opts1, sizeof(screen->opts1)))) { debug_printf("D3D12: failed to get device options\n"); return false; } if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS2, &screen->opts2, sizeof(screen->opts2)))) { debug_printf("D3D12: failed to get device options\n"); return false; } if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &screen->opts3, sizeof(screen->opts3)))) { debug_printf("D3D12: failed to get device options\n"); return false; } if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS4, &screen->opts4, sizeof(screen->opts4)))) { debug_printf("D3D12: failed to get device options\n"); return false; } screen->dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS12, &screen->opts12, sizeof(screen->opts12)); screen->dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS14, &screen->opts14, sizeof(screen->opts14)); #ifndef _GAMING_XBOX screen->dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS19, &screen->opts19, sizeof(screen->opts19)); #endif screen->architecture.NodeIndex = 0; if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_ARCHITECTURE, &screen->architecture, sizeof(screen->architecture)))) { debug_printf("D3D12: failed to get device architecture\n"); return false; } D3D12_FEATURE_DATA_FEATURE_LEVELS feature_levels; static const D3D_FEATURE_LEVEL levels[] = { D3D_FEATURE_LEVEL_1_0_GENERIC, D3D_FEATURE_LEVEL_1_0_CORE, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_12_0, D3D_FEATURE_LEVEL_12_1, }; feature_levels.NumFeatureLevels = ARRAY_SIZE(levels); feature_levels.pFeatureLevelsRequested = levels; if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS, &feature_levels, sizeof(feature_levels)))) { debug_printf("D3D12: failed to get device feature levels\n"); return false; } #ifdef HAVE_GALLIUM_D3D12_GRAPHICS screen->max_feature_level = feature_levels.MaxSupportedFeatureLevel; #else screen->max_feature_level = D3D_FEATURE_LEVEL_1_0_GENERIC; #endif // HAVE_GALLIUM_D3D12_GRAPHICS screen->queue_type = (screen->max_feature_level >= D3D_FEATURE_LEVEL_11_0) ? D3D12_COMMAND_LIST_TYPE_DIRECT : D3D12_COMMAND_LIST_TYPE_COMPUTE; #ifdef HAVE_GALLIUM_D3D12_GRAPHICS if (screen->max_feature_level >= D3D_FEATURE_LEVEL_11_0) { static const D3D_SHADER_MODEL valid_shader_models[] = { D3D_SHADER_MODEL_6_8, D3D_SHADER_MODEL_6_7, D3D_SHADER_MODEL_6_6, D3D_SHADER_MODEL_6_5, D3D_SHADER_MODEL_6_4, D3D_SHADER_MODEL_6_3, D3D_SHADER_MODEL_6_2, D3D_SHADER_MODEL_6_1, D3D_SHADER_MODEL_6_0, }; for (UINT i = 0; i < ARRAY_SIZE(valid_shader_models); ++i) { D3D12_FEATURE_DATA_SHADER_MODEL shader_model = { valid_shader_models[i] }; if (SUCCEEDED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &shader_model, sizeof(shader_model)))) { static_assert(D3D_SHADER_MODEL_6_0 == 0x60 && SHADER_MODEL_6_0 == 0x60000, "Validating math below"); static_assert(D3D_SHADER_MODEL_6_8 == 0x68 && SHADER_MODEL_6_8 == 0x60008, "Validating math below"); screen->max_shader_model = static_cast(((shader_model.HighestShaderModel & 0xf0) << 12) | (shader_model.HighestShaderModel & 0xf)); break; } } } #endif // HAVE_GALLIUM_D3D12_GRAPHICS D3D12_COMMAND_QUEUE_DESC queue_desc; queue_desc.Type = screen->queue_type; queue_desc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL; queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; queue_desc.NodeMask = 0; #ifndef _GAMING_XBOX ID3D12Device9 *device9; if (SUCCEEDED(screen->dev->QueryInterface(&device9))) { if (FAILED(device9->CreateCommandQueue1(&queue_desc, OpenGLOn12CreatorID, IID_PPV_ARGS(&screen->cmdqueue)))) return false; device9->Release(); } else #endif { if (FAILED(screen->dev->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(&screen->cmdqueue)))) return false; } if (FAILED(screen->dev->CreateFence(0, D3D12_FENCE_FLAG_SHARED, IID_PPV_ARGS(&screen->fence)))) return false; if (!d3d12_init_residency(screen)) return false; UINT64 timestamp_freq; if (FAILED(screen->cmdqueue->GetTimestampFrequency(×tamp_freq))) timestamp_freq = 10000000; screen->timestamp_multiplier = 1000000000.0f / timestamp_freq; d3d12_screen_fence_init(&screen->base); d3d12_screen_resource_init(&screen->base); #ifdef HAVE_GALLIUM_D3D12_VIDEO d3d12_screen_video_init(&screen->base); #endif struct pb_desc desc; desc.alignment = D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT; desc.usage = (pb_usage_flags)(PB_USAGE_CPU_WRITE | PB_USAGE_GPU_READ); screen->bufmgr = d3d12_bufmgr_create(screen); if (!screen->bufmgr) return false; screen->cache_bufmgr = pb_cache_manager_create(screen->bufmgr, 0xfffff, 2, 0, 512 * 1024 * 1024); if (!screen->cache_bufmgr) return false; screen->slab_cache_bufmgr = pb_cache_manager_create(screen->bufmgr, 0xfffff, 2, 0, 512 * 1024 * 1024); if (!screen->slab_cache_bufmgr) return false; screen->slab_bufmgr = pb_slab_range_manager_create(screen->slab_cache_bufmgr, 16, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT, &desc); if (!screen->slab_bufmgr) return false; screen->readback_slab_cache_bufmgr = pb_cache_manager_create(screen->bufmgr, 0xfffff, 2, 0, 512 * 1024 * 1024); if (!screen->readback_slab_cache_bufmgr) return false; desc.usage = (pb_usage_flags)(PB_USAGE_CPU_READ_WRITE | PB_USAGE_GPU_WRITE); screen->readback_slab_bufmgr = pb_slab_range_manager_create(screen->readback_slab_cache_bufmgr, 16, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT, &desc); if (!screen->readback_slab_bufmgr) return false; #ifdef HAVE_GALLIUM_D3D12_GRAPHICS if (screen->max_feature_level >= D3D_FEATURE_LEVEL_11_0) { screen->rtv_pool = d3d12_descriptor_pool_new(screen, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 64); screen->dsv_pool = d3d12_descriptor_pool_new(screen, D3D12_DESCRIPTOR_HEAP_TYPE_DSV, 64); screen->view_pool = d3d12_descriptor_pool_new(screen, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1024); if (!screen->rtv_pool || !screen->dsv_pool || !screen->view_pool) return false; d3d12_init_null_srvs(screen); d3d12_init_null_uavs(screen); d3d12_init_null_rtv(screen); screen->have_load_at_vertex = can_attribute_at_vertex(screen); screen->support_shader_images = can_shader_image_load_all_formats(screen); static constexpr uint64_t known_good_warp_version = 10ull << 48 | 22000ull << 16; bool warp_with_broken_int64 = (screen->vendor_id == HW_VENDOR_MICROSOFT && screen->driver_version < known_good_warp_version); unsigned supported_int_sizes = 32 | (screen->opts1.Int64ShaderOps && !warp_with_broken_int64 ? 64 : 0); unsigned supported_float_sizes = 32 | (screen->opts.DoublePrecisionFloatShaderOps ? 64 : 0); dxil_get_nir_compiler_options(&screen->nir_options, screen->max_shader_model, supported_int_sizes, supported_float_sizes); } #endif // HAVE_GALLIUM_D3D12_GRAPHICS #ifndef _GAMING_XBOX ID3D12Device8 *dev8; if (SUCCEEDED(screen->dev->QueryInterface(&dev8))) { dev8->Release(); screen->support_create_not_resident = true; } screen->dev->QueryInterface(&screen->dev10); #endif const char *mesa_version = "Mesa " PACKAGE_VERSION MESA_GIT_SHA1; struct mesa_sha1 sha1_ctx; uint8_t sha1[SHA1_DIGEST_LENGTH]; STATIC_ASSERT(PIPE_UUID_SIZE <= sizeof(sha1)); /* The driver UUID is used for determining sharability of images and memory * between two instances in separate processes. People who want to * share memory need to also check the device UUID or LUID so all this * needs to be is the build-id. */ _mesa_sha1_compute(mesa_version, strlen(mesa_version), sha1); memcpy(screen->driver_uuid, sha1, PIPE_UUID_SIZE); /* The device UUID uniquely identifies the given device within the machine. */ _mesa_sha1_init(&sha1_ctx); _mesa_sha1_update(&sha1_ctx, &screen->vendor_id, sizeof(screen->vendor_id)); _mesa_sha1_update(&sha1_ctx, &screen->device_id, sizeof(screen->device_id)); _mesa_sha1_update(&sha1_ctx, &screen->subsys_id, sizeof(screen->subsys_id)); _mesa_sha1_update(&sha1_ctx, &screen->revision, sizeof(screen->revision)); _mesa_sha1_final(&sha1_ctx, sha1); memcpy(screen->device_uuid, sha1, PIPE_UUID_SIZE); return true; }