• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © Microsoft Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include "d3d12_screen.h"
25 
26 #include "d3d12_bufmgr.h"
27 #include "d3d12_compiler.h"
28 #include "d3d12_context.h"
29 #include "d3d12_debug.h"
30 #include "d3d12_fence.h"
31 #ifdef HAVE_GALLIUM_D3D12_VIDEO
32 #include "d3d12_video_screen.h"
33 #endif
34 #include "d3d12_format.h"
35 #include "d3d12_interop_public.h"
36 #include "d3d12_residency.h"
37 #include "d3d12_resource.h"
38 #include "d3d12_nir_passes.h"
39 
40 #include "pipebuffer/pb_bufmgr.h"
41 #include "util/u_debug.h"
42 #include "util/u_math.h"
43 #include "util/u_memory.h"
44 #include "util/u_screen.h"
45 #include "util/u_dl.h"
46 #include "util/mesa-sha1.h"
47 
48 #include "nir.h"
49 #include "frontend/sw_winsys.h"
50 
51 #include "nir_to_dxil.h"
52 #include "git_sha1.h"
53 
54 #ifndef _GAMING_XBOX
55 #include <directx/d3d12sdklayers.h>
56 #endif
57 
58 #if defined(_WIN32) && defined(_WIN64) && !defined(_GAMING_XBOX)
59 #include <filesystem>
60 #include <shlobj.h>
61 #endif
62 
63 #include <dxguids/dxguids.h>
64 static GUID OpenGLOn12CreatorID = { 0x6bb3cd34, 0x0d19, 0x45ab, { 0x97, 0xed, 0xd7, 0x20, 0xba, 0x3d, 0xfc, 0x80 } };
65 
66 static const struct debug_named_value
67 d3d12_debug_options[] = {
68    { "verbose",      D3D12_DEBUG_VERBOSE,       NULL },
69    { "blit",         D3D12_DEBUG_BLIT,          "Trace blit and copy resource calls" },
70    { "experimental", D3D12_DEBUG_EXPERIMENTAL,  "Enable experimental shader models feature" },
71    { "dxil",         D3D12_DEBUG_DXIL,          "Dump DXIL during program compile" },
72    { "disass",       D3D12_DEBUG_DISASS,        "Dump disassambly of created DXIL shader" },
73    { "res",          D3D12_DEBUG_RESOURCE,      "Debug resources" },
74    { "debuglayer",   D3D12_DEBUG_DEBUG_LAYER,   "Enable debug layer" },
75    { "gpuvalidator", D3D12_DEBUG_GPU_VALIDATOR, "Enable GPU validator" },
76    { "singleton",    D3D12_DEBUG_SINGLETON,     "Disallow use of device factory" },
77    { "pix",          D3D12_DEBUG_PIX,           "Load WinPixGpuCaptuerer.dll" },
78    DEBUG_NAMED_VALUE_END
79 };
80 
81 DEBUG_GET_ONCE_FLAGS_OPTION(d3d12_debug, "D3D12_DEBUG", d3d12_debug_options, 0)
82 
83 uint32_t
84 d3d12_debug;
85 
86 enum {
87     HW_VENDOR_AMD                   = 0x1002,
88     HW_VENDOR_INTEL                 = 0x8086,
89     HW_VENDOR_MICROSOFT             = 0x1414,
90     HW_VENDOR_NVIDIA                = 0x10de,
91 };
92 
93 static const char *
d3d12_get_vendor(struct pipe_screen * pscreen)94 d3d12_get_vendor(struct pipe_screen *pscreen)
95 {
96    return "Microsoft Corporation";
97 }
98 
99 static const char *
d3d12_get_device_vendor(struct pipe_screen * pscreen)100 d3d12_get_device_vendor(struct pipe_screen *pscreen)
101 {
102    struct d3d12_screen* screen = d3d12_screen(pscreen);
103 
104    switch (screen->vendor_id) {
105    case HW_VENDOR_MICROSOFT:
106       return "Microsoft";
107    case HW_VENDOR_AMD:
108       return "AMD";
109    case HW_VENDOR_NVIDIA:
110       return "NVIDIA";
111    case HW_VENDOR_INTEL:
112       return "Intel";
113    default:
114       return "Unknown";
115    }
116 }
117 
118 static int
d3d12_get_video_mem(struct pipe_screen * pscreen)119 d3d12_get_video_mem(struct pipe_screen *pscreen)
120 {
121    struct d3d12_screen* screen = d3d12_screen(pscreen);
122 
123    return static_cast<int>(screen->memory_device_size_megabytes + screen->memory_system_size_megabytes);
124 }
125 
126 static int
d3d12_get_shader_param(struct pipe_screen * pscreen,enum pipe_shader_type shader,enum pipe_shader_cap param)127 d3d12_get_shader_param(struct pipe_screen *pscreen,
128                        enum pipe_shader_type shader,
129                        enum pipe_shader_cap param)
130 {
131    struct d3d12_screen *screen = d3d12_screen(pscreen);
132 
133    if (shader == PIPE_SHADER_TASK ||
134        shader == PIPE_SHADER_MESH)
135       return 0;
136 
137    switch (param) {
138    case PIPE_SHADER_CAP_MAX_INSTRUCTIONS:
139    case PIPE_SHADER_CAP_MAX_ALU_INSTRUCTIONS:
140    case PIPE_SHADER_CAP_MAX_TEX_INSTRUCTIONS:
141    case PIPE_SHADER_CAP_MAX_TEX_INDIRECTIONS:
142    case PIPE_SHADER_CAP_MAX_CONTROL_FLOW_DEPTH:
143          return INT_MAX;
144       return 0;
145 
146    case PIPE_SHADER_CAP_MAX_INPUTS:
147       switch (shader) {
148       case PIPE_SHADER_VERTEX: return D3D12_VS_INPUT_REGISTER_COUNT;
149       case PIPE_SHADER_FRAGMENT: return D3D12_PS_INPUT_REGISTER_COUNT;
150       case PIPE_SHADER_GEOMETRY: return D3D12_GS_INPUT_REGISTER_COUNT;
151       case PIPE_SHADER_TESS_CTRL: return D3D12_HS_CONTROL_POINT_PHASE_INPUT_REGISTER_COUNT;
152       case PIPE_SHADER_TESS_EVAL: return D3D12_DS_INPUT_CONTROL_POINT_REGISTER_COUNT;
153       case PIPE_SHADER_COMPUTE: return 0;
154       default: unreachable("Unexpected shader");
155       }
156       break;
157 
158    case PIPE_SHADER_CAP_MAX_OUTPUTS:
159       switch (shader) {
160       case PIPE_SHADER_VERTEX: return D3D12_VS_OUTPUT_REGISTER_COUNT;
161       case PIPE_SHADER_FRAGMENT: return D3D12_PS_OUTPUT_REGISTER_COUNT;
162       case PIPE_SHADER_GEOMETRY: return D3D12_GS_OUTPUT_REGISTER_COUNT;
163       case PIPE_SHADER_TESS_CTRL: return D3D12_HS_CONTROL_POINT_PHASE_OUTPUT_REGISTER_COUNT;
164       case PIPE_SHADER_TESS_EVAL: return D3D12_DS_OUTPUT_REGISTER_COUNT;
165       case PIPE_SHADER_COMPUTE: return 0;
166       default: unreachable("Unexpected shader");
167       }
168       break;
169 
170    case PIPE_SHADER_CAP_MAX_TEXTURE_SAMPLERS:
171       if (screen->opts.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1)
172          return 16;
173       return PIPE_MAX_SAMPLERS;
174 
175    case PIPE_SHADER_CAP_MAX_CONST_BUFFER0_SIZE:
176       return 65536;
177 
178    case PIPE_SHADER_CAP_MAX_CONST_BUFFERS:
179       if (screen->opts.ResourceBindingTier < D3D12_RESOURCE_BINDING_TIER_3)
180          return 13; /* 15 - 2 for lowered uniforms and state vars*/
181       return 15;
182 
183    case PIPE_SHADER_CAP_MAX_TEMPS:
184       return INT_MAX;
185 
186    case PIPE_SHADER_CAP_INDIRECT_TEMP_ADDR:
187    case PIPE_SHADER_CAP_SUBROUTINES:
188       return 0; /* not implemented */
189 
190    case PIPE_SHADER_CAP_INDIRECT_CONST_ADDR:
191    case PIPE_SHADER_CAP_INTEGERS:
192       return 1;
193 
194    case PIPE_SHADER_CAP_INT64_ATOMICS:
195    case PIPE_SHADER_CAP_FP16:
196       return 0; /* not implemented */
197 
198    case PIPE_SHADER_CAP_TGSI_SQRT_SUPPORTED:
199       return 0; /* not implemented */
200 
201    case PIPE_SHADER_CAP_MAX_SAMPLER_VIEWS:
202       /* Note: This is wrong, but this is the max value that
203        * TC can support to avoid overflowing an array.
204        */
205       return PIPE_MAX_SAMPLERS;
206 
207    case PIPE_SHADER_CAP_TGSI_ANY_INOUT_DECL_RANGE:
208       return 0; /* no idea */
209 
210    case PIPE_SHADER_CAP_MAX_SHADER_BUFFERS:
211       return
212          (screen->max_feature_level >= D3D_FEATURE_LEVEL_11_1 ||
213           screen->opts.ResourceBindingTier >= D3D12_RESOURCE_BINDING_TIER_3) ?
214          PIPE_MAX_SHADER_BUFFERS : D3D12_PS_CS_UAV_REGISTER_COUNT;
215 
216    case PIPE_SHADER_CAP_SUPPORTED_IRS:
217       return 1 << PIPE_SHADER_IR_NIR;
218 
219    case PIPE_SHADER_CAP_MAX_SHADER_IMAGES:
220       if (!screen->support_shader_images)
221          return 0;
222       return
223          (screen->max_feature_level >= D3D_FEATURE_LEVEL_11_1 ||
224           screen->opts.ResourceBindingTier >= D3D12_RESOURCE_BINDING_TIER_3) ?
225          PIPE_MAX_SHADER_IMAGES : D3D12_PS_CS_UAV_REGISTER_COUNT;
226 
227    case PIPE_SHADER_CAP_MAX_HW_ATOMIC_COUNTERS:
228    case PIPE_SHADER_CAP_MAX_HW_ATOMIC_COUNTER_BUFFERS:
229    case PIPE_SHADER_CAP_CONT_SUPPORTED:
230       return 0; /* not implemented */
231 
232    /* should only get here on unhandled cases */
233    default: return 0;
234    }
235 }
236 
237 static int
d3d12_get_compute_param(struct pipe_screen * pscreen,enum pipe_shader_ir ir,enum pipe_compute_cap cap,void * ret)238 d3d12_get_compute_param(struct pipe_screen *pscreen,
239                         enum pipe_shader_ir ir,
240                         enum pipe_compute_cap cap,
241                         void *ret)
242 {
243    switch (cap) {
244    case PIPE_COMPUTE_CAP_MAX_GRID_SIZE: {
245       uint64_t *grid = (uint64_t *)ret;
246       grid[0] = grid[1] = grid[2] = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION;
247       return sizeof(uint64_t) * 3;
248    }
249    case PIPE_COMPUTE_CAP_MAX_BLOCK_SIZE: {
250       uint64_t *block = (uint64_t *)ret;
251       block[0] = D3D12_CS_THREAD_GROUP_MAX_X;
252       block[1] = D3D12_CS_THREAD_GROUP_MAX_Y;
253       block[2] = D3D12_CS_THREAD_GROUP_MAX_Z;
254       return sizeof(uint64_t) * 3;
255    }
256    case PIPE_COMPUTE_CAP_MAX_VARIABLE_THREADS_PER_BLOCK:
257    case PIPE_COMPUTE_CAP_MAX_THREADS_PER_BLOCK:
258       *(uint64_t *)ret = D3D12_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP;
259       return sizeof(uint64_t);
260    case PIPE_COMPUTE_CAP_MAX_LOCAL_SIZE:
261       *(uint64_t *)ret = D3D12_CS_TGSM_REGISTER_COUNT /*DWORDs*/ * 4;
262       return sizeof(uint64_t);
263    default:
264       return 0;
265    }
266 }
267 
268 static void
d3d12_init_screen_caps(struct d3d12_screen * screen)269 d3d12_init_screen_caps(struct d3d12_screen *screen)
270 {
271    struct pipe_caps *caps = (struct pipe_caps *)&screen->base.caps;
272 
273    caps->accelerated = screen->vendor_id != HW_VENDOR_MICROSOFT ? 1 : 0;
274    caps->uma = screen->architecture.UMA;
275    caps->video_memory = d3d12_get_video_mem(&screen->base);
276 
277    if (screen->max_feature_level < D3D_FEATURE_LEVEL_11_0)
278       return;
279 
280    u_init_pipe_screen_caps(&screen->base, caps->accelerated);
281 
282    caps->npot_textures = true;
283 
284    /* D3D12 only supports dual-source blending for a single
285     * render-target. From the D3D11 functional spec (which also defines
286     * this for D3D12):
287     *
288     * "When Dual Source Color Blending is enabled, the Pixel Shader must
289     *  have only a single RenderTarget bound, at slot 0, and must output
290     *  both o0 and o1. Writing to other outputs (o2, o3 etc.) produces
291     *  undefined results for the corresponding RenderTargets, if bound
292     *  illegally."
293     *
294     * Source: https://microsoft.github.io/DirectX-Specs/d3d/archive/D3D11_3_FunctionalSpec.htm#17.6%20Dual%20Source%20Color%20Blending
295     */
296    caps->max_dual_source_render_targets = 1;
297 
298    caps->anisotropic_filter = true;
299 
300    caps->max_render_targets = D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT;
301 
302    caps->texture_swizzle = true;
303 
304    caps->max_texel_buffer_elements = 1 << D3D12_REQ_BUFFER_RESOURCE_TEXEL_COUNT_2_TO_EXP;
305 
306    caps->max_texture_2d_size = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION;
307 
308    static_assert(D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION == (1 << 11),
309                  "D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION");
310    caps->max_texture_3d_levels = 12;
311 
312    caps->max_texture_cube_levels = D3D12_REQ_MIP_LEVELS;
313 
314    caps->primitive_restart = true;
315    caps->indep_blend_enable = true;
316    caps->indep_blend_func = true;
317    caps->fragment_shader_texture_lod = true;
318    caps->fragment_shader_derivatives = true;
319    caps->quads_follow_provoking_vertex_convention = true;
320    caps->mixed_color_depth_bits = true;
321 
322    caps->vertex_input_alignment = PIPE_VERTEX_INPUT_ALIGNMENT_4BYTE;
323 
324    /* We need to do some lowering that requires a link to the sampler */
325    caps->nir_samplers_as_deref = true;
326 
327    caps->nir_images_as_deref = true;
328 
329    caps->max_texture_array_layers = D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION;
330 
331    caps->depth_clip_disable = true;
332 
333    caps->tgsi_texcoord = true;
334 
335    caps->vertex_color_unclamped = true;
336 
337    caps->glsl_feature_level = 460;
338    caps->glsl_feature_level_compatibility = 460;
339    caps->essl_feature_level = 310;
340 
341    caps->compute = true;
342 
343    caps->texture_multisample = true;
344 
345    caps->cube_map_array = true;
346 
347    caps->texture_buffer_objects = true;
348 
349    caps->texture_transfer_modes = PIPE_TEXTURE_TRANSFER_BLIT;
350 
351    caps->endianness = PIPE_ENDIAN_NATIVE; /* unsure */
352 
353    caps->max_viewports = D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
354 
355    caps->mixed_framebuffer_sizes = true;
356 
357    caps->max_texture_gather_components = 4;
358 
359    caps->fs_coord_pixel_center_half_integer = true;
360    caps->fs_coord_origin_upper_left = true;
361 
362    caps->max_vertex_attrib_stride = 2048; /* FIXME: no clue how to query this */
363 
364    caps->texture_float_linear = true;
365    caps->texture_half_float_linear = true;
366 
367    caps->shader_buffer_offset_alignment = D3D12_RAW_UAV_SRV_BYTE_ALIGNMENT;
368 
369    caps->constant_buffer_offset_alignment = D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT;
370 
371    caps->pci_group =
372    caps->pci_bus =
373    caps->pci_device =
374    caps->pci_function = 0; /* TODO: figure these out */
375 
376    caps->flatshade = false;
377    caps->alpha_test = false;
378    caps->two_sided_color = false;
379    caps->clip_planes = 0;
380 
381    caps->shader_stencil_export = screen->opts.PSSpecifiedStencilRefSupported;
382 
383    caps->seamless_cube_map = true;
384    caps->texture_query_lod = true;
385    caps->vs_instanceid = true;
386    caps->tgsi_tex_txf_lz = true;
387    caps->occlusion_query = true;
388    caps->viewport_transform_lowered = true;
389    caps->psiz_clamped = true;
390    caps->blend_equation_separate = true;
391    caps->conditional_render = true;
392    caps->conditional_render_inverted = true;
393    caps->query_timestamp = true;
394    caps->vertex_element_instance_divisor = true;
395    caps->image_store_formatted = true;
396    caps->glsl_tess_levels_as_inputs = true;
397 
398    caps->max_stream_output_buffers = D3D12_SO_BUFFER_SLOT_COUNT;
399 
400    caps->max_stream_output_separate_components =
401    caps->max_stream_output_interleaved_components = D3D12_SO_OUTPUT_COMPONENT_COUNT;
402 
403    /* Geometry shader output. */
404    caps->max_geometry_output_vertices =
405       D3D12_GS_MAX_OUTPUT_VERTEX_COUNT_ACROSS_INSTANCES;
406    caps->max_geometry_total_output_components =
407       D3D12_REQ_GS_INVOCATION_32BIT_OUTPUT_COMPONENT_LIMIT;
408 
409    /* Subtract one so that implicit position can be added */
410    caps->max_varyings = D3D12_PS_INPUT_REGISTER_COUNT - 1;
411 
412    caps->max_combined_shader_output_resources =
413       screen->max_feature_level <= D3D_FEATURE_LEVEL_11_0 ? D3D12_PS_CS_UAV_REGISTER_COUNT :
414       (screen->opts.ResourceBindingTier <= D3D12_RESOURCE_BINDING_TIER_2 ? D3D12_UAV_SLOT_COUNT : 0);
415 
416    caps->start_instance = true;
417    caps->draw_parameters = true;
418    caps->draw_indirect = true;
419    caps->multi_draw_indirect = true;
420    caps->multi_draw_indirect_params = true;
421    caps->framebuffer_no_attachment = true;
422    caps->sample_shading = true;
423    caps->stream_output_pause_resume = true;
424    caps->stream_output_interleave_buffers = true;
425    caps->int64 = true;
426    caps->doubles = true;
427    caps->device_reset_status_query = true;
428    caps->robust_buffer_access_behavior = true;
429    caps->memobj = true;
430    caps->fence_signal = true;
431    caps->timeline_semaphore_import = true;
432    caps->clip_halfz = true;
433    caps->vs_layer_viewport = true;
434    caps->copy_between_compressed_and_plain_formats = true;
435    caps->shader_array_components = true;
436    caps->texture_mirror_clamp_to_edge = true;
437    caps->query_time_elapsed = true;
438    caps->fs_fine_derivative = true;
439    caps->cull_distance = true;
440    caps->texture_query_samples = true;
441    caps->texture_barrier = true;
442    caps->gl_spirv = true;
443    caps->polygon_offset_clamp = true;
444    caps->shader_group_vote = true;
445    caps->shader_ballot = true;
446    caps->query_pipeline_statistics = true;
447    caps->query_so_overflow = true;
448 
449    caps->query_buffer_object =
450       (screen->opts3.WriteBufferImmediateSupportFlags & D3D12_COMMAND_LIST_SUPPORT_FLAG_DIRECT) != 0;
451 
452    caps->max_vertex_streams = D3D12_SO_BUFFER_SLOT_COUNT;
453 
454    /* This is asking about varyings, not total registers, so remove the 2 tess factor registers. */
455    caps->max_shader_patch_varyings = D3D12_HS_OUTPUT_PATCH_CONSTANT_REGISTER_COUNT - 2;
456 
457    /* Picking a value in line with other drivers. Without this, we can end up easily hitting OOM
458     * if an app just creates, initializes, and destroys resources without explicitly flushing. */
459    caps->max_texture_upload_memory_budget = 64 * 1024 * 1024;
460 
461    caps->sampler_view_target = screen->opts12.RelaxedFormatCastingSupported;
462 
463 #ifndef _GAMING_XBOX
464    caps->query_memory_info = true;
465 #endif
466 
467    caps->min_line_width =
468    caps->min_line_width_aa =
469    caps->min_point_size =
470    caps->min_point_size_aa = 1;
471 
472    caps->point_size_granularity =
473    caps->line_width_granularity = 0.1;
474 
475    caps->max_line_width =
476    caps->max_line_width_aa = 1.0f; /* no clue */
477 
478    caps->max_point_size =
479    caps->max_point_size_aa = D3D12_MAX_POINT_SIZE;
480 
481    caps->max_texture_anisotropy = D3D12_MAX_MAXANISOTROPY;
482 
483    caps->max_texture_lod_bias = 15.99f;
484 }
485 
486 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)487 d3d12_is_format_supported(struct pipe_screen *pscreen,
488                           enum pipe_format format,
489                           enum pipe_texture_target target,
490                           unsigned sample_count,
491                           unsigned storage_sample_count,
492                           unsigned bind)
493 {
494    struct d3d12_screen *screen = d3d12_screen(pscreen);
495 
496    if (MAX2(1, sample_count) != MAX2(1, storage_sample_count))
497       return false;
498 
499    if (target == PIPE_BUFFER) {
500       /* Replace emulated vertex element formats for the tests */
501       format = d3d12_emulated_vtx_format(format);
502    } else {
503       /* Allow 3-comp 32 bit formats only for BOs (needed for ARB_tbo_rgb32) */
504       if ((format == PIPE_FORMAT_R32G32B32_FLOAT ||
505            format == PIPE_FORMAT_R32G32B32_SINT ||
506            format == PIPE_FORMAT_R32G32B32_UINT))
507          return false;
508    }
509 
510    /* Don't advertise alpha/luminance_alpha formats because they can't be used
511     * for render targets (except A8_UNORM) and can't be emulated by R/RG formats.
512     * Let the state tracker choose an RGBA format instead. For YUV formats, we
513     * want the state tracker to lower these to individual planes. */
514    if (format != PIPE_FORMAT_A8_UNORM &&
515        (util_format_is_alpha(format) ||
516         util_format_is_luminance_alpha(format) ||
517         util_format_is_yuv(format)))
518       return false;
519 
520    if (format == PIPE_FORMAT_NONE) {
521       /* For UAV-only rendering, aka ARB_framebuffer_no_attachments */
522       switch (sample_count) {
523       case 0:
524       case 1:
525       case 4:
526       case 8:
527       case 16:
528          return true;
529       default:
530          return false;
531       }
532    }
533 
534    DXGI_FORMAT dxgi_format = d3d12_get_format(format);
535    if (dxgi_format == DXGI_FORMAT_UNKNOWN)
536       return false;
537 
538    enum D3D12_FORMAT_SUPPORT1 dim_support = D3D12_FORMAT_SUPPORT1_NONE;
539    switch (target) {
540    case PIPE_TEXTURE_1D:
541    case PIPE_TEXTURE_1D_ARRAY:
542       dim_support = D3D12_FORMAT_SUPPORT1_TEXTURE1D;
543       break;
544    case PIPE_TEXTURE_2D:
545    case PIPE_TEXTURE_RECT:
546    case PIPE_TEXTURE_2D_ARRAY:
547       dim_support = D3D12_FORMAT_SUPPORT1_TEXTURE2D;
548       break;
549    case PIPE_TEXTURE_3D:
550       dim_support = D3D12_FORMAT_SUPPORT1_TEXTURE3D;
551       break;
552    case PIPE_TEXTURE_CUBE:
553    case PIPE_TEXTURE_CUBE_ARRAY:
554       dim_support = D3D12_FORMAT_SUPPORT1_TEXTURECUBE;
555       break;
556    case PIPE_BUFFER:
557       dim_support = D3D12_FORMAT_SUPPORT1_BUFFER;
558       break;
559    default:
560       unreachable("Unknown target");
561    }
562 
563    if (bind & PIPE_BIND_DISPLAY_TARGET) {
564       enum pipe_format dt_format = format == PIPE_FORMAT_R16G16B16A16_FLOAT ? PIPE_FORMAT_R8G8B8A8_UNORM : format;
565       if (!screen->winsys->is_displaytarget_format_supported(screen->winsys, bind, dt_format))
566          return false;
567    }
568 
569    D3D12_FEATURE_DATA_FORMAT_SUPPORT fmt_info;
570    fmt_info.Format = d3d12_get_resource_rt_format(format);
571    if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT,
572                                                &fmt_info, sizeof(fmt_info))))
573       return false;
574 
575    if (!(fmt_info.Support1 & dim_support))
576       return false;
577 
578    if (target == PIPE_BUFFER) {
579       if (bind & PIPE_BIND_VERTEX_BUFFER &&
580           !(fmt_info.Support1 & D3D12_FORMAT_SUPPORT1_IA_VERTEX_BUFFER))
581          return false;
582 
583       if (bind & PIPE_BIND_INDEX_BUFFER) {
584          if (format != PIPE_FORMAT_R16_UINT &&
585              format != PIPE_FORMAT_R32_UINT)
586             return false;
587       }
588 
589       if (sample_count > 0)
590          return false;
591    } else {
592       /* all other targets are texture-targets */
593       if (bind & PIPE_BIND_RENDER_TARGET &&
594           !(fmt_info.Support1 & D3D12_FORMAT_SUPPORT1_RENDER_TARGET))
595          return false;
596 
597       if (bind & PIPE_BIND_BLENDABLE &&
598          !(fmt_info.Support1 & D3D12_FORMAT_SUPPORT1_BLENDABLE))
599          return false;
600 
601       if (bind & PIPE_BIND_SHADER_IMAGE &&
602          (fmt_info.Support2 & (D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD | D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE)) !=
603             (D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD | D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE))
604          return false;
605 
606       D3D12_FEATURE_DATA_FORMAT_SUPPORT fmt_info_sv;
607       if (util_format_is_depth_or_stencil(format)) {
608          fmt_info_sv.Format = d3d12_get_resource_srv_format(format, target);
609          if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT,
610                                                      &fmt_info_sv, sizeof(fmt_info_sv))))
611             return false;
612       } else
613          fmt_info_sv = fmt_info;
614 
615       if (bind & PIPE_BIND_DEPTH_STENCIL &&
616           !(fmt_info.Support1 & D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL))
617             return false;
618 
619       if (sample_count > 0) {
620          if (!(fmt_info_sv.Support1 & D3D12_FORMAT_SUPPORT1_MULTISAMPLE_LOAD))
621             return false;
622 
623          if (!util_is_power_of_two_nonzero(sample_count))
624             return false;
625 
626          if (bind & PIPE_BIND_SHADER_IMAGE)
627             return false;
628 
629          D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS ms_info = {};
630          ms_info.Format = dxgi_format;
631          ms_info.SampleCount = sample_count;
632          if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,
633                                                      &ms_info,
634                                                      sizeof(ms_info))) ||
635              !ms_info.NumQualityLevels)
636             return false;
637       }
638    }
639    return true;
640 }
641 
642 void
d3d12_deinit_screen(struct d3d12_screen * screen)643 d3d12_deinit_screen(struct d3d12_screen *screen)
644 {
645 #ifdef HAVE_GALLIUM_D3D12_GRAPHICS
646    if (screen->max_feature_level >= D3D_FEATURE_LEVEL_11_0) {
647       if (screen->rtv_pool) {
648          d3d12_descriptor_pool_free(screen->rtv_pool);
649          screen->rtv_pool = nullptr;
650       }
651       if (screen->dsv_pool) {
652          d3d12_descriptor_pool_free(screen->dsv_pool);
653          screen->dsv_pool = nullptr;
654       }
655       if (screen->view_pool) {
656          d3d12_descriptor_pool_free(screen->view_pool);
657          screen->view_pool = nullptr;
658       }
659    }
660 #endif // HAVE_GALLIUM_D3D12_GRAPHICS
661    if (screen->readback_slab_bufmgr) {
662       screen->readback_slab_bufmgr->destroy(screen->readback_slab_bufmgr);
663       screen->readback_slab_bufmgr = nullptr;
664    }
665    if (screen->slab_bufmgr) {
666       screen->slab_bufmgr->destroy(screen->slab_bufmgr);
667       screen->slab_bufmgr = nullptr;
668    }
669    if (screen->cache_bufmgr) {
670       screen->cache_bufmgr->destroy(screen->cache_bufmgr);
671       screen->cache_bufmgr = nullptr;
672    }
673    if (screen->slab_cache_bufmgr) {
674       screen->slab_cache_bufmgr->destroy(screen->slab_cache_bufmgr);
675       screen->slab_cache_bufmgr = nullptr;
676    }
677    if (screen->readback_slab_cache_bufmgr) {
678       screen->readback_slab_cache_bufmgr->destroy(screen->readback_slab_cache_bufmgr);
679       screen->readback_slab_cache_bufmgr = nullptr;
680    }
681    if (screen->bufmgr) {
682       screen->bufmgr->destroy(screen->bufmgr);
683       screen->bufmgr = nullptr;
684    }
685    d3d12_deinit_residency(screen);
686    if (screen->fence) {
687       screen->fence->Release();
688       screen->fence = nullptr;
689    }
690    if (screen->cmdqueue) {
691       screen->cmdqueue->Release();
692       screen->cmdqueue = nullptr;
693    }
694    if (screen->dev10) {
695       screen->dev10->Release();
696       screen->dev10 = nullptr;
697    }
698    if (screen->dev) {
699       screen->dev->Release();
700       screen->dev = nullptr;
701    }
702 }
703 
704 void
d3d12_destroy_screen(struct d3d12_screen * screen)705 d3d12_destroy_screen(struct d3d12_screen *screen)
706 {
707    slab_destroy_parent(&screen->transfer_pool);
708    mtx_destroy(&screen->submit_mutex);
709    mtx_destroy(&screen->descriptor_pool_mutex);
710 
711 #ifdef HAVE_GALLIUM_D3D12_GRAPHICS
712    d3d12_varying_cache_destroy(screen);
713    mtx_destroy(&screen->varying_info_mutex);
714 #endif // HAVE_GALLIUM_D3D12_GRAPHICS
715 
716    if (screen->d3d12_mod)
717       util_dl_close(screen->d3d12_mod);
718    glsl_type_singleton_decref();
719    FREE(screen);
720 }
721 
722 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)723 d3d12_flush_frontbuffer(struct pipe_screen * pscreen,
724                         struct pipe_context *pctx,
725                         struct pipe_resource *pres,
726                         unsigned level, unsigned layer,
727                         void *winsys_drawable_handle,
728                         unsigned nboxes,
729                         struct pipe_box *sub_box)
730 {
731    struct d3d12_screen *screen = d3d12_screen(pscreen);
732    struct sw_winsys *winsys = screen->winsys;
733    struct d3d12_resource *res = d3d12_resource(pres);
734 
735    if (!winsys || !pctx)
736      return;
737 
738    assert(res->dt || res->dt_proxy);
739    if (res->dt_proxy) {
740      struct pipe_blit_info blit;
741 
742      memset(&blit, 0, sizeof(blit));
743      blit.dst.resource = res->dt_proxy;
744      blit.dst.box.width = blit.dst.resource->width0;
745      blit.dst.box.height = blit.dst.resource->height0;
746      blit.dst.box.depth = 1;
747      blit.dst.format = blit.dst.resource->format;
748      blit.src.resource = pres;
749      blit.src.box.width = blit.src.resource->width0;
750      blit.src.box.height = blit.src.resource->height0;
751      blit.src.box.depth = 1;
752      blit.src.format = blit.src.resource->format;
753      blit.mask = PIPE_MASK_RGBA;
754      blit.filter = PIPE_TEX_FILTER_NEAREST;
755 
756      pctx->blit(pctx, &blit);
757      pres = res->dt_proxy;
758      res = d3d12_resource(pres);
759    }
760 
761    assert(res->dt);
762    void *map = winsys->displaytarget_map(winsys, res->dt, 0);
763 
764    if (map) {
765       pctx = threaded_context_unwrap_sync(pctx);
766       pipe_transfer *transfer = nullptr;
767       void *res_map = pipe_texture_map(pctx, pres, level, layer, PIPE_MAP_READ, 0, 0,
768                                         u_minify(pres->width0, level),
769                                         u_minify(pres->height0, level),
770                                         &transfer);
771       if (res_map) {
772          util_copy_rect((uint8_t*)map, pres->format, res->dt_stride, 0, 0,
773                         transfer->box.width, transfer->box.height,
774                         (const uint8_t*)res_map, transfer->stride, 0, 0);
775          pipe_texture_unmap(pctx, transfer);
776       }
777       winsys->displaytarget_unmap(winsys, res->dt);
778    }
779 
780 #if defined(_WIN32) && !defined(_GAMING_XBOX) && defined(HAVE_GALLIUM_D3D12_GRAPHICS)
781    // WindowFromDC is Windows-only, and this method requires an HWND, so only use it on Windows
782    ID3D12SharingContract *sharing_contract;
783    if (SUCCEEDED(screen->cmdqueue->QueryInterface(IID_PPV_ARGS(&sharing_contract)))) {
784       ID3D12Resource *d3d12_res = d3d12_resource_resource(res);
785       sharing_contract->Present(d3d12_res, 0, WindowFromDC((HDC)winsys_drawable_handle));
786       sharing_contract->Release();
787    }
788 #endif
789 
790    winsys->displaytarget_display(winsys, res->dt, winsys_drawable_handle, nboxes, sub_box);
791 }
792 
793 #ifndef _GAMING_XBOX
794 static ID3D12Debug *
get_debug_interface(util_dl_library * d3d12_mod,ID3D12DeviceFactory * factory)795 get_debug_interface(util_dl_library *d3d12_mod, ID3D12DeviceFactory *factory)
796 {
797    ID3D12Debug *debug = nullptr;
798    if (factory) {
799       factory->GetConfigurationInterface(CLSID_D3D12Debug, IID_PPV_ARGS(&debug));
800       return debug;
801    }
802 
803    typedef HRESULT(WINAPI *PFN_D3D12_GET_DEBUG_INTERFACE)(REFIID riid, void **ppFactory);
804    PFN_D3D12_GET_DEBUG_INTERFACE D3D12GetDebugInterface;
805 
806    D3D12GetDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)util_dl_get_proc_address(d3d12_mod, "D3D12GetDebugInterface");
807    if (!D3D12GetDebugInterface) {
808       debug_printf("D3D12: failed to load D3D12GetDebugInterface from D3D12.DLL\n");
809       return NULL;
810    }
811 
812    if (FAILED(D3D12GetDebugInterface(IID_PPV_ARGS(&debug)))) {
813       debug_printf("D3D12: D3D12GetDebugInterface failed\n");
814       return NULL;
815    }
816 
817    return debug;
818 }
819 
820 static void
enable_d3d12_debug_layer(util_dl_library * d3d12_mod,ID3D12DeviceFactory * factory)821 enable_d3d12_debug_layer(util_dl_library *d3d12_mod, ID3D12DeviceFactory *factory)
822 {
823    ID3D12Debug *debug = get_debug_interface(d3d12_mod, factory);
824    if (debug) {
825       debug->EnableDebugLayer();
826       debug->Release();
827    }
828 }
829 
830 static void
enable_gpu_validation(util_dl_library * d3d12_mod,ID3D12DeviceFactory * factory)831 enable_gpu_validation(util_dl_library *d3d12_mod, ID3D12DeviceFactory *factory)
832 {
833    ID3D12Debug *debug = get_debug_interface(d3d12_mod, factory);
834    ID3D12Debug3 *debug3;
835    if (debug) {
836       if (SUCCEEDED(debug->QueryInterface(IID_PPV_ARGS(&debug3)))) {
837          debug3->SetEnableGPUBasedValidation(true);
838          debug3->Release();
839       }
840       debug->Release();
841    }
842 }
843 #endif
844 
845 #ifdef _GAMING_XBOX
846 
847 static ID3D12Device3 *
create_device(util_dl_library * d3d12_mod,IUnknown * adapter)848 create_device(util_dl_library *d3d12_mod, IUnknown *adapter)
849 {
850    D3D12XBOX_PROCESS_DEBUG_FLAGS debugFlags =
851       D3D12XBOX_PROCESS_DEBUG_FLAG_ENABLE_COMMON_STATE_PROMOTION; /* For compatibility with desktop D3D12 */
852 
853    if (d3d12_debug & D3D12_DEBUG_EXPERIMENTAL) {
854       debug_printf("D3D12: experimental shader models are not supported on GDKX\n");
855       return nullptr;
856    }
857 
858    if (d3d12_debug & D3D12_DEBUG_GPU_VALIDATOR) {
859       debug_printf("D3D12: gpu validation is not supported on GDKX\n"); /* FIXME: Is this right? */
860       return nullptr;
861    }
862 
863    if (d3d12_debug & D3D12_DEBUG_DEBUG_LAYER)
864       debugFlags |= D3D12XBOX_PROCESS_DEBUG_FLAG_DEBUG;
865 
866    D3D12XBOX_CREATE_DEVICE_PARAMETERS params = {};
867    params.Version = D3D12_SDK_VERSION;
868    params.ProcessDebugFlags = debugFlags;
869    params.GraphicsCommandQueueRingSizeBytes = D3D12XBOX_DEFAULT_SIZE_BYTES;
870    params.GraphicsScratchMemorySizeBytes = D3D12XBOX_DEFAULT_SIZE_BYTES;
871    params.ComputeScratchMemorySizeBytes = D3D12XBOX_DEFAULT_SIZE_BYTES;
872 
873    ID3D12Device3 *dev = nullptr;
874 
875    typedef HRESULT(WINAPI * PFN_D3D12XBOXCREATEDEVICE)(IGraphicsUnknown *, const D3D12XBOX_CREATE_DEVICE_PARAMETERS *, REFIID, void **);
876    PFN_D3D12XBOXCREATEDEVICE D3D12XboxCreateDevice =
877       (PFN_D3D12XBOXCREATEDEVICE) util_dl_get_proc_address(d3d12_mod, "D3D12XboxCreateDevice");
878    if (!D3D12XboxCreateDevice) {
879       debug_printf("D3D12: failed to load D3D12XboxCreateDevice from D3D12 DLL\n");
880       return NULL;
881    }
882    if (FAILED(D3D12XboxCreateDevice((IGraphicsUnknown*) adapter, &params, IID_PPV_ARGS(&dev))))
883       debug_printf("D3D12: D3D12XboxCreateDevice failed\n");
884 
885    return dev;
886 }
887 
888 #else
889 
890 static ID3D12Device3 *
create_device(util_dl_library * d3d12_mod,IUnknown * adapter,ID3D12DeviceFactory * factory)891 create_device(util_dl_library *d3d12_mod, IUnknown *adapter, ID3D12DeviceFactory *factory)
892 {
893 
894 #ifdef _WIN32
895    if (d3d12_debug & D3D12_DEBUG_EXPERIMENTAL)
896 #endif
897    {
898       if (factory) {
899          if (FAILED(factory->EnableExperimentalFeatures(1, &D3D12ExperimentalShaderModels, nullptr, nullptr))) {
900             debug_printf("D3D12: failed to enable experimental shader models\n");
901             return nullptr;
902          }
903       } else {
904          typedef HRESULT(WINAPI *PFN_D3D12ENABLEEXPERIMENTALFEATURES)(UINT, const IID*, void*, UINT*);
905          PFN_D3D12ENABLEEXPERIMENTALFEATURES D3D12EnableExperimentalFeatures =
906             (PFN_D3D12ENABLEEXPERIMENTALFEATURES)util_dl_get_proc_address(d3d12_mod, "D3D12EnableExperimentalFeatures");
907 
908          if (!D3D12EnableExperimentalFeatures ||
909              FAILED(D3D12EnableExperimentalFeatures(1, &D3D12ExperimentalShaderModels, NULL, NULL))) {
910             debug_printf("D3D12: failed to enable experimental shader models\n");
911             return nullptr;
912          }
913       }
914    }
915 
916    ID3D12Device3 *dev = nullptr;
917    if (factory) {
918       factory->SetFlags(D3D12_DEVICE_FACTORY_FLAG_ALLOW_RETURNING_EXISTING_DEVICE |
919          D3D12_DEVICE_FACTORY_FLAG_ALLOW_RETURNING_INCOMPATIBLE_EXISTING_DEVICE);
920       /* Fallback to D3D_FEATURE_LEVEL_11_0 for D3D12 versions without generic support */
921       if (FAILED(factory->CreateDevice(adapter, D3D_FEATURE_LEVEL_1_0_GENERIC, IID_PPV_ARGS(&dev))))
922          if (FAILED(factory->CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&dev))))
923             debug_printf("D3D12: D3D12CreateDevice failed\n");
924    } else {
925       typedef HRESULT(WINAPI *PFN_D3D12CREATEDEVICE)(IUnknown*, D3D_FEATURE_LEVEL, REFIID, void**);
926       PFN_D3D12CREATEDEVICE D3D12CreateDevice = (PFN_D3D12CREATEDEVICE)util_dl_get_proc_address(d3d12_mod, "D3D12CreateDevice");
927       if (!D3D12CreateDevice) {
928          debug_printf("D3D12: failed to load D3D12CreateDevice from D3D12.DLL\n");
929          return NULL;
930       }
931       /* Fallback to D3D_FEATURE_LEVEL_11_0 for D3D12 versions without generic support */
932       if (FAILED(D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_1_0_GENERIC, IID_PPV_ARGS(&dev))))
933          if (FAILED(D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&dev))))
934             debug_printf("D3D12: D3D12CreateDevice failed\n");
935    }
936 
937    return dev;
938 }
939 
940 #endif /* _GAMING_XBOX */
941 
942 static bool
can_attribute_at_vertex(struct d3d12_screen * screen)943 can_attribute_at_vertex(struct d3d12_screen *screen)
944 {
945    switch (screen->vendor_id)  {
946    case HW_VENDOR_MICROSOFT:
947       return true;
948    default:
949       return screen->opts3.BarycentricsSupported;
950    }
951 }
952 
953 static bool
can_shader_image_load_all_formats(struct d3d12_screen * screen)954 can_shader_image_load_all_formats(struct d3d12_screen *screen)
955 {
956    if (!screen->opts.TypedUAVLoadAdditionalFormats)
957       return false;
958 
959    /* All of these are required by ARB_shader_image_load_store */
960    static const DXGI_FORMAT additional_formats[] = {
961       DXGI_FORMAT_R16G16B16A16_UNORM,
962       DXGI_FORMAT_R16G16B16A16_SNORM,
963       DXGI_FORMAT_R32G32_FLOAT,
964       DXGI_FORMAT_R32G32_UINT,
965       DXGI_FORMAT_R32G32_SINT,
966       DXGI_FORMAT_R10G10B10A2_UNORM,
967       DXGI_FORMAT_R10G10B10A2_UINT,
968       DXGI_FORMAT_R11G11B10_FLOAT,
969       DXGI_FORMAT_R8G8B8A8_SNORM,
970       DXGI_FORMAT_R16G16_FLOAT,
971       DXGI_FORMAT_R16G16_UNORM,
972       DXGI_FORMAT_R16G16_UINT,
973       DXGI_FORMAT_R16G16_SNORM,
974       DXGI_FORMAT_R16G16_SINT,
975       DXGI_FORMAT_R8G8_UNORM,
976       DXGI_FORMAT_R8G8_UINT,
977       DXGI_FORMAT_R8G8_SNORM,
978       DXGI_FORMAT_R8G8_SINT,
979       DXGI_FORMAT_R16_UNORM,
980       DXGI_FORMAT_R16_SNORM,
981       DXGI_FORMAT_R8_SNORM,
982    };
983 
984    for (unsigned i = 0; i < ARRAY_SIZE(additional_formats); ++i) {
985       D3D12_FEATURE_DATA_FORMAT_SUPPORT support = { additional_formats[i] };
986       if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &support, sizeof(support))) ||
987          (support.Support1 & D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW) == D3D12_FORMAT_SUPPORT1_NONE ||
988          (support.Support2 & (D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD | D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE)) !=
989             (D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD | D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE))
990          return false;
991    }
992 
993    return true;
994 }
995 
996 static void
d3d12_init_null_srvs(struct d3d12_screen * screen)997 d3d12_init_null_srvs(struct d3d12_screen *screen)
998 {
999    for (unsigned i = 0; i < RESOURCE_DIMENSION_COUNT; ++i) {
1000       D3D12_SHADER_RESOURCE_VIEW_DESC srv = {};
1001 
1002       srv.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
1003       srv.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
1004       switch (i) {
1005       case RESOURCE_DIMENSION_BUFFER:
1006       case RESOURCE_DIMENSION_UNKNOWN:
1007          srv.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
1008          srv.Buffer.FirstElement = 0;
1009          srv.Buffer.NumElements = 0;
1010          srv.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE;
1011          srv.Buffer.StructureByteStride = 0;
1012          break;
1013       case RESOURCE_DIMENSION_TEXTURE1D:
1014          srv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D;
1015          srv.Texture1D.MipLevels = 1;
1016          srv.Texture1D.MostDetailedMip = 0;
1017          srv.Texture1D.ResourceMinLODClamp = 0.0f;
1018          break;
1019       case RESOURCE_DIMENSION_TEXTURE1DARRAY:
1020          srv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY;
1021          srv.Texture1DArray.MipLevels = 1;
1022          srv.Texture1DArray.ArraySize = 1;
1023          srv.Texture1DArray.MostDetailedMip = 0;
1024          srv.Texture1DArray.FirstArraySlice = 0;
1025          srv.Texture1DArray.ResourceMinLODClamp = 0.0f;
1026          break;
1027       case RESOURCE_DIMENSION_TEXTURE2D:
1028          srv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
1029          srv.Texture2D.MipLevels = 1;
1030          srv.Texture2D.MostDetailedMip = 0;
1031          srv.Texture2D.PlaneSlice = 0;
1032          srv.Texture2D.ResourceMinLODClamp = 0.0f;
1033          break;
1034       case RESOURCE_DIMENSION_TEXTURE2DARRAY:
1035          srv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
1036          srv.Texture2DArray.MipLevels = 1;
1037          srv.Texture2DArray.ArraySize = 1;
1038          srv.Texture2DArray.MostDetailedMip = 0;
1039          srv.Texture2DArray.FirstArraySlice = 0;
1040          srv.Texture2DArray.PlaneSlice = 0;
1041          srv.Texture2DArray.ResourceMinLODClamp = 0.0f;
1042          break;
1043       case RESOURCE_DIMENSION_TEXTURE2DMS:
1044          srv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS;
1045          break;
1046       case RESOURCE_DIMENSION_TEXTURE2DMSARRAY:
1047          srv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY;
1048          srv.Texture2DMSArray.ArraySize = 1;
1049          srv.Texture2DMSArray.FirstArraySlice = 0;
1050          break;
1051       case RESOURCE_DIMENSION_TEXTURE3D:
1052          srv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
1053          srv.Texture3D.MipLevels = 1;
1054          srv.Texture3D.MostDetailedMip = 0;
1055          srv.Texture3D.ResourceMinLODClamp = 0.0f;
1056          break;
1057       case RESOURCE_DIMENSION_TEXTURECUBE:
1058          srv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
1059          srv.TextureCube.MipLevels = 1;
1060          srv.TextureCube.MostDetailedMip = 0;
1061          srv.TextureCube.ResourceMinLODClamp = 0.0f;
1062          break;
1063       case RESOURCE_DIMENSION_TEXTURECUBEARRAY:
1064          srv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY;
1065          srv.TextureCubeArray.MipLevels = 1;
1066          srv.TextureCubeArray.NumCubes = 1;
1067          srv.TextureCubeArray.MostDetailedMip = 0;
1068          srv.TextureCubeArray.First2DArrayFace = 0;
1069          srv.TextureCubeArray.ResourceMinLODClamp = 0.0f;
1070          break;
1071       }
1072 
1073       if (srv.ViewDimension != D3D12_SRV_DIMENSION_UNKNOWN)
1074       {
1075          d3d12_descriptor_pool_alloc_handle(screen->view_pool, &screen->null_srvs[i]);
1076          screen->dev->CreateShaderResourceView(NULL, &srv, screen->null_srvs[i].cpu_handle);
1077       }
1078    }
1079 }
1080 
1081 static void
d3d12_init_null_uavs(struct d3d12_screen * screen)1082 d3d12_init_null_uavs(struct d3d12_screen *screen)
1083 {
1084    for (unsigned i = 0; i < RESOURCE_DIMENSION_COUNT; ++i) {
1085       D3D12_UNORDERED_ACCESS_VIEW_DESC uav = {};
1086 
1087       uav.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
1088       switch (i) {
1089       case RESOURCE_DIMENSION_BUFFER:
1090       case RESOURCE_DIMENSION_UNKNOWN:
1091          uav.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
1092          uav.Buffer.FirstElement = 0;
1093          uav.Buffer.NumElements = 0;
1094          uav.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE;
1095          uav.Buffer.StructureByteStride = 0;
1096          uav.Buffer.CounterOffsetInBytes = 0;
1097          break;
1098       case RESOURCE_DIMENSION_TEXTURE1D:
1099          uav.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE1D;
1100          uav.Texture1D.MipSlice = 0;
1101          break;
1102       case RESOURCE_DIMENSION_TEXTURE1DARRAY:
1103          uav.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE1DARRAY;
1104          uav.Texture1DArray.MipSlice = 0;
1105          uav.Texture1DArray.ArraySize = 1;
1106          uav.Texture1DArray.FirstArraySlice = 0;
1107          break;
1108       case RESOURCE_DIMENSION_TEXTURE2D:
1109          uav.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
1110          uav.Texture2D.MipSlice = 0;
1111          uav.Texture2D.PlaneSlice = 0;
1112          break;
1113       case RESOURCE_DIMENSION_TEXTURE2DARRAY:
1114       case RESOURCE_DIMENSION_TEXTURECUBE:
1115       case RESOURCE_DIMENSION_TEXTURECUBEARRAY:
1116          uav.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1117          uav.Texture2DArray.MipSlice = 0;
1118          uav.Texture2DArray.ArraySize = 1;
1119          uav.Texture2DArray.FirstArraySlice = 0;
1120          uav.Texture2DArray.PlaneSlice = 0;
1121          break;
1122       case RESOURCE_DIMENSION_TEXTURE2DMS:
1123       case RESOURCE_DIMENSION_TEXTURE2DMSARRAY:
1124          break;
1125       case RESOURCE_DIMENSION_TEXTURE3D:
1126          uav.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
1127          uav.Texture3D.MipSlice = 0;
1128          uav.Texture3D.FirstWSlice = 0;
1129          uav.Texture3D.WSize = 1;
1130          break;
1131       }
1132 
1133       if (uav.ViewDimension != D3D12_UAV_DIMENSION_UNKNOWN)
1134       {
1135          d3d12_descriptor_pool_alloc_handle(screen->view_pool, &screen->null_uavs[i]);
1136          screen->dev->CreateUnorderedAccessView(NULL, NULL, &uav, screen->null_uavs[i].cpu_handle);
1137       }
1138    }
1139 }
1140 
1141 static void
d3d12_init_null_rtv(struct d3d12_screen * screen)1142 d3d12_init_null_rtv(struct d3d12_screen *screen)
1143 {
1144    D3D12_RENDER_TARGET_VIEW_DESC rtv = {};
1145    rtv.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
1146    rtv.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
1147    rtv.Texture2D.MipSlice = 0;
1148    rtv.Texture2D.PlaneSlice = 0;
1149    d3d12_descriptor_pool_alloc_handle(screen->rtv_pool, &screen->null_rtv);
1150    screen->dev->CreateRenderTargetView(NULL, &rtv, screen->null_rtv.cpu_handle);
1151 }
1152 
1153 static void
d3d12_get_adapter_luid(struct pipe_screen * pscreen,char * luid)1154 d3d12_get_adapter_luid(struct pipe_screen *pscreen, char *luid)
1155 {
1156    struct d3d12_screen *screen = d3d12_screen(pscreen);
1157    memcpy(luid, &screen->adapter_luid, PIPE_LUID_SIZE);
1158 }
1159 
1160 static void
d3d12_get_device_uuid(struct pipe_screen * pscreen,char * uuid)1161 d3d12_get_device_uuid(struct pipe_screen *pscreen, char *uuid)
1162 {
1163    struct d3d12_screen *screen = d3d12_screen(pscreen);
1164    memcpy(uuid, &screen->device_uuid, PIPE_UUID_SIZE);
1165 }
1166 
1167 static void
d3d12_get_driver_uuid(struct pipe_screen * pscreen,char * uuid)1168 d3d12_get_driver_uuid(struct pipe_screen *pscreen, char *uuid)
1169 {
1170    struct d3d12_screen *screen = d3d12_screen(pscreen);
1171    memcpy(uuid, &screen->driver_uuid, PIPE_UUID_SIZE);
1172 }
1173 
1174 static uint32_t
d3d12_get_node_mask(struct pipe_screen * pscreen)1175 d3d12_get_node_mask(struct pipe_screen *pscreen)
1176 {
1177    /* This implementation doesn't support linked adapters */
1178    return 1;
1179 }
1180 
1181 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)1182 d3d12_create_fence_win32(struct pipe_screen *pscreen, struct pipe_fence_handle **pfence, void *handle, const void *name, enum pipe_fd_type type)
1183 {
1184    d3d12_fence_reference((struct d3d12_fence **)pfence, nullptr);
1185    if(type == PIPE_FD_TYPE_TIMELINE_SEMAPHORE)
1186       *pfence = (struct pipe_fence_handle*) d3d12_open_fence(d3d12_screen(pscreen), handle, name);
1187 }
1188 
1189 static void
d3d12_set_fence_timeline_value(struct pipe_screen * pscreen,struct pipe_fence_handle * pfence,uint64_t value)1190 d3d12_set_fence_timeline_value(struct pipe_screen *pscreen, struct pipe_fence_handle *pfence, uint64_t value)
1191 {
1192    d3d12_fence(pfence)->value = value;
1193 }
1194 
1195 static uint32_t
d3d12_interop_query_device_info(struct pipe_screen * pscreen,uint32_t data_size,void * data)1196 d3d12_interop_query_device_info(struct pipe_screen *pscreen, uint32_t data_size, void *data)
1197 {
1198    if (data_size < sizeof(d3d12_interop_device_info) || !data)
1199       return 0;
1200    d3d12_interop_device_info *info = (d3d12_interop_device_info *)data;
1201    struct d3d12_screen *screen = d3d12_screen(pscreen);
1202 
1203    static_assert(sizeof(info->adapter_luid) == sizeof(screen->adapter_luid),
1204                  "Using uint64_t instead of Windows-specific type");
1205    memcpy(&info->adapter_luid, &screen->adapter_luid, sizeof(screen->adapter_luid));
1206    info->device = screen->dev;
1207    info->queue = screen->cmdqueue;
1208    return sizeof(*info);
1209 }
1210 
1211 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)1212 d3d12_interop_export_object(struct pipe_screen *pscreen, struct pipe_resource *res,
1213                               uint32_t data_size, void *data, bool *need_export_dmabuf)
1214 {
1215    if (data_size < sizeof(d3d12_interop_resource_info) || !data)
1216       return 0;
1217    d3d12_interop_resource_info *info = (d3d12_interop_resource_info *)data;
1218 
1219    info->resource = d3d12_resource_underlying(d3d12_resource(res), &info->buffer_offset);
1220    *need_export_dmabuf = false;
1221    return sizeof(*info);
1222 }
1223 
1224 static int
d3d12_screen_get_fd(struct pipe_screen * pscreen)1225 d3d12_screen_get_fd(struct pipe_screen *pscreen)
1226 {
1227    struct d3d12_screen *screen = d3d12_screen(pscreen);
1228    struct sw_winsys *winsys = screen->winsys;
1229 
1230    if (winsys->get_fd)
1231       return winsys->get_fd(winsys);
1232    else
1233       return -1;
1234 }
1235 
1236 #ifdef _WIN32
d3d12_fence_get_win32_handle(struct pipe_screen * pscreen,struct pipe_fence_handle * fence_handle,uint64_t * fence_value)1237 static void* d3d12_fence_get_win32_handle(struct pipe_screen *pscreen,
1238                                           struct pipe_fence_handle *fence_handle,
1239                                           uint64_t *fence_value)
1240 {
1241    struct d3d12_screen *screen = d3d12_screen(pscreen);
1242    struct d3d12_fence* fence = (struct d3d12_fence*) fence_handle;
1243    HANDLE shared_handle = nullptr;
1244    screen->dev->CreateSharedHandle(fence->cmdqueue_fence,
1245                                    NULL,
1246                                    GENERIC_ALL,
1247                                    NULL,
1248                                    &shared_handle);
1249    if(shared_handle)
1250       *fence_value = fence->value;
1251 
1252    return (void*) shared_handle;
1253 }
1254 #endif
1255 
1256 static void
d3d12_query_memory_info(struct pipe_screen * pscreen,struct pipe_memory_info * info)1257 d3d12_query_memory_info(struct pipe_screen *pscreen, struct pipe_memory_info *info)
1258 {
1259    struct d3d12_screen *screen = d3d12_screen(pscreen);
1260 
1261    // megabytes to kilobytes
1262    if (screen->architecture.UMA) {
1263       /* https://asawicki.info/news_1755_untangling_direct3d_12_memory_heap_types_and_pools
1264          All allocations are made in D3D12_MEMORY_POOL_L0 and they increase the usage of
1265          DXGI_MEMORY_SEGMENT_GROUP_LOCAL, as there is only one unified memory and it's all "local" to the GPU.
1266        */
1267       info->total_device_memory =
1268          static_cast<unsigned int>(CLAMP((screen->memory_device_size_megabytes << 10) + (screen->memory_system_size_megabytes << 10), 0u, UINT32_MAX));
1269       info->total_staging_memory = 0;
1270    } else {
1271       info->total_device_memory = static_cast<unsigned int>(CLAMP(screen->memory_device_size_megabytes << 10, 0u, UINT32_MAX));
1272       info->total_staging_memory = static_cast<unsigned int>(CLAMP(screen->memory_system_size_megabytes << 10, 0u, UINT32_MAX));;
1273    }
1274 
1275    d3d12_memory_info m;
1276    screen->get_memory_info(screen, &m);
1277    // bytes to kilobytes
1278    if (m.budget_local > m.usage_local) {
1279       info->avail_device_memory = static_cast<unsigned int>(CLAMP((m.budget_local - m.usage_local) / 1024, 0u, UINT32_MAX));
1280    } else {
1281       info->avail_device_memory = 0;
1282    }
1283    if (m.budget_nonlocal > m.usage_nonlocal) {
1284       info->avail_staging_memory = static_cast<unsigned int>(CLAMP(m.budget_nonlocal - m.usage_nonlocal / 1024, 0u, UINT32_MAX));
1285    } else {
1286       info->avail_staging_memory = 0;
1287    }
1288 
1289    info->device_memory_evicted = static_cast<unsigned int>(CLAMP(screen->total_bytes_evicted / 1024, 0u, UINT32_MAX));
1290    info->nr_device_memory_evictions = screen->num_evictions;
1291 }
1292 
1293 bool
d3d12_init_screen_base(struct d3d12_screen * screen,struct sw_winsys * winsys,LUID * adapter_luid)1294 d3d12_init_screen_base(struct d3d12_screen *screen, struct sw_winsys *winsys, LUID *adapter_luid)
1295 {
1296    glsl_type_singleton_init_or_ref();
1297    d3d12_debug = static_cast<uint32_t>(debug_get_option_d3d12_debug());
1298 
1299    screen->winsys = winsys;
1300    if (adapter_luid)
1301       screen->adapter_luid = *adapter_luid;
1302    mtx_init(&screen->descriptor_pool_mutex, mtx_plain);
1303    mtx_init(&screen->submit_mutex, mtx_plain);
1304 
1305    list_inithead(&screen->context_list);
1306    screen->context_id_count = 16;
1307 
1308    // Fill the array backwards, because we'll pop off the back to assign ids
1309    for (unsigned i = 0; i < 16; ++i)
1310       screen->context_id_list[i] = 15 - i;
1311 
1312 #ifdef HAVE_GALLIUM_D3D12_GRAPHICS
1313    d3d12_varying_cache_init(screen);
1314    mtx_init(&screen->varying_info_mutex, mtx_plain);
1315    screen->base.get_compiler_options = d3d12_get_compiler_options;
1316 #endif // HAVE_GALLIUM_D3D12_GRAPHICS
1317 
1318    slab_create_parent(&screen->transfer_pool, sizeof(struct d3d12_transfer), 16);
1319 
1320    screen->base.get_vendor = d3d12_get_vendor;
1321    screen->base.get_device_vendor = d3d12_get_device_vendor;
1322    screen->base.get_screen_fd = d3d12_screen_get_fd;
1323    screen->base.get_shader_param = d3d12_get_shader_param;
1324    screen->base.get_compute_param = d3d12_get_compute_param;
1325    screen->base.is_format_supported = d3d12_is_format_supported;
1326 
1327    screen->base.context_create = d3d12_context_create;
1328    screen->base.flush_frontbuffer = d3d12_flush_frontbuffer;
1329    screen->base.get_device_luid = d3d12_get_adapter_luid;
1330    screen->base.get_device_uuid = d3d12_get_device_uuid;
1331    screen->base.get_driver_uuid = d3d12_get_driver_uuid;
1332    screen->base.get_device_node_mask = d3d12_get_node_mask;
1333    screen->base.create_fence_win32 = d3d12_create_fence_win32;
1334    screen->base.set_fence_timeline_value = d3d12_set_fence_timeline_value;
1335    screen->base.interop_query_device_info = d3d12_interop_query_device_info;
1336    screen->base.interop_export_object = d3d12_interop_export_object;
1337 #ifdef _WIN32
1338    screen->base.fence_get_win32_handle = d3d12_fence_get_win32_handle;
1339 #endif
1340    screen->base.query_memory_info = d3d12_query_memory_info;
1341 
1342    screen->d3d12_mod = util_dl_open(
1343       UTIL_DL_PREFIX
1344 #ifdef _GAMING_XBOX_SCARLETT
1345       "d3d12_xs"
1346 #elif defined(_GAMING_XBOX)
1347       "d3d12_x"
1348 #else
1349       "d3d12"
1350 #endif
1351       UTIL_DL_EXT
1352    );
1353    if (!screen->d3d12_mod) {
1354       debug_printf("D3D12: failed to load D3D12.DLL\n");
1355       return false;
1356    }
1357    return true;
1358 }
1359 
1360 #ifdef _WIN32
1361 extern "C" IMAGE_DOS_HEADER __ImageBase;
1362 static const char *
try_find_d3d12core_next_to_self(char * path,DWORD path_arr_size)1363 try_find_d3d12core_next_to_self(char *path, DWORD path_arr_size)
1364 {
1365    uint32_t path_size = GetModuleFileNameA((HINSTANCE)&__ImageBase,
1366                                            path, path_arr_size);
1367    if (!path_arr_size || path_size == path_arr_size) {
1368       debug_printf("Unable to get path to self\n");
1369       return nullptr;
1370    }
1371 
1372    auto last_slash = strrchr(path, '\\');
1373    if (!last_slash) {
1374       debug_printf("Unable to get path to self\n");
1375       return nullptr;
1376    }
1377 
1378    *(last_slash + 1) = '\0';
1379    if (strcat_s(path, path_arr_size, "D3D12Core.dll") != 0) {
1380       debug_printf("Unable to get path to D3D12Core.dll next to self\n");
1381       return nullptr;
1382    }
1383 
1384    if (GetFileAttributesA(path) == INVALID_FILE_ATTRIBUTES) {
1385       debug_printf("No D3D12Core.dll exists next to self\n");
1386       return nullptr;
1387    }
1388 
1389    *(last_slash + 1) = '\0';
1390    return path;
1391 }
1392 #endif
1393 
1394 #ifndef _GAMING_XBOX
1395 static ID3D12DeviceFactory *
try_create_device_factory(util_dl_library * d3d12_mod)1396 try_create_device_factory(util_dl_library *d3d12_mod)
1397 {
1398 #if defined(_WIN32) && defined(_WIN64)
1399    if (d3d12_debug & D3D12_DEBUG_PIX) {
1400       if (GetModuleHandleW(L"WinPixGpuCapturer.dll") == nullptr) {
1401          LPWSTR program_files_path = nullptr;
1402          SHGetKnownFolderPath(FOLDERID_ProgramFiles, KF_FLAG_DEFAULT, NULL, &program_files_path);
1403 
1404          auto pix_installation_path = std::filesystem::path(program_files_path) / "Microsoft PIX";
1405          std::wstring newest_version;
1406          for (auto const &directory : std::filesystem::directory_iterator(pix_installation_path)) {
1407             if (directory.is_directory() &&
1408                 (newest_version.empty() || newest_version < directory.path().filename().c_str()))
1409                newest_version = directory.path().filename().wstring();
1410          }
1411          if (newest_version.empty()) {
1412             debug_printf("D3D12: Failed to find any PIX installations\n");
1413          }
1414          else if (!LoadLibraryW((pix_installation_path / newest_version / L"WinPixGpuCapturer.dll").c_str()) &&
1415                   // Try the x64 subdirectory for x64-on-arm64
1416                   !LoadLibraryW((pix_installation_path / newest_version / L"x64/WinPixGpuCapturer.dll").c_str())) {
1417             debug_printf("D3D12: Failed to load WinPixGpuCapturer.dll from %S\n", newest_version.c_str());
1418          }
1419       }
1420    }
1421 #endif
1422 
1423    if (d3d12_debug & D3D12_DEBUG_SINGLETON)
1424       return nullptr;
1425 
1426    /* A device factory allows us to isolate things like debug layer enablement from other callers,
1427     * and can potentially even refer to a different D3D12 redist implementation from others.
1428     */
1429    ID3D12DeviceFactory *factory = nullptr;
1430 
1431    typedef HRESULT(WINAPI *PFN_D3D12_GET_INTERFACE)(REFCLSID clsid, REFIID riid, void **ppFactory);
1432    PFN_D3D12_GET_INTERFACE D3D12GetInterface = (PFN_D3D12_GET_INTERFACE)util_dl_get_proc_address(d3d12_mod, "D3D12GetInterface");
1433    if (!D3D12GetInterface) {
1434       debug_printf("D3D12: Failed to retrieve D3D12GetInterface");
1435       return nullptr;
1436    }
1437 
1438 #ifdef _WIN32
1439    /* First, try to create a device factory from a DLL-parallel D3D12Core.dll */
1440    ID3D12SDKConfiguration *sdk_config = nullptr;
1441    if (SUCCEEDED(D3D12GetInterface(CLSID_D3D12SDKConfiguration, IID_PPV_ARGS(&sdk_config)))) {
1442       ID3D12SDKConfiguration1 *sdk_config1 = nullptr;
1443       if (SUCCEEDED(sdk_config->QueryInterface(&sdk_config1))) {
1444          char self_path[MAX_PATH];
1445          const char *d3d12core_path = try_find_d3d12core_next_to_self(self_path, sizeof(self_path));
1446          if (d3d12core_path) {
1447             if (SUCCEEDED(sdk_config1->CreateDeviceFactory(D3D12_PREVIEW_SDK_VERSION, d3d12core_path, IID_PPV_ARGS(&factory))) ||
1448                 SUCCEEDED(sdk_config1->CreateDeviceFactory(D3D12_SDK_VERSION, d3d12core_path, IID_PPV_ARGS(&factory)))) {
1449                sdk_config->Release();
1450                sdk_config1->Release();
1451                return factory;
1452             }
1453          }
1454 
1455          /* Nope, seems we don't have a matching D3D12Core.dll next to ourselves */
1456          sdk_config1->Release();
1457       }
1458 
1459       /* It's possible there's a D3D12Core.dll next to the .exe, for development/testing purposes. If so, we'll be notified
1460        * by environment variables what the relative path is and the version to use.
1461        */
1462       const char *d3d12core_relative_path = getenv("D3D12_AGILITY_RELATIVE_PATH");
1463       const char *d3d12core_sdk_version = getenv("D3D12_AGILITY_SDK_VERSION");
1464       if (d3d12core_relative_path && d3d12core_sdk_version) {
1465          (void)sdk_config->SetSDKVersion(atoi(d3d12core_sdk_version), d3d12core_relative_path);
1466       }
1467       sdk_config->Release();
1468    }
1469 #endif
1470 
1471    (void)D3D12GetInterface(CLSID_D3D12DeviceFactory, IID_PPV_ARGS(&factory));
1472    return factory;
1473 }
1474 #endif
1475 
1476 bool
d3d12_init_screen(struct d3d12_screen * screen,IUnknown * adapter)1477 d3d12_init_screen(struct d3d12_screen *screen, IUnknown *adapter)
1478 {
1479    assert(screen->base.destroy != nullptr);
1480 
1481    // Device can be imported with d3d12_create_dxcore_screen_from_d3d12_device
1482    if (!screen->dev) {
1483 #ifndef _GAMING_XBOX
1484       ID3D12DeviceFactory *factory = try_create_device_factory(screen->d3d12_mod);
1485 
1486 #if !MESA_DEBUG
1487       if (d3d12_debug & D3D12_DEBUG_DEBUG_LAYER)
1488 #endif
1489          enable_d3d12_debug_layer(screen->d3d12_mod, factory);
1490 
1491       if (d3d12_debug & D3D12_DEBUG_GPU_VALIDATOR)
1492          enable_gpu_validation(screen->d3d12_mod, factory);
1493 
1494       screen->dev = create_device(screen->d3d12_mod, adapter, factory);
1495 
1496       if (factory)
1497          factory->Release();
1498 #else
1499       screen->dev = create_device(screen->d3d12_mod, adapter);
1500 #endif
1501 
1502       if (!screen->dev) {
1503          debug_printf("D3D12: failed to create device\n");
1504          return false;
1505       }
1506    }
1507    screen->adapter_luid = GetAdapterLuid(screen->dev);
1508 
1509 #ifndef _GAMING_XBOX
1510    ID3D12InfoQueue *info_queue;
1511    if (SUCCEEDED(screen->dev->QueryInterface(IID_PPV_ARGS(&info_queue)))) {
1512       D3D12_MESSAGE_SEVERITY severities[] = {
1513          D3D12_MESSAGE_SEVERITY_INFO,
1514          D3D12_MESSAGE_SEVERITY_WARNING,
1515       };
1516 
1517       D3D12_MESSAGE_ID msg_ids[] = {
1518          D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE,
1519       };
1520 
1521       D3D12_INFO_QUEUE_FILTER NewFilter = {};
1522       NewFilter.DenyList.NumSeverities = ARRAY_SIZE(severities);
1523       NewFilter.DenyList.pSeverityList = severities;
1524       NewFilter.DenyList.NumIDs = ARRAY_SIZE(msg_ids);
1525       NewFilter.DenyList.pIDList = msg_ids;
1526 
1527       info_queue->PushStorageFilter(&NewFilter);
1528       info_queue->Release();
1529    }
1530 #endif /* !_GAMING_XBOX */
1531 
1532    if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS,
1533                                                &screen->opts,
1534                                                sizeof(screen->opts)))) {
1535       debug_printf("D3D12: failed to get device options\n");
1536       return false;
1537    }
1538    if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS1,
1539                                                &screen->opts1,
1540                                                sizeof(screen->opts1)))) {
1541       debug_printf("D3D12: failed to get device options\n");
1542       return false;
1543    }
1544    if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS2,
1545                                                &screen->opts2,
1546                                                sizeof(screen->opts2)))) {
1547       debug_printf("D3D12: failed to get device options\n");
1548       return false;
1549    }
1550    if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3,
1551                                                &screen->opts3,
1552                                                sizeof(screen->opts3)))) {
1553       debug_printf("D3D12: failed to get device options\n");
1554       return false;
1555    }
1556    if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS4,
1557                                                &screen->opts4,
1558                                                sizeof(screen->opts4)))) {
1559       debug_printf("D3D12: failed to get device options\n");
1560       return false;
1561    }
1562    screen->dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS12, &screen->opts12, sizeof(screen->opts12));
1563    screen->dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS14, &screen->opts14, sizeof(screen->opts14));
1564 #ifndef _GAMING_XBOX
1565    screen->dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS19, &screen->opts19, sizeof(screen->opts19));
1566 #endif
1567 
1568    screen->architecture.NodeIndex = 0;
1569    if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_ARCHITECTURE,
1570                                                &screen->architecture,
1571                                                sizeof(screen->architecture)))) {
1572       debug_printf("D3D12: failed to get device architecture\n");
1573       return false;
1574    }
1575 
1576    D3D12_FEATURE_DATA_FEATURE_LEVELS feature_levels;
1577    static const D3D_FEATURE_LEVEL levels[] = {
1578 #ifndef _GAMING_XBOX
1579       D3D_FEATURE_LEVEL_1_0_GENERIC,
1580       D3D_FEATURE_LEVEL_1_0_CORE,
1581 #endif
1582       D3D_FEATURE_LEVEL_11_0,
1583       D3D_FEATURE_LEVEL_11_1,
1584       D3D_FEATURE_LEVEL_12_0,
1585       D3D_FEATURE_LEVEL_12_1,
1586    };
1587    feature_levels.NumFeatureLevels = ARRAY_SIZE(levels);
1588    feature_levels.pFeatureLevelsRequested = levels;
1589    if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS,
1590                                                &feature_levels,
1591                                                sizeof(feature_levels)))) {
1592       debug_printf("D3D12: failed to get device feature levels\n");
1593       return false;
1594    }
1595 
1596 #ifdef HAVE_GALLIUM_D3D12_GRAPHICS
1597    screen->max_feature_level = feature_levels.MaxSupportedFeatureLevel;
1598 #else
1599    screen->max_feature_level = D3D_FEATURE_LEVEL_1_0_GENERIC;
1600 #endif // HAVE_GALLIUM_D3D12_GRAPHICS
1601 
1602    screen->queue_type = (screen->max_feature_level >= D3D_FEATURE_LEVEL_11_0) ? D3D12_COMMAND_LIST_TYPE_DIRECT : D3D12_COMMAND_LIST_TYPE_COMPUTE;
1603 
1604 #ifdef HAVE_GALLIUM_D3D12_GRAPHICS
1605    if (screen->max_feature_level >= D3D_FEATURE_LEVEL_11_0) {
1606       static const D3D_SHADER_MODEL valid_shader_models[] = {
1607 #ifndef _GAMING_XBOX
1608          D3D_SHADER_MODEL_6_8,
1609 #endif
1610          D3D_SHADER_MODEL_6_7, D3D_SHADER_MODEL_6_6, D3D_SHADER_MODEL_6_5, D3D_SHADER_MODEL_6_4,
1611          D3D_SHADER_MODEL_6_3, D3D_SHADER_MODEL_6_2, D3D_SHADER_MODEL_6_1, D3D_SHADER_MODEL_6_0,
1612       };
1613       for (UINT i = 0; i < ARRAY_SIZE(valid_shader_models); ++i) {
1614          D3D12_FEATURE_DATA_SHADER_MODEL shader_model = { valid_shader_models[i] };
1615          if (SUCCEEDED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &shader_model, sizeof(shader_model)))) {
1616             static_assert(D3D_SHADER_MODEL_6_0 == 0x60 && SHADER_MODEL_6_0 == 0x60000, "Validating math below");
1617 #ifndef _GAMING_XBOX
1618             static_assert(D3D_SHADER_MODEL_6_8 == 0x68 && SHADER_MODEL_6_8 == 0x60008, "Validating math below");
1619 #endif
1620             screen->max_shader_model = static_cast<dxil_shader_model>(((shader_model.HighestShaderModel & 0xf0) << 12) |
1621                                                                      (shader_model.HighestShaderModel & 0xf));
1622             break;
1623          }
1624       }
1625    }
1626 #endif // HAVE_GALLIUM_D3D12_GRAPHICS
1627 
1628    D3D12_COMMAND_QUEUE_DESC queue_desc;
1629    queue_desc.Type = screen->queue_type;
1630    queue_desc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
1631    queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
1632    queue_desc.NodeMask = 0;
1633 
1634 #ifndef _GAMING_XBOX
1635    ID3D12Device9 *device9;
1636    if (SUCCEEDED(screen->dev->QueryInterface(&device9))) {
1637       if (FAILED(device9->CreateCommandQueue1(&queue_desc, OpenGLOn12CreatorID,
1638                                               IID_PPV_ARGS(&screen->cmdqueue))))
1639          return false;
1640       device9->Release();
1641    } else
1642 #endif
1643    {
1644       if (FAILED(screen->dev->CreateCommandQueue(&queue_desc,
1645                                                  IID_PPV_ARGS(&screen->cmdqueue))))
1646          return false;
1647    }
1648 
1649    if (FAILED(screen->dev->CreateFence(0, D3D12_FENCE_FLAG_SHARED, IID_PPV_ARGS(&screen->fence))))
1650       return false;
1651 
1652    if (!d3d12_init_residency(screen))
1653       return false;
1654 
1655    UINT64 timestamp_freq;
1656    if (FAILED(screen->cmdqueue->GetTimestampFrequency(&timestamp_freq)))
1657        timestamp_freq = 10000000;
1658    screen->timestamp_multiplier = 1000000000.0f / timestamp_freq;
1659 
1660    d3d12_screen_fence_init(&screen->base);
1661    d3d12_screen_resource_init(&screen->base);
1662 #ifdef HAVE_GALLIUM_D3D12_VIDEO
1663    d3d12_screen_video_init(&screen->base);
1664 #endif
1665 
1666    d3d12_init_screen_caps(screen);
1667 
1668    struct pb_desc desc;
1669    desc.alignment = D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT;
1670    desc.usage = (pb_usage_flags)(PB_USAGE_CPU_WRITE | PB_USAGE_GPU_READ);
1671 
1672    screen->bufmgr = d3d12_bufmgr_create(screen);
1673    if (!screen->bufmgr)
1674       return false;
1675 
1676    screen->cache_bufmgr = pb_cache_manager_create(screen->bufmgr, 0xfffff, 2, 0, 512 * 1024 * 1024);
1677    if (!screen->cache_bufmgr)
1678       return false;
1679 
1680    screen->slab_cache_bufmgr = pb_cache_manager_create(screen->bufmgr, 0xfffff, 2, 0, 512 * 1024 * 1024);
1681    if (!screen->slab_cache_bufmgr)
1682       return false;
1683 
1684    screen->slab_bufmgr = pb_slab_range_manager_create(screen->slab_cache_bufmgr, 16,
1685                                                       D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,
1686                                                       D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,
1687                                                       &desc);
1688    if (!screen->slab_bufmgr)
1689       return false;
1690 
1691    screen->readback_slab_cache_bufmgr = pb_cache_manager_create(screen->bufmgr, 0xfffff, 2, 0, 512 * 1024 * 1024);
1692    if (!screen->readback_slab_cache_bufmgr)
1693       return false;
1694 
1695    desc.usage = (pb_usage_flags)(PB_USAGE_CPU_READ_WRITE | PB_USAGE_GPU_WRITE);
1696    screen->readback_slab_bufmgr = pb_slab_range_manager_create(screen->readback_slab_cache_bufmgr, 16,
1697                                                                D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,
1698                                                                D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,
1699                                                                &desc);
1700    if (!screen->readback_slab_bufmgr)
1701       return false;
1702 
1703 #ifdef HAVE_GALLIUM_D3D12_GRAPHICS
1704    if (screen->max_feature_level >= D3D_FEATURE_LEVEL_11_0) {
1705       screen->rtv_pool = d3d12_descriptor_pool_new(screen,
1706                                                    D3D12_DESCRIPTOR_HEAP_TYPE_RTV,
1707                                                    64);
1708       screen->dsv_pool = d3d12_descriptor_pool_new(screen,
1709                                                    D3D12_DESCRIPTOR_HEAP_TYPE_DSV,
1710                                                    64);
1711       screen->view_pool = d3d12_descriptor_pool_new(screen,
1712                                                    D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
1713                                                    1024);
1714       if (!screen->rtv_pool || !screen->dsv_pool || !screen->view_pool)
1715          return false;
1716 
1717       d3d12_init_null_srvs(screen);
1718       d3d12_init_null_uavs(screen);
1719       d3d12_init_null_rtv(screen);
1720 
1721       screen->have_load_at_vertex = can_attribute_at_vertex(screen);
1722       screen->support_shader_images = can_shader_image_load_all_formats(screen);
1723       static constexpr uint64_t known_good_warp_version = 10ull << 48 | 22000ull << 16;
1724       bool warp_with_broken_int64 =
1725          (screen->vendor_id == HW_VENDOR_MICROSOFT && screen->driver_version < known_good_warp_version);
1726       unsigned supported_int_sizes = 32 | (screen->opts1.Int64ShaderOps && !warp_with_broken_int64 ? 64 : 0);
1727       unsigned supported_float_sizes = 32 | (screen->opts.DoublePrecisionFloatShaderOps ? 64 : 0);
1728       dxil_get_nir_compiler_options(&screen->nir_options,
1729                                     screen->max_shader_model,
1730                                     supported_int_sizes,
1731                                     supported_float_sizes);
1732    }
1733 #endif // HAVE_GALLIUM_D3D12_GRAPHICS
1734 
1735 #ifndef _GAMING_XBOX
1736       ID3D12Device8 *dev8;
1737       if (SUCCEEDED(screen->dev->QueryInterface(&dev8))) {
1738          dev8->Release();
1739          screen->support_create_not_resident = true;
1740       }
1741       screen->dev->QueryInterface(&screen->dev10);
1742 #endif
1743 
1744    const char *mesa_version = "Mesa " PACKAGE_VERSION MESA_GIT_SHA1;
1745    struct mesa_sha1 sha1_ctx;
1746    uint8_t sha1[SHA1_DIGEST_LENGTH];
1747    STATIC_ASSERT(PIPE_UUID_SIZE <= sizeof(sha1));
1748 
1749    /* The driver UUID is used for determining sharability of images and memory
1750     * between two instances in separate processes.  People who want to
1751     * share memory need to also check the device UUID or LUID so all this
1752     * needs to be is the build-id.
1753     */
1754    _mesa_sha1_compute(mesa_version, strlen(mesa_version), sha1);
1755    memcpy(screen->driver_uuid, sha1, PIPE_UUID_SIZE);
1756 
1757    /* The device UUID uniquely identifies the given device within the machine. */
1758    _mesa_sha1_init(&sha1_ctx);
1759    _mesa_sha1_update(&sha1_ctx, &screen->vendor_id, sizeof(screen->vendor_id));
1760    _mesa_sha1_update(&sha1_ctx, &screen->device_id, sizeof(screen->device_id));
1761    _mesa_sha1_update(&sha1_ctx, &screen->subsys_id, sizeof(screen->subsys_id));
1762    _mesa_sha1_update(&sha1_ctx, &screen->revision, sizeof(screen->revision));
1763    _mesa_sha1_final(&sha1_ctx, sha1);
1764    memcpy(screen->device_uuid, sha1, PIPE_UUID_SIZE);
1765 
1766    return true;
1767 }
1768