From 840bd459df2165f62af9ca27a35b400a57769ca9 Mon Sep 17 00:00:00 2001 From: aliaspider Date: Wed, 24 Jan 2018 20:51:19 +0100 Subject: [PATCH] (D3D11) add a font driver. --- Makefile.common | 3 +- gfx/common/d3d11_common.h | 26 ++ gfx/common/d3dcompiler_common.c | 86 ++++- gfx/common/d3dcompiler_common.h | 1 + gfx/common/dxgi_common.c | 23 +- gfx/common/dxgi_common.h | 2 + gfx/drivers/d3d11.c | 238 ++++++++++---- gfx/drivers/d3d_shaders/sprite_sm4.hlsl.h | 86 +++++ gfx/drivers_font/d3d11_font.c | 369 ++++++++++++++++++++++ gfx/font_driver.c | 36 +++ gfx/font_driver.h | 2 + griffin/griffin.c | 4 + 12 files changed, 801 insertions(+), 75 deletions(-) create mode 100644 gfx/drivers/d3d_shaders/sprite_sm4.hlsl.h create mode 100644 gfx/drivers_font/d3d11_font.c diff --git a/Makefile.common b/Makefile.common index 95215e95da..92d363a2ab 100644 --- a/Makefile.common +++ b/Makefile.common @@ -1302,7 +1302,8 @@ ifeq ($(HAVE_D3D10), 1) endif ifeq ($(HAVE_D3D11), 1) - OBJ += gfx/drivers/d3d11.o gfx/common/d3d11_common.o + OBJ += gfx/drivers/d3d11.o gfx/common/d3d11_common.o \ + gfx/drivers_font/d3d11_font.o DEFINES += -DHAVE_D3D11 endif diff --git a/gfx/common/d3d11_common.h b/gfx/common/d3d11_common.h index e42e9ff056..b8666daeec 100644 --- a/gfx/common/d3d11_common.h +++ b/gfx/common/d3d11_common.h @@ -2473,6 +2473,19 @@ typedef struct bool dirty; } d3d11_texture_t; +typedef struct +{ + struct + { + float x, y, w, h; + } pos; + struct + { + float u, v, w, h; + } coords; + UINT32 colors[4]; +} d3d11_sprite_t; + typedef struct { unsigned cur_mon_id; @@ -2480,6 +2493,7 @@ typedef struct D3D11Device device; D3D_FEATURE_LEVEL supportedFeatureLevel; D3D11DeviceContext ctx; + D3D11RasterizerState state; D3D11RenderTargetView renderTargetView; D3D11InputLayout layout; D3D11Buffer ubo; @@ -2515,6 +2529,18 @@ typedef struct D3D11_VIEWPORT viewport; int rotation; } frame; + struct + { + D3D11VertexShader vs; + D3D11PixelShader ps; + D3D11PixelShader ps_8bit; + D3D11GeometryShader gs; + D3D11Buffer vbo; + D3D11InputLayout layout; + int offset; + int size; + bool enabled; + } sprites; } d3d11_video_t; void d3d11_init_texture(D3D11Device device, d3d11_texture_t* texture); diff --git a/gfx/common/d3dcompiler_common.c b/gfx/common/d3dcompiler_common.c index 61ed6c3349..edee55ec8a 100644 --- a/gfx/common/d3dcompiler_common.c +++ b/gfx/common/d3dcompiler_common.c @@ -19,6 +19,14 @@ #include "gfx/common/d3dcompiler_common.h" #include "verbosity.h" +static dylib_t d3dcompiler_dll; +static const char* d3dcompiler_dll_list[] = { + "D3DCompiler_47.dll", "D3DCompiler_46.dll", "D3DCompiler_45.dll", "D3DCompiler_44.dll", + "D3DCompiler_43.dll", "D3DCompiler_42.dll", "D3DCompiler_41.dll", "D3DCompiler_40.dll", + "D3DCompiler_39.dll", "D3DCompiler_38.dll", "D3DCompiler_37.dll", "D3DCompiler_36.dll", + "D3DCompiler_35.dll", "D3DCompiler_34.dll", "D3DCompiler_33.dll", NULL, +}; + HRESULT WINAPI D3DCompile( LPCVOID pSrcData, SIZE_T SrcDataSize, @@ -32,22 +40,13 @@ HRESULT WINAPI D3DCompile( ID3DBlob** ppCode, ID3DBlob** ppErrorMsgs) { - static dylib_t d3dcompiler_dll; - static const char* dll_list[] = { - "D3DCompiler_47.dll", "D3DCompiler_46.dll", "D3DCompiler_45.dll", "D3DCompiler_44.dll", - "D3DCompiler_43.dll", "D3DCompiler_42.dll", "D3DCompiler_41.dll", "D3DCompiler_40.dll", - "D3DCompiler_39.dll", "D3DCompiler_38.dll", "D3DCompiler_37.dll", "D3DCompiler_36.dll", - "D3DCompiler_35.dll", "D3DCompiler_34.dll", "D3DCompiler_33.dll", NULL, - }; - const char** dll_name = dll_list; - + const char** dll_name = d3dcompiler_dll_list; while (!d3dcompiler_dll && *dll_name) d3dcompiler_dll = dylib_load(*dll_name++); if (d3dcompiler_dll) { static pD3DCompile fp; - if (!fp) fp = (pD3DCompile)dylib_proc(d3dcompiler_dll, "D3DCompile"); @@ -60,6 +59,40 @@ HRESULT WINAPI D3DCompile( return TYPE_E_CANTLOADLIBRARY; } +HRESULT WINAPI D3DCompileFromFile( + LPCWSTR pFileName, + const D3D_SHADER_MACRO* pDefines, + ID3DInclude* pInclude, + LPCSTR pEntrypoint, + LPCSTR pTarget, + UINT Flags1, + UINT Flags2, + ID3DBlob** ppCode, + ID3DBlob** ppErrorMsgs) +{ + const char** dll_name = d3dcompiler_dll_list; + while (!d3dcompiler_dll && *dll_name) + d3dcompiler_dll = dylib_load(*dll_name++); + + if (d3dcompiler_dll) + { + typedef HRESULT(WINAPI * pD3DCompileFromFile)( + LPCWSTR pFileName, const D3D_SHADER_MACRO* pDefines, ID3DInclude* pInclude, + LPCSTR pEntrypoint, LPCSTR pTarget, UINT Flags1, UINT Flags2, ID3DBlob** ppCode, + ID3DBlob** ppErrorMsgs); + static pD3DCompileFromFile fp; + if (!fp) + fp = (pD3DCompileFromFile)dylib_proc(d3dcompiler_dll, "D3DCompileFromFile"); + + if (fp) + return fp( + pFileName, pDefines, pInclude, pEntrypoint, pTarget, Flags1, Flags2, ppCode, + ppErrorMsgs); + } + + return TYPE_E_CANTLOADLIBRARY; +} + bool d3d_compile(const char* src, size_t size, LPCSTR entrypoint, LPCSTR target, D3DBlob* out) { D3DBlob error_msg; @@ -71,12 +104,35 @@ bool d3d_compile(const char* src, size_t size, LPCSTR entrypoint, LPCSTR target, if (FAILED(D3DCompile( src, size, NULL, NULL, NULL, entrypoint, target, compileflags, 0, out, &error_msg))) - return false; - - if (error_msg) { - RARCH_ERR("D3DCompile failed :\n%s\n", (const char*)D3DGetBufferPointer(error_msg)); - Release(error_msg); + if (error_msg) + { + RARCH_ERR("D3DCompile failed :\n%s\n", (const char*)D3DGetBufferPointer(error_msg)); + Release(error_msg); + } + return false; + } + + return true; +} + +bool d3d_compile_from_file(LPCWSTR filename, LPCSTR entrypoint, LPCSTR target, D3DBlob* out) +{ + D3DBlob error_msg; + UINT compileflags = 0; + +#ifdef DEBUG + compileflags |= D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; +#endif + + if (FAILED(D3DCompileFromFile( + filename, NULL, NULL, entrypoint, target, compileflags, 0, out, &error_msg))) + { + if (error_msg) + { + RARCH_ERR("D3DCompile failed :\n%s\n", (const char*)D3DGetBufferPointer(error_msg)); + Release(error_msg); + } return false; } diff --git a/gfx/common/d3dcompiler_common.h b/gfx/common/d3dcompiler_common.h index 7a71c614f7..a0ed08b35c 100644 --- a/gfx/common/d3dcompiler_common.h +++ b/gfx/common/d3dcompiler_common.h @@ -89,3 +89,4 @@ D3DUnregisterDestructionCallback(D3DDestructionNotifier destruction_notifier, UI /* end of auto-generated */ bool d3d_compile(const char* src, size_t size, LPCSTR entrypoint, LPCSTR target, D3DBlob* out); +bool d3d_compile_from_file(LPCWSTR filename, LPCSTR entrypoint, LPCSTR target, D3DBlob* out); diff --git a/gfx/common/dxgi_common.c b/gfx/common/dxgi_common.c index b64e6c6265..7bc53da303 100644 --- a/gfx/common/dxgi_common.c +++ b/gfx/common/dxgi_common.c @@ -76,6 +76,20 @@ DXGI_FORMAT* dxgi_get_format_fallback_list(DXGI_FORMAT format) DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN }; return formats; } + case DXGI_FORMAT_A8_UNORM: + { + static DXGI_FORMAT formats[] = { DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_R8_UNORM, + DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN }; + return formats; + } + case DXGI_FORMAT_R8_UNORM: + { + static DXGI_FORMAT formats[] = { DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_A8_UNORM, + DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN }; + return formats; + } default: assert(0); } @@ -87,7 +101,8 @@ DXGI_FORMAT* dxgi_get_format_fallback_list(DXGI_FORMAT format) dst_gb, dst_bb, dst_ab, dst_rs, dst_gs, dst_bs, dst_as) \ do \ { \ - if (((src_rs == dst_rs && src_rb == dst_rb) || !dst_rb) && \ + if ((sizeof(src_type) == sizeof(dst_type)) && \ + ((src_rs == dst_rs && src_rb == dst_rb) || !dst_rb) && \ ((src_gs == dst_gs && src_gb == dst_gb) || !dst_gb) && \ ((src_bs == dst_bs && src_bb == dst_bb) || !dst_bb) && \ ((src_as == dst_as && src_ab == dst_ab) || !dst_ab)) \ @@ -184,6 +199,8 @@ DXGI_FORMAT* dxgi_get_format_fallback_list(DXGI_FORMAT format) #define DXGI_FORMAT_R8G8B8A8_UNORM_DESCS UINT32, 8, 8, 8, 8, 0, 8, 16, 24 #define DXGI_FORMAT_B8G8R8X8_UNORM_DESCS UINT32, 8, 8, 8, 0, 16, 8, 0, 0 #define DXGI_FORMAT_B8G8R8A8_UNORM_DESCS UINT32, 8, 8, 8, 8, 16, 8, 0, 24 +#define DXGI_FORMAT_A8_UNORM_DESCS UINT8, 0, 0, 0, 8, 0, 0, 0, 0 +#define DXGI_FORMAT_R8_UNORM_DESCS UINT8, 8, 0, 0, 0, 0, 0, 0, 0 #define DXGI_FORMAT_B5G6R5_UNORM_DESCS UINT16, 5, 6, 5, 0, 11, 5, 0, 0 #define DXGI_FORMAT_B5G5R5A1_UNORM_DESCS UINT16, 5, 5, 5, 1, 10, 5, 0, 11 #define DXGI_FORMAT_B4G4R4A4_UNORM_DESCS UINT16, 4, 4, 4, 4, 8, 4, 0, 12 @@ -192,6 +209,8 @@ DXGI_FORMAT* dxgi_get_format_fallback_list(DXGI_FORMAT format) #define FORMAT_SRC_LIST() \ FORMAT_SRC(DXGI_FORMAT_R8G8B8A8_UNORM); \ FORMAT_SRC(DXGI_FORMAT_B8G8R8X8_UNORM); \ + FORMAT_SRC(DXGI_FORMAT_A8_UNORM); \ + FORMAT_SRC(DXGI_FORMAT_R8_UNORM); \ FORMAT_SRC(DXGI_FORMAT_B5G6R5_UNORM); \ FORMAT_SRC(DXGI_FORMAT_B5G5R5A1_UNORM); \ FORMAT_SRC(DXGI_FORMAT_B4G4R4A4_UNORM); \ @@ -201,6 +220,8 @@ DXGI_FORMAT* dxgi_get_format_fallback_list(DXGI_FORMAT format) #define FORMAT_DST_LIST(srcfmt) \ FORMAT_DST(srcfmt, DXGI_FORMAT_R8G8B8A8_UNORM); \ FORMAT_DST(srcfmt, DXGI_FORMAT_B8G8R8X8_UNORM); \ + FORMAT_DST(srcfmt, DXGI_FORMAT_A8_UNORM); \ + FORMAT_DST(srcfmt, DXGI_FORMAT_R8_UNORM); \ FORMAT_DST(srcfmt, DXGI_FORMAT_B5G6R5_UNORM); \ FORMAT_DST(srcfmt, DXGI_FORMAT_B5G5R5A1_UNORM); \ FORMAT_DST(srcfmt, DXGI_FORMAT_B4G4R4A4_UNORM); \ diff --git a/gfx/common/dxgi_common.h b/gfx/common/dxgi_common.h index 1bfa91d4ea..f583bc102f 100644 --- a/gfx/common/dxgi_common.h +++ b/gfx/common/dxgi_common.h @@ -542,6 +542,8 @@ static inline HRESULT DXGICreateFactory(DXGIFactory* factory) /* internal */ +#define DXGI_COLOR_RGBA(r, g, b, a) (((UINT32)(a) << 24) | ((UINT32)(b) << 16) | ((UINT32)(g) << 8) | ((UINT32)(r) << 0)) + typedef enum { DXGI_FORMAT_EX_A4R4G4B4_UNORM = 1000, } DXGI_FORMAT_EX; diff --git a/gfx/drivers/d3d11.c b/gfx/drivers/d3d11.c index f79c2e69d9..d2b3e4f6ef 100644 --- a/gfx/drivers/d3d11.c +++ b/gfx/drivers/d3d11.c @@ -22,6 +22,7 @@ #include "../../verbosity.h" #include "../configuration.h" #include "../video_driver.h" +#include "../font_driver.h" #include "../common/win32_common.h" #include "../common/d3d11_common.h" #include "../common/dxgi_common.h" @@ -71,6 +72,49 @@ static void d3d11_update_viewport(void* data, bool force_full) d3d11->resize_viewport = false; } +static void d3d11_gfx_free(void* data) +{ + d3d11_video_t* d3d11 = (d3d11_video_t*)data; + + if (!d3d11) + return; + + Release(d3d11->frame.ubo); + Release(d3d11->frame.texture.view); + Release(d3d11->frame.texture.handle); + Release(d3d11->frame.texture.staging); + Release(d3d11->frame.vbo); + + Release(d3d11->menu.texture.handle); + Release(d3d11->menu.texture.staging); + Release(d3d11->menu.texture.view); + Release(d3d11->menu.vbo); + + Release(d3d11->sprites.vs); + Release(d3d11->sprites.ps); + Release(d3d11->sprites.gs); + Release(d3d11->sprites.vbo); + Release(d3d11->sprites.layout); + + Release(d3d11->ubo); + Release(d3d11->blend_enable); + Release(d3d11->blend_disable); + Release(d3d11->sampler_nearest); + Release(d3d11->sampler_linear); + Release(d3d11->ps); + Release(d3d11->vs); + Release(d3d11->layout); + Release(d3d11->state); + Release(d3d11->renderTargetView); + Release(d3d11->swapChain); + Release(d3d11->ctx); + Release(d3d11->device); + + win32_monitor_from_window(); + win32_destroy_window(); + free(d3d11); +} + static void* d3d11_gfx_init(const video_info_t* video, const input_driver_t** input, void** input_data) { @@ -143,8 +187,8 @@ d3d11_gfx_init(const video_info_t* video, const input_driver_t** input, void** i d3d11->viewport.Width = video->width; d3d11->viewport.Height = video->height; d3d11->resize_viewport = true; - d3d11->vsync = video->vsync; - d3d11->format = video->rgb32 ? DXGI_FORMAT_B8G8R8X8_UNORM : DXGI_FORMAT_B5G6R5_UNORM; + d3d11->vsync = video->vsync; + d3d11->format = video->rgb32 ? DXGI_FORMAT_B8G8R8X8_UNORM : DXGI_FORMAT_B5G6R5_UNORM; d3d11->frame.texture.desc.Format = d3d11_get_closest_match_texture2D(d3d11->device, d3d11->format); @@ -197,19 +241,20 @@ d3d11_gfx_init(const video_info_t* video, const input_driver_t** input, void** i { D3D11_BUFFER_DESC desc = { - .Usage = D3D11_USAGE_DYNAMIC, - .ByteWidth = sizeof(vertices), - .BindFlags = D3D11_BIND_VERTEX_BUFFER, - .StructureByteStride = 0, /* sizeof(Vertex) ? */ - .CPUAccessFlags = D3D11_CPU_ACCESS_WRITE, + .Usage = D3D11_USAGE_IMMUTABLE, + .ByteWidth = sizeof(vertices), + .BindFlags = D3D11_BIND_VERTEX_BUFFER, }; D3D11_SUBRESOURCE_DATA vertexData = { vertices }; - D3D11CreateBuffer(d3d11->device, &desc, &vertexData, &d3d11->menu.vbo); - desc.Usage = D3D11_USAGE_IMMUTABLE; - desc.CPUAccessFlags = 0; D3D11CreateBuffer(d3d11->device, &desc, &vertexData, &d3d11->frame.vbo); + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + D3D11CreateBuffer(d3d11->device, &desc, &vertexData, &d3d11->menu.vbo); + + d3d11->sprites.size = sizeof(d3d11_sprite_t) * 1024; + desc.ByteWidth = d3d11->sprites.size; + D3D11CreateBuffer(d3d11->device, &desc, NULL, &d3d11->sprites.vbo); } - D3D11SetPrimitiveTopology(d3d11->ctx, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); } { @@ -246,9 +291,70 @@ d3d11_gfx_init(const video_info_t* video, const input_driver_t** input, void** i Release(ps_code); } - D3D11SetInputLayout(d3d11->ctx, d3d11->layout); - D3D11SetVShader(d3d11->ctx, d3d11->vs, NULL, 0); - D3D11SetPShader(d3d11->ctx, d3d11->ps, NULL, 0); + { + D3DBlob vs_code; + D3DBlob ps_code; + D3DBlob ps_A8_code; + D3DBlob gs_code; + + static const char sprite[] = +#include "d3d_shaders/sprite_sm4.hlsl.h" + ; + + D3D11_INPUT_ELEMENT_DESC desc[] = { + { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(d3d11_sprite_t, pos), + D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(d3d11_sprite_t, coords), + D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(d3d11_sprite_t, colors[0]), + D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(d3d11_sprite_t, colors[1]), + D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 2, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(d3d11_sprite_t, colors[2]), + D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 3, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(d3d11_sprite_t, colors[3]), + D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; +#if 1 + d3d_compile(sprite, sizeof(sprite), "VSMain", "vs_5_0", &vs_code); + d3d_compile(sprite, sizeof(sprite), "PSMain", "ps_5_0", &ps_code); + d3d_compile(sprite, sizeof(sprite), "PSMainA8", "ps_5_0", &ps_A8_code); + d3d_compile(sprite, sizeof(sprite), "GSMain", "gs_5_0", &gs_code); +#else + if (!d3d_compile_from_file( + L"gfx/drivers/d3d_shaders/sprite_sm4.hlsl", "VSMain", "vs_5_0", &vs_code)) + goto error; + if (!d3d_compile_from_file( + L"gfx/drivers/d3d_shaders/sprite_sm4.hlsl", "PSMain", "ps_5_0", &ps_code)) + goto error; + if (!d3d_compile_from_file( + L"gfx/drivers/d3d_shaders/sprite_sm4.hlsl", "PSMainA8", "ps_5_0", &ps_A8_code)) + goto error; + if (!d3d_compile_from_file( + L"gfx/drivers/d3d_shaders/sprite_sm4.hlsl", "GSMain", "gs_5_0", &gs_code)) + goto error; +#endif + D3D11CreateVertexShader( + d3d11->device, D3DGetBufferPointer(vs_code), D3DGetBufferSize(vs_code), NULL, + &d3d11->sprites.vs); + D3D11CreatePixelShader( + d3d11->device, D3DGetBufferPointer(ps_code), D3DGetBufferSize(ps_code), NULL, + &d3d11->sprites.ps); + D3D11CreatePixelShader( + d3d11->device, D3DGetBufferPointer(ps_A8_code), D3DGetBufferSize(ps_A8_code), NULL, + &d3d11->sprites.ps_8bit); + D3D11CreateGeometryShader( + d3d11->device, D3DGetBufferPointer(gs_code), D3DGetBufferSize(gs_code), NULL, + &d3d11->sprites.gs); + D3D11CreateInputLayout( + d3d11->device, desc, countof(desc), D3DGetBufferPointer(vs_code), + D3DGetBufferSize(vs_code), &d3d11->sprites.layout); + + Release(vs_code); + Release(ps_code); + Release(ps_A8_code); + Release(gs_code); + } { D3D11_BLEND_DESC blend_desc = { @@ -270,11 +376,22 @@ d3d11_gfx_init(const video_info_t* video, const input_driver_t** input, void** i blend_desc.RenderTarget[0].BlendEnable = FALSE; D3D11CreateBlendState(d3d11->device, &blend_desc, &d3d11->blend_disable); } + { + D3D11_RASTERIZER_DESC desc = { + .FillMode = D3D11_FILL_SOLID, + .CullMode = D3D11_CULL_NONE, + .DepthClipEnable = TRUE, + }; + D3D11CreateRasterizerState(d3d11->device, &desc, &d3d11->state); + } + D3D11SetState(d3d11->ctx, d3d11->state); + + font_driver_init_osd(d3d11, false, video->is_threaded, FONT_DRIVER_RENDER_D3D11_API); return d3d11; error: - free(d3d11); + d3d11_gfx_free(d3d11); return NULL; } @@ -312,6 +429,11 @@ static bool d3d11_gfx_frame( PERF_START(); D3D11ClearRenderTargetView(d3d11->ctx, d3d11->renderTargetView, d3d11->clearcolor); + D3D11SetVShader(d3d11->ctx, d3d11->vs, NULL, 0); + D3D11SetPShader(d3d11->ctx, d3d11->ps, NULL, 0); + D3D11SetGShader(d3d11->ctx, NULL, NULL, 0); + D3D11SetInputLayout(d3d11->ctx, d3d11->layout); + D3D11SetPrimitiveTopology(d3d11->ctx, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); if (frame && width && height) { @@ -341,21 +463,24 @@ static bool d3d11_gfx_frame( d3d11_update_viewport(d3d11, false); D3D11SetViewports(d3d11->ctx, 1, &d3d11->frame.viewport); - D3D11SetVertexBuffers(d3d11->ctx, 0, 1, &d3d11->frame.vbo, &stride, &offset); - D3D11SetVShaderConstantBuffers(d3d11->ctx, 0, 1, &d3d11->frame.ubo); D3D11SetPShaderResources(d3d11->ctx, 0, 1, &d3d11->frame.texture.view); D3D11SetPShaderSamplers(d3d11->ctx, 0, 1, &d3d11->frame.sampler); + D3D11SetVertexBuffers(d3d11->ctx, 0, 1, &d3d11->frame.vbo, &stride, &offset); + D3D11SetVShaderConstantBuffers(d3d11->ctx, 0, 1, &d3d11->frame.ubo); D3D11SetBlendState(d3d11->ctx, d3d11->blend_disable, NULL, D3D11_DEFAULT_SAMPLE_MASK); D3D11Draw(d3d11->ctx, 4, 0); - D3D11SetBlendState(d3d11->ctx, d3d11->blend_enable, NULL, D3D11_DEFAULT_SAMPLE_MASK); + // D3D11SetBlendState(d3d11->ctx, d3d11->blend_enable, NULL, D3D11_DEFAULT_SAMPLE_MASK); if (d3d11->menu.enabled && d3d11->menu.texture.handle) { if (d3d11->menu.texture.dirty) + { D3D11CopyTexture2DSubresourceRegion( d3d11->ctx, d3d11->menu.texture.handle, 0, 0, 0, 0, d3d11->menu.texture.staging, 0, NULL); + d3d11->menu.texture.dirty = false; + } if (d3d11->menu.fullscreen) D3D11SetViewports(d3d11->ctx, 1, &d3d11->viewport); @@ -367,13 +492,33 @@ static bool d3d11_gfx_frame( D3D11Draw(d3d11->ctx, 4, 0); } } + { + UINT sprite_stride = sizeof(d3d11_sprite_t); + UINT offset = 0; + D3D11SetViewports(d3d11->ctx, 1, &d3d11->viewport); + D3D11SetVShader(d3d11->ctx, d3d11->sprites.vs, NULL, 0); + D3D11SetPShader(d3d11->ctx, d3d11->sprites.ps, NULL, 0); + D3D11SetGShader(d3d11->ctx, d3d11->sprites.gs, NULL, 0); + D3D11SetInputLayout(d3d11->ctx, d3d11->sprites.layout); + D3D11SetPrimitiveTopology(d3d11->ctx, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); + D3D11SetVertexBuffers(d3d11->ctx, 0, 1, &d3d11->sprites.vbo, &sprite_stride, &offset); + D3D11SetPShaderSamplers(d3d11->ctx, 0, 1, &d3d11->sampler_linear); + D3D11SetBlendState(d3d11->ctx, d3d11->blend_enable, NULL, D3D11_DEFAULT_SAMPLE_MASK); + + d3d11->sprites.offset = 0; + d3d11->sprites.enabled = true; + + if (msg && *msg) + { + font_driver_render_msg(video_info, NULL, msg, NULL); + gfx_ctx_d3d.update_window_title(NULL, video_info); + } + d3d11->sprites.enabled = false; + } DXGIPresent(d3d11->swapChain, !!d3d11->vsync, 0); PERF_STOP(); - if (msg && *msg) - gfx_ctx_d3d.update_window_title(NULL, video_info); - return true; } @@ -415,42 +560,6 @@ static bool d3d11_gfx_has_windowed(void* data) return true; } -static void d3d11_gfx_free(void* data) -{ - d3d11_video_t* d3d11 = (d3d11_video_t*)data; - - if (!d3d11) - return; - - Release(d3d11->frame.ubo); - Release(d3d11->frame.texture.view); - Release(d3d11->frame.texture.handle); - Release(d3d11->frame.texture.staging); - Release(d3d11->frame.vbo); - - Release(d3d11->menu.texture.handle); - Release(d3d11->menu.texture.staging); - Release(d3d11->menu.texture.view); - Release(d3d11->menu.vbo); - - Release(d3d11->ubo); - Release(d3d11->blend_enable); - Release(d3d11->blend_disable); - Release(d3d11->sampler_nearest); - Release(d3d11->sampler_linear); - Release(d3d11->ps); - Release(d3d11->vs); - Release(d3d11->layout); - Release(d3d11->renderTargetView); - Release(d3d11->swapChain); - Release(d3d11->ctx); - Release(d3d11->device); - - win32_monitor_from_window(); - win32_destroy_window(); - free(d3d11); -} - static bool d3d11_gfx_set_shader(void* data, enum rarch_shader_type type, const char* path) { (void)data; @@ -524,6 +633,19 @@ static void d3d11_gfx_apply_state_changes(void* data) d3d11->resize_viewport = true; } +static void d3d11_gfx_set_osd_msg( + void* data, video_frame_info_t* video_info, const char* msg, const void* params, void* font) +{ + d3d11_video_t* d3d11 = (d3d11_video_t*)data; + + if (d3d11) + { + if (d3d11->sprites.enabled) + font_driver_render_msg(video_info, font, msg, params); + else + printf("OSD msg: %s\n", msg); + } +} static const video_poke_interface_t d3d11_poke_interface = { NULL, /* set_coords */ NULL, /* set_mvp */ @@ -540,7 +662,7 @@ static const video_poke_interface_t d3d11_poke_interface = { d3d11_gfx_apply_state_changes, d3d11_set_menu_texture_frame, d3d11_set_menu_texture_enable, - NULL, /* set_osd_msg */ + d3d11_gfx_set_osd_msg, NULL, /* show_mouse */ NULL, /* grab_mouse_toggle */ NULL, /* get_current_shader */ diff --git a/gfx/drivers/d3d_shaders/sprite_sm4.hlsl.h b/gfx/drivers/d3d_shaders/sprite_sm4.hlsl.h new file mode 100644 index 0000000000..2e1c081eb1 --- /dev/null +++ b/gfx/drivers/d3d_shaders/sprite_sm4.hlsl.h @@ -0,0 +1,86 @@ + +#define SRC(src) #src +SRC( + + struct VSInput + { + float4 position : POSITION; + float4 texcoord : TEXCOORD0; + float4 color0 : COLOR0; + float4 color1 : COLOR1; + float4 color2 : COLOR2; + float4 color3 : COLOR3; + }; + struct GSInput + { + float4 position : POSITION; + float4 texcoord : TEXCOORD0; + float4 color0 : COLOR0; + float4 color1 : COLOR1; + float4 color2 : COLOR2; + float4 color3 : COLOR3; + }; + struct PSInput + { + float4 position : SV_POSITION; + float2 texcoord : TEXCOORD0; + float4 color : COLOR; + }; + + GSInput VSMain(VSInput input) + { + GSInput output; + output.position = input.position * 2.0; + output.position.w *= -1.0; + output.position.x = output.position.x - 1.0; + output.position.y = 1.0 - output.position.y; + output.texcoord = input.texcoord; + output.color0 = input.color0; + output.color1 = input.color1; + output.color2 = input.color2; + output.color3 = input.color3; + return output; + } + + [maxvertexcount(4)] + void GSMain(point GSInput input[1], inout TriangleStream triStream) + { + PSInput output; + output.position.zw = float2(0.0f, 1.0f); + + output.position.xy = input[0].position.xy + input[0].position.zw * float2(1.0, 0.0); + output.texcoord = input[0].texcoord.xy + input[0].texcoord.zw * float2(1.0, 0.0); + output.color = input[0].color0; + triStream.Append(output); + + output.position.xy = input[0].position.xy + input[0].position.zw * float2(0.0, 0.0); + output.texcoord = input[0].texcoord.xy + input[0].texcoord.zw * float2(0.0, 0.0); + output.color = input[0].color1; + triStream.Append(output); + + output.position.xy = input[0].position.xy + input[0].position.zw * float2(1.0, 1.0); + output.texcoord = input[0].texcoord.xy + input[0].texcoord.zw * float2(1.0, 1.0); + output.color = input[0].color2; + triStream.Append(output); + + output.position.xy = input[0].position.xy + input[0].position.zw * float2(0.0, 1.0); + output.texcoord = input[0].texcoord.xy + input[0].texcoord.zw * float2(0.0, 1.0); + output.color = input[0].color3; + triStream.Append(output); + } + + uniform sampler s0; + uniform Texture2D t0; + float4 PSMain(PSInput input) : SV_TARGET + { + return input.color * t0.Sample(s0, input.texcoord); + // return input.color; + }; + float4 PSMainA8(PSInput input) : SV_TARGET + { + // return t0.Sample(s0, input.texcoord).a; + return input.color * t0.Sample(s0, input.texcoord).a; + // return input.color; + }; + +) diff --git a/gfx/drivers_font/d3d11_font.c b/gfx/drivers_font/d3d11_font.c new file mode 100644 index 0000000000..4f91e77e2a --- /dev/null +++ b/gfx/drivers_font/d3d11_font.c @@ -0,0 +1,369 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2014-2018 - Ali Bouhlel + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include +#include +#include +#include +#include + +#include "gfx/font_driver.h" +#include "gfx/video_driver.h" +#include "gfx/common/d3d11_common.h" + +#include "verbosity.h" + +typedef struct +{ + d3d11_texture_t texture; + const font_renderer_driver_t* font_driver; + void* font_data; + struct font_atlas* atlas; +} d3d11_font_t; + +static void* +d3d11_font_init_font(void* data, const char* font_path, float font_size, bool is_threaded) +{ + uint32_t i; + d3d11_video_t* d3d11 = (d3d11_video_t*)data; + d3d11_font_t* font = (d3d11_font_t*)calloc(1, sizeof(*font)); + + if (!font) + return NULL; + + if (!font_renderer_create_default( + (const void**)&font->font_driver, &font->font_data, font_path, font_size)) + { + RARCH_WARN("Couldn't initialize font renderer.\n"); + free(font); + return NULL; + } + + font->atlas = font->font_driver->get_atlas(font->font_data); + font->texture.desc.Width = font->atlas->width; + font->texture.desc.Height = font->atlas->height; + font->texture.desc.Format = + d3d11_get_closest_match_texture2D(d3d11->device, DXGI_FORMAT_A8_UNORM); + DEBUG_INT(font->texture.desc.Format); + d3d11_init_texture(d3d11->device, &font->texture); + d3d11_update_texture( + d3d11->ctx, font->atlas->width, font->atlas->height, font->atlas->width, DXGI_FORMAT_A8_UNORM, + font->atlas->buffer, &font->texture); + font->texture.dirty = true; + font->atlas->dirty = false; + + return font; +} + +static void d3d11_font_free_font(void* data, bool is_threaded) +{ + d3d11_font_t* font = (d3d11_font_t*)data; + + if (!font) + return; + + if (font->font_driver && font->font_data && font->font_driver->free) + font->font_driver->free(font->font_data); + + Release(font->texture.handle); + Release(font->texture.staging); + Release(font->texture.view); + free(font); +} + +static int d3d11_font_get_message_width(void* data, const char* msg, unsigned msg_len, float scale) +{ + d3d11_font_t* font = (d3d11_font_t*)data; + + unsigned i; + int delta_x = 0; + + if (!font) + return 0; + + for (i = 0; i < msg_len; i++) + { + const char* msg_tmp = &msg[i]; + unsigned code = utf8_walk(&msg_tmp); + unsigned skip = msg_tmp - &msg[i]; + + if (skip > 1) + i += skip - 1; + + const struct font_glyph* glyph = font->font_driver->get_glyph(font->font_data, code); + + if (!glyph) /* Do something smarter here ... */ + glyph = font->font_driver->get_glyph(font->font_data, '?'); + + if (!glyph) + continue; + + delta_x += glyph->advance_x; + } + + return delta_x * scale; +} + +static void d3d11_font_render_line( + video_frame_info_t* video_info, + d3d11_font_t* font, + const char* msg, + unsigned msg_len, + float scale, + const unsigned int color, + float pos_x, + float pos_y, + unsigned text_align) +{ + unsigned i; + d3d11_video_t* d3d11 = (d3d11_video_t*)video_driver_get_ptr(false); + unsigned width = video_info->width; + unsigned height = video_info->height; + int x = roundf(pos_x * width); + int y = roundf((1.0 - pos_y) * height); + + if (!d3d11->sprites.enabled || d3d11->sprites.offset + msg_len > d3d11->sprites.size) + return; + + switch (text_align) + { + case TEXT_ALIGN_RIGHT: + x -= d3d11_font_get_message_width(font, msg, msg_len, scale); + break; + + case TEXT_ALIGN_CENTER: + x -= d3d11_font_get_message_width(font, msg, msg_len, scale) / 2; + break; + } + + D3D11_MAPPED_SUBRESOURCE mapped_vbo; + D3D11MapBuffer(d3d11->ctx, d3d11->sprites.vbo, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mapped_vbo); + d3d11_sprite_t* v = (d3d11_sprite_t*)mapped_vbo.pData + d3d11->sprites.offset; + + for (i = 0; i < msg_len; i++) + { + const char* msg_tmp = &msg[i]; + unsigned code = utf8_walk(&msg_tmp); + unsigned skip = msg_tmp - &msg[i]; + + if (skip > 1) + i += skip - 1; + + const struct font_glyph* glyph = font->font_driver->get_glyph(font->font_data, code); + + if (!glyph) /* Do something smarter here ... */ + glyph = font->font_driver->get_glyph(font->font_data, '?'); + + if (!glyph) + continue; + + v->pos.x = (x + glyph->draw_offset_x) * scale / (float)d3d11->viewport.Width; + v->pos.y = (y + glyph->draw_offset_y) * scale / (float)d3d11->viewport.Height; + v->pos.w = glyph->width * scale / (float)d3d11->viewport.Width; + v->pos.h = glyph->height * scale / (float)d3d11->viewport.Height; + + v->coords.u = glyph->atlas_offset_x / (float)font->texture.desc.Width; + v->coords.v = glyph->atlas_offset_y / (float)font->texture.desc.Height; + v->coords.w = glyph->width / (float)font->texture.desc.Width; + v->coords.h = glyph->height / (float)font->texture.desc.Height; + + v->colors[0] = color; + v->colors[1] = color; + v->colors[2] = color; + v->colors[3] = color; + + v++; + + x += glyph->advance_x * scale; + y += glyph->advance_y * scale; + } + + v++; + + int count = v - ((d3d11_sprite_t*)mapped_vbo.pData + d3d11->sprites.offset); + D3D11UnmapBuffer(d3d11->ctx, d3d11->sprites.vbo, 0); + + if (!count) + return; + + if (font->atlas->dirty) + { + + d3d11_update_texture( + d3d11->ctx, font->atlas->width, font->atlas->height, font->atlas->width, DXGI_FORMAT_A8_UNORM, + font->atlas->buffer, &font->texture); + font->atlas->dirty = false; + font->texture.dirty = true; + } + + if(font->texture.dirty) + { + D3D11_BOX frame_box = { 0, 0, 0, font->atlas->width, font->atlas->height, 1 }; + D3D11CopyTexture2DSubresourceRegion( + d3d11->ctx, font->texture.handle, 0, 0, 0, 0, font->texture.staging, 0, + &frame_box); + font->texture.dirty = false; + } + + D3D11SetPShader(d3d11->ctx, d3d11->sprites.ps_8bit, NULL, 0); + D3D11SetPShaderResources(d3d11->ctx, 0, 1, &font->texture.view); + D3D11Draw(d3d11->ctx, count, d3d11->sprites.offset); + D3D11SetPShader(d3d11->ctx, d3d11->sprites.ps, NULL, 0); + + d3d11->sprites.offset += count; +} + +static void d3d11_font_render_message( + video_frame_info_t* video_info, + d3d11_font_t* font, + const char* msg, + float scale, + const unsigned int color, + float pos_x, + float pos_y, + unsigned text_align) +{ + int lines = 0; + float line_height; + + if (!msg || !*msg) + return; + + /* If the font height is not supported just draw as usual */ + if (!font->font_driver->get_line_height) + { + d3d11_font_render_line( + video_info, font, msg, strlen(msg), scale, color, pos_x, pos_y, text_align); + return; + } + + line_height = scale / font->font_driver->get_line_height(font->font_data); + + for (;;) + { + const char* delim = strchr(msg, '\n'); + + /* Draw the line */ + if (delim) + { + unsigned msg_len = delim - msg; + d3d11_font_render_line( + video_info, font, msg, msg_len, scale, color, pos_x, + pos_y - (float)lines * line_height, text_align); + msg += msg_len + 1; + lines++; + } + else + { + unsigned msg_len = strlen(msg); + d3d11_font_render_line( + video_info, font, msg, msg_len, scale, color, pos_x, + pos_y - (float)lines * line_height, text_align); + break; + } + } +} + +static void d3d11_font_render_msg( + video_frame_info_t* video_info, void* data, const char* msg, const void* userdata) +{ + float x, y, scale, drop_mod, drop_alpha; + int drop_x, drop_y; + enum text_alignment text_align; + unsigned color, color_dark, r, g, b, alpha, r_dark, g_dark, b_dark, alpha_dark; + d3d11_font_t* font = (d3d11_font_t*)data; + const struct font_params* params = (const struct font_params*)userdata; + unsigned width = video_info->width; + unsigned height = video_info->height; + + if (!font || !msg || !*msg) + return; + + if (params) + { + x = params->x; + y = params->y; + scale = params->scale; + text_align = params->text_align; + drop_x = params->drop_x; + drop_y = params->drop_y; + drop_mod = params->drop_mod; + drop_alpha = params->drop_alpha; + r = FONT_COLOR_GET_RED(params->color); + g = FONT_COLOR_GET_GREEN(params->color); + b = FONT_COLOR_GET_BLUE(params->color); + alpha = FONT_COLOR_GET_ALPHA(params->color); + color = params->color; + } + else + { + x = video_info->font_msg_pos_x; + y = video_info->font_msg_pos_y; + scale = 1.0f; + text_align = TEXT_ALIGN_LEFT; + + r = (video_info->font_msg_color_r * 255); + g = (video_info->font_msg_color_g * 255); + b = (video_info->font_msg_color_b * 255); + alpha = 255; + color = DXGI_COLOR_RGBA(r, g, b, alpha); + + drop_x = -2; + drop_y = -2; + drop_mod = 0.3f; + drop_alpha = 1.0f; + } + + if (drop_x || drop_y) + { + r_dark = r * drop_mod; + g_dark = g * drop_mod; + b_dark = b * drop_mod; + alpha_dark = alpha * drop_alpha; + color_dark = DXGI_COLOR_RGBA(r_dark, g_dark, b_dark, alpha_dark); + + d3d11_font_render_message( + video_info, font, msg, scale, color_dark, x + scale * drop_x / width, + y + scale * drop_y / height, text_align); + } + + d3d11_font_render_message(video_info, font, msg, scale, color, x, y, text_align); +} + +static const struct font_glyph* d3d11_font_get_glyph(void* data, uint32_t code) +{ + d3d11_font_t* font = (d3d11_font_t*)data; + + if (!font || !font->font_driver) + return NULL; + + if (!font->font_driver->ident) + return NULL; + + return font->font_driver->get_glyph((void*)font->font_driver, code); +} + +static void d3d11_font_bind_block(void* data, void* userdata) { (void)data; } + +font_renderer_t d3d11_font = { + d3d11_font_init_font, + d3d11_font_free_font, + d3d11_font_render_msg, + "d3d11font", + d3d11_font_get_glyph, + d3d11_font_bind_block, + NULL, /* flush */ + d3d11_font_get_message_width, +}; diff --git a/gfx/font_driver.c b/gfx/font_driver.c index 03fac4bad7..fd54e019fa 100644 --- a/gfx/font_driver.c +++ b/gfx/font_driver.c @@ -278,6 +278,37 @@ static bool vulkan_font_init_first( } #endif +#ifdef HAVE_D3D11 +static const font_renderer_t *d3d11_font_backends[] = { + &d3d11_font, + NULL, +}; + +static bool d3d11_font_init_first( + const void **font_driver, void **font_handle, + void *video_data, const char *font_path, + float font_size, bool is_threaded) +{ + unsigned i; + + for (i = 0; d3d11_font_backends[i]; i++) + { + void *data = d3d11_font_backends[i]->init(video_data, + font_path, font_size, + is_threaded); + + if (!data) + continue; + + *font_driver = d3d11_font_backends[i]; + *font_handle = data; + return true; + } + + return false; +} +#endif + #ifdef HAVE_VITA2D static const font_renderer_t *vita2d_font_backends[] = { &vita2d_vita_font @@ -394,6 +425,11 @@ static bool font_init_first( return vulkan_font_init_first(font_driver, font_handle, video_data, font_path, font_size, is_threaded); #endif +#ifdef HAVE_D3D11 + case FONT_DRIVER_RENDER_D3D11_API: + return d3d11_font_init_first(font_driver, font_handle, + video_data, font_path, font_size, is_threaded); +#endif #ifdef HAVE_VITA2D case FONT_DRIVER_RENDER_VITA2D: return vita2d_font_init_first(font_driver, font_handle, diff --git a/gfx/font_driver.h b/gfx/font_driver.h index 2656d358c6..2cfa3fe7ae 100644 --- a/gfx/font_driver.h +++ b/gfx/font_driver.h @@ -31,6 +31,7 @@ enum font_driver_render_api FONT_DRIVER_RENDER_DONT_CARE, FONT_DRIVER_RENDER_OPENGL_API, FONT_DRIVER_RENDER_DIRECT3D_API, + FONT_DRIVER_RENDER_D3D11_API, FONT_DRIVER_RENDER_VITA2D, FONT_DRIVER_RENDER_CTR, FONT_DRIVER_RENDER_WIIU, @@ -184,6 +185,7 @@ extern font_renderer_t vita2d_vita_font; extern font_renderer_t ctr_font; extern font_renderer_t wiiu_font; extern font_renderer_t vulkan_raster_font; +extern font_renderer_t d3d11_font; extern font_renderer_t caca_font; extern font_renderer_t gdi_font; extern font_renderer_t vga_font; diff --git a/griffin/griffin.c b/griffin/griffin.c index 002141d6c3..26a7fdbc3d 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -512,6 +512,10 @@ FONTS #include "../gfx/drivers_font/vulkan_raster_font.c" #endif +#if defined(HAVE_D3D11) +#include "../gfx/drivers_font/d3d11_font.c" +#endif + /*============================================================ INPUT ============================================================ */