/* * 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" #include "d3d12_format.h" #include "d3d12_public.h" #include "d3d12_resource.h" #include "d3d12_nir_passes.h" #include "pipebuffer/pb_bufmgr.h" #include "util/debug.h" #include "util/u_math.h" #include "util/u_memory.h" #include "util/u_screen.h" #include "nir.h" #include "frontend/sw_winsys.h" #include #include static const struct debug_named_value 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" }, DEBUG_NAMED_VALUE_END }; DEBUG_GET_ONCE_FLAGS_OPTION(d3d12_debug, "D3D12_DEBUG", 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->adapter_desc.VendorId) { 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 const char * d3d12_get_name(struct pipe_screen *pscreen) { struct d3d12_screen* screen = d3d12_screen(pscreen); if (screen->adapter_desc.Description[0] == '\0') return "D3D12 (Unknown)"; static char buf[1000]; snprintf(buf, sizeof(buf), "D3D12 (%S)", screen->adapter_desc.Description); return buf; } static int d3d12_get_video_mem(struct pipe_screen *pscreen) { struct d3d12_screen* screen = d3d12_screen(pscreen); // Note: memory sizes in bytes, but stored in size_t, so may be capped at 4GB. // In that case, adding before conversion to MB can easily overflow. return (screen->adapter_desc.DedicatedVideoMemory >> 20) + (screen->adapter_desc.DedicatedSystemMemory >> 20) + (screen->adapter_desc.SharedSystemMemory >> 20); } static int d3d12_get_param(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: if (screen->max_feature_level >= D3D_FEATURE_LEVEL_10_0) return 8; else if (screen->max_feature_level == D3D_FEATURE_LEVEL_9_3) return 4; return 1; case PIPE_CAP_TEXTURE_SWIZZLE: return 1; case PIPE_CAP_MAX_TEXTURE_2D_SIZE: if (screen->max_feature_level >= D3D_FEATURE_LEVEL_11_0) return 16384; else if (screen->max_feature_level >= D3D_FEATURE_LEVEL_10_0) return 8192; else if (screen->max_feature_level >= D3D_FEATURE_LEVEL_9_3) return 4096; return 2048; case PIPE_CAP_MAX_TEXTURE_3D_LEVELS: if (screen->max_feature_level >= D3D_FEATURE_LEVEL_10_0) return 11; return 9; case PIPE_CAP_MAX_TEXTURE_CUBE_LEVELS: if (screen->max_feature_level >= D3D_FEATURE_LEVEL_11_0) return 14; else if (screen->max_feature_level >= D3D_FEATURE_LEVEL_10_0) return 13; else if (screen->max_feature_level == D3D_FEATURE_LEVEL_9_3) return 12; return 9; 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_VERTEX_SHADER_SATURATE: case PIPE_CAP_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION: case PIPE_CAP_VERTEX_BUFFER_STRIDE_4BYTE_ALIGNED_ONLY: case PIPE_CAP_RGB_OVERRIDE_DST_ALPHA_BLEND: 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_MAX_TEXTURE_ARRAY_LAYERS: if (screen->max_feature_level >= D3D_FEATURE_LEVEL_11_0) return 1 << 14; else if (screen->max_feature_level >= D3D_FEATURE_LEVEL_10_0) return 1 << 13; return 0; case PIPE_CAP_DEPTH_CLIP_DISABLE: return 1; case PIPE_CAP_TGSI_TEXCOORD: return 0; case PIPE_CAP_MIXED_COLORBUFFER_FORMATS: return 1; case PIPE_CAP_VERTEX_COLOR_UNCLAMPED: return 1; case PIPE_CAP_GLSL_FEATURE_LEVEL: return 330; case PIPE_CAP_GLSL_FEATURE_LEVEL_COMPATIBILITY: return 140; #if 0 /* TODO: Enable me */ case PIPE_CAP_COMPUTE: return 0; #endif case PIPE_CAP_TEXTURE_MULTISAMPLE: return 1; #if 0 /* TODO: Enable me */ case PIPE_CAP_CUBE_MAP_ARRAY: return screen->max_feature_level >= D3D_FEATURE_LEVEL_10_1; #endif case PIPE_CAP_TEXTURE_BUFFER_OBJECTS: return 1; case PIPE_CAP_PREFER_BLIT_BASED_TEXTURE_TRANSFER: return 0; /* unsure */ case PIPE_CAP_ENDIANNESS: return PIPE_ENDIAN_NATIVE; /* unsure */ case PIPE_CAP_MAX_VIEWPORTS: return 1; /* probably wrong */ case PIPE_CAP_MIXED_FRAMEBUFFER_SIZES: return 1; #if 0 /* TODO: Enable me. Enables ARB_texture_gather */ case PIPE_CAP_MAX_TEXTURE_GATHER_COMPONENTS: return 4; #endif case PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER: case PIPE_CAP_TGSI_FS_COORD_ORIGIN_UPPER_LEFT: return 1; case PIPE_CAP_TGSI_FS_FACE_IS_INTEGER_SYSVAL: return 1; case PIPE_CAP_ACCELERATED: return 1; 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_SHAREABLE_SHADERS: return 1; #if 0 /* TODO: Enable me. Enables GL_ARB_shader_storage_buffer_object */ case PIPE_CAP_SHADER_BUFFER_OFFSET_ALIGNMENT: return screen->max_feature_level >= D3D_FEATURE_LEVEL_10_0; #endif case PIPE_CAP_CONSTANT_BUFFER_OFFSET_ALIGNMENT: return 256; 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_GLSL_OPTIMIZE_CONSERVATIVELY: return 0; /* not sure */ 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_TGSI_INSTANCEID: case PIPE_CAP_TGSI_TEX_TXF_LZ: case PIPE_CAP_OCCLUSION_QUERY: case PIPE_CAP_POINT_SPRITE: 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_QUERY_TIMESTAMP: case PIPE_CAP_VERTEX_ELEMENT_INSTANCE_DIVISOR: case PIPE_CAP_VERTEX_ELEMENT_SRC_OFFSET_4BYTE_ALIGNED_ONLY: return 1; case PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS: return 4; case PIPE_CAP_MAX_STREAM_OUTPUT_SEPARATE_COMPONENTS: case PIPE_CAP_MAX_STREAM_OUTPUT_INTERLEAVED_COMPONENTS: return 16 * 4; /* Geometry shader output. */ case PIPE_CAP_MAX_GEOMETRY_OUTPUT_VERTICES: return 256; case PIPE_CAP_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS: return 256 * 4; case PIPE_CAP_MAX_VARYINGS: return 32; default: return u_pipe_screen_get_param_defaults(pscreen, param); } } static float d3d12_get_paramf(struct pipe_screen *pscreen, enum pipe_capf param) { struct d3d12_screen *screen = d3d12_screen(pscreen); switch (param) { case PIPE_CAPF_MAX_LINE_WIDTH: case PIPE_CAPF_MAX_LINE_WIDTH_AA: return 1.0f; /* no clue */ case PIPE_CAPF_MAX_POINT_WIDTH: case PIPE_CAPF_MAX_POINT_WIDTH_AA: return D3D12_MAX_POINT_SIZE; case PIPE_CAPF_MAX_TEXTURE_ANISOTROPY: return screen->max_feature_level >= D3D_FEATURE_LEVEL_10_0 ? 16.0f : 2.0f; 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); 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: if (shader == PIPE_SHADER_VERTEX || shader == PIPE_SHADER_FRAGMENT || shader == PIPE_SHADER_GEOMETRY) return INT_MAX; return 0; case PIPE_SHADER_CAP_MAX_INPUTS: return screen->max_feature_level >= D3D_FEATURE_LEVEL_10_1 ? 32 : 16; case PIPE_SHADER_CAP_MAX_OUTPUTS: if (shader == PIPE_SHADER_FRAGMENT) { /* same as max MRTs (not sure if this is correct) */ if (screen->max_feature_level >= D3D_FEATURE_LEVEL_10_0) return 8; else if (screen->max_feature_level == D3D_FEATURE_LEVEL_9_3) return 4; return 1; } return screen->max_feature_level >= D3D_FEATURE_LEVEL_10_1 ? 32 : 16; 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_BUFFER_SIZE: return 65536; case PIPE_SHADER_CAP_MAX_CONST_BUFFERS: return 13; /* 15 - 2 for lowered uniforms and state vars*/ 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_PREFERRED_IR: return PIPE_SHADER_IR_NIR; case PIPE_SHADER_CAP_TGSI_SQRT_SUPPORTED: return 0; /* not implemented */ case PIPE_SHADER_CAP_MAX_SAMPLER_VIEWS: if (screen->opts.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1) return 128; return PIPE_MAX_SHADER_SAMPLER_VIEWS; case PIPE_SHADER_CAP_TGSI_DROUND_SUPPORTED: case PIPE_SHADER_CAP_TGSI_DFRACEXP_DLDEXP_SUPPORTED: case PIPE_SHADER_CAP_TGSI_FMA_SUPPORTED: return 0; /* not implemented */ case PIPE_SHADER_CAP_TGSI_ANY_INOUT_DECL_RANGE: return 0; /* no idea */ case PIPE_SHADER_CAP_MAX_UNROLL_ITERATIONS_HINT: return 32; /* arbitrary */ #if 0 case PIPE_SHADER_CAP_MAX_SHADER_BUFFERS: return 8; /* no clue */ #endif case PIPE_SHADER_CAP_SUPPORTED_IRS: return 1 << PIPE_SHADER_IR_NIR; case PIPE_SHADER_CAP_MAX_SHADER_IMAGES: return 0; /* TODO: enable me */ case PIPE_SHADER_CAP_LOWER_IF_THRESHOLD: case PIPE_SHADER_CAP_TGSI_SKIP_MERGE_REGISTERS: return 0; /* unsure */ case PIPE_SHADER_CAP_TGSI_LDEXP_SUPPORTED: case PIPE_SHADER_CAP_MAX_HW_ATOMIC_COUNTERS: case PIPE_SHADER_CAP_MAX_HW_ATOMIC_COUNTER_BUFFERS: case PIPE_SHADER_CAP_TGSI_CONT_SUPPORTED: return 0; /* not implemented */ } /* should only get here on unhandled cases */ 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. */ if (format != PIPE_FORMAT_A8_UNORM && (util_format_is_alpha(format) || util_format_is_luminance_alpha(format))) 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"); } 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 && !(fmt_info.Support1 & D3D12_FORMAT_SUPPORT1_IA_INDEX_BUFFER)) 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; 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_DISPLAY_TARGET && (!(fmt_info.Support1 & D3D12_FORMAT_SUPPORT1_DISPLAY) || // Disable formats that don't support flip model dxgi_format == DXGI_FORMAT_B8G8R8X8_UNORM || dxgi_format == DXGI_FORMAT_B5G5R5A1_UNORM || dxgi_format == DXGI_FORMAT_B5G6R5_UNORM || dxgi_format == DXGI_FORMAT_B4G4R4A4_UNORM)) return false; 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; 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; } static void d3d12_destroy_screen(struct pipe_screen *pscreen) { struct d3d12_screen *screen = d3d12_screen(pscreen); slab_destroy_parent(&screen->transfer_pool); screen->slab_bufmgr->destroy(screen->slab_bufmgr); screen->cache_bufmgr->destroy(screen->cache_bufmgr); screen->bufmgr->destroy(screen->bufmgr); FREE(screen); } static void d3d12_flush_frontbuffer(struct pipe_screen * pscreen, struct pipe_resource *pres, unsigned level, unsigned layer, void *winsys_drawable_handle, 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); ID3D12Resource *d3d12_res = d3d12_resource_resource(res); if (!winsys) return; assert(res->dt); void *map = winsys->displaytarget_map(winsys, res->dt, 0); if (map) { d3d12_res->ReadFromSubresource(map, res->dt_stride, 0, 0, NULL); winsys->displaytarget_unmap(winsys, res->dt); } ID3D12SharingContract *sharing_contract; if (SUCCEEDED(screen->cmdqueue->QueryInterface(__uuidof(sharing_contract), (void **)&sharing_contract))) sharing_contract->Present(d3d12_res, 0, WindowFromDC((HDC)winsys_drawable_handle)); winsys->displaytarget_display(winsys, res->dt, winsys_drawable_handle, sub_box); } static ID3D12Debug * get_debug_interface() { typedef HRESULT(WINAPI *PFN_D3D12_GET_DEBUG_INTERFACE)(REFIID riid, void **ppFactory); PFN_D3D12_GET_DEBUG_INTERFACE D3D12GetDebugInterface; HMODULE hD3D12Mod = LoadLibrary("D3D12.DLL"); if (!hD3D12Mod) { debug_printf("D3D12: failed to load D3D12.DLL\n"); return NULL; } D3D12GetDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)GetProcAddress(hD3D12Mod, "D3D12GetDebugInterface"); if (!D3D12GetDebugInterface) { debug_printf("D3D12: failed to load D3D12GetDebugInterface from D3D12.DLL\n"); return NULL; } ID3D12Debug *debug; if (FAILED(D3D12GetDebugInterface(__uuidof(ID3D12Debug), (void **)&debug))) { debug_printf("D3D12: D3D12GetDebugInterface failed\n"); return NULL; } return debug; } static void enable_d3d12_debug_layer() { ID3D12Debug *debug = get_debug_interface(); if (debug) debug->EnableDebugLayer(); } static void enable_gpu_validation() { ID3D12Debug *debug = get_debug_interface(); ID3D12Debug3 *debug3; if (debug && SUCCEEDED(debug->QueryInterface(__uuidof(debug), (void **)&debug3))) debug3->SetEnableGPUBasedValidation(true); } static IDXGIFactory4 * get_dxgi_factory() { static const GUID IID_IDXGIFactory4 = { 0x1bc6ea02, 0xef36, 0x464f, { 0xbf, 0x0c, 0x21, 0xca, 0x39, 0xe5, 0x16, 0x8a } }; typedef HRESULT(WINAPI *PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory); PFN_CREATE_DXGI_FACTORY CreateDXGIFactory; HMODULE hDXGIMod = LoadLibrary("DXGI.DLL"); if (!hDXGIMod) { debug_printf("D3D12: failed to load DXGI.DLL\n"); return NULL; } CreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY)GetProcAddress(hDXGIMod, "CreateDXGIFactory"); if (!CreateDXGIFactory) { debug_printf("D3D12: failed to load CreateDXGIFactory from DXGI.DLL\n"); return NULL; } IDXGIFactory4 *factory = NULL; HRESULT hr = CreateDXGIFactory(IID_IDXGIFactory4, (void **)&factory); if (FAILED(hr)) { debug_printf("D3D12: CreateDXGIFactory failed: %08x\n", hr); return NULL; } return factory; } static IDXGIAdapter1 * choose_adapter(IDXGIFactory4 *factory, LUID *adapter) { IDXGIAdapter1 *ret; if (adapter) { if (SUCCEEDED(factory->EnumAdapterByLuid(*adapter, __uuidof(IDXGIAdapter1), (void**)&ret))) return ret; debug_printf("D3D12: requested adapter missing, falling back to auto-detection...\n"); } bool want_warp = env_var_as_boolean("LIBGL_ALWAYS_SOFTWARE", false); if (want_warp) { if (SUCCEEDED(factory->EnumWarpAdapter(__uuidof(IDXGIAdapter1), (void**)&ret))) return ret; debug_printf("D3D12: failed to enum warp adapter\n"); return NULL; } // The first adapter is the default if (SUCCEEDED(factory->EnumAdapters1(0, &ret))) return ret; return NULL; } static ID3D12Device * create_device(IDXGIAdapter1 *adapter) { typedef HRESULT(WINAPI *PFN_D3D12CREATEDEVICE)(IUnknown*, D3D_FEATURE_LEVEL, REFIID, void**); typedef HRESULT(WINAPI *PFN_D3D12ENABLEEXPERIMENTALFEATURES)(UINT, const IID*, void*, UINT*); PFN_D3D12CREATEDEVICE D3D12CreateDevice; PFN_D3D12ENABLEEXPERIMENTALFEATURES D3D12EnableExperimentalFeatures; HMODULE hD3D12Mod = LoadLibrary("D3D12.DLL"); if (!hD3D12Mod) { debug_printf("D3D12: failed to load D3D12.DLL\n"); return NULL; } if (d3d12_debug & D3D12_DEBUG_EXPERIMENTAL) { D3D12EnableExperimentalFeatures = (PFN_D3D12ENABLEEXPERIMENTALFEATURES)GetProcAddress(hD3D12Mod, "D3D12EnableExperimentalFeatures"); D3D12EnableExperimentalFeatures(1, &D3D12ExperimentalShaderModels, NULL, NULL); } D3D12CreateDevice = (PFN_D3D12CREATEDEVICE)GetProcAddress(hD3D12Mod, "D3D12CreateDevice"); if (!D3D12CreateDevice) { debug_printf("D3D12: failed to load D3D12CreateDevice from D3D12.DLL\n"); return NULL; } ID3D12Device *dev; if (SUCCEEDED(D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), (void **)&dev))) return dev; debug_printf("D3D12: D3D12CreateDevice failed\n"); return NULL; } static bool can_attribute_at_vertex(struct d3d12_screen *screen) { switch (screen->adapter_desc.VendorId) { case HW_VENDOR_MICROSOFT: return true; default: return screen->opts3.BarycentricsSupported; } } struct pipe_screen * d3d12_create_screen(struct sw_winsys *winsys, LUID *adapter_luid) { struct d3d12_screen *screen = CALLOC_STRUCT(d3d12_screen); if (!screen) return NULL; d3d12_debug = debug_get_option_d3d12_debug(); screen->winsys = winsys; screen->base.get_name = d3d12_get_name; screen->base.get_vendor = d3d12_get_vendor; screen->base.get_device_vendor = d3d12_get_device_vendor; 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.is_format_supported = d3d12_is_format_supported; screen->base.get_compiler_options = d3d12_get_compiler_options; screen->base.context_create = d3d12_context_create; screen->base.flush_frontbuffer = d3d12_flush_frontbuffer; screen->base.destroy = d3d12_destroy_screen; #ifndef DEBUG if (d3d12_debug & D3D12_DEBUG_DEBUG_LAYER) #endif enable_d3d12_debug_layer(); if (d3d12_debug & D3D12_DEBUG_GPU_VALIDATOR) enable_gpu_validation(); screen->factory = get_dxgi_factory(); if (!screen->factory) { debug_printf("D3D12: failed to create DXGI factory\n"); goto failed; } screen->adapter = choose_adapter(screen->factory, adapter_luid); if (!screen->adapter) { debug_printf("D3D12: no suitable adapter\n"); return NULL; } if (FAILED(screen->adapter->GetDesc1(&screen->adapter_desc))) { debug_printf("D3D12: failed to retrieve adapter description\n"); return NULL; } screen->dev = create_device(screen->adapter); if (!screen->dev) { debug_printf("D3D12: failed to create device\n"); goto failed; } ID3D12InfoQueue *info_queue; if (SUCCEEDED(screen->dev->QueryInterface(__uuidof(info_queue), (void **)&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); } if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &screen->opts, sizeof(screen->opts)))) { debug_printf("D3D12: failed to get device options\n"); goto failed; } if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS2, &screen->opts2, sizeof(screen->opts2)))) { debug_printf("D3D12: failed to get device options\n"); goto failed; } if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &screen->opts3, sizeof(screen->opts3)))) { debug_printf("D3D12: failed to get device options\n"); goto failed; } if (FAILED(screen->dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS4, &screen->opts4, sizeof(screen->opts4)))) { debug_printf("D3D12: failed to get device options\n"); goto failed; } 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"); goto failed; } D3D12_FEATURE_DATA_FEATURE_LEVELS feature_levels; static const D3D_FEATURE_LEVEL levels[] = { 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"); goto failed; } screen->max_feature_level = feature_levels.MaxSupportedFeatureLevel; D3D12_COMMAND_QUEUE_DESC queue_desc; queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; queue_desc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL; queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; queue_desc.NodeMask = 0; if (FAILED(screen->dev->CreateCommandQueue(&queue_desc, __uuidof(screen->cmdqueue), (void **)&screen->cmdqueue))) goto failed; UINT64 timestamp_freq; if (FAILED(screen->cmdqueue->GetTimestampFrequency(×tamp_freq))) timestamp_freq = 10000000; screen->timestamp_multiplier = 1000000000.0 / timestamp_freq; d3d12_screen_fence_init(&screen->base); d3d12_screen_resource_init(&screen->base); slab_create_parent(&screen->transfer_pool, sizeof(struct d3d12_transfer), 16); struct pb_desc desc; desc.alignment = D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT; desc.usage = (pb_usage_flags)PB_USAGE_ALL; screen->bufmgr = d3d12_bufmgr_create(screen); screen->cache_bufmgr = pb_cache_manager_create(screen->bufmgr, 0xfffff, 2, 0, 64 * 1024 * 1024); screen->slab_bufmgr = pb_slab_range_manager_create(screen->cache_bufmgr, 16, 512, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT, &desc); screen->have_load_at_vertex = can_attribute_at_vertex(screen); return &screen->base; failed: FREE(screen); return NULL; }