diff --git a/Makefile.common b/Makefile.common index bbd69c3a23..5de5f3d9b9 100644 --- a/Makefile.common +++ b/Makefile.common @@ -1267,7 +1267,9 @@ endif ifeq ($(HAVE_D3D10), 1) OBJ += gfx/drivers/d3d10.o \ - gfx/common/d3d10_common.o + gfx/common/d3d10_common.o \ + gfx/drivers_font/d3d10_font.o \ + menu/drivers_display/menu_display_d3d10.o DEFINES += -DHAVE_D3D10 endif diff --git a/gfx/common/d3d10_common.c b/gfx/common/d3d10_common.c index 45d364d08f..12adaf5493 100644 --- a/gfx/common/d3d10_common.c +++ b/gfx/common/d3d10_common.c @@ -18,6 +18,7 @@ #include #include "d3d10_common.h" +#include "d3dcompiler_common.h" #ifdef HAVE_DYNAMIC #include @@ -104,6 +105,7 @@ void d3d10_init_texture(D3D10Device device, d3d10_texture_t* texture) } void d3d10_update_texture( + D3D10Device ctx, int width, int height, int pitch, @@ -112,8 +114,13 @@ void d3d10_update_texture( d3d10_texture_t* texture) { D3D10_MAPPED_TEXTURE2D mapped_texture; + D3D10_BOX frame_box = { 0, 0, 0, width, height, 1 }; - D3D10MapTexture2D(texture->staging, 0, D3D10_MAP_WRITE, 0, + if (!texture || !texture->staging) + return; + + D3D10MapTexture2D(texture->staging, + 0, D3D10_MAP_WRITE, 0, &mapped_texture); #if 0 @@ -130,8 +137,11 @@ void d3d10_update_texture( D3D10UnmapTexture2D(texture->staging, 0); - if (texture->desc.Usage == D3D10_USAGE_DEFAULT) - texture->dirty = true; + D3D10CopyTexture2DSubresourceRegion( + ctx, texture->handle, 0, 0, 0, 0, texture->staging, 0, &frame_box); + + if (texture->desc.MiscFlags & D3D10_RESOURCE_MISC_GENERATE_MIPS) + D3D10GenerateMips(ctx, texture->view); } DXGI_FORMAT @@ -155,3 +165,65 @@ d3d10_get_closest_match(D3D10Device device, assert(*format); return *format; } + +bool d3d10_init_shader( + D3D10Device device, + const char* src, + size_t size, + const void* src_name, + LPCSTR vs_entry, + LPCSTR ps_entry, + LPCSTR gs_entry, + const D3D10_INPUT_ELEMENT_DESC* input_element_descs, + UINT num_elements, + d3d10_shader_t* out) +{ + D3DBlob vs_code = NULL; + D3DBlob ps_code = NULL; + D3DBlob gs_code = NULL; + + bool success = true; + + if (!src) /* LPCWSTR filename */ + { + if (vs_entry && !d3d_compile_from_file((LPCWSTR)src_name, vs_entry, "vs_5_0", &vs_code)) + success = false; + if (ps_entry && !d3d_compile_from_file((LPCWSTR)src_name, ps_entry, "ps_5_0", &ps_code)) + success = false; + if (gs_entry && !d3d_compile_from_file((LPCWSTR)src_name, gs_entry, "gs_5_0", &gs_code)) + success = false; + } + else /* char array */ + { + if (vs_entry && !d3d_compile(src, size, (LPCSTR)src_name, vs_entry, "vs_5_0", &vs_code)) + success = false; + if (ps_entry && !d3d_compile(src, size, (LPCSTR)src_name, ps_entry, "ps_5_0", &ps_code)) + success = false; + if (gs_entry && !d3d_compile(src, size, (LPCSTR)src_name, gs_entry, "gs_5_0", &gs_code)) + success = false; + } + + if (vs_code) + D3D10CreateVertexShader( + device, D3DGetBufferPointer(vs_code), D3DGetBufferSize(vs_code), &out->vs); + + if (ps_code) + D3D10CreatePixelShader( + device, D3DGetBufferPointer(ps_code), D3DGetBufferSize(ps_code), &out->ps); + + if (gs_code) + D3D10CreateGeometryShader( + device, D3DGetBufferPointer(gs_code), D3DGetBufferSize(gs_code), &out->gs); + + if (vs_code && input_element_descs) + D3D10CreateInputLayout( + device, + (D3D10_INPUT_ELEMENT_DESC*)input_element_descs, num_elements, D3DGetBufferPointer(vs_code), + D3DGetBufferSize(vs_code), &out->layout); + + Release(vs_code); + Release(ps_code); + Release(gs_code); + + return success; +} diff --git a/gfx/common/d3d10_common.h b/gfx/common/d3d10_common.h index 500f898bd6..bff18cb40f 100644 --- a/gfx/common/d3d10_common.h +++ b/gfx/common/d3d10_common.h @@ -20,6 +20,12 @@ #include "dxgi_common.h" #include +#include "../drivers_shader/slang_process.h" + +typedef D3D10_MAPPED_TEXTURE3D D3D10_MAPPED_SUBRESOURCE; + +typedef const ID3D10SamplerState* D3D10SamplerStateRef; + typedef ID3D10InputLayout* D3D10InputLayout; typedef ID3D10RasterizerState* D3D10RasterizerState; typedef ID3D10DepthStencilState* D3D10DepthStencilState; @@ -50,6 +56,7 @@ typedef ID3D10Debug* D3D10Debug; typedef ID3D10SwitchToRef* D3D10SwitchToRef; typedef ID3D10InfoQueue* D3D10InfoQueue; + #if !defined(__cplusplus) || defined(CINTERFACE) static INLINE void D3D10SetResourceEvictionPriority(D3D10Resource resource, UINT eviction_priority) { @@ -236,6 +243,7 @@ static INLINE void D3D10SetVShader(D3D10Device device, D3D10VertexShader vertex_ { device->lpVtbl->VSSetShader(device, vertex_shader); } + static INLINE void D3D10DrawIndexed( D3D10Device device, UINT index_count, UINT start_index_location, INT base_vertex_location) { @@ -265,6 +273,28 @@ static INLINE void D3D10SetVertexBuffers( device->lpVtbl->IASetVertexBuffers( device, start_slot, num_buffers, vertex_buffers, strides, offsets); } + +static INLINE void D3D10SetVertexBuffer( + D3D10Device device_context, + UINT slot, + D3D10Buffer const vertex_buffer, + UINT stride, + UINT offset) +{ + D3D10SetVertexBuffers(device_context, slot, 1, (D3D10Buffer* const)&vertex_buffer, &stride, &offset); +} +static INLINE void D3D10SetVShaderConstantBuffer( + D3D10Device device_context, UINT slot, D3D10Buffer const constant_buffer) +{ + D3D10SetVShaderConstantBuffers(device_context, slot, 1, (ID3D10Buffer ** const)&constant_buffer); +} + +static INLINE void D3D10SetPShaderConstantBuffer( + D3D10Device device_context, UINT slot, D3D10Buffer const constant_buffer) +{ + D3D10SetPShaderConstantBuffers(device_context, slot, 1, (ID3D10Buffer** const)&constant_buffer); +} + static INLINE void D3D10SetIndexBuffer(D3D10Device device, D3D10Buffer index_buffer, DXGI_FORMAT format, UINT offset) { @@ -1047,25 +1077,79 @@ typedef struct D3D10Texture2D handle; D3D10Texture2D staging; D3D10_TEXTURE2D_DESC desc; + D3D10RenderTargetView rt_view; D3D10ShaderResourceView view; - bool dirty; - bool ignore_alpha; + D3D10SamplerStateRef sampler; + float4_t size_data; } d3d10_texture_t; +typedef struct +{ + struct + { + float x, y, w, h; + } pos; + struct + { + float u, v, w, h; + } coords; + UINT32 colors[4]; + struct + { + float scaling; + float rotation; + } params; +} d3d10_sprite_t; + +#ifndef ALIGN +#ifdef _MSC_VER +#define ALIGN(x) __declspec(align(x)) +#else +#define ALIGN(x) __attribute__((aligned(x))) +#endif +#endif + +typedef struct ALIGN(16) +{ + math_matrix_4x4 mvp; + struct + { + float width; + float height; + } OutputSize; + float time; +} d3d10_uniform_t; + +static_assert( + (!(sizeof(d3d10_uniform_t) & 0xF)), "sizeof(d3d10_uniform_t) must be a multiple of 16"); + +typedef struct d3d10_shader_t +{ + D3D10VertexShader vs; + D3D10PixelShader ps; + D3D10GeometryShader gs; + D3D10InputLayout layout; +} d3d10_shader_t; + typedef struct { unsigned cur_mon_id; DXGISwapChain swapChain; D3D10Device device; + D3D10RasterizerState state; D3D10RenderTargetView renderTargetView; - D3D10InputLayout layout; D3D10Buffer ubo; + d3d10_uniform_t ubo_values; + D3D10SamplerState samplers[RARCH_FILTER_MAX][RARCH_WRAP_MAX]; + D3D10InputLayout layout; D3D10VertexShader vs; D3D10PixelShader ps; D3D10SamplerState sampler_nearest; D3D10SamplerState sampler_linear; D3D10BlendState blend_enable; D3D10BlendState blend_disable; + D3D10BlendState blend_pipeline; + D3D10Buffer menu_pipeline_vbo; math_matrix_4x4 mvp, mvp_no_rot; struct video_viewport vp; D3D10_VIEWPORT viewport; @@ -1075,6 +1159,31 @@ typedef struct bool resize_chain; bool keep_aspect; bool resize_viewport; + bool resize_render_targets; + bool init_history; + d3d10_shader_t shaders[GFX_MAX_SHADERS]; + + struct + { + d3d10_shader_t shader; + d3d10_shader_t shader_font; + D3D10Buffer vbo; + int offset; + int capacity; + bool enabled; + } sprites; + +#ifdef HAVE_OVERLAY + struct + { + D3D10Buffer vbo; + d3d10_texture_t* textures; + bool enabled; + bool fullscreen; + int count; + } overlays; +#endif + struct { d3d10_texture_t texture; @@ -1085,18 +1194,41 @@ typedef struct } menu; struct { - d3d10_texture_t texture; + d3d10_texture_t texture[GFX_MAX_FRAME_HISTORY + 1]; D3D10Buffer vbo; D3D10Buffer ubo; D3D10SamplerState sampler; D3D10_VIEWPORT viewport; + float4_t output_size; int rotation; } frame; + + struct + { + d3d10_shader_t shader; + D3D10Buffer buffers[SLANG_CBUFFER_MAX]; + d3d10_texture_t rt; + d3d10_texture_t feedback; + D3D10_VIEWPORT viewport; + pass_semantics_t semantics; + uint32_t frame_count; + } pass[GFX_MAX_SHADERS]; + + struct video_shader* shader_preset; + d3d10_texture_t luts[GFX_MAX_TEXTURES]; } d3d10_video_t; void d3d10_init_texture(D3D10Device device, d3d10_texture_t* texture); +static INLINE void d3d10_release_texture(d3d10_texture_t* texture) +{ + Release(texture->handle); + Release(texture->staging); + Release(texture->view); + Release(texture->rt_view); +} void d3d10_update_texture( + D3D10Device ctx, int width, int height, int pitch, @@ -1107,6 +1239,26 @@ void d3d10_update_texture( DXGI_FORMAT d3d10_get_closest_match( D3D10Device device, DXGI_FORMAT desired_format, UINT desired_format_support); +bool d3d10_init_shader( + D3D10Device device, + const char* src, + size_t size, + const void* src_name, + LPCSTR vs_entry, + LPCSTR ps_entry, + LPCSTR gs_entry, + const D3D10_INPUT_ELEMENT_DESC* input_element_descs, + UINT num_elements, + d3d10_shader_t* out); + +static INLINE void d3d10_release_shader(d3d10_shader_t* shader) +{ + Release(shader->layout); + Release(shader->vs); + Release(shader->ps); + Release(shader->gs); +} + static INLINE DXGI_FORMAT d3d10_get_closest_match_texture2D(D3D10Device device, DXGI_FORMAT desired_format) { @@ -1114,3 +1266,20 @@ d3d10_get_closest_match_texture2D(D3D10Device device, DXGI_FORMAT desired_format device, desired_format, D3D10_FORMAT_SUPPORT_TEXTURE2D | D3D10_FORMAT_SUPPORT_SHADER_SAMPLE); } + +static INLINE void d3d10_set_shader(D3D10Device ctx, d3d10_shader_t* shader) +{ + D3D10SetInputLayout(ctx, shader->layout); + D3D10SetVShader(ctx, shader->vs); + D3D10SetPShader(ctx, shader->ps); + D3D10SetGShader(ctx, shader->gs); +} + +#if !defined(__cplusplus) || defined(CINTERFACE) +static INLINE void +d3d10_set_texture_and_sampler(D3D10Device ctx, UINT slot, d3d10_texture_t* texture) +{ + D3D10SetPShaderResources(ctx, slot, 1, &texture->view); + D3D10SetPShaderSamplers(ctx, slot, 1, (D3D10SamplerState*)&texture->sampler); +} +#endif diff --git a/gfx/common/d3d11_common.c b/gfx/common/d3d11_common.c index 7ae98d995d..d236f9bcfa 100644 --- a/gfx/common/d3d11_common.c +++ b/gfx/common/d3d11_common.c @@ -140,11 +140,20 @@ void d3d11_update_texture( if (!texture || !texture->staging) return; - D3D11MapTexture2D(ctx, texture->staging, 0, D3D11_MAP_WRITE, 0, &mapped_texture); + D3D11MapTexture2D(ctx, texture->staging, + 0, D3D11_MAP_WRITE, 0, &mapped_texture); +#if 0 + PERF_START(); + conv_rgb565_argb8888(mapped_texture.pData, data, width, height, + mapped_texture.RowPitch, pitch); + PERF_STOP(); +#else dxgi_copy( - width, height, format, pitch, data, texture->desc.Format, mapped_texture.RowPitch, + width, height, format, pitch, data, + texture->desc.Format, mapped_texture.RowPitch, mapped_texture.pData); +#endif D3D11UnmapTexture2D(ctx, texture->staging, 0); diff --git a/gfx/common/d3d11_common.h b/gfx/common/d3d11_common.h index 68333f1605..69128cd07a 100644 --- a/gfx/common/d3d11_common.h +++ b/gfx/common/d3d11_common.h @@ -237,6 +237,7 @@ static INLINE void D3D11SetPShaderSamplers( device_context->lpVtbl->PSSetSamplers( device_context, start_slot, num_samplers, samplers); } + static INLINE void D3D11SetVShader( D3D11DeviceContext device_context, D3D11VertexShader vertex_shader, diff --git a/gfx/drivers/d3d10.c b/gfx/drivers/d3d10.c index 214436e096..98e4791fd8 100644 --- a/gfx/drivers/d3d10.c +++ b/gfx/drivers/d3d10.c @@ -16,16 +16,197 @@ #define CINTERFACE #include + #include +#include #include "../../driver.h" #include "../../verbosity.h" #include "../../configuration.h" #include "../video_driver.h" +#include "../font_driver.h" #include "../common/win32_common.h" #include "../common/d3d10_common.h" #include "../common/dxgi_common.h" #include "../common/d3dcompiler_common.h" +#ifdef HAVE_MENU +#include "../../menu/menu_driver.h" +#endif + +#ifdef HAVE_OVERLAY +static void d3d10_free_overlays(d3d10_video_t* d3d10) +{ + unsigned i; + for (i = 0; i < d3d10->overlays.count; i++) + d3d10_release_texture(&d3d10->overlays.textures[i]); + + Release(d3d10->overlays.vbo); +} + +static void +d3d10_overlay_vertex_geom(void* data, unsigned index, float x, float y, float w, float h) +{ + D3D10_MAPPED_SUBRESOURCE mapped_vbo; + d3d10_video_t* d3d10 = (d3d10_video_t*)data; + + if (!d3d10) + return; + + D3D10MapBuffer(d3d10->overlays.vbo, + D3D10_MAP_WRITE_NO_OVERWRITE, 0, (void**)&mapped_vbo); + { + d3d10_sprite_t* sprites = (d3d10_sprite_t*)mapped_vbo.pData; + sprites[index].pos.x = x; + sprites[index].pos.y = y; + sprites[index].pos.w = w; + sprites[index].pos.h = h; + } + D3D10UnmapBuffer(d3d10->overlays.vbo); +} + +static void d3d10_overlay_tex_geom(void* data, unsigned index, float u, float v, float w, float h) +{ + D3D10_MAPPED_SUBRESOURCE mapped_vbo; + d3d10_video_t* d3d10 = (d3d10_video_t*)data; + + if (!d3d10) + return; + + D3D10MapBuffer( + d3d10->overlays.vbo, + D3D10_MAP_WRITE_NO_OVERWRITE, 0, (void**)&mapped_vbo); + { + d3d10_sprite_t* sprites = (d3d10_sprite_t*)mapped_vbo.pData; + sprites[index].coords.u = u; + sprites[index].coords.v = v; + sprites[index].coords.w = w; + sprites[index].coords.h = h; + } + D3D10UnmapBuffer(d3d10->overlays.vbo); +} + +static void d3d10_overlay_set_alpha(void* data, unsigned index, float mod) +{ + D3D10_MAPPED_SUBRESOURCE mapped_vbo; + d3d10_video_t* d3d10 = (d3d10_video_t*)data; + + if (!d3d10) + return; + + D3D10MapBuffer( + d3d10->overlays.vbo, + D3D10_MAP_WRITE_NO_OVERWRITE, 0, (void**)&mapped_vbo); + + { + d3d10_sprite_t* sprites = (d3d10_sprite_t*)mapped_vbo.pData; + sprites[index].colors[0] = DXGI_COLOR_RGBA(0xFF, 0xFF, 0xFF, mod * 0xFF); + sprites[index].colors[1] = sprites[index].colors[0]; + sprites[index].colors[2] = sprites[index].colors[0]; + sprites[index].colors[3] = sprites[index].colors[0]; + } + D3D10UnmapBuffer(d3d10->overlays.vbo); +} + +static bool d3d10_overlay_load(void* data, const void* image_data, unsigned num_images) +{ + D3D10_BUFFER_DESC desc; + D3D10_MAPPED_SUBRESOURCE mapped_vbo; + int i; + d3d10_sprite_t* sprites; + d3d10_video_t* d3d10 = (d3d10_video_t*)data; + const struct texture_image* images = (const struct texture_image*)image_data; + + if (!d3d10) + return false; + + d3d10_free_overlays(d3d10); + d3d10->overlays.count = num_images; + d3d10->overlays.textures = (d3d10_texture_t*)calloc( + num_images, sizeof(d3d10_texture_t)); + + desc.ByteWidth = sizeof(d3d10_sprite_t) * num_images; + desc.Usage = D3D10_USAGE_DYNAMIC; + desc.BindFlags = D3D10_BIND_VERTEX_BUFFER; + desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; + desc.MiscFlags = 0; +#if 0 + desc.StructureByteStride = 0; +#endif + D3D10CreateBuffer(d3d10->device, &desc, NULL, &d3d10->overlays.vbo); + + D3D10MapBuffer(d3d10->overlays.vbo, + D3D10_MAP_WRITE_DISCARD, 0, (void**)&mapped_vbo); + sprites = (d3d10_sprite_t*)mapped_vbo.pData; + + for (i = 0; i < num_images; i++) + { + + d3d10->overlays.textures[i].desc.Width = images[i].width; + d3d10->overlays.textures[i].desc.Height = images[i].height; + d3d10->overlays.textures[i].desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + + d3d10_init_texture(d3d10->device, &d3d10->overlays.textures[i]); + + d3d10_update_texture( + d3d10->device, + images[i].width, + images[i].height, 0, DXGI_FORMAT_B8G8R8A8_UNORM, + images[i].pixels, &d3d10->overlays.textures[i]); + + sprites[i].pos.x = 0.0f; + sprites[i].pos.y = 0.0f; + sprites[i].pos.w = 1.0f; + sprites[i].pos.h = 1.0f; + + sprites[i].coords.u = 0.0f; + sprites[i].coords.v = 0.0f; + sprites[i].coords.w = 1.0f; + sprites[i].coords.h = 1.0f; + + sprites[i].params.scaling = 1; + sprites[i].params.rotation = 0; + + sprites[i].colors[0] = 0xFFFFFFFF; + sprites[i].colors[1] = sprites[i].colors[0]; + sprites[i].colors[2] = sprites[i].colors[0]; + sprites[i].colors[3] = sprites[i].colors[0]; + } + D3D10UnmapBuffer(d3d10->overlays.vbo); + + return true; +} + +static void d3d10_overlay_enable(void* data, bool state) +{ + d3d10_video_t* d3d10 = (d3d10_video_t*)data; + + if (!d3d10) + return; + + d3d10->overlays.enabled = state; + win32_show_cursor(state); +} + +static void d3d10_overlay_full_screen(void* data, bool enable) +{ + d3d10_video_t* d3d10 = (d3d10_video_t*)data; + + if (!d3d10) + return; + + d3d10->overlays.fullscreen = enable; +} + +static void d3d10_get_overlay_interface(void* data, const video_overlay_interface_t** iface) +{ + static const video_overlay_interface_t overlay_interface = { + d3d10_overlay_enable, d3d10_overlay_load, d3d10_overlay_tex_geom, + d3d10_overlay_vertex_geom, d3d10_overlay_full_screen, d3d10_overlay_set_alpha, + }; + + *iface = &overlay_interface; +} +#endif static void d3d10_set_filtering(void* data, unsigned index, bool smooth) { @@ -73,12 +254,322 @@ static void d3d10_update_viewport(void* data, bool force_full) d3d10->resize_viewport = false; } +static void d3d10_free_shader_preset(d3d10_video_t* d3d10) +{ + unsigned i; + if (!d3d10->shader_preset) + return; + + for (i = 0; i < d3d10->shader_preset->passes; i++) + { + unsigned j; + + free(d3d10->shader_preset->pass[i].source.string.vertex); + free(d3d10->shader_preset->pass[i].source.string.fragment); + free(d3d10->pass[i].semantics.textures); + d3d10_release_shader(&d3d10->pass[i].shader); + d3d10_release_texture(&d3d10->pass[i].rt); + d3d10_release_texture(&d3d10->pass[i].feedback); + + for (j = 0; j < SLANG_CBUFFER_MAX; j++) + { + free(d3d10->pass[i].semantics.cbuffers[j].uniforms); + Release(d3d10->pass[i].buffers[j]); + } + } + + memset(d3d10->pass, 0, sizeof(d3d10->pass)); + + /* only free the history textures here */ + for (i = 1; i <= d3d10->shader_preset->history_size; i++) + d3d10_release_texture(&d3d10->frame.texture[i]); + + memset( + &d3d10->frame.texture[1], 0, + sizeof(d3d10->frame.texture[1]) * d3d10->shader_preset->history_size); + + for (i = 0; i < d3d10->shader_preset->luts; i++) + d3d10_release_texture(&d3d10->luts[i]); + + memset(d3d10->luts, 0, sizeof(d3d10->luts)); + + free(d3d10->shader_preset); + d3d10->shader_preset = NULL; + d3d10->init_history = false; + d3d10->resize_render_targets = false; +} + + +static void d3d10_gfx_free(void* data) +{ + unsigned i; + d3d10_video_t* d3d10 = (d3d10_video_t*)data; + + if (!d3d10) + return; + +#ifdef HAVE_OVERLAY + d3d10_free_overlays(d3d10); +#endif + + d3d10_free_shader_preset(d3d10); + + d3d10_release_texture(&d3d10->frame.texture[0]); + Release(d3d10->frame.ubo); + Release(d3d10->frame.vbo); + + d3d10_release_texture(&d3d10->menu.texture); + Release(d3d10->menu.vbo); + + d3d10_release_shader(&d3d10->sprites.shader); + d3d10_release_shader(&d3d10->sprites.shader_font); + Release(d3d10->sprites.vbo); + + for (i = 0; i < GFX_MAX_SHADERS; i++) + d3d10_release_shader(&d3d10->shaders[i]); + + Release(d3d10->menu_pipeline_vbo); + Release(d3d10->blend_pipeline); + + Release(d3d10->ubo); + + Release(d3d10->blend_enable); + Release(d3d10->blend_disable); + + for (i = 0; i < RARCH_WRAP_MAX; i++) + { + Release(d3d10->samplers[RARCH_FILTER_LINEAR][i]); + Release(d3d10->samplers[RARCH_FILTER_NEAREST][i]); + } + + Release(d3d10->state); + Release(d3d10->renderTargetView); + Release(d3d10->swapChain); + + font_driver_free_osd(); + +#if 0 + if (video_driver_is_video_cache_context()) + { + cached_device_d3d10 = d3d10->device; + cached_context = d3d10->context; + } + else +#endif + { + Release(d3d10->device); + } + + win32_monitor_from_window(); + win32_destroy_window(); + free(d3d10); +} + +static bool d3d10_gfx_set_shader(void* data, + enum rarch_shader_type type, const char* path) +{ +#if defined(HAVE_SLANG) && defined(HAVE_SPIRV_CROSS) + unsigned i; + d3d10_texture_t* source; + d3d10_video_t* d3d10 = (d3d10_video_t*)data; + + if (!d3d10) + return false; + + D3D10Flush(d3d10->device); + d3d10_free_shader_preset(d3d10); + + if (!path) + return true; + + if (type != RARCH_SHADER_SLANG) + { + RARCH_WARN("Only .slang or .slangp shaders are supported. Falling back to stock.\n"); + return false; + } + + config_file_t* conf = config_file_new(path); + + if (!conf) + return false; + + d3d10->shader_preset = (struct video_shader*)calloc(1, sizeof(*d3d10->shader_preset)); + + if (!video_shader_read_conf_cgp(conf, d3d10->shader_preset)) + goto error; + + video_shader_resolve_relative(d3d10->shader_preset, path); + + source = &d3d10->frame.texture[0]; + for (i = 0; i < d3d10->shader_preset->passes; source = &d3d10->pass[i++].rt) + { + unsigned j; + /* clang-format off */ + semantics_map_t semantics_map = { + { + /* Original */ + { &d3d10->frame.texture[0].view, 0, + &d3d10->frame.texture[0].size_data, 0}, + + /* Source */ + { &source->view, 0, + &source->size_data, 0}, + + /* OriginalHistory */ + { &d3d10->frame.texture[0].view, sizeof(*d3d10->frame.texture), + &d3d10->frame.texture[0].size_data, sizeof(*d3d10->frame.texture)}, + + /* PassOutput */ + { &d3d10->pass[0].rt.view, sizeof(*d3d10->pass), + &d3d10->pass[0].rt.size_data, sizeof(*d3d10->pass)}, + + /* PassFeedback */ + { &d3d10->pass[0].feedback.view, sizeof(*d3d10->pass), + &d3d10->pass[0].feedback.size_data, sizeof(*d3d10->pass)}, + + /* User */ + { &d3d10->luts[0].view, sizeof(*d3d10->luts), + &d3d10->luts[0].size_data, sizeof(*d3d10->luts)}, + }, + { + &d3d10->mvp, /* MVP */ + &d3d10->pass[i].rt.size_data, /* OutputSize */ + &d3d10->frame.output_size, /* FinalViewportSize */ + &d3d10->pass[i].frame_count, /* FrameCount */ + } + }; + /* clang-format on */ + + if (!slang_process( + d3d10->shader_preset, i, RARCH_SHADER_HLSL, 50, &semantics_map, + &d3d10->pass[i].semantics)) + goto error; + + { + static const D3D10_INPUT_ELEMENT_DESC desc[] = { + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d10_vertex_t, position), + D3D10_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 1, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d10_vertex_t, texcoord), + D3D10_INPUT_PER_VERTEX_DATA, 0 }, + }; +#ifdef DEBUG + bool save_hlsl = true; +#else + bool save_hlsl = false; +#endif + static const char vs_ext[] = ".vs.hlsl"; + static const char ps_ext[] = ".ps.hlsl"; + char vs_path[PATH_MAX_LENGTH]; + char ps_path[PATH_MAX_LENGTH]; + const char* slang_path = d3d10->shader_preset->pass[i].source.path; + const char* vs_src = d3d10->shader_preset->pass[i].source.string.vertex; + const char* ps_src = d3d10->shader_preset->pass[i].source.string.fragment; + int base_len = strlen(slang_path) - strlen(".slang"); + + if (base_len <= 0) + base_len = strlen(slang_path); + + strncpy(vs_path, slang_path, base_len); + strncpy(ps_path, slang_path, base_len); + strncpy(vs_path + base_len, vs_ext, sizeof(vs_ext)); + strncpy(ps_path + base_len, ps_ext, sizeof(ps_ext)); + + if (!d3d10_init_shader( + d3d10->device, vs_src, 0, vs_path, "main", NULL, NULL, desc, countof(desc), + &d3d10->pass[i].shader)) + save_hlsl = true; + + if (!d3d10_init_shader( + d3d10->device, ps_src, 0, ps_path, NULL, "main", NULL, NULL, 0, + &d3d10->pass[i].shader)) + save_hlsl = true; + + if (save_hlsl) + { + FILE* fp = fopen(vs_path, "w"); + fwrite(vs_src, 1, strlen(vs_src), fp); + fclose(fp); + + fp = fopen(ps_path, "w"); + fwrite(ps_src, 1, strlen(ps_src), fp); + fclose(fp); + } + + free(d3d10->shader_preset->pass[i].source.string.vertex); + free(d3d10->shader_preset->pass[i].source.string.fragment); + + d3d10->shader_preset->pass[i].source.string.vertex = NULL; + d3d10->shader_preset->pass[i].source.string.fragment = NULL; + + if (!d3d10->pass[i].shader.vs || !d3d10->pass[i].shader.ps) + goto error; + } + + for (j = 0; j < SLANG_CBUFFER_MAX; j++) + { + D3D10_BUFFER_DESC desc; + desc.ByteWidth = d3d10->pass[i].semantics.cbuffers[j].size; + desc.Usage = D3D10_USAGE_DYNAMIC; + desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER; + desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; + desc.MiscFlags = 0; +#if 0 + desc.StructureByteStride = 0; +#endif + + if (!desc.ByteWidth) + continue; + + D3D10CreateBuffer(d3d10->device, &desc, NULL, &d3d10->pass[i].buffers[j]); + } + } + + for (i = 0; i < d3d10->shader_preset->luts; i++) + { + struct texture_image image = { 0 }; + image.supports_rgba = true; + + if (!image_texture_load(&image, d3d10->shader_preset->lut[i].path)) + goto error; + + d3d10->luts[i].desc.Width = image.width; + d3d10->luts[i].desc.Height = image.height; + d3d10->luts[i].desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + + if (d3d10->shader_preset->lut[i].mipmap) + d3d10->luts[i].desc.MiscFlags = D3D10_RESOURCE_MISC_GENERATE_MIPS; + + d3d10_init_texture(d3d10->device, &d3d10->luts[i]); + + d3d10_update_texture( + d3d10->device, + image.width, image.height, 0, DXGI_FORMAT_R8G8B8A8_UNORM, image.pixels, + &d3d10->luts[i]); + + image_texture_free(&image); + } + + video_shader_resolve_current_parameters(conf, d3d10->shader_preset); + config_file_free(conf); + + d3d10->resize_render_targets = true; + d3d10->init_history = true; + + return true; + +error: + d3d10_free_shader_preset(d3d10); +#endif + + return false; +} + static void* d3d10_gfx_init(const video_info_t* video, const input_driver_t** input, void** input_data) { - WNDCLASSEX wndclass = { 0 }; MONITORINFOEX current_mon; HMONITOR hm_to_use; + WNDCLASSEX wndclass = { 0 }; settings_t* settings = config_get_ptr(); d3d10_video_t* d3d10 = (d3d10_video_t*)calloc(1, sizeof(*d3d10)); @@ -136,9 +627,10 @@ d3d10_gfx_init(const video_info_t* video, const input_driver_t** input, void** i flags |= D3D10_CREATE_DEVICE_DEBUG; #endif - D3D10CreateDeviceAndSwapChain( + if (FAILED(D3D10CreateDeviceAndSwapChain( NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL, flags, D3D10_SDK_VERSION, &desc, - (IDXGISwapChain**)&d3d10->swapChain, &d3d10->device); + (IDXGISwapChain**)&d3d10->swapChain, &d3d10->device))) + goto error; } { @@ -153,21 +645,28 @@ d3d10_gfx_init(const video_info_t* video, const input_driver_t** input, void** i d3d10->viewport.Width = video->width; d3d10->viewport.Height = video->height; d3d10->resize_viewport = true; - d3d10->keep_aspect = video->force_aspect; - d3d10->vsync = video->vsync; - d3d10->format = video->rgb32 ? DXGI_FORMAT_B8G8R8X8_UNORM : DXGI_FORMAT_B5G6R5_UNORM; + d3d10->keep_aspect = video->force_aspect; + d3d10->vsync = video->vsync; + d3d10->format = video->rgb32 ? + DXGI_FORMAT_B8G8R8X8_UNORM : DXGI_FORMAT_B5G6R5_UNORM; - d3d10->frame.texture.desc.Format = - d3d10_get_closest_match_texture2D(d3d10->device, d3d10->format); - d3d10->frame.texture.desc.Usage = D3D10_USAGE_DEFAULT; + d3d10->frame.texture[0].desc.Format = d3d10_get_closest_match_texture2D(d3d10->device, d3d10->format); + d3d10->frame.texture[0].desc.Usage = D3D10_USAGE_DEFAULT; + d3d10->frame.texture[0].desc.Width = 4; + d3d10->frame.texture[0].desc.Height = 4; + + d3d10_init_texture(d3d10->device, &d3d10->frame.texture[0]); d3d10->menu.texture.desc.Usage = D3D10_USAGE_DEFAULT; matrix_4x4_ortho(d3d10->mvp_no_rot, 0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f); + d3d10->ubo_values.OutputSize.width = d3d10->viewport.Width; + d3d10->ubo_values.OutputSize.height = d3d10->viewport.Height; + { - D3D10_BUFFER_DESC desc; D3D10_SUBRESOURCE_DATA ubo_data; + D3D10_BUFFER_DESC desc; desc.ByteWidth = sizeof(math_matrix_4x4); desc.Usage = D3D10_USAGE_DYNAMIC; @@ -182,9 +681,11 @@ d3d10_gfx_init(const video_info_t* video, const input_driver_t** input, void** i D3D10CreateBuffer(d3d10->device, &desc, &ubo_data, &d3d10->ubo); D3D10CreateBuffer(d3d10->device, &desc, NULL, &d3d10->frame.ubo); } + d3d10_gfx_set_rotation(d3d10, 0); { + unsigned i; unsigned k; D3D10_SAMPLER_DESC desc; @@ -201,86 +702,189 @@ d3d10_gfx_init(const video_info_t* video, const input_driver_t** input, void** i for (k = 0; k < 4; k++) desc.BorderColor[k] = 0.0f; - D3D10CreateSamplerState(d3d10->device, &desc, &d3d10->sampler_nearest); + /* Initialize samplers */ + for (i = 0; i < RARCH_WRAP_MAX; i++) + { + switch (i) + { + case RARCH_WRAP_BORDER: + desc.AddressU = D3D10_TEXTURE_ADDRESS_BORDER; + break; - desc.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR; - D3D10CreateSamplerState(d3d10->device, &desc, &d3d10->sampler_linear); + case RARCH_WRAP_EDGE: + desc.AddressU = D3D10_TEXTURE_ADDRESS_CLAMP; + break; + + case RARCH_WRAP_REPEAT: + desc.AddressU = D3D10_TEXTURE_ADDRESS_WRAP; + break; + + case RARCH_WRAP_MIRRORED_REPEAT: + desc.AddressU = D3D10_TEXTURE_ADDRESS_MIRROR; + break; + } + desc.AddressV = desc.AddressU; + desc.AddressW = desc.AddressU; + + desc.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR; + D3D10CreateSamplerState(d3d10->device, &desc, + &d3d10->samplers[RARCH_FILTER_LINEAR][i]); + + desc.Filter = D3D10_FILTER_MIN_MAG_MIP_POINT; + D3D10CreateSamplerState(d3d10->device, &desc, + &d3d10->samplers[RARCH_FILTER_NEAREST][i]); + } } d3d10_set_filtering(d3d10, 0, video->smooth); { + D3D10_BUFFER_DESC desc; d3d10_vertex_t vertices[] = { { { 0.0f, 0.0f }, { 0.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, { { 0.0f, 1.0f }, { 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, { { 1.0f, 0.0f }, { 1.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, { { 1.0f, 1.0f }, { 1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, }; + D3D10_SUBRESOURCE_DATA + vertexData = { vertices }; - { - D3D10_SUBRESOURCE_DATA vertexData; - D3D10_BUFFER_DESC desc; + desc.ByteWidth = sizeof(vertices); + desc.Usage = D3D10_USAGE_IMMUTABLE; + desc.BindFlags = D3D10_BIND_VERTEX_BUFFER; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; - desc.ByteWidth = sizeof(vertices); - desc.Usage = D3D10_USAGE_DYNAMIC; - desc.BindFlags = D3D10_BIND_VERTEX_BUFFER; - desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; - desc.MiscFlags = 0; + D3D10CreateBuffer(d3d10->device, &desc, &vertexData, &d3d10->frame.vbo); + desc.Usage = D3D10_USAGE_DYNAMIC; + desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; + D3D10CreateBuffer(d3d10->device, &desc, &vertexData, &d3d10->menu.vbo); - vertexData.pSysMem = vertices; - vertexData.SysMemPitch = 0; - vertexData.SysMemSlicePitch = 0; - - D3D10CreateBuffer(d3d10->device, &desc, &vertexData, &d3d10->frame.vbo); - desc.Usage = D3D10_USAGE_IMMUTABLE; - desc.CPUAccessFlags = 0; - D3D10CreateBuffer(d3d10->device, &desc, &vertexData, &d3d10->menu.vbo); - } - D3D10SetPrimitiveTopology(d3d10->device, D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + d3d10->sprites.capacity = 4096; + desc.ByteWidth = sizeof(d3d10_sprite_t) * d3d10->sprites.capacity; + D3D10CreateBuffer(d3d10->device, &desc, NULL, &d3d10->sprites.vbo); } { - D3DBlob vs_code; - D3DBlob ps_code; - - static const char stock[] = -#include "d3d_shaders/opaque_sm5.hlsl.h" - ; - D3D10_INPUT_ELEMENT_DESC desc[] = { { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d10_vertex_t, position), - D3D10_INPUT_PER_VERTEX_DATA, 0 }, + D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d10_vertex_t, texcoord), - D3D10_INPUT_PER_VERTEX_DATA, 0 }, + D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(d3d10_vertex_t, color), - D3D10_INPUT_PER_VERTEX_DATA, 0 }, + D3D10_INPUT_PER_VERTEX_DATA, 0 }, }; - d3d_compile(stock, sizeof(stock), NULL, "VSMain", "vs_4_0", &vs_code); - d3d_compile(stock, sizeof(stock), NULL, "PSMain", "ps_4_0", &ps_code); + static const char shader[] = +#include "d3d_shaders/opaque_sm5.hlsl.h" + ; - D3D10CreateVertexShader( - d3d10->device, D3DGetBufferPointer(vs_code), D3DGetBufferSize(vs_code), &d3d10->vs); - D3D10CreatePixelShader( - d3d10->device, D3DGetBufferPointer(ps_code), D3DGetBufferSize(ps_code), &d3d10->ps); - D3D10CreateInputLayout( - d3d10->device, desc, countof(desc), D3DGetBufferPointer(vs_code), - D3DGetBufferSize(vs_code), &d3d10->layout); - - Release(vs_code); - Release(ps_code); + if (!d3d10_init_shader( + d3d10->device, shader, sizeof(shader), NULL, "VSMain", "PSMain", NULL, desc, + countof(desc), &d3d10->shaders[VIDEO_SHADER_STOCK_BLEND])) + goto error; } - D3D10SetInputLayout(d3d10->device, d3d10->layout); - D3D10SetVShader(d3d10->device, d3d10->vs); - D3D10SetPShader(d3d10->device, d3d10->ps); + { + D3D10_INPUT_ELEMENT_DESC desc[] = { + { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(d3d10_sprite_t, pos), + D3D10_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(d3d10_sprite_t, coords), + D3D10_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(d3d10_sprite_t, colors[0]), + D3D10_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(d3d10_sprite_t, colors[1]), + D3D10_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 2, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(d3d10_sprite_t, colors[2]), + D3D10_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 3, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(d3d10_sprite_t, colors[3]), + D3D10_INPUT_PER_VERTEX_DATA, 0 }, + { "PARAMS", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d10_sprite_t, params), + D3D10_INPUT_PER_VERTEX_DATA, 0 }, + }; + + static const char shader[] = +#include "d3d_shaders/sprite_sm4.hlsl.h" + ; + + if (!d3d10_init_shader( + d3d10->device, shader, sizeof(shader), NULL, "VSMain", "PSMain", "GSMain", desc, + countof(desc), &d3d10->sprites.shader)) + goto error; + if (!d3d10_init_shader( + d3d10->device, shader, sizeof(shader), NULL, "VSMain", "PSMainA8", "GSMain", desc, + countof(desc), &d3d10->sprites.shader_font)) + goto error; + } + + { + D3D10_INPUT_ELEMENT_DESC desc[] = { + { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 }, + }; + + static const char ribbon[] = +#include "d3d_shaders/ribbon_sm4.hlsl.h" + ; + static const char ribbon_simple[] = +#include "d3d_shaders/ribbon_simple_sm4.hlsl.h" + ; + + if (!d3d10_init_shader( + d3d10->device, ribbon, sizeof(ribbon), NULL, "VSMain", "PSMain", NULL, desc, + countof(desc), &d3d10->shaders[VIDEO_SHADER_MENU])) + goto error; + + if (!d3d10_init_shader( + d3d10->device, ribbon_simple, sizeof(ribbon_simple), NULL, "VSMain", "PSMain", NULL, + desc, countof(desc), &d3d10->shaders[VIDEO_SHADER_MENU_2])) + goto error; + } + + { + D3D10_INPUT_ELEMENT_DESC desc[] = { + { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d10_vertex_t, position), + D3D10_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d10_vertex_t, texcoord), + D3D10_INPUT_PER_VERTEX_DATA, 0 }, + }; + + static const char simple_snow[] = +#include "d3d_shaders/simple_snow_sm4.hlsl.h" + ; + static const char snow[] = +#include "d3d_shaders/snow_sm4.hlsl.h" + ; + static const char bokeh[] = +#include "d3d_shaders/bokeh_sm4.hlsl.h" + ; + static const char snowflake[] = +#include "d3d_shaders/snowflake_sm4.hlsl.h" + ; + + if (!d3d10_init_shader( + d3d10->device, simple_snow, sizeof(simple_snow), NULL, "VSMain", "PSMain", NULL, + desc, countof(desc), &d3d10->shaders[VIDEO_SHADER_MENU_3])) + goto error; + if (!d3d10_init_shader( + d3d10->device, snow, sizeof(snow), NULL, "VSMain", "PSMain", NULL, desc, + countof(desc), &d3d10->shaders[VIDEO_SHADER_MENU_4])) + goto error; + + if (!d3d10_init_shader( + d3d10->device, bokeh, sizeof(bokeh), NULL, "VSMain", "PSMain", NULL, desc, + countof(desc), &d3d10->shaders[VIDEO_SHADER_MENU_5])) + goto error; + + if (!d3d10_init_shader( + d3d10->device, snowflake, sizeof(snowflake), NULL, "VSMain", "PSMain", NULL, desc, + countof(desc), &d3d10->shaders[VIDEO_SHADER_MENU_6])) + goto error; + } { unsigned k; D3D10_BLEND_DESC blend_desc; - - for (k = 0; k < 8; k++) { blend_desc.BlendEnable[k] = TRUE; @@ -300,13 +904,171 @@ d3d10_gfx_init(const video_info_t* video, const input_driver_t** input, void** i D3D10CreateBlendState(d3d10->device, &blend_desc, &d3d10->blend_disable); } + { + D3D10_RASTERIZER_DESC desc = { (D3D10_FILL_MODE)0 }; + + desc.FillMode = D3D10_FILL_SOLID; + desc.CullMode = D3D10_CULL_NONE; + + D3D10CreateRasterizerState(d3d10->device, &desc, &d3d10->state); + } + + D3D10SetState(d3d10->device, d3d10->state); + + font_driver_init_osd(d3d10, false, video->is_threaded, FONT_DRIVER_RENDER_D3D10_API); + + if (settings->bools.video_shader_enable) + { + const char* ext = path_get_extension(settings->paths.path_shader); + + if (ext && !strncmp(ext, "slang", 5)) + d3d10_gfx_set_shader(d3d10, RARCH_SHADER_SLANG, settings->paths.path_shader); + } + +#if 0 + if (video_driver_get_hw_context()->context_type == RETRO_HW_CONTEXT_DIRECT3D && + video_driver_get_hw_context()->version_major == 11) + { + d3d10->hw.enable = true; + d3d10->hw.iface.interface_type = RETRO_HW_RENDER_INTERFACE_D3D11; + d3d10->hw.iface.interface_version = RETRO_HW_RENDER_INTERFACE_D3D11_VERSION; + d3d10->hw.iface.handle = d3d10; + d3d10->hw.iface.device = d3d10->device; + d3d10->hw.iface.context = d3d10->context; + d3d10->hw.iface.featureLevel = d3d10->supportedFeatureLevel; + d3d10->hw.iface.D3DCompile = D3DCompile; + } +#endif + return d3d10; error: - free(d3d10); + d3d10_gfx_free(d3d10); return NULL; } +static void d3d10_init_history(d3d10_video_t* d3d10, unsigned width, unsigned height) +{ + unsigned i; + + /* todo: should we init history to max_width/max_height instead ? + * to prevent out of memory errors happening several frames later + * and to reduce memory fragmentation */ + + assert(d3d10->shader_preset); + for (i = 0; i < d3d10->shader_preset->history_size + 1; i++) + { + d3d10->frame.texture[i].desc.Width = width; + d3d10->frame.texture[i].desc.Height = height; + d3d10->frame.texture[i].desc.Format = d3d10->frame.texture[0].desc.Format; + d3d10->frame.texture[i].desc.Usage = d3d10->frame.texture[0].desc.Usage; + d3d10_init_texture(d3d10->device, &d3d10->frame.texture[i]); + /* todo: clear texture ? */ + } + d3d10->init_history = false; +} + +static void d3d10_init_render_targets(d3d10_video_t* d3d10, + unsigned width, unsigned height) +{ + unsigned i; + + assert(d3d10->shader_preset); + + for (i = 0; i < d3d10->shader_preset->passes; i++) + { + struct video_shader_pass* pass = &d3d10->shader_preset->pass[i]; + + if (pass->fbo.valid) + { + + switch (pass->fbo.type_x) + { + case RARCH_SCALE_INPUT: + width *= pass->fbo.scale_x; + break; + + case RARCH_SCALE_VIEWPORT: + width = d3d10->vp.width * pass->fbo.scale_x; + break; + + case RARCH_SCALE_ABSOLUTE: + width = pass->fbo.abs_x; + break; + + default: + break; + } + + if (!width) + width = d3d10->vp.width; + + switch (pass->fbo.type_y) + { + case RARCH_SCALE_INPUT: + height *= pass->fbo.scale_y; + break; + + case RARCH_SCALE_VIEWPORT: + height = d3d10->vp.height * pass->fbo.scale_y; + break; + + case RARCH_SCALE_ABSOLUTE: + height = pass->fbo.abs_y; + break; + + default: + break; + } + + if (!height) + height = d3d10->vp.height; + } + else if (i == (d3d10->shader_preset->passes - 1)) + { + width = d3d10->vp.width; + height = d3d10->vp.height; + } + + RARCH_LOG("[D3D10]: Updating framebuffer size %u x %u.\n", width, height); + + if ((i != (d3d10->shader_preset->passes - 1)) || (width != d3d10->vp.width) || + (height != d3d10->vp.height)) + { + d3d10->pass[i].viewport.Width = width; + d3d10->pass[i].viewport.Height = height; + d3d10->pass[i].viewport.MaxDepth = 1.0; + d3d10->pass[i].rt.desc.Width = width; + d3d10->pass[i].rt.desc.Height = height; + d3d10->pass[i].rt.desc.BindFlags = D3D10_BIND_RENDER_TARGET; + d3d10->pass[i].rt.desc.Format = glslang_format_to_dxgi(d3d10->pass[i].semantics.format); + d3d10_init_texture(d3d10->device, &d3d10->pass[i].rt); + + if (pass->feedback) + { + d3d10->pass[i].feedback.desc = d3d10->pass[i].rt.desc; + d3d10_init_texture(d3d10->device, &d3d10->pass[i].feedback); + /* todo: do we need to clear it to black here ? */ + } + } + else + { + d3d10->pass[i].rt.size_data.x = width; + d3d10->pass[i].rt.size_data.y = height; + d3d10->pass[i].rt.size_data.z = 1.0f / width; + d3d10->pass[i].rt.size_data.w = 1.0f / height; + } + } + + d3d10->resize_render_targets = false; + +#if 0 +error: + d3d10_free_shader_preset(d3d10); + return false; +#endif +} + static bool d3d10_gfx_frame( void* data, const void* frame, @@ -317,9 +1079,10 @@ static bool d3d10_gfx_frame( const char* msg, video_frame_info_t* video_info) { - (void)msg; - - d3d10_video_t* d3d10 = (d3d10_video_t*)data; + unsigned i; + d3d10_texture_t* texture = NULL; + d3d10_video_t * d3d10 = (d3d10_video_t*)data; + D3D10Device context = d3d10->device; if (d3d10->resize_chain) { @@ -337,71 +1100,291 @@ static bool d3d10_gfx_frame( d3d10->viewport.Width = video_info->width; d3d10->viewport.Height = video_info->height; + d3d10->ubo_values.OutputSize.width = d3d10->viewport.Width; + d3d10->ubo_values.OutputSize.height = d3d10->viewport.Height; + d3d10->resize_chain = false; d3d10->resize_viewport = true; + + video_driver_set_size(&video_info->width, &video_info->height); } PERF_START(); - D3D10ClearRenderTargetView(d3d10->device, d3d10->renderTargetView, d3d10->clearcolor); + +#if 0 /* custom viewport doesn't call apply_state_changes, so we can't rely on this for now */ + if (d3d10->resize_viewport) +#endif + d3d10_update_viewport(d3d10, false); + + D3D10SetPrimitiveTopology(context, D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + +#if 0 + if (d3d10->hw.enable) + { + D3D10SetRenderTargets(context, 1, &d3d10->renderTargetView, NULL); + D3D10SetState(context, d3d10->state); + } +#endif if (frame && width && height) { - D3D10_BOX frame_box = { 0, 0, 0, width, height, 1 }; - - if (d3d10->frame.texture.desc.Width != width || d3d10->frame.texture.desc.Height != height) + if (d3d10->shader_preset) { - d3d10->frame.texture.desc.Width = width; - d3d10->frame.texture.desc.Height = height; - d3d10_init_texture(d3d10->device, &d3d10->frame.texture); + if (d3d10->frame.texture[0].desc.Width != width || + d3d10->frame.texture[0].desc.Height != height) + d3d10->resize_render_targets = true; + + if (d3d10->resize_render_targets) + { + unsigned i; + + /* release all render targets first to avoid memory fragmentation */ + for (i = 0; i < d3d10->shader_preset->passes; i++) + { + d3d10_release_texture(&d3d10->pass[i].rt); + d3d10_release_texture(&d3d10->pass[i].feedback); + memset(&d3d10->pass[i].rt, 0, sizeof(d3d10->pass[i].rt)); + memset(&d3d10->pass[i].feedback, 0, sizeof(d3d10->pass[i].feedback)); + } + } + + if (d3d10->shader_preset->history_size) + { + if (d3d10->init_history) + d3d10_init_history(d3d10, width, height); + else + { + int k; + /* todo: what about frame-duping ? + * maybe clone d3d10_texture_t with AddRef */ + d3d10_texture_t tmp = d3d10->frame.texture[d3d10->shader_preset->history_size]; + for (k = d3d10->shader_preset->history_size; k > 0; k--) + d3d10->frame.texture[k] = d3d10->frame.texture[k - 1]; + d3d10->frame.texture[0] = tmp; + } + } } - d3d10_update_texture(width, height, pitch, d3d10->format, frame, &d3d10->frame.texture); - D3D10CopyTexture2DSubresourceRegion( - d3d10->device, d3d10->frame.texture.handle, 0, 0, 0, 0, d3d10->frame.texture.staging, 0, - &frame_box); + /* either no history, or we moved a texture of a different size in the front slot */ + if (d3d10->frame.texture[0].desc.Width != width || + d3d10->frame.texture[0].desc.Height != height) + { + d3d10->frame.texture[0].desc.Width = width; + d3d10->frame.texture[0].desc.Height = height; + d3d10_init_texture(d3d10->device, &d3d10->frame.texture[0]); + } + + if (d3d10->resize_render_targets) + d3d10_init_render_targets(d3d10, width, height); + + if (frame != RETRO_HW_FRAME_BUFFER_VALID) + d3d10_update_texture( + d3d10->device, + width, height, pitch, d3d10->format, frame, &d3d10->frame.texture[0]); } + D3D10SetVertexBuffer(context, 0, d3d10->frame.vbo, sizeof(d3d10_vertex_t), 0); + D3D10SetBlendState(context, d3d10->blend_disable, NULL, D3D10_DEFAULT_SAMPLE_MASK); + + texture = d3d10->frame.texture; + + if (d3d10->shader_preset) { - UINT stride = sizeof(d3d10_vertex_t); - UINT offset = 0; -#if 0 /* custom viewport doesn't call apply_state_changes, so we can't rely on this for now */ - if (d3d10->resize_viewport) -#endif - d3d10_update_viewport(d3d10, false); + unsigned i; - D3D10SetViewports(d3d10->device, 1, &d3d10->frame.viewport); - D3D10SetVertexBuffers(d3d10->device, 0, 1, &d3d10->frame.vbo, &stride, &offset); - D3D10SetVShaderConstantBuffers(d3d10->device, 0, 1, &d3d10->frame.ubo); - D3D10SetPShaderResources(d3d10->device, 0, 1, &d3d10->frame.texture.view); - D3D10SetPShaderSamplers(d3d10->device, 0, 1, &d3d10->frame.sampler); - - D3D10SetBlendState(d3d10->device, d3d10->blend_disable, NULL, D3D10_DEFAULT_SAMPLE_MASK); - D3D10Draw(d3d10->device, 4, 0); - D3D10SetBlendState(d3d10->device, d3d10->blend_enable, NULL, D3D10_DEFAULT_SAMPLE_MASK); - - if (d3d10->menu.enabled && d3d10->menu.texture.handle) + for (i = 0; i < d3d10->shader_preset->passes; i++) { - if (d3d10->menu.texture.dirty) - D3D10CopyTexture2DSubresourceRegion( - d3d10->device, d3d10->menu.texture.handle, 0, 0, 0, 0, - d3d10->menu.texture.staging, 0, NULL); + if (d3d10->shader_preset->pass[i].feedback) + { + d3d10_texture_t tmp = d3d10->pass[i].feedback; + d3d10->pass[i].feedback = d3d10->pass[i].rt; + d3d10->pass[i].rt = tmp; + } + } - if (d3d10->menu.fullscreen) - D3D10SetViewports(d3d10->device, 1, &d3d10->viewport); - D3D10SetVertexBuffers(d3d10->device, 0, 1, &d3d10->menu.vbo, &stride, &offset); - D3D10SetVShaderConstantBuffers(d3d10->device, 0, 1, &d3d10->ubo); - D3D10SetPShaderResources(d3d10->device, 0, 1, &d3d10->menu.texture.view); - D3D10SetPShaderSamplers(d3d10->device, 0, 1, &d3d10->menu.sampler); + for (i = 0; i < d3d10->shader_preset->passes; i++) + { + unsigned j; - D3D10Draw(d3d10->device, 4, 0); + d3d10_set_shader(context, &d3d10->pass[i].shader); + + if (d3d10->shader_preset->pass[i].frame_count_mod) + d3d10->pass[i].frame_count = + frame_count % d3d10->shader_preset->pass[i].frame_count_mod; + else + d3d10->pass[i].frame_count = frame_count; + + for (j = 0; j < SLANG_CBUFFER_MAX; j++) + { + D3D10Buffer buffer = d3d10->pass[i].buffers[j]; + cbuffer_sem_t* buffer_sem = &d3d10->pass[i].semantics.cbuffers[j]; + + if (buffer_sem->stage_mask && buffer_sem->uniforms) + { + D3D10_MAPPED_SUBRESOURCE res; + uniform_sem_t* uniform = buffer_sem->uniforms; + + D3D10MapBuffer(buffer, D3D10_MAP_WRITE_DISCARD, 0, (void**)&res); + while (uniform->size) + { + if (uniform->data) + memcpy((uint8_t*)res.pData + uniform->offset, uniform->data, uniform->size); + uniform++; + } + D3D10UnmapBuffer(buffer); + + if (buffer_sem->stage_mask & SLANG_STAGE_VERTEX_MASK) + D3D10SetVShaderConstantBuffers(context, buffer_sem->binding, 1, &buffer); + + if (buffer_sem->stage_mask & SLANG_STAGE_FRAGMENT_MASK) + D3D10SetPShaderConstantBuffers(context, buffer_sem->binding, 1, &buffer); + } + } + + { + D3D10RenderTargetView null_rt = NULL; + D3D10SetRenderTargets(context, 1, &null_rt, NULL); + } + + { + D3D10ShaderResourceView textures[SLANG_NUM_BINDINGS] = { NULL }; + D3D10SamplerState samplers[SLANG_NUM_BINDINGS] = { NULL }; + + texture_sem_t* texture_sem = d3d10->pass[i].semantics.textures; + while (texture_sem->stage_mask) + { + int binding = texture_sem->binding; + textures[binding] = *(D3D10ShaderResourceView*)texture_sem->texture_data; + samplers[binding] = d3d10->samplers[texture_sem->filter][texture_sem->wrap]; + texture_sem++; + } + +#if 0 + if (d3d10->hw.enable && (i == 0)) + D3D10SetPShaderResources(context, 1, SLANG_NUM_BINDINGS - 1, textures + 1); + else +#endif + D3D10SetPShaderResources(context, 0, SLANG_NUM_BINDINGS, textures); + + D3D10SetPShaderSamplers(context, 0, SLANG_NUM_BINDINGS, samplers); + } + + if (d3d10->pass[i].rt.handle) + { + D3D10SetRenderTargets(context, 1, &d3d10->pass[i].rt.rt_view, NULL); +#if 0 + D3D10ClearRenderTargetView(context, d3d10->pass[i].rt.rt_view, d3d10->clearcolor); +#endif + D3D10SetViewports(context, 1, &d3d10->pass[i].viewport); + + D3D10Draw(context, 4, 0); + texture = &d3d10->pass[i].rt; + } + else + { + texture = NULL; + break; + } + } + D3D10SetRenderTargets(context, 1, &d3d10->renderTargetView, NULL); + } + + if (texture) + { + d3d10_set_shader(context, &d3d10->shaders[VIDEO_SHADER_STOCK_BLEND]); +#if 0 + /* TODO/FIXME */ + if (!d3d10->hw.enable || d3d10->shader_preset) +#endif + D3D10SetPShaderResources(context, 0, 1, &texture->view); + D3D10SetPShaderSamplers( + context, 0, 1, &d3d10->samplers[RARCH_FILTER_UNSPEC][RARCH_WRAP_DEFAULT]); + D3D10SetVShaderConstantBuffers(context, 0, 1, &d3d10->frame.ubo); + } + + D3D10ClearRenderTargetView(context, d3d10->renderTargetView, d3d10->clearcolor); + D3D10SetViewports(context, 1, &d3d10->frame.viewport); + + D3D10Draw(context, 4, 0); + + D3D10SetBlendState(context, d3d10->blend_enable, NULL, D3D10_DEFAULT_SAMPLE_MASK); + + if (d3d10->menu.enabled && d3d10->menu.texture.handle) + { + if (d3d10->menu.fullscreen) + D3D10SetViewports(context, 1, &d3d10->viewport); + + d3d10_set_shader(context, &d3d10->shaders[VIDEO_SHADER_STOCK_BLEND]); + D3D10SetVertexBuffer(context, 0, d3d10->menu.vbo, sizeof(d3d10_vertex_t), 0); + D3D10SetVShaderConstantBuffers(context, 0, 1, &d3d10->ubo); + d3d10_set_texture_and_sampler(context, 0, &d3d10->menu.texture); + D3D10Draw(context, 4, 0); + } + + d3d10_set_shader(context, &d3d10->sprites.shader); + D3D10SetPrimitiveTopology(context, D3D10_PRIMITIVE_TOPOLOGY_POINTLIST); + D3D10SetVShaderConstantBuffer(context, 0, d3d10->ubo); + D3D10SetPShaderConstantBuffer(context, 0, d3d10->ubo); + + d3d10->sprites.enabled = true; + +#ifdef HAVE_MENU + if (d3d10->menu.enabled) + { + D3D10SetViewports(context, 1, &d3d10->viewport); + D3D10SetVertexBuffer(context, 0, d3d10->sprites.vbo, sizeof(d3d10_sprite_t), 0); + menu_driver_frame(video_info); + } + else +#endif + if (video_info->statistics_show) + { + struct font_params* osd_params = (struct font_params*)&video_info->osd_stat_params; + + if (osd_params) + { + D3D10SetViewports(context, 1, &d3d10->viewport); + D3D10SetBlendState(d3d10->device, d3d10->blend_enable, NULL, D3D10_DEFAULT_SAMPLE_MASK); + D3D10SetVertexBuffer(context, 0, d3d10->sprites.vbo, sizeof(d3d10_sprite_t), 0); + font_driver_render_msg( + video_info, NULL, video_info->stat_text, + (const struct font_params*)&video_info->osd_stat_params); } } - DXGIPresent(d3d10->swapChain, !!d3d10->vsync, 0); - PERF_STOP(); +#ifdef HAVE_OVERLAY + if (d3d10->overlays.enabled) + { + if (d3d10->overlays.fullscreen) + D3D10SetViewports(context, 1, &d3d10->viewport); + else + D3D10SetViewports(context, 1, &d3d10->frame.viewport); + + D3D10SetBlendState(d3d10->device, d3d10->blend_enable, NULL, D3D10_DEFAULT_SAMPLE_MASK); + D3D10SetVertexBuffer(context, 0, d3d10->overlays.vbo, sizeof(d3d10_sprite_t), 0); + D3D10SetPShaderSamplers( + context, 0, 1, &d3d10->samplers[RARCH_FILTER_UNSPEC][RARCH_WRAP_DEFAULT]); + + for (i = 0; i < d3d10->overlays.count; i++) + { + D3D10SetPShaderResources(context, 0, 1, &d3d10->overlays.textures[i].view); + D3D10Draw(d3d10->device, 1, i); + } + } +#endif if (msg && *msg) + { + D3D10SetViewports(d3d10->device, 1, &d3d10->viewport); + D3D10SetBlendState(d3d10->device, d3d10->blend_enable, NULL, D3D10_DEFAULT_SAMPLE_MASK); + D3D10SetVertexBuffer(d3d10->device, 0, d3d10->sprites.vbo, sizeof(d3d10_sprite_t), 0); + font_driver_render_msg(video_info, NULL, msg, NULL); dxgi_update_title(video_info); + } + d3d10->sprites.enabled = false; + + PERF_STOP(); + DXGIPresent(d3d10->swapChain, !!d3d10->vsync, 0); return true; } @@ -440,45 +1423,14 @@ static bool d3d10_gfx_has_windowed(void* data) return true; } -static void d3d10_gfx_free(void* data) +static struct video_shader* d3d10_gfx_get_current_shader(void* data) { d3d10_video_t* d3d10 = (d3d10_video_t*)data; - Release(d3d10->frame.ubo); - Release(d3d10->frame.vbo); - Release(d3d10->frame.texture.view); - Release(d3d10->frame.texture.handle); - Release(d3d10->frame.texture.staging); + if (!d3d10) + return NULL; - Release(d3d10->menu.texture.handle); - Release(d3d10->menu.texture.staging); - Release(d3d10->menu.texture.view); - Release(d3d10->menu.vbo); - - Release(d3d10->ubo); - Release(d3d10->blend_enable); - Release(d3d10->blend_disable); - Release(d3d10->sampler_nearest); - Release(d3d10->sampler_linear); - Release(d3d10->ps); - Release(d3d10->vs); - Release(d3d10->layout); - Release(d3d10->renderTargetView); - Release(d3d10->swapChain); - Release(d3d10->device); - - win32_monitor_from_window(); - win32_destroy_window(); - free(d3d10); -} - -static bool d3d10_gfx_set_shader(void* data, enum rarch_shader_type type, const char* path) -{ - (void)data; - (void)type; - (void)path; - - return false; + return d3d10->shader_preset; } static void d3d10_gfx_viewport_info(void* data, struct video_viewport* vp) @@ -509,17 +1461,19 @@ static void d3d10_set_menu_texture_frame( if ( d3d10->menu.texture.desc.Width != width || d3d10->menu.texture.desc.Height != height) { - d3d10->menu.texture.desc.Format = d3d10_get_closest_match_texture2D( - d3d10->device, format); + d3d10->menu.texture.desc.Format = format; d3d10->menu.texture.desc.Width = width; d3d10->menu.texture.desc.Height = height; d3d10_init_texture(d3d10->device, &d3d10->menu.texture); } - d3d10_update_texture(width, height, pitch, format, + d3d10_update_texture(d3d10->device, + width, height, pitch, format, frame, &d3d10->menu.texture); - d3d10->menu.sampler = settings->bools.menu_linear_filter - ? d3d10->sampler_linear : d3d10->sampler_nearest; + d3d10->menu.texture.sampler = d3d10->samplers + [settings->bools.menu_linear_filter + ? RARCH_FILTER_LINEAR + : RARCH_FILTER_NEAREST][RARCH_WRAP_DEFAULT]; } static void d3d10_set_menu_texture_enable(void* data, bool state, bool full_screen) @@ -545,17 +1499,98 @@ static void d3d10_gfx_apply_state_changes(void* data) { d3d10_video_t* d3d10 = (d3d10_video_t*)data; -#if 0 if (d3d10) d3d10->resize_viewport = true; -#endif } +static void d3d10_gfx_set_osd_msg( + void* data, video_frame_info_t* video_info, const char* msg, const void* params, void* font) +{ + d3d10_video_t* d3d10 = (d3d10_video_t*)data; + + if (d3d10) + { + if (d3d10->sprites.enabled) + font_driver_render_msg(video_info, font, msg, (const struct font_params*)params); + else + printf("OSD msg: %s\n", msg); + } +} + +static void d3d10_gfx_show_mouse(void* data, bool state) { win32_show_cursor(state); } + +static uintptr_t d3d10_gfx_load_texture( + void* video_data, void* data, bool threaded, enum texture_filter_type filter_type) +{ + d3d10_texture_t* texture = NULL; + d3d10_video_t* d3d10 = (d3d10_video_t*)video_data; + struct texture_image* image = (struct texture_image*)data; + + if (!d3d10) + return 0; + + texture = (d3d10_texture_t*)calloc(1, sizeof(*texture)); + + if (!texture) + return 0; + + switch (filter_type) + { + case TEXTURE_FILTER_MIPMAP_LINEAR: + texture->desc.MiscFlags = D3D10_RESOURCE_MISC_GENERATE_MIPS; + /* fallthrough */ + case TEXTURE_FILTER_LINEAR: + texture->sampler = d3d10->samplers[RARCH_FILTER_LINEAR][RARCH_WRAP_EDGE]; + break; + case TEXTURE_FILTER_MIPMAP_NEAREST: + texture->desc.MiscFlags = D3D10_RESOURCE_MISC_GENERATE_MIPS; + /* fallthrough */ + case TEXTURE_FILTER_NEAREST: + texture->sampler = d3d10->samplers[RARCH_FILTER_NEAREST][RARCH_WRAP_EDGE]; + break; + } + + texture->desc.Width = image->width; + texture->desc.Height = image->height; + texture->desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + + d3d10_init_texture(d3d10->device, texture); + + d3d10_update_texture( + d3d10->device, + image->width, image->height, 0, DXGI_FORMAT_B8G8R8A8_UNORM, image->pixels, + texture); + + return (uintptr_t)texture; +} +static void d3d10_gfx_unload_texture(void* data, uintptr_t handle) +{ + d3d10_texture_t* texture = (d3d10_texture_t*)handle; + + if (!texture) + return; + + Release(texture->view); + Release(texture->staging); + Release(texture->handle); + free(texture); +} + +#if 0 +static bool +d3d10_get_hw_render_interface(void* data, const struct retro_hw_render_interface** iface) +{ + d3d10_video_t* d3d10 = (d3d10_video_t*)data; + *iface = (const struct retro_hw_render_interface*)&d3d10->hw.iface; + return d3d10->hw.enable; +} +#endif + static const video_poke_interface_t d3d10_poke_interface = { NULL, /* set_coords */ NULL, /* set_mvp */ - NULL, /* load_texture */ - NULL, /* unload_texture */ + d3d10_gfx_load_texture, + d3d10_gfx_unload_texture, NULL, /* set_video_mode */ win32_get_refresh_rate, d3d10_set_filtering, @@ -568,12 +1603,16 @@ static const video_poke_interface_t d3d10_poke_interface = { d3d10_gfx_apply_state_changes, d3d10_set_menu_texture_frame, d3d10_set_menu_texture_enable, - NULL, /* set_osd_msg */ - NULL, /* show_mouse */ + d3d10_gfx_set_osd_msg, + d3d10_gfx_show_mouse, NULL, /* grab_mouse_toggle */ - NULL, /* get_current_shader */ + d3d10_gfx_get_current_shader, NULL, /* get_current_software_framebuffer */ +#if 0 + d3d11_get_hw_render_interface, +#else NULL, /* get_hw_render_interface */ +#endif }; static void d3d10_gfx_get_poke_interface(void* data, const video_poke_interface_t** iface) @@ -599,7 +1638,7 @@ video_driver_t video_d3d10 = { NULL, /* read_frame_raw */ #ifdef HAVE_OVERLAY - NULL, /* overlay_interface */ + d3d10_get_overlay_interface, #endif d3d10_gfx_get_poke_interface, }; diff --git a/gfx/drivers/d3d11.c b/gfx/drivers/d3d11.c index fe29c3406b..839b8c7608 100644 --- a/gfx/drivers/d3d11.c +++ b/gfx/drivers/d3d11.c @@ -996,6 +996,7 @@ static void d3d11_init_history(d3d11_video_t* d3d11, unsigned width, unsigned he } d3d11->init_history = false; } + static void d3d11_init_render_targets(d3d11_video_t* d3d11, unsigned width, unsigned height) { unsigned i; diff --git a/gfx/drivers_font/d3d10_font.c b/gfx/drivers_font/d3d10_font.c new file mode 100644 index 0000000000..43a0c309c3 --- /dev/null +++ b/gfx/drivers_font/d3d10_font.c @@ -0,0 +1,379 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2018 - Daniel De Matteis + * 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 . + */ + +#define CINTERFACE + +#include +#include +#include +#include +#include + +#include "../font_driver.h" +#include "../video_driver.h" +#include "../common/d3d10_common.h" + +#include "../../verbosity.h" + +typedef struct +{ + d3d10_texture_t texture; + const font_renderer_driver_t* font_driver; + void* font_data; + struct font_atlas* atlas; +} d3d10_font_t; + +static void* +d3d10_font_init_font(void* data, const char* font_path, float font_size, bool is_threaded) +{ + d3d10_video_t* d3d10 = (d3d10_video_t*)data; + d3d10_font_t* font = (d3d10_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.sampler = d3d10->samplers[RARCH_FILTER_LINEAR][RARCH_WRAP_BORDER]; + font->texture.desc.Width = font->atlas->width; + font->texture.desc.Height = font->atlas->height; + font->texture.desc.Format = DXGI_FORMAT_A8_UNORM; + d3d10_init_texture(d3d10->device, &font->texture); + d3d10_update_texture( + d3d10->device, + font->atlas->width, font->atlas->height, font->atlas->width, + DXGI_FORMAT_A8_UNORM, font->atlas->buffer, &font->texture); + font->atlas->dirty = false; + + return font; +} + +static void d3d10_font_free_font(void* data, bool is_threaded) +{ + d3d10_font_t* font = (d3d10_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 d3d10_font_get_message_width(void* data, const char* msg, unsigned msg_len, float scale) +{ + d3d10_font_t* font = (d3d10_font_t*)data; + + unsigned i; + int delta_x = 0; + + if (!font) + return 0; + + for (i = 0; i < msg_len; i++) + { + const struct font_glyph *glyph; + const char* msg_tmp = &msg[i]; + unsigned code = utf8_walk(&msg_tmp); + unsigned skip = msg_tmp - &msg[i]; + + if (skip > 1) + i += skip - 1; + + 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 d3d10_font_render_line( + video_frame_info_t* video_info, + d3d10_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, count; + D3D10_MAPPED_SUBRESOURCE mapped_vbo; + d3d10_sprite_t* v; + d3d10_video_t* d3d10 = (d3d10_video_t*)video_info->userdata; + 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 ( !d3d10 || + !d3d10->sprites.enabled || + msg_len > (unsigned)d3d10->sprites.capacity) + return; + + if (d3d10->sprites.offset + msg_len > (unsigned)d3d10->sprites.capacity) + d3d10->sprites.offset = 0; + + switch (text_align) + { + case TEXT_ALIGN_RIGHT: + x -= d3d10_font_get_message_width(font, msg, msg_len, scale); + break; + + case TEXT_ALIGN_CENTER: + x -= d3d10_font_get_message_width(font, msg, msg_len, scale) / 2; + break; + } + + D3D10MapBuffer(d3d10->sprites.vbo, D3D10_MAP_WRITE_NO_OVERWRITE, 0, (void**)&mapped_vbo); + v = (d3d10_sprite_t*)mapped_vbo.pData + d3d10->sprites.offset; + + for (i = 0; i < msg_len; i++) + { + const struct font_glyph* glyph; + const char* msg_tmp = &msg[i]; + unsigned code = utf8_walk(&msg_tmp); + unsigned skip = msg_tmp - &msg[i]; + + if (skip > 1) + i += skip - 1; + + 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)d3d10->viewport.Width; + v->pos.y = (y + glyph->draw_offset_y) * scale / (float)d3d10->viewport.Height; + v->pos.w = glyph->width * scale / (float)d3d10->viewport.Width; + v->pos.h = glyph->height * scale / (float)d3d10->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->params.scaling = 1; + v->params.rotation = 0; + + 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; + } + + count = v - ((d3d10_sprite_t*)mapped_vbo.pData + d3d10->sprites.offset); + D3D10UnmapBuffer(d3d10->sprites.vbo); + + if (!count) + return; + + if (font->atlas->dirty) + { + d3d10_update_texture( + d3d10->device, + font->atlas->width, font->atlas->height, font->atlas->width, + DXGI_FORMAT_A8_UNORM, font->atlas->buffer, &font->texture); + font->atlas->dirty = false; + } + + d3d10_set_texture_and_sampler(d3d10->device, 0, &font->texture); + D3D10SetBlendState(d3d10->device, d3d10->blend_enable, NULL, D3D10_DEFAULT_SAMPLE_MASK); + + D3D10SetPShader(d3d10->device, d3d10->sprites.shader_font.ps); + D3D10Draw(d3d10->device, count, d3d10->sprites.offset); + D3D10SetPShader(d3d10->device, d3d10->sprites.shader.ps); + + d3d10->sprites.offset += count; +} + +static void d3d10_font_render_message( + video_frame_info_t* video_info, + d3d10_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) + { + d3d10_font_render_line( + video_info, font, msg, strlen(msg), scale, color, pos_x, pos_y, text_align); + return; + } + + line_height = font->font_driver->get_line_height(font->font_data) * scale / video_info->height; + + for (;;) + { + const char* delim = strchr(msg, '\n'); + + /* Draw the line */ + if (delim) + { + unsigned msg_len = delim - msg; + d3d10_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); + d3d10_font_render_line( + video_info, font, msg, msg_len, scale, color, pos_x, + pos_y - (float)lines * line_height, text_align); + break; + } + } +} + +static void d3d10_font_render_msg( + video_frame_info_t* video_info, void* data, + const char* msg, const struct font_params *params) +{ + 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; + d3d10_font_t* font = (d3d10_font_t*)data; + 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 = DXGI_COLOR_RGBA(r, g, b, alpha); + } + 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); + + d3d10_font_render_message( + video_info, font, msg, scale, color_dark, + x + scale * drop_x / width, + y + scale * drop_y / height, text_align); + } + + d3d10_font_render_message(video_info, font, msg, scale, + color, x, y, text_align); +} + +static const struct font_glyph* d3d10_font_get_glyph(void *data, uint32_t code) +{ + d3d10_font_t* font = (d3d10_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 d3d10_font_bind_block(void* data, void *userdata) +{ + (void)data; +} + +font_renderer_t d3d10_font = { + d3d10_font_init_font, + d3d10_font_free_font, + d3d10_font_render_msg, + "d3d10font", + d3d10_font_get_glyph, + d3d10_font_bind_block, + NULL, /* flush */ + d3d10_font_get_message_width, +}; diff --git a/gfx/font_driver.c b/gfx/font_driver.c index 75a5adb2f5..28080b80a5 100644 --- a/gfx/font_driver.c +++ b/gfx/font_driver.c @@ -310,6 +310,37 @@ static bool vulkan_font_init_first( } #endif +#ifdef HAVE_D3D10 +static const font_renderer_t *d3d10_font_backends[] = { + &d3d10_font, + NULL, +}; + +static bool d3d10_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; d3d10_font_backends[i]; i++) + { + void *data = d3d10_font_backends[i]->init(video_data, + font_path, font_size, + is_threaded); + + if (!data) + continue; + + *font_driver = d3d10_font_backends[i]; + *font_handle = data; + return true; + } + + return false; +} +#endif + #ifdef HAVE_D3D11 static const font_renderer_t *d3d11_font_backends[] = { &d3d11_font, @@ -493,6 +524,11 @@ static bool font_init_first( return d3d9_font_init_first(font_driver, font_handle, video_data, font_path, font_size, is_threaded); #endif +#ifdef HAVE_D3D10 + case FONT_DRIVER_RENDER_D3D10_API: + return d3d10_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, diff --git a/gfx/font_driver.h b/gfx/font_driver.h index 939eccb951..7d1818b4a3 100644 --- a/gfx/font_driver.h +++ b/gfx/font_driver.h @@ -163,6 +163,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 d3d10_font; extern font_renderer_t d3d11_font; extern font_renderer_t d3d12_font; extern font_renderer_t caca_font; diff --git a/gfx/video_defines.h b/gfx/video_defines.h index 96437c0590..997850b856 100644 --- a/gfx/video_defines.h +++ b/gfx/video_defines.h @@ -84,6 +84,7 @@ enum font_driver_render_api FONT_DRIVER_RENDER_OPENGL_API, FONT_DRIVER_RENDER_D3D8_API, FONT_DRIVER_RENDER_D3D9_API, + FONT_DRIVER_RENDER_D3D10_API, FONT_DRIVER_RENDER_D3D11_API, FONT_DRIVER_RENDER_D3D12_API, FONT_DRIVER_RENDER_VITA2D, diff --git a/griffin/griffin.c b/griffin/griffin.c index 81f8f00a13..d2b12c0674 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -510,6 +510,10 @@ FONTS #include "../gfx/drivers_font/vulkan_raster_font.c" #endif +#if defined(HAVE_D3D10) +#include "../gfx/drivers_font/d3d10_font.c" +#endif + #if defined(HAVE_D3D11) #include "../gfx/drivers_font/d3d11_font.c" #endif @@ -1169,6 +1173,10 @@ MENU #include "../menu/drivers_display/menu_display_d3d9.c" #endif +#if defined(HAVE_D3D10) +#include "../menu/drivers_display/menu_display_d3d10.c" +#endif + #if defined(HAVE_D3D11) #include "../menu/drivers_display/menu_display_d3d11.c" #endif diff --git a/menu/drivers_display/menu_display_d3d10.c b/menu/drivers_display/menu_display_d3d10.c new file mode 100644 index 0000000000..d5e200a638 --- /dev/null +++ b/menu/drivers_display/menu_display_d3d10.c @@ -0,0 +1,289 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2018 - Daniel De Matteis + * 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 . + */ + +#define CINTERFACE + +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "../menu_driver.h" + +#include "../../retroarch.h" +#include "../../gfx/font_driver.h" +#include "../../gfx/video_driver.h" +#include "../../gfx/common/d3d10_common.h" + +static const float* menu_display_d3d10_get_default_vertices(void) +{ + return NULL; +} + +static const float* menu_display_d3d10_get_default_tex_coords(void) +{ + return NULL; +} + +static void* menu_display_d3d10_get_default_mvp(video_frame_info_t *video_info) +{ + return NULL; +} + +static void menu_display_d3d10_blend_begin(video_frame_info_t *video_info) +{ + d3d10_video_t* d3d10 = video_info ? (d3d10_video_t*)video_info->userdata : NULL; + D3D10SetBlendState(d3d10->device, + d3d10->blend_enable, NULL, D3D10_DEFAULT_SAMPLE_MASK); +} + +static void menu_display_d3d10_blend_end(video_frame_info_t *video_info) +{ + d3d10_video_t* d3d10 = video_info ? (d3d10_video_t*)video_info->userdata : NULL; + D3D10SetBlendState(d3d10->device, + d3d10->blend_disable, NULL, D3D10_DEFAULT_SAMPLE_MASK); +} + +static void menu_display_d3d10_viewport(void* data, video_frame_info_t *video_info) +{ +} + +static void menu_display_d3d10_draw(void* data, video_frame_info_t *video_info) +{ + int vertex_count; + d3d10_video_t* d3d10 = video_info ? (d3d10_video_t*)video_info->userdata : NULL; + menu_display_ctx_draw_t* draw = (menu_display_ctx_draw_t*)data; + + if (!d3d10 || !draw || !draw->texture) + return; + + switch (draw->pipeline.id) + { + case VIDEO_SHADER_MENU: + case VIDEO_SHADER_MENU_2: + case VIDEO_SHADER_MENU_3: + case VIDEO_SHADER_MENU_4: + case VIDEO_SHADER_MENU_5: + case VIDEO_SHADER_MENU_6: + d3d10_set_shader(d3d10->device, &d3d10->shaders[draw->pipeline.id]); + D3D10Draw(d3d10->device, draw->coords->vertices, 0); + + D3D10SetBlendState(d3d10->device, d3d10->blend_enable, NULL, D3D10_DEFAULT_SAMPLE_MASK); + d3d10_set_shader(d3d10->device, &d3d10->sprites.shader); + D3D10SetVertexBuffer(d3d10->device, 0, d3d10->sprites.vbo, sizeof(d3d10_sprite_t), 0); + D3D10SetPrimitiveTopology(d3d10->device, D3D10_PRIMITIVE_TOPOLOGY_POINTLIST); + return; + } + + if (draw->coords->vertex && draw->coords->tex_coord && draw->coords->color) + vertex_count = draw->coords->vertices; + else + vertex_count = 1; + + if (!d3d10->sprites.enabled || vertex_count > d3d10->sprites.capacity) + return; + + if (d3d10->sprites.offset + vertex_count > d3d10->sprites.capacity) + d3d10->sprites.offset = 0; + + { + D3D10_MAPPED_SUBRESOURCE mapped_vbo; + d3d10_sprite_t* sprite = NULL; + + D3D10MapBuffer(d3d10->sprites.vbo, D3D10_MAP_WRITE_NO_OVERWRITE, 0, (void**)&mapped_vbo); + + sprite = (d3d10_sprite_t*)mapped_vbo.pData + d3d10->sprites.offset; + + if (vertex_count == 1) + { + sprite->pos.x = draw->x / (float)d3d10->viewport.Width; + sprite->pos.y = + (d3d10->viewport.Height - draw->y - draw->height) / (float)d3d10->viewport.Height; + sprite->pos.w = draw->width / (float)d3d10->viewport.Width; + sprite->pos.h = draw->height / (float)d3d10->viewport.Height; + + sprite->coords.u = 0.0f; + sprite->coords.v = 0.0f; + sprite->coords.w = 1.0f; + sprite->coords.h = 1.0f; + + if (draw->scale_factor) + sprite->params.scaling = draw->scale_factor; + else + sprite->params.scaling = 1.0f; + + sprite->params.rotation = draw->rotation; + + sprite->colors[3] = DXGI_COLOR_RGBA( + 0xFF * draw->coords->color[0], 0xFF * draw->coords->color[1], + 0xFF * draw->coords->color[2], 0xFF * draw->coords->color[3]); + sprite->colors[2] = DXGI_COLOR_RGBA( + 0xFF * draw->coords->color[4], 0xFF * draw->coords->color[5], + 0xFF * draw->coords->color[6], 0xFF * draw->coords->color[7]); + sprite->colors[1] = DXGI_COLOR_RGBA( + 0xFF * draw->coords->color[8], 0xFF * draw->coords->color[9], + 0xFF * draw->coords->color[10], 0xFF * draw->coords->color[11]); + sprite->colors[0] = DXGI_COLOR_RGBA( + 0xFF * draw->coords->color[12], 0xFF * draw->coords->color[13], + 0xFF * draw->coords->color[14], 0xFF * draw->coords->color[15]); + } + else + { + int i; + const float* vertex = draw->coords->vertex; + const float* tex_coord = draw->coords->tex_coord; + const float* color = draw->coords->color; + + for (i = 0; i < vertex_count; i++) + { + d3d10_vertex_t* v = (d3d10_vertex_t*)sprite; + v->position[0] = *vertex++; + v->position[1] = *vertex++; + v->texcoord[0] = *tex_coord++; + v->texcoord[1] = *tex_coord++; + v->color[0] = *color++; + v->color[1] = *color++; + v->color[2] = *color++; + v->color[3] = *color++; + + sprite++; + } + + d3d10_set_shader(d3d10->device, &d3d10->shaders[VIDEO_SHADER_STOCK_BLEND]); + D3D10SetPrimitiveTopology(d3d10->device, D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + } + + D3D10UnmapBuffer(d3d10->sprites.vbo); + } + + d3d10_set_texture_and_sampler(d3d10->device, 0, (d3d10_texture_t*)draw->texture); + D3D10Draw(d3d10->device, vertex_count, d3d10->sprites.offset); + d3d10->sprites.offset += vertex_count; + + if (vertex_count > 1) + { + d3d10_set_shader(d3d10->device, &d3d10->sprites.shader); + D3D10SetPrimitiveTopology(d3d10->device, D3D10_PRIMITIVE_TOPOLOGY_POINTLIST); + } + + return; +} + +static void menu_display_d3d10_draw_pipeline(void* data, + video_frame_info_t *video_info) +{ + menu_display_ctx_draw_t* draw = (menu_display_ctx_draw_t*)data; + d3d10_video_t* d3d10 = video_info ? (d3d10_video_t*)video_info->userdata : NULL; + + if (!d3d10 || !draw) + return; + + switch (draw->pipeline.id) + { + case VIDEO_SHADER_MENU: + case VIDEO_SHADER_MENU_2: + { + video_coord_array_t* ca = menu_display_get_coords_array(); + + if (!d3d10->menu_pipeline_vbo) + { + D3D10_BUFFER_DESC desc = { 0 }; + desc.Usage = D3D10_USAGE_IMMUTABLE; + desc.ByteWidth = ca->coords.vertices * 2 * sizeof(float); + desc.BindFlags = D3D10_BIND_VERTEX_BUFFER; + + D3D10_SUBRESOURCE_DATA vertexData = { ca->coords.vertex }; + D3D10CreateBuffer(d3d10->device, &desc, &vertexData, &d3d10->menu_pipeline_vbo); + } + D3D10SetVertexBuffer(d3d10->device, 0, d3d10->menu_pipeline_vbo, 2 * sizeof(float), 0); + draw->coords->vertices = ca->coords.vertices; + D3D10SetBlendState(d3d10->device, d3d10->blend_pipeline, NULL, D3D10_DEFAULT_SAMPLE_MASK); + break; + } + + case VIDEO_SHADER_MENU_3: + case VIDEO_SHADER_MENU_4: + case VIDEO_SHADER_MENU_5: + case VIDEO_SHADER_MENU_6: + D3D10SetVertexBuffer(d3d10->device, 0, d3d10->frame.vbo, sizeof(d3d10_vertex_t), 0); + draw->coords->vertices = 4; + break; + default: + return; + } + + D3D10SetPrimitiveTopology(d3d10->device, D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + + d3d10->ubo_values.time += 0.01f; + + { + D3D10_MAPPED_SUBRESOURCE mapped_ubo; + D3D10MapBuffer(d3d10->ubo, D3D10_MAP_WRITE_DISCARD, 0, (void**)&mapped_ubo); + *(d3d10_uniform_t*)mapped_ubo.pData = d3d10->ubo_values; + D3D10UnmapBuffer(d3d10->ubo); + } +} + +static void menu_display_d3d10_restore_clear_color(void) {} + +static void menu_display_d3d10_clear_color( + menu_display_ctx_clearcolor_t* clearcolor, + video_frame_info_t *video_info) +{ + d3d10_video_t *d3d10 = video_info ? + (d3d10_video_t*)video_info->userdata : NULL; + + if (!d3d10 || !clearcolor) + return; + + D3D10ClearRenderTargetView(d3d10->device, + d3d10->renderTargetView, (float*)clearcolor); +} + +static bool menu_display_d3d10_font_init_first( + void** font_handle, + void* video_data, + const char* font_path, + float font_size, + bool is_threaded) +{ + font_data_t** handle = (font_data_t**)font_handle; + font_data_t* new_handle = font_driver_init_first( + video_data, font_path, font_size, true, + is_threaded, FONT_DRIVER_RENDER_D3D10_API); + if (!new_handle) + return false; + *handle = new_handle; + return true; +} + +menu_display_ctx_driver_t menu_display_ctx_d3d10 = { + menu_display_d3d10_draw, + menu_display_d3d10_draw_pipeline, + menu_display_d3d10_viewport, + menu_display_d3d10_blend_begin, + menu_display_d3d10_blend_end, + menu_display_d3d10_restore_clear_color, + menu_display_d3d10_clear_color, + menu_display_d3d10_get_default_mvp, + menu_display_d3d10_get_default_vertices, + menu_display_d3d10_get_default_tex_coords, + menu_display_d3d10_font_init_first, + MENU_VIDEO_DRIVER_DIRECT3D10, + "menu_display_d3d10", + true +}; diff --git a/menu/menu_driver.c b/menu/menu_driver.c index ddbadabe02..c9ba81d516 100644 --- a/menu/menu_driver.c +++ b/menu/menu_driver.c @@ -236,6 +236,10 @@ static bool menu_display_check_compatibility( if (string_is_equal(video_driver, "d3d9")) return true; break; + case MENU_VIDEO_DRIVER_DIRECT3D10: + if (string_is_equal(video_driver, "d3d10")) + return true; + break; case MENU_VIDEO_DRIVER_DIRECT3D11: if (string_is_equal(video_driver, "d3d11")) return true; diff --git a/menu/menu_driver.h b/menu/menu_driver.h index 412e920478..f5e37241c9 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -285,6 +285,7 @@ enum menu_display_driver_type MENU_VIDEO_DRIVER_VULKAN, MENU_VIDEO_DRIVER_DIRECT3D8, MENU_VIDEO_DRIVER_DIRECT3D9, + MENU_VIDEO_DRIVER_DIRECT3D10, MENU_VIDEO_DRIVER_DIRECT3D11, MENU_VIDEO_DRIVER_DIRECT3D12, MENU_VIDEO_DRIVER_VITA2D,