From 0adbd6905f06e458cfc517f44e99a88138cb2ab3 Mon Sep 17 00:00:00 2001 From: aliaspider Date: Mon, 10 Apr 2023 01:08:44 +0100 Subject: [PATCH] add D3D12 HW_render support. (#15177) --- gfx/common/d3d12_common.h | 9 ++- gfx/drivers/d3d12.c | 98 ++++++++++++++++++++++++-- gfx/video_driver.c | 4 ++ libretro-common/include/libretro_d3d.h | 28 ++++++++ runloop.c | 10 ++- 5 files changed, 139 insertions(+), 10 deletions(-) diff --git a/gfx/common/d3d12_common.h b/gfx/common/d3d12_common.h index 8cb03070bb..4941601f02 100644 --- a/gfx/common/d3d12_common.h +++ b/gfx/common/d3d12_common.h @@ -25,6 +25,8 @@ #include "dxgi_common.h" #include +#include + #include "../common/d3dcompiler_common.h" #include "../drivers_shader/slang_process.h" @@ -166,7 +168,8 @@ enum d3d12_video_flags D3D12_ST_FLAG_HDR_ENABLE = (1 << 11), D3D12_ST_FLAG_VSYNC = (1 << 12), D3D12_ST_FLAG_WAITABLE_SWAPCHAINS = (1 << 13), - D3D12_ST_FLAG_WAIT_FOR_VBLANK = (1 << 14) + D3D12_ST_FLAG_WAIT_FOR_VBLANK = (1 << 14), + D3D12_ST_FLAG_HW_IFACE_ENABLE = (1 << 15) }; typedef struct @@ -188,6 +191,10 @@ typedef struct #endif /* DEBUG */ #endif /* DEVICE_DEBUG */ + struct retro_hw_render_interface_d3d12 hw_iface; + D3D12Resource hw_render_texture; + DXGI_FORMAT hw_render_texture_format; + IDXGIAdapter1 *adapters[D3D12_MAX_GPU_COUNT]; struct string_list *gpu_list; diff --git a/gfx/drivers/d3d12.c b/gfx/drivers/d3d12.c index 06ae24cb21..c3c0e69f70 100644 --- a/gfx/drivers/d3d12.c +++ b/gfx/drivers/d3d12.c @@ -887,7 +887,7 @@ static bool d3d12_gfx_init_pipelines(d3d12_video_t* d3d12) } #endif - desc.BlendState.RenderTarget[0] = d3d12_blend_enable_desc; + desc.BlendState.RenderTarget[0] = d3d12_blend_disable_desc; desc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; { @@ -1738,7 +1738,7 @@ static void d3d12_init_queue(d3d12_video_t* d3d12) { static const D3D12_COMMAND_QUEUE_DESC desc = { D3D12_COMMAND_LIST_TYPE_DIRECT, - 0, + D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, D3D12_COMMAND_QUEUE_FLAG_NONE, 0 }; @@ -1793,6 +1793,13 @@ static void d3d12_create_fullscreen_quad_vbo( D3D12Unmap(*vbo, 0, NULL); } +static void d3d12_set_hw_render_texture(void* data, ID3D12Resource* texture, DXGI_FORMAT format) +{ + d3d12_video_t* d3d12 = (d3d12_video_t*)data; + d3d12->hw_render_texture = texture; + d3d12->hw_render_texture_format = format; +} + static void *d3d12_gfx_init(const video_info_t* video, input_driver_t** input, void** input_data) { @@ -1982,6 +1989,20 @@ static void *d3d12_gfx_init(const video_info_t* video, d3d12_gfx_set_shader(d3d12, type, shader_preset); } + if ( video_driver_get_hw_context()->context_type == RETRO_HW_CONTEXT_DIRECT3D + && video_driver_get_hw_context()->version_major == 12) + { + d3d12->flags |= D3D12_ST_FLAG_HW_IFACE_ENABLE; + d3d12->hw_iface.interface_type = RETRO_HW_RENDER_INTERFACE_D3D12; + d3d12->hw_iface.interface_version = RETRO_HW_RENDER_INTERFACE_D3D12_VERSION; + d3d12->hw_iface.handle = d3d12; + d3d12->hw_iface.device = d3d12->device; + d3d12->hw_iface.queue = d3d12->queue.handle; + d3d12->hw_iface.required_state = D3D12_RESOURCE_STATE_COPY_SOURCE; + d3d12->hw_iface.set_texture = d3d12_set_hw_render_texture; + d3d12->hw_iface.D3DCompile = D3DCompile; + } + return d3d12; error: @@ -2332,6 +2353,20 @@ static bool d3d12_gfx_frame( if (frame && width && height) { + if (frame == RETRO_HW_FRAME_BUFFER_VALID) + { + if (d3d12->frame.texture[0].desc.Format != d3d12->hw_render_texture_format) + { + d3d12->frame.texture[0].desc.Width = width; + d3d12->frame.texture[0].desc.Height = height; + d3d12->frame.texture[0].desc.Format = d3d12->hw_render_texture_format; + d3d12_release_texture(&d3d12->frame.texture[0]); + d3d12_init_texture(d3d12->device, &d3d12->frame.texture[0]); + + d3d12->flags |= D3D12_ST_FLAG_INIT_HISTORY; + } + } + if (d3d12->shader_preset) { if (d3d12->shader_preset->luts && d3d12->luts[0].dirty) @@ -2387,11 +2422,51 @@ static bool d3d12_gfx_frame( if (d3d12->flags & D3D12_ST_FLAG_RESIZE_RTS) d3d12_init_render_targets(d3d12, width, height); - d3d12_update_texture(width, height, pitch, d3d12->format, - frame, &d3d12->frame.texture[0]); + if(frame == RETRO_HW_FRAME_BUFFER_VALID) + { + D3D12_BOX src_box; + D3D12_TEXTURE_COPY_LOCATION src, dst; - d3d12_upload_texture(d3d12->queue.cmd, &d3d12->frame.texture[0], - d3d12); + src_box.left = 0; + src_box.top = 0; + src_box.front = 0; + src_box.right = width; + src_box.bottom = height; + src_box.back = 1; + + src.pResource = d3d12->hw_render_texture; + src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + src.SubresourceIndex = 0; + + dst.pResource = d3d12->frame.texture[0].handle; + dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + dst.SubresourceIndex = 0; + + D3D12_RESOURCE_TRANSITION( + d3d12->queue.cmd, + d3d12->frame.texture[0].handle, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, + D3D12_RESOURCE_STATE_COPY_DEST); + + D3D12CopyTextureRegion(d3d12->queue.cmd, &dst, 0, 0, 0, &src, &src_box); + + D3D12_RESOURCE_TRANSITION( + d3d12->queue.cmd, + d3d12->frame.texture[0].handle, + D3D12_RESOURCE_STATE_COPY_DEST, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + + d3d12->hw_render_texture = NULL; + } + else + { + d3d12_update_texture(width, height, pitch, d3d12->format, + frame, &d3d12->frame.texture[0]); + + d3d12_upload_texture(d3d12->queue.cmd, &d3d12->frame.texture[0], + d3d12); + + } } D3D12IASetVertexBuffers(d3d12->queue.cmd, 0, 1, &d3d12->frame.vbo_view); @@ -3058,6 +3133,15 @@ static void d3d12_gfx_unload_texture(void* data, free(texture); } +static bool d3d12_get_hw_render_interface( + void* data, const struct retro_hw_render_interface** iface) +{ + d3d12_video_t* d3d12 = (d3d12_video_t*)data; + *iface = (const struct retro_hw_render_interface*) + &d3d12->hw_iface; + return d3d12->flags & D3D12_ST_FLAG_HW_IFACE_ENABLE; +} + #ifndef __WINRT__ static void d3d12_get_video_output_size(void *data, unsigned *width, unsigned *height, char *desc, size_t desc_len) @@ -3112,7 +3196,7 @@ static const video_poke_interface_t d3d12_poke_interface = { NULL, /* grab_mouse_toggle */ d3d12_gfx_get_current_shader, NULL, /* get_current_software_framebuffer */ - NULL, /* get_hw_render_interface */ + d3d12_get_hw_render_interface, #ifdef HAVE_DXGI_HDR d3d12_set_hdr_max_nits, d3d12_set_hdr_paper_white_nits, diff --git a/gfx/video_driver.c b/gfx/video_driver.c index e32997e59a..a2916b9763 100644 --- a/gfx/video_driver.c +++ b/gfx/video_driver.c @@ -505,6 +505,10 @@ const char *hw_render_context_name( if (type == RETRO_HW_CONTEXT_DIRECT3D && major == 11) return "d3d11"; #endif +#ifdef HAVE_D3D12 + if (type == RETRO_HW_CONTEXT_DIRECT3D && major == 12) + return "d3d12"; +#endif #ifdef HAVE_D3D9 #if defined(HAVE_HLSL) if (type == RETRO_HW_CONTEXT_DIRECT3D && major == 9) diff --git a/libretro-common/include/libretro_d3d.h b/libretro-common/include/libretro_d3d.h index 78f36a5a01..8e1824323b 100644 --- a/libretro-common/include/libretro_d3d.h +++ b/libretro-common/include/libretro_d3d.h @@ -56,4 +56,32 @@ struct retro_hw_render_interface_d3d11 #endif +#ifdef HAVE_D3D12 + +#include +#include + +#define RETRO_HW_RENDER_INTERFACE_D3D12_VERSION 1 + +struct retro_hw_render_interface_d3d12 +{ + /* Must be set to RETRO_HW_RENDER_INTERFACE_D3D12. */ + enum retro_hw_render_interface_type interface_type; + /* Must be set to RETRO_HW_RENDER_INTERFACE_D3D12_VERSION. */ + unsigned interface_version; + + /* Opaque handle to the d3d12 backend in the frontend + * which must be passed along to all function pointers + * in this interface. + */ + void* handle; + ID3D12Device *device; + ID3D12CommandQueue *queue; + pD3DCompile D3DCompile; + D3D12_RESOURCE_STATES required_state; + void (*set_texture)(void* handle, ID3D12Resource* texture, DXGI_FORMAT format); +}; + +#endif + #endif /* LIBRETRO_DIRECT3D_H__ */ diff --git a/runloop.c b/runloop.c index 1567c22424..4f9b06f921 100644 --- a/runloop.c +++ b/runloop.c @@ -740,7 +740,8 @@ static bool dynamic_verify_hw_context( return false; break; case RETRO_HW_CONTEXT_DIRECT3D: - if (!(string_is_equal(video_ident, "d3d11") && major == 11)) + if (!((string_is_equal(video_ident, "d3d11") && major == 11) || + (string_is_equal(video_ident, "d3d12") && major == 12))) return false; break; default: @@ -834,7 +835,7 @@ static bool dynamic_request_hw_context(enum retro_hw_context_type type, break; #endif -#if defined(HAVE_D3D9) || defined(HAVE_D3D11) +#if defined(HAVE_D3D9) || defined(HAVE_D3D11) || defined(HAVE_D3D12) case RETRO_HW_CONTEXT_DIRECT3D: switch (major) { @@ -847,6 +848,11 @@ static bool dynamic_request_hw_context(enum retro_hw_context_type type, case 11: RARCH_LOG("Requesting D3D11 context.\n"); break; +#endif +#ifdef HAVE_D3D12 + case 12: + RARCH_LOG("Requesting D3D12 context.\n"); + break; #endif default: RARCH_LOG("Requesting unknown context.\n");