diff options
author | 2017-01-05 18:03:26 +0100 | |
---|---|---|
committer | 2017-01-05 18:03:25 +0100 | |
commit | ff28f114b4591eafc1a64e2e000997b763a9e369 (patch) | |
tree | fd7dc2e5c11bf3f65ceef4f05a7b01cf61c17227 | |
parent | 34c3e7866bc3e173a0cfb272286aaf8f774c01f4 (diff) | |
parent | 2b95c8e50bbfa22320ca8ddd04d3d94052a5c4ed (diff) |
Merge pull request #1843 from anikom15/hlsl
New phosphor persistence shaders for HLSL
-rw-r--r-- | hlsl/ghosting.fx | 159 | ||||
-rw-r--r-- | hlsl/phosphor.fx | 52 | ||||
-rw-r--r-- | ini/presets/gameboy.ini | 3 | ||||
-rw-r--r-- | ini/presets/gba.ini | 3 | ||||
-rw-r--r-- | ini/presets/lcd-matrix.ini | 3 | ||||
-rw-r--r-- | ini/presets/lcd.ini | 3 | ||||
-rw-r--r-- | ini/presets/raster.ini | 4 | ||||
-rw-r--r-- | ini/presets/vector-mono.ini | 4 | ||||
-rw-r--r-- | ini/presets/vector.ini | 4 | ||||
-rw-r--r-- | src/osd/modules/render/d3d/d3dcomm.h | 14 | ||||
-rw-r--r-- | src/osd/modules/render/d3d/d3dhlsl.cpp | 125 | ||||
-rw-r--r-- | src/osd/modules/render/d3d/d3dhlsl.h | 15 | ||||
-rw-r--r-- | src/osd/modules/render/drawd3d.cpp | 27 | ||||
-rw-r--r-- | src/osd/windows/winmain.cpp | 6 | ||||
-rw-r--r-- | src/osd/windows/winmain.h | 12 |
15 files changed, 375 insertions, 59 deletions
diff --git a/hlsl/ghosting.fx b/hlsl/ghosting.fx new file mode 100644 index 00000000000..f09bab41fba --- /dev/null +++ b/hlsl/ghosting.fx @@ -0,0 +1,159 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz, Westley M. Martinez +//----------------------------------------------------------------------------- +// Ghosting Effect +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Sampler Definitions +//----------------------------------------------------------------------------- + +texture Diffuse; + +sampler DiffuseSampler = sampler_state +{ + Texture = <Diffuse>; + SRGBTexture = TRUE; + MipFilter = LINEAR; + MinFilter = LINEAR; + MagFilter = LINEAR; + AddressU = CLAMP; + AddressV = CLAMP; + AddressW = CLAMP; +}; + +texture LastPass; + +sampler PreviousSampler = sampler_state +{ + Texture = <LastPass>; + SRGBTexture = TRUE; + MipFilter = LINEAR; + MinFilter = LINEAR; + MagFilter = LINEAR; + AddressU = CLAMP; + AddressV = CLAMP; + AddressW = CLAMP; +}; + +//----------------------------------------------------------------------------- +// Vertex Definitions +//----------------------------------------------------------------------------- + +struct VS_OUTPUT +{ + float4 Position : POSITION; + float4 Color : COLOR0; + float2 TexCoord : TEXCOORD0; + float2 PrevCoord : TEXCOORD1; +}; + +struct VS_INPUT +{ + float3 Position : POSITION; + float4 Color : COLOR0; + float2 TexCoord : TEXCOORD0; +}; + +struct PS_INPUT +{ + float4 Color : COLOR0; + float2 TexCoord : TEXCOORD0; + float2 PrevCoord : TEXCOORD1; +}; + +//----------------------------------------------------------------------------- +// Phosphor Vertex Shader +//----------------------------------------------------------------------------- + +uniform float2 ScreenDims; +uniform float2 TargetDims; + +uniform bool Passthrough; + +VS_OUTPUT vs_main(VS_INPUT Input) +{ + VS_OUTPUT Output = (VS_OUTPUT)0; + + Output.Position = float4(Input.Position.xyz, 1.0f); + Output.Position.xy /= ScreenDims; + Output.Position.y = 1.0f - Output.Position.y; // flip y + Output.Position.xy -= 0.5f; // center + Output.Position.xy *= 2.0f; // zoom + + Output.TexCoord = Input.TexCoord; + Output.TexCoord += 0.5f / TargetDims; // half texel offset correction (DX9) + + Output.PrevCoord = Output.TexCoord; + + Output.Color = Input.Color; + + return Output; +} + +//----------------------------------------------------------------------------- +// Phosphor Pixel Shader +//----------------------------------------------------------------------------- + +uniform float DeltaTime = 0.0f; +uniform float3 LCDRise = { 0.0f, 0.0f, 0.0f }; +uniform float3 LCDFall = { 0.0f, 0.0f, 0.0f }; +static const float TAU_FACTOR = 0.159154943; + +float4 ps_main(PS_INPUT Input) : COLOR +{ + float4 CurrPix = tex2D(DiffuseSampler, Input.TexCoord); + float3 PrevPix = tex2D(PreviousSampler, Input.PrevCoord).rgb; + float3 tau = { 0.0f, 0.0f, 0.0f }; + float r = PrevPix.r; + float g = PrevPix.g; + float b = PrevPix.b; + + if (CurrPix.r > r) { + tau.r = LCDRise.r * TAU_FACTOR; + r = tau.r == 0 ? CurrPix.r : (CurrPix.r - r) * + (1 - exp(-DeltaTime / tau.r)) + r; + } + else { + tau.r = LCDFall.r * TAU_FACTOR; + r = tau.r == 0 ? CurrPix.r : (r - CurrPix.r) * + exp(-DeltaTime / tau.r) + CurrPix.r; + } + if (CurrPix.g > g) { + tau.g = LCDRise.g * TAU_FACTOR; + g = tau.g == 0 ? CurrPix.g : (CurrPix.g - g) * + (1 - exp(-DeltaTime / tau.g)) + g; + } + else { + tau.g = LCDFall.g * TAU_FACTOR; + g = tau.g == 0 ? CurrPix.g : (g - CurrPix.g) * + exp(-DeltaTime / tau.g) + CurrPix.g; + } + if (CurrPix.b > b) { + tau.b = LCDRise.b * TAU_FACTOR; + b = tau.b == 0 ? CurrPix.b : (CurrPix.b - b) * + (1 - exp(-DeltaTime / tau.b)) + b; + } + else { + tau.b = LCDFall.b * TAU_FACTOR; + b = tau.b == 0 ? CurrPix.b : (b - CurrPix.b) * + exp(-DeltaTime / tau.b) + CurrPix.b; + } + return Passthrough ? CurrPix : float4(r, g, b, CurrPix.a); +} + +//----------------------------------------------------------------------------- +// Phosphor Technique +//----------------------------------------------------------------------------- + +technique DefaultTechnique +{ + pass Pass0 + { + SRGBWriteEnable = TRUE; + Lighting = FALSE; + + VertexShader = compile vs_2_0 vs_main(); + PixelShader = compile ps_2_0 ps_main(); + } +} diff --git a/hlsl/phosphor.fx b/hlsl/phosphor.fx index d78473a2c6e..e7f585a1f2f 100644 --- a/hlsl/phosphor.fx +++ b/hlsl/phosphor.fx @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Ryan Holtz +// copyright-holders:Ryan Holtz, Westley M. Martinez //----------------------------------------------------------------------------- // Phosphor Effect //----------------------------------------------------------------------------- @@ -13,6 +13,7 @@ texture Diffuse; sampler DiffuseSampler = sampler_state { Texture = <Diffuse>; + SRGBTexture = TRUE; MipFilter = LINEAR; MinFilter = LINEAR; MagFilter = LINEAR; @@ -26,6 +27,7 @@ texture LastPass; sampler PreviousSampler = sampler_state { Texture = <LastPass>; + SRGBTexture = TRUE; MipFilter = LINEAR; MinFilter = LINEAR; MagFilter = LINEAR; @@ -93,24 +95,51 @@ VS_OUTPUT vs_main(VS_INPUT Input) // Phosphor Pixel Shader //----------------------------------------------------------------------------- -uniform float3 Phosphor = float3(0.0f, 0.0f, 0.0f); +uniform int Mode = 0; uniform float DeltaTime = 0.0f; -static const float F = 30.0f; +uniform float3 TimeConstant = { 0.0f, 0.0f, 0.0f }; +uniform float3 Beta = { 0.0f, 0.0f, 0.0f }; +static const float TAU_FACTOR = 0.4342944819; +static const float GAMMA_INV_FACTOR = TAU_FACTOR / 100; float4 ps_main(PS_INPUT Input) : COLOR { float4 CurrPix = tex2D(DiffuseSampler, Input.TexCoord); float3 PrevPix = tex2D(PreviousSampler, Input.PrevCoord).rgb; + float r = PrevPix.r; + float g = PrevPix.g; + float b = PrevPix.b; + + if (Mode == 0) { + r = 0; + g = 0; + b = 0; + } + else if (Mode == 1) { + float3 tau = TimeConstant * TAU_FACTOR; - PrevPix.r *= Phosphor.r == 0 ? 0 : pow(Phosphor.r, F * DeltaTime); - PrevPix.g *= Phosphor.g == 0 ? 0 : pow(Phosphor.g, F * DeltaTime); - PrevPix.b *= Phosphor.b == 0 ? 0 : pow(Phosphor.b, F * DeltaTime); - float RedMax = max(CurrPix.r, PrevPix.r); - float GreenMax = max(CurrPix.g, PrevPix.g); - float BlueMax = max(CurrPix.b, PrevPix.b); + r *= tau.r == 0 ? 0 : exp(-DeltaTime / tau.r); + g *= tau.g == 0 ? 0 : exp(-DeltaTime / tau.g); + b *= tau.b == 0 ? 0 : exp(-DeltaTime / tau.b); + } + else { + float3 gamma = 1 / (TimeConstant * GAMMA_INV_FACTOR); + + if (r != 0.0f) + r = pow(gamma.r * DeltaTime + pow(1 / r, 1 / Beta.r), + -Beta.r); + if (g != 0.0f) + g = pow(gamma.g * DeltaTime + pow(1 / g, 1 / Beta.g), + -Beta.g); + if (b != 0.0f) + b = pow(gamma.b * DeltaTime + pow(1 / b, 1 / Beta.b), + -Beta.b); + } - return Passthrough ? - CurrPix : float4(RedMax, GreenMax, BlueMax, CurrPix.a); + r = max(CurrPix.r, r); + g = max(CurrPix.g, g); + b = max(CurrPix.b, b); + return Passthrough ? CurrPix : float4(r, g, b, CurrPix.a); } //----------------------------------------------------------------------------- @@ -121,6 +150,7 @@ technique DefaultTechnique { pass Pass0 { + SRGBWriteEnable = TRUE; Lighting = FALSE; VertexShader = compile vs_2_0 vs_main(); diff --git a/ini/presets/gameboy.ini b/ini/presets/gameboy.ini index 088af358ee1..3ac98f98ee0 100644 --- a/ini/presets/gameboy.ini +++ b/ini/presets/gameboy.ini @@ -31,7 +31,8 @@ offset 0.0,0.10,0.05 scale 0.9,0.8,1.0 power 1.4,1.2,1.8 floor 0.0,0.0,0.0 -phosphor_life 0.65,0.65,0.65 +lcd_rise_time 0.25,0.25,0.25 +lcd_fall_time 0.1,0.1,0.1 # # NTSC POST-PROCESSING OPTIONS diff --git a/ini/presets/gba.ini b/ini/presets/gba.ini index d895acafd6c..1be2a736d4e 100644 --- a/ini/presets/gba.ini +++ b/ini/presets/gba.ini @@ -31,7 +31,8 @@ offset 0.0,0.0,0.0 scale 1.0,1.0,1.0 power 1.0,1.0,1.0 floor 0.0,0.0,0.0 -phosphor_life 0.5,0.5,0.5 +lcd_rise_time 0.05,0.05,0.05 +lcd_fall_time 0.1,0.1,0.1 # # NTSC POST-PROCESSING OPTIONS diff --git a/ini/presets/lcd-matrix.ini b/ini/presets/lcd-matrix.ini index 7c97229d9f4..7103ae5bc8f 100644 --- a/ini/presets/lcd-matrix.ini +++ b/ini/presets/lcd-matrix.ini @@ -31,7 +31,8 @@ offset 0.0,0.0,0.0 scale 1.0,1.0,1.0 power 1.0,1.0,1.0 floor 0.0,0.0,0.0 -phosphor_life 0.5,0.5,0.5 +lcd_rise_time 0.25,0.25,0.25 +lcd_fall_time 0.1,0.1,0.1 # # NTSC POST-PROCESSING OPTIONS diff --git a/ini/presets/lcd.ini b/ini/presets/lcd.ini index d895acafd6c..1be2a736d4e 100644 --- a/ini/presets/lcd.ini +++ b/ini/presets/lcd.ini @@ -31,7 +31,8 @@ offset 0.0,0.0,0.0 scale 1.0,1.0,1.0 power 1.0,1.0,1.0 floor 0.0,0.0,0.0 -phosphor_life 0.5,0.5,0.5 +lcd_rise_time 0.05,0.05,0.05 +lcd_fall_time 0.1,0.1,0.1 # # NTSC POST-PROCESSING OPTIONS diff --git a/ini/presets/raster.ini b/ini/presets/raster.ini index 8f852cf5a10..6d3edf3889f 100644 --- a/ini/presets/raster.ini +++ b/ini/presets/raster.ini @@ -37,7 +37,9 @@ offset -0.30,-0.20,-0.05 scale 1.15,1.05,0.90 power 0.90,0.90,1.15 floor 0.025,0.025,0.025 -phosphor_life 0.25,0.25,0.25 +phosphor_mode 2 +phosphor_time 0.005,0.050,0.050 +phosphor_beta 1.0,1.0,1.0 # # NTSC POST-PROCESSING OPTIONS diff --git a/ini/presets/vector-mono.ini b/ini/presets/vector-mono.ini index 00ff7978f5d..2778bc69d7a 100644 --- a/ini/presets/vector-mono.ini +++ b/ini/presets/vector-mono.ini @@ -37,7 +37,9 @@ offset 0.0,0.0,0.0 scale 1.0,1.0,1.0 power 1.0,1.0,1.0 floor 0.0,0.0,0.0 -phosphor_life 0.5,0.5,0.5 +phosphor_mode 2 +phosphor_time 0.01,0.01,0.01 +phosphor_beta 1.0,1.0,1.0 # # NTSC POST-PROCESSING OPTIONS diff --git a/ini/presets/vector.ini b/ini/presets/vector.ini index ea41036f3e5..7f1c887919e 100644 --- a/ini/presets/vector.ini +++ b/ini/presets/vector.ini @@ -40,7 +40,9 @@ offset 0.0,0.0,0.0 scale 1.0,1.0,1.0 power 1.0,1.0,1.0 floor 0.0,0.0,0.0 -phosphor_life 0.5,0.5,0.5 +phosphor_mode 2 +phosphor_time 0.005,0.050,0.050 +phosphor_beta 1.0,1.0,1.0 # # NTSC POST-PROCESSING OPTIONS diff --git a/src/osd/modules/render/d3d/d3dcomm.h b/src/osd/modules/render/d3d/d3dcomm.h index 38b93adb7ac..98a720988c0 100644 --- a/src/osd/modules/render/d3d/d3dcomm.h +++ b/src/osd/modules/render/d3d/d3dcomm.h @@ -220,7 +220,7 @@ class d3d_render_target { public: // construction/destruction - d3d_render_target(): target_width(0), target_height(0), width(0), height(0), screen_index(0), bloom_count(0) + d3d_render_target(): target_width(0), target_height(0), width(0), height(0), screen_index(0), bloom_count(0), cache_index(0) { for (int index = 0; index < MAX_BLOOM_COUNT; index++) { @@ -234,16 +234,16 @@ public: source_surface[index] = nullptr; target_texture[index] = nullptr; target_surface[index] = nullptr; + cache_texture[index] = nullptr; + cache_surface[index] = nullptr; } - - cache_texture = nullptr; - cache_surface = nullptr; } ~d3d_render_target(); bool init(renderer_d3d9 *d3d, int source_width, int source_height, int target_width, int target_height, int screen_index); int next_index(int index) { return ++index > 1 ? 0 : index; } + int next_cache_index() { cache_index = ++cache_index > 1 ? 0 : cache_index; return cache_index; } // real target dimension int target_width; @@ -260,8 +260,8 @@ public: IDirect3DSurface9 *source_surface[2]; IDirect3DTexture9 *source_texture[2]; - IDirect3DSurface9 *cache_surface; - IDirect3DTexture9 *cache_texture; + IDirect3DSurface9 *cache_surface[2]; + IDirect3DTexture9 *cache_texture[2]; IDirect3DSurface9 *bloom_surface[MAX_BLOOM_COUNT]; IDirect3DTexture9 *bloom_texture[MAX_BLOOM_COUNT]; @@ -269,6 +269,8 @@ public: float bloom_dims[MAX_BLOOM_COUNT][2]; int bloom_count; + + int cache_index; }; #endif diff --git a/src/osd/modules/render/d3d/d3dhlsl.cpp b/src/osd/modules/render/d3d/d3dhlsl.cpp index a6cfad8cae9..17861ef3ce1 100644 --- a/src/osd/modules/render/d3d/d3dhlsl.cpp +++ b/src/osd/modules/render/d3d/d3dhlsl.cpp @@ -169,9 +169,9 @@ shaders::shaders() : snap_copy_target(nullptr), snap_copy_texture(nullptr), snap_target(nullptr), snap_texture(nullptr), snap_width(0), snap_height(0), initialized(false), backbuffer(nullptr), curr_effect(nullptr), default_effect(nullptr), prescale_effect(nullptr), post_effect(nullptr), distortion_effect(nullptr), - focus_effect(nullptr), phosphor_effect(nullptr), deconverge_effect(nullptr), color_effect(nullptr), - ntsc_effect(nullptr), bloom_effect(nullptr), downsample_effect(nullptr), vector_effect(nullptr), - curr_texture(nullptr), curr_render_target(nullptr), curr_poly(nullptr), + focus_effect(nullptr), phosphor_effect(nullptr), ghosting_effect(nullptr), deconverge_effect(nullptr), + color_effect(nullptr), ntsc_effect(nullptr), bloom_effect(nullptr), downsample_effect(nullptr), + vector_effect(nullptr), curr_texture(nullptr), curr_render_target(nullptr), curr_poly(nullptr), d3dx_create_effect_from_file_ptr(nullptr) { } @@ -518,7 +518,15 @@ bool shaders::init(d3d_base *d3dintf, running_machine *machine, renderer_d3d9 *r get_vector(winoptions.screen_scale(), 3, options->scale, true); get_vector(winoptions.screen_power(), 3, options->power, true); get_vector(winoptions.screen_floor(), 3, options->floor, true); - get_vector(winoptions.screen_phosphor(), 3, options->phosphor, true); + options->phosphor_mode = winoptions.screen_phosphor_mode(); + get_vector(winoptions.screen_phosphor_time(), 3, + options->phosphor_time, true); + get_vector(winoptions.screen_phosphor_beta(), 3, + options->phosphor_beta, true); + get_vector(winoptions.screen_lcd_rise_time(), 3, + options->lcd_rise_time, true); + get_vector(winoptions.screen_lcd_fall_time(), 3, + options->lcd_fall_time, true); options->saturation = winoptions.screen_saturation(); options->yiq_enable = winoptions.screen_yiq_enable(); options->yiq_jitter = winoptions.screen_yiq_jitter(); @@ -709,6 +717,7 @@ int shaders::create_resources() distortion_effect = new effect(this, d3d->get_device(), "distortion.fx", fx_dir); prescale_effect = new effect(this, d3d->get_device(), "prescale.fx", fx_dir); phosphor_effect = new effect(this, d3d->get_device(), "phosphor.fx", fx_dir); + ghosting_effect = new effect(this, d3d->get_device(), "ghosting.fx", fx_dir); focus_effect = new effect(this, d3d->get_device(), "focus.fx", fx_dir); deconverge_effect = new effect(this, d3d->get_device(), "deconverge.fx", fx_dir); color_effect = new effect(this, d3d->get_device(), "color.fx", fx_dir); @@ -722,6 +731,7 @@ int shaders::create_resources() !distortion_effect->is_valid() || !prescale_effect->is_valid() || !phosphor_effect->is_valid() || + !ghosting_effect->is_valid() || !focus_effect->is_valid() || !deconverge_effect->is_valid() || !color_effect->is_valid() || @@ -733,12 +743,13 @@ int shaders::create_resources() return 1; } - effect *effects[13] = { + effect *effects[14] = { default_effect, post_effect, distortion_effect, prescale_effect, phosphor_effect, + ghosting_effect, focus_effect, deconverge_effect, color_effect, @@ -749,7 +760,7 @@ int shaders::create_resources() vector_effect }; - for (int i = 0; i < 13; i++) + for (int i = 0; i < 14; i++) { effects[i]->add_uniform("SourceDims", uniform::UT_VEC2, uniform::CU_SOURCE_DIMS); effects[i]->add_uniform("TargetDims", uniform::UT_VEC2, uniform::CU_TARGET_DIMS); @@ -786,7 +797,12 @@ int shaders::create_resources() focus_effect->add_uniform("Defocus", uniform::UT_VEC2, uniform::CU_FOCUS_SIZE); - phosphor_effect->add_uniform("Phosphor", uniform::UT_VEC3, uniform::CU_PHOSPHOR_LIFE); + phosphor_effect->add_uniform("Mode", uniform::UT_INT, uniform::CU_PHOSPHOR_MODE); + phosphor_effect->add_uniform("TimeConstant", uniform::UT_VEC3, uniform::CU_PHOSPHOR_TIME); + phosphor_effect->add_uniform("Beta", uniform::UT_VEC3, uniform::CU_PHOSPHOR_BETA); + + ghosting_effect->add_uniform("LCDRise", uniform::UT_FLOAT, uniform::CU_LCD_RISE_TIME); + ghosting_effect->add_uniform("LCDFall", uniform::UT_FLOAT, uniform::CU_LCD_FALL_TIME); post_effect->add_uniform("ShadowAlpha", uniform::UT_FLOAT, uniform::CU_POST_SHADOW_ALPHA); post_effect->add_uniform("ShadowCount", uniform::UT_VEC2, uniform::CU_POST_SHADOW_COUNT); @@ -839,6 +855,7 @@ void shaders::begin_draw() distortion_effect->set_technique("DefaultTechnique"); prescale_effect->set_technique("DefaultTechnique"); phosphor_effect->set_technique("DefaultTechnique"); + ghosting_effect->set_technique("DefaultTechnique"); focus_effect->set_technique("DefaultTechnique"); deconverge_effect->set_technique("DefaultTechnique"); color_effect->set_technique("DefaultTechnique"); @@ -1068,31 +1085,64 @@ int shaders::defocus_pass(d3d_render_target *rt, int source_index, poly_info *po int shaders::phosphor_pass(d3d_render_target *rt, int source_index, poly_info *poly, int vertnum) { int next_index = source_index; + auto stype = machine->first_screen()->screen_type(); - // skip phosphor if no influencing settings - if (options->phosphor[0] == 0.0f && options->phosphor[1] == 0.0f && options->phosphor[2] == 0.0f) + // skip if screen doesn't use phosphors + if ((stype != SCREEN_TYPE_RASTER && stype != SCREEN_TYPE_VECTOR) || + options->phosphor_mode == 0) { return next_index; } - // Shader needs time between last update curr_effect = phosphor_effect; curr_effect->update_uniforms(); curr_effect->set_texture("Diffuse", rt->target_texture[next_index]); - curr_effect->set_texture("LastPass", rt->cache_texture); + curr_effect->set_texture("LastPass", rt->cache_texture[rt->cache_index]); curr_effect->set_bool("Passthrough", false); curr_effect->set_float("DeltaTime", delta_time()); - next_index = rt->next_index(next_index); + rt->next_cache_index(); + blit(rt->cache_surface[rt->cache_index], false, D3DPT_TRIANGLELIST, 0, 2); + + // copy cached texture to target texture + curr_effect->update_uniforms(); + curr_effect->set_texture("Diffuse", rt->cache_texture[rt->cache_index]); + curr_effect->set_texture("LastPass", rt->cache_texture[rt->cache_index]); + curr_effect->set_bool("Passthrough", true); + blit(rt->target_surface[next_index], false, D3DPT_TRIANGLELIST, 0, 2); - // Pass along our phosphor'd screen + return next_index; +} + +int shaders::ghosting_pass(d3d_render_target *rt, int source_index, poly_info *poly, int vertnum) +{ + int next_index = source_index; + auto stype = machine->first_screen()->screen_type(); + + if (stype != SCREEN_TYPE_LCD || + (options->lcd_rise_time == 0 && options->lcd_fall_time == 0)) + { + return next_index; + } + + curr_effect = ghosting_effect; curr_effect->update_uniforms(); curr_effect->set_texture("Diffuse", rt->target_texture[next_index]); - curr_effect->set_texture("LastPass", rt->target_texture[next_index]); + curr_effect->set_texture("LastPass", rt->cache_texture[rt->cache_index]); + curr_effect->set_bool("Passthrough", false); + curr_effect->set_float("DeltaTime", delta_time()); + + rt->next_cache_index(); + blit(rt->cache_surface[rt->cache_index], false, D3DPT_TRIANGLELIST, 0, 2); + + // copy cached texture to target texture + curr_effect->update_uniforms(); + curr_effect->set_texture("Diffuse", rt->cache_texture[rt->cache_index]); + curr_effect->set_texture("LastPass", rt->cache_texture[rt->cache_index]); curr_effect->set_bool("Passthrough", true); - blit(rt->cache_surface, false, D3DPT_TRIANGLELIST, 0, 2); + blit(rt->target_surface[next_index], false, D3DPT_TRIANGLELIST, 0, 2); return next_index; } @@ -1364,8 +1414,10 @@ void shaders::render_quad(poly_info *poly, int vertnum) next_index = deconverge_pass(rt, next_index, poly, vertnum); // handled in bgfx next_index = defocus_pass(rt, next_index, poly, vertnum); next_index = phosphor_pass(rt, next_index, poly, vertnum); + next_index = ghosting_pass(rt, next_index, poly, vertnum); // create bloom textures + // This may be phosphor or ghosting, depending on screen type int phosphor_index = next_index; next_index = post_pass(rt, next_index, poly, vertnum, true); next_index = downsample_pass(rt, next_index, poly, vertnum); @@ -1443,8 +1495,10 @@ void shaders::render_quad(poly_info *poly, int vertnum) next_index = deconverge_pass(rt, next_index, poly, vertnum); next_index = defocus_pass(rt, next_index, poly, vertnum); next_index = phosphor_pass(rt, next_index, poly, vertnum); + next_index = ghosting_pass(rt, next_index, poly, vertnum); // create bloom textures + // This may be phosphor or ghosting, depending on screen type int phosphor_index = next_index; next_index = post_pass(rt, next_index, poly, vertnum, true); next_index = downsample_pass(rt, next_index, poly, vertnum); @@ -1735,6 +1789,11 @@ void shaders::delete_resources() delete phosphor_effect; phosphor_effect = nullptr; } + if (ghosting_effect != nullptr) + { + delete ghosting_effect; + ghosting_effect = nullptr; + } if (focus_effect != nullptr) { delete focus_effect; @@ -1949,7 +2008,11 @@ enum slider_option SLIDER_SCALE, SLIDER_POWER, SLIDER_FLOOR, - SLIDER_PHOSPHOR, + SLIDER_PHOSPHOR_MODE, + SLIDER_PHOSPHOR_TIME, + SLIDER_PHOSPHOR_BETA, + SLIDER_LCD_RISE_TIME, + SLIDER_LCD_FALL_TIME, SLIDER_BLOOM_BLEND_MODE, SLIDER_BLOOM_SCALE, SLIDER_BLOOM_OVERDRIVE, @@ -1982,6 +2045,7 @@ enum slider_screen_type SLIDER_SCREEN_TYPE_RASTER = 1, SLIDER_SCREEN_TYPE_VECTOR = 2, SLIDER_SCREEN_TYPE_LCD = 4, + SLIDER_SCREEN_TYPE_RASTER_OR_VECTOR = SLIDER_SCREEN_TYPE_RASTER | SLIDER_SCREEN_TYPE_VECTOR, SLIDER_SCREEN_TYPE_LCD_OR_RASTER = SLIDER_SCREEN_TYPE_RASTER | SLIDER_SCREEN_TYPE_LCD, SLIDER_SCREEN_TYPE_ANY = SLIDER_SCREEN_TYPE_RASTER | SLIDER_SCREEN_TYPE_VECTOR | SLIDER_SCREEN_TYPE_LCD }; @@ -2027,7 +2091,11 @@ slider_desc shaders::s_sliders[] = { "Signal Scale,", -200, 100, 200, 1, SLIDER_COLOR, SLIDER_SCREEN_TYPE_ANY, SLIDER_SCALE, 0.01f, "%2.2f", {} }, { "Signal Exponent,", -800, 0, 800, 1, SLIDER_COLOR, SLIDER_SCREEN_TYPE_ANY, SLIDER_POWER, 0.01f, "%2.2f", {} }, { "Signal Floor,", 0, 0, 100, 1, SLIDER_COLOR, SLIDER_SCREEN_TYPE_ANY, SLIDER_FLOOR, 0.01f, "%2.2f", {} }, - { "Phosphor Persistence,", 0, 0, 100, 1, SLIDER_COLOR, SLIDER_SCREEN_TYPE_ANY, SLIDER_PHOSPHOR, 0.01f, "%2.2f", {} }, + { "Phosphor Persistence Mode,", 0, 0, 2, 1, SLIDER_INT_ENUM, SLIDER_SCREEN_TYPE_RASTER_OR_VECTOR, SLIDER_PHOSPHOR_MODE, 0, "%s", { "Off", "Exponential", "Inverse Power" } }, + { "Phosphor Persistence Time Constant,",1, 5000, 10000,10, SLIDER_COLOR, SLIDER_SCREEN_TYPE_RASTER_OR_VECTOR, SLIDER_PHOSPHOR_TIME, 0.0001f, "%4.4f", {} }, + { "Phosphor Persistence beta,", 50, 100, 200, 1, SLIDER_COLOR, SLIDER_SCREEN_TYPE_RASTER_OR_VECTOR, SLIDER_PHOSPHOR_BETA, 0.01f, "%2.2f", {} }, + { "LCD Rise Time Constant,", 0, 0, 100, 1, SLIDER_COLOR, SLIDER_SCREEN_TYPE_LCD, SLIDER_LCD_RISE_TIME, 0.01f, "%2.2f", {} }, + { "LCD Fall Time Constant,", 0, 0, 100, 1, SLIDER_COLOR, SLIDER_SCREEN_TYPE_LCD, SLIDER_LCD_FALL_TIME, 0.01f, "%2.2f", {} }, { "Bloom Blend Mode", 0, 0, 1, 1, SLIDER_INT_ENUM, SLIDER_SCREEN_TYPE_ANY, SLIDER_BLOOM_BLEND_MODE, 0, "%s", { "Brighten", "Darken" } }, { "Bloom Scale", 0, 0, 2000, 5, SLIDER_FLOAT, SLIDER_SCREEN_TYPE_ANY, SLIDER_BLOOM_SCALE, 0.001f, "%1.3f", {} }, { "Bloom Overdrive,", 0, 0, 2000, 5, SLIDER_COLOR, SLIDER_SCREEN_TYPE_ANY, SLIDER_BLOOM_OVERDRIVE, 0.001f, "%1.3f", {} }, @@ -2099,7 +2167,11 @@ void *shaders::get_slider_option(int id, int index) case SLIDER_SCALE: return &(options->scale[index]); case SLIDER_POWER: return &(options->power[index]); case SLIDER_FLOOR: return &(options->floor[index]); - case SLIDER_PHOSPHOR: return &(options->phosphor[index]); + case SLIDER_PHOSPHOR_MODE: return &(options->phosphor_mode); + case SLIDER_PHOSPHOR_TIME: return &(options->phosphor_time[index]); + case SLIDER_PHOSPHOR_BETA: return &(options->phosphor_beta[index]); + case SLIDER_LCD_RISE_TIME: return &(options->lcd_rise_time[index]); + case SLIDER_LCD_FALL_TIME: return &(options->lcd_fall_time[index]); case SLIDER_BLOOM_BLEND_MODE: return &(options->bloom_blend_mode); case SLIDER_BLOOM_SCALE: return &(options->bloom_scale); case SLIDER_BLOOM_OVERDRIVE: return &(options->bloom_overdrive[index]); @@ -2386,8 +2458,21 @@ void uniform::update() m_shader->set_vector("Defocus", 2, &options->defocus[0]); break; - case CU_PHOSPHOR_LIFE: - m_shader->set_vector("Phosphor", 3, options->phosphor); + case CU_PHOSPHOR_MODE: + m_shader->set_int("Mode", options->phosphor_mode); + break; + case CU_PHOSPHOR_TIME: + m_shader->set_vector("TimeConstant", 3, options->phosphor_time); + break; + case CU_PHOSPHOR_BETA: + m_shader->set_vector("Beta", 3, options->phosphor_beta); + break; + + case CU_LCD_RISE_TIME: + m_shader->set_vector("LCDRise", 3, options->lcd_rise_time); + break; + case CU_LCD_FALL_TIME: + m_shader->set_vector("LCDFall", 3, options->lcd_fall_time); break; case CU_POST_REFLECTION: diff --git a/src/osd/modules/render/d3d/d3dhlsl.h b/src/osd/modules/render/d3d/d3dhlsl.h index ed25d2c52e8..6c94be09793 100644 --- a/src/osd/modules/render/d3d/d3dhlsl.h +++ b/src/osd/modules/render/d3d/d3dhlsl.h @@ -77,7 +77,12 @@ public: CU_FOCUS_SIZE, - CU_PHOSPHOR_LIFE, + CU_PHOSPHOR_MODE, + CU_PHOSPHOR_TIME, + CU_PHOSPHOR_BETA, + + CU_LCD_RISE_TIME, + CU_LCD_FALL_TIME, CU_POST_VIGNETTING, CU_POST_DISTORTION, @@ -203,7 +208,11 @@ struct hlsl_options float scale[3]; float power[3]; float floor[3]; - float phosphor[3]; + int phosphor_mode; + float phosphor_time[3]; + float phosphor_beta[3]; + float lcd_rise_time[3]; + float lcd_fall_time[3]; float saturation; // NTSC @@ -332,6 +341,7 @@ private: int deconverge_pass(d3d_render_target *rt, int source_index, poly_info *poly, int vertnum); int defocus_pass(d3d_render_target *rt, int source_index, poly_info *poly, int vertnum); int phosphor_pass(d3d_render_target *rt, int source_index, poly_info *poly, int vertnum); + int ghosting_pass(d3d_render_target *rt, int source_index, poly_info *poly, int vertnum); int post_pass(d3d_render_target *rt, int source_index, poly_info *poly, int vertnum, bool prepare_bloom); int downsample_pass(d3d_render_target *rt, int source_index, poly_info *poly, int vertnum); int bloom_pass(d3d_render_target *rt, int source_index, poly_info *poly, int vertnum); @@ -381,6 +391,7 @@ private: effect * distortion_effect; // pointer to the distortion-effect object effect * focus_effect; // pointer to the focus-effect object effect * phosphor_effect; // pointer to the phosphor-effect object + effect * ghosting_effect; // pointer te the LCD ghosting effect object effect * deconverge_effect; // pointer to the deconvergence-effect object effect * color_effect; // pointer to the color-effect object effect * ntsc_effect; // pointer to the NTSC effect object diff --git a/src/osd/modules/render/drawd3d.cpp b/src/osd/modules/render/drawd3d.cpp index d0a1ce6c9d1..4cc547b5181 100644 --- a/src/osd/modules/render/drawd3d.cpp +++ b/src/osd/modules/render/drawd3d.cpp @@ -1120,6 +1120,13 @@ bool renderer_d3d9::device_verify_caps() success = false; } + result = d3dintf->d3dobj->CheckDeviceFormat(m_adapter, D3DDEVTYPE_HAL, m_pixformat, 0, D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F); + if (FAILED(result)) + { + osd_printf_error("Direct3D Error: Your graphics card does not support the A16B16G16R16F texture format.\n"); + success = false; + } + if (!success) { osd_printf_error("This feature or features are required to use the Direct3D renderer. Please\n"); @@ -2662,13 +2669,13 @@ d3d_render_target::~d3d_render_target() if (target_surface[index] != nullptr) target_surface[index]->Release(); - } - if (cache_texture != nullptr) - cache_texture->Release(); + if (cache_texture[index] != nullptr) + cache_texture[index]->Release(); - if (cache_surface != nullptr) - cache_surface->Release(); + if (cache_surface[index] != nullptr) + cache_surface[index]->Release(); + } } @@ -2701,13 +2708,13 @@ bool d3d_render_target::init(renderer_d3d9 *d3d, int source_width, int source_he return false; target_texture[index]->GetSurfaceLevel(0, &target_surface[index]); - } - result = d3d->get_device()->CreateTexture(target_width, target_height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &cache_texture, nullptr); - if (FAILED(result)) - return false; + result = d3d->get_device()->CreateTexture(target_width, target_height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A16B16G16R16F, D3DPOOL_DEFAULT, &cache_texture[index], nullptr); + if (FAILED(result)) + return false; - cache_texture->GetSurfaceLevel(0, &cache_surface); + cache_texture[index]->GetSurfaceLevel(0, &cache_surface[index]); + } auto win = d3d->assert_window(); diff --git a/src/osd/windows/winmain.cpp b/src/osd/windows/winmain.cpp index b146e8b6357..902e4eb8ccd 100644 --- a/src/osd/windows/winmain.cpp +++ b/src/osd/windows/winmain.cpp @@ -215,7 +215,11 @@ const options_entry windows_options::s_option_entries[] = { WINOPTION_SCALE";fs_scale", "1.0,1.0,1.0", OPTION_STRING, "signal scaling value (multiplicative)" }, { WINOPTION_POWER";fs_power", "1.0,1.0,1.0", OPTION_STRING, "signal power value (exponential)" }, { WINOPTION_FLOOR";fs_floor", "0.0,0.0,0.0", OPTION_STRING, "signal floor level" }, - { WINOPTION_PHOSPHOR";fs_phosphor", "0.0,0.0,0.0", OPTION_STRING, "phosphorescence decay rate (0.0 is instant, 1.0 is forever)" }, + { WINOPTION_PHOSPHOR_MODE";fs_phosphor_mode", "0", OPTION_STRING, "phosphorescence decay mode (0: off, 1: exponential, 2: inverse-power)" }, + { WINOPTION_PHOSPHOR_TIME";fs_phosphor_time", "0.5,0.5,0.5", OPTION_STRING, "exponential time constant" }, + { WINOPTION_PHOSPHOR_BETA";fs_phosphor_beta", "1.0,1.0,1.0", OPTION_STRING, "inverse power order" }, + { WINOPTION_LCD_RISE_TIME";fs_lcd_rise_time", "0.0,0.0,0.0", OPTION_STRING, "LCD persistence rise time constant" }, + { WINOPTION_LCD_FALL_TIME";fs_lcd_fall_time", "0.0,0.0,0.0", OPTION_STRING, "LCD persistence fall time constant" }, /* NTSC simulation below this line */ { nullptr, nullptr, OPTION_HEADER, "NTSC POST-PROCESSING OPTIONS" }, { WINOPTION_YIQ_ENABLE";yiq", "0", OPTION_BOOLEAN, "enables YIQ-space HLSL post-processing" }, diff --git a/src/osd/windows/winmain.h b/src/osd/windows/winmain.h index 1c40a346d34..c9391aeb75d 100644 --- a/src/osd/windows/winmain.h +++ b/src/osd/windows/winmain.h @@ -68,7 +68,11 @@ #define WINOPTION_SCALE "scale" #define WINOPTION_POWER "power" #define WINOPTION_FLOOR "floor" -#define WINOPTION_PHOSPHOR "phosphor_life" +#define WINOPTION_PHOSPHOR_MODE "phosphor_mode" +#define WINOPTION_PHOSPHOR_TIME "phosphor_time" +#define WINOPTION_PHOSPHOR_BETA "phosphor_beta" +#define WINOPTION_LCD_RISE_TIME "lcd_rise_time" +#define WINOPTION_LCD_FALL_TIME "lcd_fall_time" #define WINOPTION_SATURATION "saturation" #define WINOPTION_YIQ_ENABLE "yiq_enable" #define WINOPTION_YIQ_JITTER "yiq_jitter" @@ -197,7 +201,11 @@ public: const char *screen_scale() const { return value(WINOPTION_SCALE); } const char *screen_power() const { return value(WINOPTION_POWER); } const char *screen_floor() const { return value(WINOPTION_FLOOR); } - const char *screen_phosphor() const { return value(WINOPTION_PHOSPHOR); } + int screen_phosphor_mode() const { return int_value(WINOPTION_PHOSPHOR_MODE); } + const char* screen_phosphor_time() const { return value(WINOPTION_PHOSPHOR_TIME); } + const char* screen_phosphor_beta() const { return value(WINOPTION_PHOSPHOR_BETA); } + const char* screen_lcd_rise_time() const { return value(WINOPTION_LCD_RISE_TIME); } + const char* screen_lcd_fall_time() const { return value(WINOPTION_LCD_FALL_TIME); } float screen_saturation() const { return float_value(WINOPTION_SATURATION); } // full screen options |