From 796e691522ba5c47fc0610da4f557514563f85b9 Mon Sep 17 00:00:00 2001 From: Ryan Holtz Date: Mon, 30 May 2011 21:10:23 +0000 Subject: [PATCH] HLSL Updates: [Ryan Holtz, Bat Country Entertainment, austere, SoltanGris42] - Added the ability to render screenshots at arbitrary resolutions. - Added the ability to record AVI videos (albeit with no audio) at arbitrary resolutions. - Added a 43-tap-wide FIR-based NTSC filter with tunable Y, I and Q frequency response. - Updated scanlines to have a user-tunable pixel-height ratio in addition to the current screen-height ratio. - Fixed a VRAM leak that was causing many dynamic-resolution drivers to run out of memory mid-run. --- .gitattributes | 1 + hlsl/deconverge.fx | 11 +- hlsl/post.fx | 7 +- hlsl/prescale.fx | 90 +++ hlsl/yiq_decode.fx | 165 ++--- hlsl/yiq_encode.fx | 49 +- src/osd/windows/d3d8intf.c | 8 + src/osd/windows/d3d9intf.c | 8 + src/osd/windows/d3dintf.h | 1 + src/osd/windows/drawd3d.c | 1367 +++++++++++++++++++++++++++++++----- src/osd/windows/drawdd.c | 2 + src/osd/windows/drawgdi.c | 2 + src/osd/windows/drawnone.c | 2 + src/osd/windows/input.c | 14 + src/osd/windows/video.c | 8 + src/osd/windows/window.c | 46 ++ src/osd/windows/window.h | 4 + src/osd/windows/winmain.c | 29 +- src/osd/windows/winmain.h | 38 +- 19 files changed, 1504 insertions(+), 348 deletions(-) create mode 100644 hlsl/prescale.fx diff --git a/.gitattributes b/.gitattributes index c5ff7b7be26..8bce026a717 100644 --- a/.gitattributes +++ b/.gitattributes @@ -16,6 +16,7 @@ hlsl/focus.fx svneol=native#text/plain hlsl/phosphor.fx svneol=native#text/plain hlsl/pincushion.fx svneol=native#text/plain hlsl/post.fx svneol=native#text/plain +hlsl/prescale.fx svneol=native#text/plain hlsl/primary.fx svneol=native#text/plain hlsl/yiq_decode.fx svneol=native#text/plain hlsl/yiq_encode.fx svneol=native#text/plain diff --git a/hlsl/deconverge.fx b/hlsl/deconverge.fx index a65f06bbe92..2618fdffad9 100644 --- a/hlsl/deconverge.fx +++ b/hlsl/deconverge.fx @@ -98,6 +98,7 @@ VS_OUTPUT vs_main(VS_INPUT Input) Output.BluCoord.y = ((((TexCoord.y / Ratios.y) - 0.5f)) * (1.0f + BluRadialConvergeY / RawHeight) + 0.5f) * Ratios.y + BluConvergeY * invDims.y; Output.TexCoord = TexCoord; + return Output; } @@ -124,9 +125,13 @@ float4 ps_main(PS_INPUT Input) : COLOR GrnCoord.y = GrnCoord.y - frac(GrnCoord.y); BluCoord.y = BluCoord.y - frac(BluCoord.y); - float RedTexel = tex2D(DiffuseSampler, lerp(TexCoord, RedCoord, Deconverge) / RawDims + 0.5f / RawDims).r; - float GrnTexel = tex2D(DiffuseSampler, lerp(TexCoord, GrnCoord, Deconverge) / RawDims + 0.5f / RawDims).g; - float BluTexel = tex2D(DiffuseSampler, lerp(TexCoord, BluCoord, Deconverge) / RawDims + 0.5f / RawDims).b; + RedCoord = lerp(TexCoord, RedCoord, Deconverge) / RawDims; + GrnCoord = lerp(TexCoord, GrnCoord, Deconverge) / RawDims; + BluCoord = lerp(TexCoord, BluCoord, Deconverge) / RawDims; + + float RedTexel = tex2D(DiffuseSampler, RedCoord + float2(0.0f, 0.5f) / RawDims).r; + float GrnTexel = tex2D(DiffuseSampler, GrnCoord + float2(0.0f, 0.5f) / RawDims).g; + float BluTexel = tex2D(DiffuseSampler, BluCoord + float2(0.0f, 0.5f) / RawDims).b; //RedTexel *= Input.RedCoord.x < (WidthRatio / RawWidth) ? 0.0f : 1.0f; //RedTexel *= Input.RedCoord.y < (HeightRatio / RawHeight) ? 0.0f : 1.0f; diff --git a/hlsl/post.fx b/hlsl/post.fx index ff1cbfa1f47..69ececd4249 100644 --- a/hlsl/post.fx +++ b/hlsl/post.fx @@ -99,6 +99,7 @@ uniform float ScanlineScale = 1.0f; uniform float ScanlineBrightScale = 1.0f; uniform float ScanlineBrightOffset = 1.0f; uniform float ScanlineOffset = 1.0f; +uniform float ScanlineHeight = 0.5f; uniform float UseShadow = 0.0f; uniform float ShadowBrightness = 1.0f; @@ -155,8 +156,8 @@ float4 ps_main(PS_INPUT Input) : COLOR // -- Scanline Simulation -- float InnerSine = BaseCoord.y * RawHeight * ScanlineScale; - float3 ScanBrightness = lerp(1.0f, abs(sin(InnerSine * PI + ScanlineOffset * RawHeight)) * ScanlineBrightScale + 1.0f, ScanlineAmount); - //float3 Scanned = BaseTexel.rgb * ScanBrightness; + float ScanBrightMod = sin(InnerSine * PI + ScanlineOffset * RawHeight); + float3 ScanBrightness = lerp(1.0f, pow(ScanBrightMod * ScanBrightMod, ScanlineHeight) * ScanlineBrightScale + 1.0f, ScanlineAmount); float3 Scanned = BaseTexel.rgb * ScanBrightness; float2 ShadowDims = float2(ShadowWidth, ShadowHeight); @@ -164,7 +165,7 @@ float4 ps_main(PS_INPUT Input) : COLOR float2 ShadowMaskSize = float2(ShadowMaskSizeX, ShadowMaskSizeY); float2 ShadowFrac = frac(BaseCoord * ShadowMaskSize * 0.5f); float2 ShadowCoord = ShadowFrac * ShadowUV + float2(1.5f / ShadowWidth, 1.5f / ShadowHeight); - float3 ShadowTexel = lerp(1.0f, tex2D(ShadowSampler, ShadowCoord), UseShadow); + float3 ShadowTexel = lerp(1.0f, tex2D(ShadowSampler, ShadowCoord).rgb, UseShadow); // -- Final Pixel -- float4 Output = float4(Scanned * lerp(1.0f, ShadowTexel, ShadowBrightness), BaseTexel.a) * Input.Color; diff --git a/hlsl/prescale.fx b/hlsl/prescale.fx new file mode 100644 index 00000000000..4ba0495320e --- /dev/null +++ b/hlsl/prescale.fx @@ -0,0 +1,90 @@ +//----------------------------------------------------------------------------- +// Passthrough Effect +//----------------------------------------------------------------------------- + +texture Diffuse; + +sampler DiffuseSampler = sampler_state +{ + Texture = ; + MipFilter = LINEAR; + MinFilter = LINEAR; + MagFilter = LINEAR; + AddressU = CLAMP; + AddressV = CLAMP; + AddressW = CLAMP; +}; + +//----------------------------------------------------------------------------- +// Vertex Definitions +//----------------------------------------------------------------------------- + +struct VS_OUTPUT +{ + float4 Position : POSITION; + float2 TexCoord : TEXCOORD0; +}; + +struct VS_INPUT +{ + float4 Position : POSITION; + float4 Color : COLOR0; + float2 TexCoord : TEXCOORD0; +}; + +struct PS_INPUT +{ + float2 TexCoord : TEXCOORD0; +}; + +//----------------------------------------------------------------------------- +// Passthrough Vertex Shader +//----------------------------------------------------------------------------- + +float TargetWidth; +float TargetHeight; + +float RawWidth; +float RawHeight; + +VS_OUTPUT vs_main(VS_INPUT Input) +{ + VS_OUTPUT Output = (VS_OUTPUT)0; + + Output.Position = float4(Input.Position.xyz, 1.0f); + Output.Position.x /= TargetWidth; + Output.Position.y /= TargetHeight; + Output.Position.y = 1.0f - Output.Position.y; + Output.Position.x -= 0.5f; + Output.Position.y -= 0.5f; + Output.Position *= float4(2.0f, 2.0f, 1.0f, 1.0f); + + Output.TexCoord = Input.TexCoord + 0.5f / float2(RawWidth, RawHeight); + + return Output; +} + +//----------------------------------------------------------------------------- +// Passthrough Pixel Shader +//----------------------------------------------------------------------------- + +float4 ps_main(PS_INPUT Input) : COLOR +{ + float4 Center = tex2D(DiffuseSampler, Input.TexCoord); + return Center; +} + +//----------------------------------------------------------------------------- +// Passthrough Effect +//----------------------------------------------------------------------------- + +technique DeconvergeTechnique +{ + pass Pass0 + { + Lighting = FALSE; + + VertexShader = compile vs_3_0 vs_main(); + PixelShader = compile ps_3_0 ps_main(); + } +} diff --git a/hlsl/yiq_decode.fx b/hlsl/yiq_decode.fx index 550a0a83062..a85590d998f 100644 --- a/hlsl/yiq_decode.fx +++ b/hlsl/yiq_decode.fx @@ -20,9 +20,9 @@ texture Diffuse; sampler DiffuseSampler = sampler_state { Texture = ; - MipFilter = POINT; - MinFilter = POINT; - MagFilter = POINT; + MipFilter = LINEAR; + MinFilter = LINEAR; + MagFilter = LINEAR; AddressU = CLAMP; AddressV = CLAMP; AddressW = CLAMP; @@ -35,15 +35,7 @@ sampler DiffuseSampler = sampler_state struct VS_OUTPUT { float4 Position : POSITION; - float4 Color : COLOR0; float4 Coord0 : TEXCOORD0; - float4 Coord1 : TEXCOORD1; - float4 Coord2 : TEXCOORD2; - float4 Coord3 : TEXCOORD3; - float4 Coord4 : TEXCOORD4; - float4 Coord5 : TEXCOORD5; - float4 Coord6 : TEXCOORD6; - float4 Coord7 : TEXCOORD7; }; struct VS_INPUT @@ -55,15 +47,7 @@ struct VS_INPUT struct PS_INPUT { - float4 Color : COLOR0; float4 Coord0 : TEXCOORD0; - float4 Coord1 : TEXCOORD1; - float4 Coord2 : TEXCOORD2; - float4 Coord3 : TEXCOORD3; - float4 Coord4 : TEXCOORD4; - float4 Coord5 : TEXCOORD5; - float4 Coord6 : TEXCOORD6; - float4 Coord7 : TEXCOORD7; }; //----------------------------------------------------------------------------- @@ -79,8 +63,6 @@ uniform float RawHeight; uniform float WidthRatio; uniform float HeightRatio; -uniform float FscValue; - VS_OUTPUT vs_main(VS_INPUT Input) { VS_OUTPUT Output = (VS_OUTPUT)0; @@ -88,25 +70,12 @@ VS_OUTPUT vs_main(VS_INPUT Input) Output.Position = float4(Input.Position.xyz, 1.0f); Output.Position.x /= TargetWidth; Output.Position.y /= TargetHeight; - //Output.Position.x /= WidthRatio; - //Output.Position.y /= HeightRatio; Output.Position.y = 1.0f - Output.Position.y; Output.Position.x -= 0.5f; Output.Position.y -= 0.5f; Output.Position *= float4(2.0f, 2.0f, 1.0f, 1.0f); - Output.Color = Input.Color; - Output.Coord0.xy = Input.TexCoord + float2(0.00f / RawWidth, 0.0f); - Output.Coord1.xy = Input.TexCoord + float2(0.25f / RawWidth, 0.0f); - Output.Coord2.xy = Input.TexCoord + float2(0.50f / RawWidth, 0.0f); - Output.Coord3.xy = Input.TexCoord + float2(0.75f / RawWidth, 0.0f); - Output.Coord4.xy = Input.TexCoord + float2(1.00f / RawWidth, 0.0f); - Output.Coord5.xy = Input.TexCoord + float2(1.25f / RawWidth, 0.0f); - Output.Coord6.xy = Input.TexCoord + float2(1.50f / RawWidth, 0.0f); - Output.Coord7.xy = Input.TexCoord + float2(1.75f / RawWidth, 0.0f); - Output.Coord0.zw = Input.TexCoord + float2(2.00f / RawWidth, 0.0f); - Output.Coord1.zw = Input.TexCoord + float2(2.25f / RawWidth, 0.0f); - Output.Coord2.zw = Input.TexCoord + float2(2.50f / RawWidth, 0.0f); - Output.Coord3.zw = Input.TexCoord + float2(2.75f / RawWidth, 0.0f); + Output.Coord0.xy = Input.TexCoord + 0.5f / float2(RawWidth, RawHeight); + Output.Coord0.zw = float2(1.0f / RawWidth, 0.0f); return Output; } @@ -115,95 +84,67 @@ VS_OUTPUT vs_main(VS_INPUT Input) // YIQ Decode Pixel Shader //----------------------------------------------------------------------------- -uniform float YSubsampleLength = 3.0f; -uniform float ISubsampleLength = 3.0f; -uniform float QSubsampleLength = 3.0f; +uniform float AValue = 0.0f; +uniform float BValue = 0.0f; +uniform float CCValue = 3.04183f; +uniform float PValue = 1.0f; +uniform float OValue = 0.0f; +uniform float ScanTime = 52.6f; -uniform float WValue; -uniform float AValue; -uniform float BValue; +uniform float YFreqResponse = 3.0f; +uniform float IFreqResponse = 1.2f; +uniform float QFreqResponse = 0.6f; float4 ps_main(PS_INPUT Input) : COLOR { float2 RawDims = float2(RawWidth, RawHeight); - float4 BaseTexel = tex2D(DiffuseSampler, Input.Coord0.xy + float2(0.5f, 0.5f) / RawDims); - float4 OrigC = tex2D(CompositeSampler, Input.Coord0.xy + float2(0.5f, 0.5f) / RawDims); - float4 OrigC2 = tex2D(CompositeSampler, Input.Coord4.xy + float2(0.5f, 0.5f) / RawDims); - float4 OrigC3 = tex2D(CompositeSampler, Input.Coord0.zw + float2(0.5f, 0.5f) / RawDims); - float4 C = OrigC; - float4 C2 = OrigC2; - float4 C3 = OrigC3; + float4 BaseTexel = tex2D(DiffuseSampler, Input.Coord0.xy + 0.5f / RawDims); + + // YIQ convolution: N coefficients each + float4 YAccum = 0.0f; + float4 IAccum = 0.0f; + float4 QAccum = 0.0f; float MaxC = 2.1183f; float MinC = -1.1183f; float CRange = MaxC - MinC; - - C = C * CRange + MinC; - C2 = C2 * CRange + MinC; - - float2 Coord0 = Input.Coord0.xy * RawDims; - float2 Coord1 = Input.Coord1.xy * RawDims; - float2 Coord2 = Input.Coord2.xy * RawDims; - float2 Coord3 = Input.Coord3.xy * RawDims; - float2 Coord4 = Input.Coord4.xy * RawDims; - float2 Coord5 = Input.Coord5.xy * RawDims; - float2 Coord6 = Input.Coord6.xy * RawDims; - float2 Coord7 = Input.Coord7.xy * RawDims; - float2 Coord8 = Input.Coord0.zw * RawDims; - float2 Coord9 = Input.Coord1.zw * RawDims; - float2 CoordA = Input.Coord2.zw * RawDims; - float2 CoordB = Input.Coord3.zw * RawDims; - - float W = WValue * 2.0f; - float T0 = Coord0.x + AValue * Coord0.y + BValue; - float T1 = Coord1.x + AValue * Coord1.y + BValue; - float T2 = Coord2.x + AValue * Coord2.y + BValue; - float T3 = Coord3.x + AValue * Coord3.y + BValue; - float T4 = Coord4.x + AValue * Coord4.y + BValue; - float T5 = Coord5.x + AValue * Coord5.y + BValue; - float T6 = Coord6.x + AValue * Coord6.y + BValue; - float T7 = Coord7.x + AValue * Coord7.y + BValue; - float T8 = Coord8.x + AValue * Coord8.y + BValue; - float T9 = Coord9.x + AValue * Coord9.y + BValue; - float TA = CoordA.x + AValue * CoordA.y + BValue; - float TB = CoordB.x + AValue * CoordB.y + BValue; - float4 Tc = float4(T0, T1, T2, T3); - float4 Tc2 = float4(T4, T5, T6, T7); - float4 Tc3 = float4(T8, T9, TA, TB); - - float Yvals[8]; - Yvals[0] = C.r; Yvals[1] = C.g; Yvals[2] = C.b; Yvals[3] = C.a; Yvals[4] = C2.r; Yvals[5] = C2.g; Yvals[6] = C2.b; Yvals[7] = C2.a; - float Ytotal = 0.0f; - for(uint idx = 0; idx < FscValue * 4.0f; idx++ ) + float Fc_y = YFreqResponse * ScanTime / (RawWidth * 4.0f / WidthRatio); + float Fc_i = IFreqResponse * ScanTime / (RawWidth * 4.0f / WidthRatio); + float Fc_q = QFreqResponse * ScanTime / (RawWidth * 4.0f / WidthRatio); + float PI = 3.1415926535897932384626433832795; + float PI2 = 2.0f * PI; + float PI2Length = PI2 / 42.0f; + for(float n = -21.0f; n < 22.0f; n += 4.0f) { - Ytotal = Ytotal + Yvals[idx]; - } - float Yavg = Ytotal / (FscValue * 4.0f); + float4 n4 = float4(n + 0.0f, n + 1.0f, n + 2.0f, n + 3.0f); + float4 CoordX = Input.Coord0.x + Input.Coord0.z * n4 * 0.25f; + float4 CoordY = Input.Coord0.y; + float4 C = tex2D(CompositeSampler, float2(CoordX.r, CoordY.r)) * CRange + MinC; + float4 WT = PI2 * CCValue * ScanTime * (CoordX * WidthRatio + AValue * CoordY * 2.0f * (RawHeight / HeightRatio) + BValue) + OValue; - float4 I = (C - Yavg) * sin(W * Tc); - float4 Q = (C - Yavg) * cos(W * Tc); - float4 I2 = (C2 - Yavg) * sin(W * Tc2); - float4 Q2 = (C2 - Yavg) * cos(W * Tc2); - float4 I3 = (C3 - Yavg) * sin(W * Tc3); - float4 Q3 = (C3 - Yavg) * cos(W * Tc3); - - float Itotal = 0.0f; - float Qtotal = 0.0f; - - float Ivals[8]; - float Qvals[8]; - Ivals[0] = I.r; Ivals[1] = I.g; Ivals[2] = I.b; Ivals[3] = I.a; Ivals[4] = I2.r; Ivals[5] = I2.g; Ivals[6] = I2.b; Ivals[7] = I2.a; - Qvals[0] = Q.r; Qvals[1] = Q.g; Qvals[2] = Q.b; Qvals[3] = Q.a; Qvals[4] = Q2.r; Qvals[5] = Q2.g; Qvals[6] = Q2.b; Qvals[7] = Q2.a; - for(uint idx = 0; idx < FscValue * 4.0f; idx++ ) - { - Itotal = Itotal + Ivals[idx]; - Qtotal = Qtotal + Qvals[idx]; + float4 SincYIn = PI2 * Fc_y * n4; + float4 IdealY = 2.0f * Fc_y * ((SincYIn != 0.0f) ? (sin(SincYIn) / SincYIn) : 1.0f); + float4 FilterY = (0.54f + 0.46f * cos(PI2Length * n4)) * IdealY; + + float4 SincIIn = PI2 * Fc_i * n4; + float4 IdealI = 2.0f * Fc_i * ((SincIIn != 0.0f) ? (sin(SincIIn) / SincIIn) : 1.0f); + float4 FilterI = (0.54f + 0.46f * cos(PI2Length * n4)) * IdealI; + + float4 SincQIn = PI2 * Fc_q * n4; + float4 IdealQ = 2.0f * Fc_q * ((SincQIn != 0.0f) ? (sin(SincQIn) / SincQIn) : 1.0f); + float4 FilterQ = (0.54f + 0.46f * cos(PI2Length * n4)) * IdealQ; + + YAccum = YAccum + C * FilterY; + IAccum = IAccum + C * cos(WT) * FilterI; + QAccum = QAccum + C * sin(WT) * FilterQ; } - float Iavg = Itotal / (FscValue * 3.0f); - float Qavg = Qtotal / (FscValue * 3.0f); - - float3 YIQ = float3(Yavg, Iavg * 1.5f, Qavg); + float Y = YAccum.r + YAccum.g + YAccum.b + YAccum.a; + float I = (IAccum.r + IAccum.g + IAccum.b + IAccum.a) * 2.0f; + float Q = (QAccum.r + QAccum.g + QAccum.b + QAccum.a) * 2.0f; + + float3 YIQ = float3(Y, I, Q); + float3 OutRGB = float3(dot(YIQ, float3(1.0f, 0.956f, 0.621f)), dot(YIQ, float3(1.0f, -0.272f, -0.647f)), dot(YIQ, float3(1.0f, -1.106f, 1.703f))); return float4(OutRGB, BaseTexel.a); diff --git a/hlsl/yiq_encode.fx b/hlsl/yiq_encode.fx index b8ee1e22de5..119a9169bf8 100644 --- a/hlsl/yiq_encode.fx +++ b/hlsl/yiq_encode.fx @@ -82,35 +82,32 @@ VS_OUTPUT vs_main(VS_INPUT Input) // YIQ Encode Pixel Shader //----------------------------------------------------------------------------- -uniform float YSubsampleLength = 3.0f; -uniform float ISubsampleLength = 3.0f; -uniform float QSubsampleLength = 3.0f; - -uniform float WValue; -uniform float AValue; -uniform float BValue; - -uniform float FscScale; +uniform float AValue = 0.0f; +uniform float BValue = 0.0f; +uniform float CCValue = 3.04183f; +uniform float PValue = 1.0f; +uniform float ScanTime = 52.6f; float4 ps_main(PS_INPUT Input) : COLOR { float2 Scaler = float2(RawWidth, RawHeight); float2 InvRatios = float2(1.0f / WidthRatio, 1.0f / HeightRatio); - float3 Texel0 = tex2D(DiffuseSampler, Input.Coord0 + float2(FscScale * 0.00f + 0.5f, 0.5f) / Scaler).rgb; - float3 Texel1 = tex2D(DiffuseSampler, Input.Coord1 + float2(FscScale * 0.25f + 0.5f, 0.5f) / Scaler).rgb; - float3 Texel2 = tex2D(DiffuseSampler, Input.Coord2 + float2(FscScale * 0.50f + 0.5f, 0.5f) / Scaler).rgb; - float3 Texel3 = tex2D(DiffuseSampler, Input.Coord3 + float2(FscScale * 0.75f + 0.5f, 0.5f) / Scaler).rgb; + float3 Texel0 = tex2D(DiffuseSampler, Input.Coord0 + float2(PValue * 0.00f + 0.5f, 0.5f) / Scaler).rgb; + float3 Texel1 = tex2D(DiffuseSampler, Input.Coord1 + float2(PValue * 0.25f + 0.5f, 0.5f) / Scaler).rgb; + float3 Texel2 = tex2D(DiffuseSampler, Input.Coord2 + float2(PValue * 0.50f + 0.5f, 0.5f) / Scaler).rgb; + float3 Texel3 = tex2D(DiffuseSampler, Input.Coord3 + float2(PValue * 0.75f + 0.5f, 0.5f) / Scaler).rgb; - float2 Coord0 = (Input.Coord0.xy + float2(0.00f / RawWidth, 0.0f)) * Scaler; - float2 Coord1 = (Input.Coord1.xy + float2(0.25f / RawWidth, 0.0f)) * Scaler; - float2 Coord2 = (Input.Coord2.xy + float2(0.50f / RawWidth, 0.0f)) * Scaler; - float2 Coord3 = (Input.Coord3.xy + float2(0.75f / RawWidth, 0.0f)) * Scaler; + float2 Coord0 = (Input.Coord0.xy + float2(0.00f / RawWidth, 0.0f)); + float2 Coord1 = (Input.Coord1.xy + float2(0.25f / RawWidth, 0.0f)); + float2 Coord2 = (Input.Coord2.xy + float2(0.50f / RawWidth, 0.0f)); + float2 Coord3 = (Input.Coord3.xy + float2(0.75f / RawWidth, 0.0f)); - float W = WValue * 2.0f; - float T0 = Coord0.x + AValue * Coord0.y + BValue; - float T1 = Coord1.x + AValue * Coord1.y + BValue; - float T2 = Coord2.x + AValue * Coord2.y + BValue; - float T3 = Coord3.x + AValue * Coord3.y + BValue; + float PI = 3.1415926535897932384626433832795; + float W = PI * 2.0f * CCValue * ScanTime; + float T0 = Coord0.x * WidthRatio + AValue * Coord0.y * 2.0f * (RawHeight / HeightRatio) + BValue; + float T1 = Coord1.x * WidthRatio + AValue * Coord1.y * 2.0f * (RawHeight / HeightRatio) + BValue; + float T2 = Coord2.x * WidthRatio + AValue * Coord2.y * 2.0f * (RawHeight / HeightRatio) + BValue; + float T3 = Coord3.x * WidthRatio + AValue * Coord3.y * 2.0f * (RawHeight / HeightRatio) + BValue; float Y0 = dot(Texel0, float3(0.299f, 0.587f, 0.114f)); float I0 = dot(Texel0, float3(0.595716f, -0.274453f, -0.321263f)); @@ -132,10 +129,10 @@ float4 ps_main(PS_INPUT Input) : COLOR float MinC = -1.1183f; float CRange = MaxC - MinC; - float C0 = Y0 + I0 * sin(T0 * W) + Q0 * cos(T0 * W); - float C1 = Y1 + I1 * sin(T1 * W) + Q1 * cos(T1 * W); - float C2 = Y2 + I2 * sin(T2 * W) + Q2 * cos(T2 * W); - float C3 = Y3 + I3 * sin(T3 * W) + Q3 * cos(T3 * W); + float C0 = Y0 + I0 * cos(T0 * W) + Q0 * sin(T0 * W); + float C1 = Y1 + I1 * cos(T1 * W) + Q1 * sin(T1 * W); + float C2 = Y2 + I2 * cos(T2 * W) + Q2 * sin(T2 * W); + float C3 = Y3 + I3 * cos(T3 * W) + Q3 * sin(T3 * W); C0 = (C0 - MinC) / CRange; C1 = (C1 - MinC) / CRange; C2 = (C2 - MinC) / CRange; diff --git a/src/osd/windows/d3d8intf.c b/src/osd/windows/d3d8intf.c index da220335b71..0218309b193 100644 --- a/src/osd/windows/d3d8intf.c +++ b/src/osd/windows/d3d8intf.c @@ -360,6 +360,13 @@ static HRESULT d3d_device_get_render_target(d3d_device *dev, DWORD index, d3d_su } +static HRESULT d3d_device_get_render_target_data(d3d_device *dev, d3d_surface *rendertarget, d3d_surface *destsurface) +{ + assert(false); + return D3D_OK; +} + + static HRESULT d3d_device_present(d3d_device *dev, const RECT *source, const RECT *dest, HWND override, RGNDATA *dirty, DWORD flags) { IDirect3DDevice8 *device = (IDirect3DDevice8 *)dev; @@ -470,6 +477,7 @@ static const d3d_device_interface d3d8_device_interface = d3d_device_end_scene, d3d_device_get_raster_status, d3d_device_get_render_target, + d3d_device_get_render_target_data, d3d_device_present, d3d_device_release, d3d_device_reset, diff --git a/src/osd/windows/d3d9intf.c b/src/osd/windows/d3d9intf.c index f2b3a19877f..dccf68cde75 100644 --- a/src/osd/windows/d3d9intf.c +++ b/src/osd/windows/d3d9intf.c @@ -398,6 +398,13 @@ static HRESULT d3d_device_get_render_target(d3d_device *dev, DWORD index, d3d_su } +static HRESULT d3d_device_get_render_target_data(d3d_device *dev, d3d_surface *rendertarget, d3d_surface *destsurface) +{ + IDirect3DDevice9 *device = (IDirect3DDevice9 *)dev; + return IDirect3DDevice9_GetRenderTargetData(device, (IDirect3DSurface9 *)rendertarget, (IDirect3DSurface9 *)destsurface); +} + + static HRESULT d3d_device_present(d3d_device *dev, const RECT *source, const RECT *dest, HWND override, RGNDATA *dirty, DWORD flags) { IDirect3DDevice9 *device = (IDirect3DDevice9 *)dev; @@ -544,6 +551,7 @@ static const d3d_device_interface d3d9_device_interface = d3d_device_end_scene, d3d_device_get_raster_status, d3d_device_get_render_target, + d3d_device_get_render_target_data, d3d_device_present, d3d_device_release, d3d_device_reset, diff --git a/src/osd/windows/d3dintf.h b/src/osd/windows/d3dintf.h index 1c939b17bdc..4819281339e 100644 --- a/src/osd/windows/d3dintf.h +++ b/src/osd/windows/d3dintf.h @@ -190,6 +190,7 @@ struct _d3d_device_interface HRESULT (*end_scene)(d3d_device *dev); HRESULT (*get_raster_status)(d3d_device *dev, D3DRASTER_STATUS *status); HRESULT (*get_render_target)(d3d_device *dev, DWORD index, d3d_surface **surface); + HRESULT (*get_render_target_data)(d3d_device *dev, d3d_surface *rendertarget, d3d_surface *destsurface); HRESULT (*present)(d3d_device *dev, const RECT *source, const RECT *dest, HWND override, RGNDATA *dirty, DWORD flags); ULONG (*release)(d3d_device *dev); HRESULT (*reset)(d3d_device *dev, d3d_present_parameters *params); diff --git a/src/osd/windows/drawd3d.c b/src/osd/windows/drawd3d.c index 47af7112138..d2bf7ed4a64 100644 --- a/src/osd/windows/drawd3d.c +++ b/src/osd/windows/drawd3d.c @@ -54,6 +54,7 @@ #include #include #include +#include #undef interface // MAME headers @@ -63,6 +64,8 @@ #include "rendutil.h" #include "options.h" #include "emuopts.h" +#include "aviio.h" +#include "png.h" // MAMEOS headers #include "d3dintf.h" @@ -116,6 +119,7 @@ typedef struct _texture_info texture_info; struct _texture_info { texture_info * next; // next texture in the list + texture_info * prev; // prev texture in the list UINT32 hash; // hash value for the texture UINT32 flags; // rendering flags render_texinfo texinfo; // copy of the texture info @@ -130,19 +134,8 @@ struct _texture_info int cur_frame; // what is our current frame? d3d_texture * d3dtex; // Direct3D texture pointer d3d_surface * d3dsurface; // Direct3D offscreen plain surface pointer - d3d_surface * d3dtarget0; // Direct3D render target surface pointer (pass 0, if necessary) - d3d_surface * d3dtarget1; // Direct3D render target surface pointer (pass 1, if necessary) - d3d_surface * d3dtarget2; // Direct3D render target surface pointer (pass 2, if necessary) - d3d_surface * d3dtarget3; // Direct3D render target surface pointer (pass 3, if necessary) - d3d_surface * d3dtarget4; // Direct3D render target surface pointer (pass 4, if necessary) - d3d_surface * d3dsmalltarget0; // Direct3D render target surface pointer (small pass 0, if necessary) - d3d_texture * d3dtexture0; // Direct3D render target texture pointer (pass 0, if necessary) - d3d_texture * d3dtexture1; // Direct3D render target texture pointer (pass 1, if necessary) - d3d_texture * d3dtexture2; // Direct3D render target texture pointer (pass 2, if necessary) - d3d_texture * d3dtexture3; // Direct3D render target texture pointer (pass 3, if necessary) - d3d_texture * d3dtexture4; // Direct3D render target texture pointer (pass 4, if necessary) - d3d_texture * d3dsmalltexture0; // Direct3D render target texture pointer (small pass 0, if necessary) d3d_texture * d3dfinaltex; // Direct3D final (post-scaled) texture + int target_index; // Direct3D target index }; @@ -169,7 +162,6 @@ struct _d3d_vertex float u0, v0; // texture stage 0 coordinates }; - /* d3d_options is the information about runtime-mutable Direct3D options */ typedef struct _d3d_options d3d_options; struct _d3d_options @@ -183,6 +175,7 @@ struct _d3d_options float screen_pincushion; float screen_scanline_alpha; float screen_scanline_scale; + float screen_scanline_height; float screen_scanline_bright_scale; float screen_scanline_bright_offset; float screen_scanline_offset; @@ -227,6 +220,88 @@ struct _d3d_options float screen_saturation; }; +static d3d_options g_d3d_hlsl_presets[6] = +{ + { 0.00f, 1, 1, 0.1875f, 0.1875f, + 0.03f, 0.03f, + 0.25f, 1.0f, 1.0f, 0.6f, 0.0f, + 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 0.0f, + 1.1f, 1.1f, 1.1f, + 0.9f, 0.9f, 0.9f, + 0.05f, 0.05f, 0.05f, + 0.45f, 0.45f, 0.45f, + 1.4f }, + { 0.15f, 512, 384, 0.1875f, 0.1875f, + 0.03f, 0.03f, + 0.25f, 1.0f, 1.0f, 0.6f, 0.0f, + 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 0.0f, + 1.1f, 1.1f, 1.1f, + 0.9f, 0.9f, 0.9f, + 0.05f, 0.05f, 0.05f, + 0.45f, 0.45f, 0.45f, + 1.4f }, + { 0.15f, 512, 384, 0.1875f, 0.1875f, + 0.03f, 0.03f, + 0.25f, 1.0f, 1.0f, 0.6f, 0.0f, + 0.0f, 0.0f, + 0.4f, 0.1f, 0.0, 0.0f,-0.25f,-0.3f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 0.0f, + 1.1f, 1.1f, 1.1f, + 0.9f, 0.9f, 0.9f, + 0.05f, 0.05f, 0.05f, + 0.45f, 0.45f, 0.45f, + 1.4f }, + { 0.15f, 512, 384, 0.1875f, 0.1875f, + 0.03f, 0.03f, + 0.25f, 1.0f, 1.0f, 0.6f, 0.0f, + 0.0f, 0.0f, + 0.4f, 0.1f, 0.0, 0.0f,-0.25f,-0.3f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + 0.05f, 0.05f, 0.05f, + 0.45f, 0.45f, 0.45f, + 1.0f }, + { 0.15f, 512, 384, 0.1875f, 0.1875f, + 0.03f, 0.03f, + 0.25f, 1.0f, 1.0f, 0.6f, 0.0f, + 0.0f, 0.0f, + 0.4f, 0.1f, 0.0, 0.0f,-0.25f,-0.3f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + 0.05f, 0.05f, 0.05f, + 0.45f, 0.45f, 0.45f, + 0.8f }, + { 0.15f, 512, 384, 0.1875f, 0.1875f, + 0.03f, 0.03f, + 0.25f, 1.0f, 1.0f, 0.6f, 0.0f, + 0.0f, 0.0f, + 0.4f, 0.1f, 0.0, 0.0f,-0.25f,-0.3f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.7f, 0.3f, 0.0f, 0.0f, 0.7f, 0.3f, 0.3f, 0.0f, 0.7f, + 0.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + 0.05f, 0.05f, 0.05f, + 0.45f, 0.45f, 0.45f, + 0.8f } +}; + /* d3d_info is the information about Direct3D for the current screen */ typedef struct _d3d_info d3d_info; struct _d3d_info @@ -249,6 +324,7 @@ struct _d3d_info int numverts; // number of accumulated vertices d3d_effect * effect; // pointer to the current effect object + d3d_effect * prescale_effect; // pointer to the current prescale-effect object d3d_effect * post_effect; // pointer to the current post-effect object d3d_effect * pincushion_effect; // pointer to the current pincushion-effect object d3d_effect * focus_effect; // pointer to the current focus-effect object @@ -291,16 +367,54 @@ struct _d3d_info bitmap_t * default_bitmap; // experimental: default bitmap texture_info * default_texture; // experimental: default texture - bool hlsl_enable; // experimental: HLSL enable flag - bool yiq_enable; // experimental: HLSL YIQ-convolution flag - d3d_surface * last_d3dtarget[9]; // Direct3D render target surface pointer for each screen's previous frame - d3d_texture * last_d3dtexture[9]; // Direct3D render target texture pointer for each screen's previous frame - float oversample_x; // experimental: render target oversampling factor (width) for shader prettification - float oversample_y; // experimental: render target oversampling factor (height) for shader prettification - bitmap_t * shadow_bitmap; // experimental: shadow mask bitmap for post-processing shader - texture_info * shadow_texture; // experimental: shadow mask texture for post-processing shader + bool hlsl_enable; // HLSL enable flag + bool yiq_enable; // HLSL YIQ-convolution flag + bool hlsl_prescale; // HLSL prescale enable flag + int hlsl_prescale_size; // HLSL prescale size + int hlsl_preset; // HLSL preset, if relevant + float oversample_x; // render target oversampling factor (width) for shader prettification + float oversample_y; // render target oversampling factor (height) for shader prettification + bitmap_t * shadow_bitmap; // shadow mask bitmap for post-processing shader + texture_info * shadow_texture; // shadow mask texture for post-processing shader int registered_targets; // Number of registered HLSL targets (i.e., screens) d3d_options * hlsl_options; // HLSL uniforms + avi_file * hlsl_avi_file; // HLSL AVI file + bitmap_t * hlsl_avi_snap; // HLSL AVI snapshot + int hlsl_avi_frame; // HLSL AVI frame + attotime hlsl_avi_frame_period; // HLSL AVI frame period + attotime hlsl_avi_next_frame_time; // HLSL AVI next frame time + d3d_surface * hlsl_avi_copy_surface; // HLSL AVI destination surface in system memory + d3d_texture * hlsl_avi_copy_texture; // HLSL AVI destination texture in system memory + d3d_surface * hlsl_avi_final_target; // HLSL AVI upscaled surface + d3d_texture * hlsl_avi_final_texture; // HLSL AVI upscaled texture + bool hlsl_render_snap; // whether or not to take HLSL post-render snapshot + bool hlsl_snap_rendered; // whether we just rendered our HLSL post-render shot or not + d3d_surface * hlsl_snap_copy_target; // HLSL snapshot destination surface in system memory + d3d_texture * hlsl_snap_copy_texture; // HLSL snapshot destination surface in system memory + d3d_surface * hlsl_snap_target; // HLSL snapshot upscaled surface + d3d_texture * hlsl_snap_texture; // HLSL snapshot upscaled texture + int hlsl_snap_width; // HLSL snapshot width + int hlsl_snap_height; // HLSL snapshot height + + // HLSL render targets + int target_use_count[9]; // Whether or not a target has been used yet + texture_info * target_in_use[9]; // Target texture that is currently in use + d3d_surface * last_hlsltarget[9]; // HLSL render target surface pointer for each screen's previous frame + d3d_texture * last_hlsltexture[9]; // HLSL render target texture pointer for each screen's previous frame + d3d_surface * hlslprescaletarget0[9]; // Direct3D render target surface pointer (prescale, if necessary) + d3d_surface * hlsltarget0[9]; // HLSL render target surface pointer (pass 0, if necessary) + d3d_surface * hlsltarget1[9]; // HLSL render target surface pointer (pass 1, if necessary) + d3d_surface * hlsltarget2[9]; // HLSL render target surface pointer (pass 2, if necessary) + d3d_surface * hlsltarget3[9]; // HLSL render target surface pointer (pass 3, if necessary) + d3d_surface * hlsltarget4[9]; // HLSL render target surface pointer (pass 4, if necessary) + d3d_surface * hlslsmalltarget0[9]; // HLSL render target surface pointer (small pass 0, if necessary) + d3d_texture * hlslprescaletexture0[9]; // HLSL render target surface pointer (prescale, if necessary) + d3d_texture * hlsltexture0[9]; // HLSL render target texture pointer (pass 0, if necessary) + d3d_texture * hlsltexture1[9]; // HLSL render target texture pointer (pass 1, if necessary) + d3d_texture * hlsltexture2[9]; // HLSL render target texture pointer (pass 2, if necessary) + d3d_texture * hlsltexture3[9]; // HLSL render target texture pointer (pass 3, if necessary) + d3d_texture * hlsltexture4[9]; // HLSL render target texture pointer (pass 4, if necessary) + d3d_texture * hlslsmalltexture0[9]; // HLSL render target texture pointer (small pass 0, if necessary) }; @@ -422,6 +536,11 @@ static INT32 slider_scanline_scale(running_machine &machine, void *arg, astring return slider_set(&(((d3d_info*)arg)->hlsl_options->screen_scanline_scale), 0.05f, "%2.2f", string, newval); } +static INT32 slider_scanline_height(running_machine &machine, void *arg, astring *string, INT32 newval) +{ + return slider_set(&(((d3d_info*)arg)->hlsl_options->screen_scanline_height), 0.05f, "%2.2f", string, newval); +} + static INT32 slider_scanline_bright_scale(running_machine &machine, void *arg, astring *string, INT32 newval) { return slider_set(&(((d3d_info*)arg)->hlsl_options->screen_scanline_bright_scale), 0.05f, "%2.2f", string, newval); @@ -656,7 +775,8 @@ static slider_state *init_slider_list(d3d_info *d3d) *tailptr = slider_alloc(d3d->window->machine(), "Screen Curvature", 0, 0, 100, 1, slider_curvature, (void*)d3d); tailptr = &(*tailptr)->next; *tailptr = slider_alloc(d3d->window->machine(), "Image Pincushion", 0, 0, 100, 1, slider_pincushion, (void*)d3d); tailptr = &(*tailptr)->next; *tailptr = slider_alloc(d3d->window->machine(), "Scanline Darkness", 0, 0, 100, 1, slider_scanline_alpha, (void*)d3d); tailptr = &(*tailptr)->next; - *tailptr = slider_alloc(d3d->window->machine(), "Scanline Size", 1, 20, 80, 1, slider_scanline_scale, (void*)d3d); tailptr = &(*tailptr)->next; + *tailptr = slider_alloc(d3d->window->machine(), "Scanline Screen Height", 1, 20, 80, 1, slider_scanline_scale, (void*)d3d); tailptr = &(*tailptr)->next; + *tailptr = slider_alloc(d3d->window->machine(), "Scanline Indiv. Height", 1, 10, 80, 1, slider_scanline_height, (void*)d3d); tailptr = &(*tailptr)->next; *tailptr = slider_alloc(d3d->window->machine(), "Scanline Brightness", 0, 20, 40, 1, slider_scanline_bright_scale, (void*)d3d); tailptr = &(*tailptr)->next; *tailptr = slider_alloc(d3d->window->machine(), "Scanline Brightness Overdrive", 0, 12, 20, 1, slider_scanline_bright_offset, (void*)d3d); tailptr = &(*tailptr)->next; *tailptr = slider_alloc(d3d->window->machine(), "Scanline Jitter", 0, 0, 40, 1, slider_scanline_offset, (void*)d3d); tailptr = &(*tailptr)->next; @@ -939,6 +1059,8 @@ static void drawd3d_exit(void); static int drawd3d_window_init(win_window_info *window); static void drawd3d_window_destroy(win_window_info *window); static render_primitive_list *drawd3d_window_get_primitives(win_window_info *window); +static void drawd3d_window_save(win_window_info *window); +static void drawd3d_window_record(win_window_info *window); static int drawd3d_window_draw(win_window_info *window, HDC dc, int update); // devices @@ -972,6 +1094,12 @@ static void texture_prescale(d3d_info *d3d, texture_info *texture); static texture_info *texture_find(d3d_info *d3d, const render_primitive *prim); static void texture_update(d3d_info *d3d, const render_primitive *prim); +// logging +static void end_hlsl_avi_recording(d3d_info *d3d); +static void hlsl_render_snapshot(d3d_info *d3d, d3d_surface *surface); +static void begin_hlsl_avi_recording(d3d_info *d3d, const char *name); +static void hlsl_record_texture(d3d_info *d3d, d3d_surface *surface); +static file_error open_next(d3d_info *d3d, emu_file &file, const char *extension, int idx); //============================================================ @@ -1005,6 +1133,8 @@ int drawd3d_init(running_machine &machine, win_draw_callbacks *callbacks) callbacks->window_init = drawd3d_window_init; callbacks->window_get_primitives = drawd3d_window_get_primitives; callbacks->window_draw = drawd3d_window_draw; + callbacks->window_save = drawd3d_window_save; + callbacks->window_record = drawd3d_window_record; callbacks->window_destroy = drawd3d_window_destroy; return 0; } @@ -1035,6 +1165,7 @@ static int drawd3d_window_init(win_window_info *window) d3d = global_alloc_clear(d3d_info); window->drawdata = d3d; d3d->window = window; + d3d->hlsl_options = NULL; // experimental: load a PNG to use for vector rendering; it is treated // as a brightness map @@ -1069,6 +1200,61 @@ error: +//============================================================ +// drawd3d_window_save +//============================================================ + +static void drawd3d_window_save(win_window_info *window) +{ + d3d_info *d3d = (d3d_info *)window->drawdata; + + if (!d3d->hlsl_enable || !d3dintf->post_fx_available) + return; + + HRESULT result = (*d3dintf->device.create_texture)(d3d->device, d3d->hlsl_snap_width, d3d->hlsl_snap_height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &d3d->hlsl_snap_copy_texture); + if (result != D3D_OK) + { + mame_printf_verbose("Direct3D: Unable to init system-memory target for HLSL snapshot (%08x), bailing\n", (UINT32)result); + return; + } + (*d3dintf->texture.get_surface_level)(d3d->hlsl_snap_copy_texture, 0, &d3d->hlsl_snap_copy_target); + + result = (*d3dintf->device.create_texture)(d3d->device, d3d->hlsl_snap_width, d3d->hlsl_snap_height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlsl_snap_texture); + if (result != D3D_OK) + { + mame_printf_verbose("Direct3D: Unable to init video-memory target for HLSL snapshot (%08x), bailing\n", (UINT32)result); + return; + } + (*d3dintf->texture.get_surface_level)(d3d->hlsl_snap_texture, 0, &d3d->hlsl_snap_target); + + d3d->hlsl_render_snap = true; + d3d->hlsl_snap_rendered = false; +} + +static void drawd3d_window_record(win_window_info *window) +{ + d3d_info *d3d = (d3d_info *)window->drawdata; + + if (!d3d->hlsl_enable || !d3dintf->post_fx_available) + return; + + windows_options &options = downcast(window->machine().options()); + const char *filename = options.d3d_hlsl_write(); + + if(d3d->hlsl_avi_file != NULL) + { + end_hlsl_avi_recording(d3d); + } + else + { + if (filename[0] != 0) + { + begin_hlsl_avi_recording(d3d, filename); + } + } +} + + //============================================================ // drawd3d_window_destroy //============================================================ @@ -1077,6 +1263,8 @@ static void drawd3d_window_destroy(win_window_info *window) { d3d_info *d3d = (d3d_info *)window->drawdata; + end_hlsl_avi_recording(d3d); + // skip if nothing if (d3d == NULL) return; @@ -1164,6 +1352,8 @@ mtlog_add("drawd3d_window_draw: begin"); result = (*d3dintf->device.clear)(d3d->device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result); + hlsl_record_texture(d3d, d3d->hlsl_avi_final_target); + // first update any textures window->primlist->acquire_lock(); for (prim = window->primlist->first(); prim != NULL; prim = prim->next()) @@ -1218,6 +1408,11 @@ mtlog_add("drawd3d_window_draw: present begin"); mtlog_add("drawd3d_window_draw: present end"); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device present call\n", (int)result); + if(d3d->hlsl_render_snap && d3d->hlsl_snap_rendered) + { + hlsl_render_snapshot(d3d, d3d->hlsl_snap_target); + } + return 0; } @@ -1326,6 +1521,11 @@ try_again: d3d->create_error_count = 0; mame_printf_verbose("Direct3D: Device created at %dx%d\n", d3d->width, d3d->height); + d3d->oversample_x = downcast(d3d->window->machine().options()).screen_oversample_x(); + d3d->oversample_y = downcast(d3d->window->machine().options()).screen_oversample_y(); + d3d->hlsl_snap_width = downcast(d3d->window->machine().options()).d3d_snap_width(); + d3d->hlsl_snap_height = downcast(d3d->window->machine().options()).d3d_snap_height(); + // set the max texture size window->target->set_max_texture_size(d3d->texture_max_width, d3d->texture_max_height); mame_printf_verbose("Direct3D: Max texture size = %dx%d\n", (int)d3d->texture_max_width, (int)d3d->texture_max_height); @@ -1362,6 +1562,7 @@ try_again: const char *fx_dir = downcast(window->machine().options()).screen_post_fx_dir(); char primary_name_cstr[1024]; char post_name_cstr[1024]; + char prescale_name_cstr[1024]; char pincushion_name_cstr[1024]; char phosphor_name_cstr[1024]; char focus_name_cstr[1024]; @@ -1376,6 +1577,9 @@ try_again: sprintf(post_name_cstr, "%s\\post.fx", fx_dir); TCHAR *post_name = tstring_from_utf8(post_name_cstr); + sprintf(prescale_name_cstr, "%s\\prescale.fx", fx_dir); + TCHAR *prescale_name = tstring_from_utf8(prescale_name_cstr); + sprintf(pincushion_name_cstr, "%s\\pincushion.fx", fx_dir); TCHAR *pincushion_name = tstring_from_utf8(pincushion_name_cstr); @@ -1401,7 +1605,7 @@ try_again: result = (*d3dintf->device.create_effect)(d3d->device, primary_name, &d3d->effect); if(result != D3D_OK) { - mame_printf_verbose("Direct3D: Unable to load primary.fx\n"); + printf("Direct3D: Unable to load primary.fx\n"); return 1; } @@ -1409,7 +1613,15 @@ try_again: result = (*d3dintf->device.create_effect)(d3d->device, post_name, &d3d->post_effect); if(result != D3D_OK) { - mame_printf_verbose("Direct3D: Unable to load post.fx\n"); + printf("Direct3D: Unable to load post.fx\n"); + return 1; + } + + // create the prescaling shader + result = (*d3dintf->device.create_effect)(d3d->device, prescale_name, &d3d->prescale_effect); + if(result != D3D_OK) + { + printf("Direct3D: Unable to load prescale.fx\n"); return 1; } @@ -1417,7 +1629,7 @@ try_again: result = (*d3dintf->device.create_effect)(d3d->device, pincushion_name, &d3d->pincushion_effect); if(result != D3D_OK) { - mame_printf_verbose("Direct3D: Unable to load pincushion.fx\n"); + printf("Direct3D: Unable to load pincushion.fx\n"); return 1; } @@ -1425,7 +1637,7 @@ try_again: result = (*d3dintf->device.create_effect)(d3d->device, phosphor_name, &d3d->phosphor_effect); if(result != D3D_OK) { - mame_printf_verbose("Direct3D: Unable to load phosphor.fx\n"); + printf("Direct3D: Unable to load phosphor.fx\n"); return 1; } @@ -1433,7 +1645,7 @@ try_again: result = (*d3dintf->device.create_effect)(d3d->device, focus_name, &d3d->focus_effect); if(result != D3D_OK) { - mame_printf_verbose("Direct3D: Unable to load focus.fx\n"); + printf("Direct3D: Unable to load focus.fx\n"); return 1; } @@ -1441,7 +1653,7 @@ try_again: result = (*d3dintf->device.create_effect)(d3d->device, deconverge_name, &d3d->deconverge_effect); if(result != D3D_OK) { - mame_printf_verbose("Direct3D: Unable to load deconverge.fx\n"); + printf("Direct3D: Unable to load deconverge.fx\n"); return 1; } @@ -1449,7 +1661,7 @@ try_again: result = (*d3dintf->device.create_effect)(d3d->device, color_name, &d3d->color_effect); if(result != D3D_OK) { - mame_printf_verbose("Direct3D: Unable to load color.fx\n"); + printf("Direct3D: Unable to load color.fx\n"); return 1; } @@ -1457,7 +1669,7 @@ try_again: result = (*d3dintf->device.create_effect)(d3d->device, yiq_encode_name, &d3d->yiq_encode_effect); if(result != D3D_OK) { - mame_printf_verbose("Direct3D: Unable to load yiq_encode.fx\n"); + printf("Direct3D: Unable to load yiq_encode.fx\n"); return 1; } @@ -1465,7 +1677,7 @@ try_again: result = (*d3dintf->device.create_effect)(d3d->device, yiq_decode_name, &d3d->yiq_decode_effect); if(result != D3D_OK) { - mame_printf_verbose("Direct3D: Unable to load yiq_decode.fx\n"); + printf("Direct3D: Unable to load yiq_decode.fx\n"); return 1; } @@ -1473,6 +1685,8 @@ try_again: osd_free(primary_name); if (post_name) osd_free(post_name); + if (prescale_name) + osd_free(prescale_name); if (pincushion_name) osd_free(pincushion_name); if (phosphor_name) @@ -1590,6 +1804,22 @@ static int device_create_resources(d3d_info *d3d) // experimental: initialize some more things if we're using HLSL if(d3d->hlsl_enable && d3dintf->post_fx_available) { + result = (*d3dintf->device.create_texture)(d3d->device, (int)(d3d->width * d3d->oversample_x), (int)(d3d->height * d3d->oversample_y), 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &d3d->hlsl_avi_copy_texture); + if (result != D3D_OK) + { + mame_printf_verbose("Direct3D: Unable to init system-memory target for HLSL AVI dumping (%08x)\n", (UINT32)result); + return 1; + } + (*d3dintf->texture.get_surface_level)(d3d->hlsl_avi_copy_texture, 0, &d3d->hlsl_avi_copy_surface); + + result = (*d3dintf->device.create_texture)(d3d->device, (int)(d3d->width * d3d->oversample_x), (int)(d3d->height * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlsl_avi_final_texture); + if (result != D3D_OK) + { + mame_printf_verbose("Direct3D: Unable to init video-memory target for HLSL AVI dumping (%08x)\n", (UINT32)result); + return 1; + } + (*d3dintf->texture.get_surface_level)(d3d->hlsl_avi_final_texture, 0, &d3d->hlsl_avi_final_target); + windows_options &options = downcast(d3d->window->machine().options()); // experimental: load a PNG to use for vector rendering; it is treated @@ -1615,57 +1845,66 @@ static int device_create_resources(d3d_info *d3d) } d3d->hlsl_options = (d3d_options*)global_alloc_clear(d3d_options); - d3d->hlsl_options->screen_shadow_mask_alpha = options.screen_shadow_mask_alpha(); - d3d->hlsl_options->screen_shadow_mask_count_x = options.screen_shadow_mask_count_x(); - d3d->hlsl_options->screen_shadow_mask_count_y = options.screen_shadow_mask_count_y(); - d3d->hlsl_options->screen_shadow_mask_u_size = options.screen_shadow_mask_u_size(); - d3d->hlsl_options->screen_shadow_mask_v_size = options.screen_shadow_mask_v_size(); - d3d->hlsl_options->screen_curvature = options.screen_curvature(); - d3d->hlsl_options->screen_pincushion = options.screen_pincushion(); - d3d->hlsl_options->screen_scanline_alpha = options.screen_scanline_amount(); - d3d->hlsl_options->screen_scanline_scale = options.screen_scanline_scale(); - d3d->hlsl_options->screen_scanline_bright_scale = options.screen_scanline_bright_scale(); - d3d->hlsl_options->screen_scanline_bright_offset = options.screen_scanline_bright_offset(); - d3d->hlsl_options->screen_scanline_offset = options.screen_scanline_offset(); - d3d->hlsl_options->screen_defocus_x = options.screen_defocus_x(); - d3d->hlsl_options->screen_defocus_y = options.screen_defocus_y(); - d3d->hlsl_options->screen_red_converge_x = options.screen_red_converge_x(); - d3d->hlsl_options->screen_red_converge_y = options.screen_red_converge_y(); - d3d->hlsl_options->screen_green_converge_x = options.screen_green_converge_x(); - d3d->hlsl_options->screen_green_converge_y = options.screen_green_converge_y(); - d3d->hlsl_options->screen_blue_converge_x = options.screen_blue_converge_x(); - d3d->hlsl_options->screen_blue_converge_y = options.screen_blue_converge_y(); - d3d->hlsl_options->screen_red_radial_converge_x = options.screen_red_radial_converge_x(); - d3d->hlsl_options->screen_red_radial_converge_y = options.screen_red_radial_converge_y(); - d3d->hlsl_options->screen_green_radial_converge_x = options.screen_green_radial_converge_x(); - d3d->hlsl_options->screen_green_radial_converge_y = options.screen_green_radial_converge_y(); - d3d->hlsl_options->screen_blue_radial_converge_x = options.screen_blue_radial_converge_x(); - d3d->hlsl_options->screen_blue_radial_converge_y = options.screen_blue_radial_converge_y(); - d3d->hlsl_options->screen_red_from_red = options.screen_red_from_red(); - d3d->hlsl_options->screen_red_from_green = options.screen_red_from_green(); - d3d->hlsl_options->screen_red_from_blue = options.screen_red_from_blue(); - d3d->hlsl_options->screen_green_from_red = options.screen_green_from_red(); - d3d->hlsl_options->screen_green_from_green = options.screen_green_from_green(); - d3d->hlsl_options->screen_green_from_blue = options.screen_green_from_blue(); - d3d->hlsl_options->screen_blue_from_red = options.screen_blue_from_red(); - d3d->hlsl_options->screen_blue_from_green = options.screen_blue_from_green(); - d3d->hlsl_options->screen_blue_from_blue = options.screen_blue_from_blue(); - d3d->hlsl_options->screen_red_offset = options.screen_red_offset(); - d3d->hlsl_options->screen_green_offset = options.screen_green_offset(); - d3d->hlsl_options->screen_blue_offset = options.screen_blue_offset(); - d3d->hlsl_options->screen_red_scale = options.screen_red_scale(); - d3d->hlsl_options->screen_green_scale = options.screen_green_scale(); - d3d->hlsl_options->screen_blue_scale = options.screen_blue_scale(); - d3d->hlsl_options->screen_red_power = options.screen_red_power(); - d3d->hlsl_options->screen_green_power = options.screen_green_power(); - d3d->hlsl_options->screen_blue_power = options.screen_blue_power(); - d3d->hlsl_options->screen_red_floor = options.screen_red_floor(); - d3d->hlsl_options->screen_green_floor = options.screen_green_floor(); - d3d->hlsl_options->screen_blue_floor = options.screen_blue_floor(); - d3d->hlsl_options->screen_red_phosphor_life = options.screen_red_phosphor(); - d3d->hlsl_options->screen_green_phosphor_life = options.screen_green_phosphor(); - d3d->hlsl_options->screen_blue_phosphor_life = options.screen_blue_phosphor(); - d3d->hlsl_options->screen_saturation = options.screen_saturation(); + + if(d3d->hlsl_preset == -1) + { + d3d->hlsl_options->screen_shadow_mask_alpha = options.screen_shadow_mask_alpha(); + d3d->hlsl_options->screen_shadow_mask_count_x = options.screen_shadow_mask_count_x(); + d3d->hlsl_options->screen_shadow_mask_count_y = options.screen_shadow_mask_count_y(); + d3d->hlsl_options->screen_shadow_mask_u_size = options.screen_shadow_mask_u_size(); + d3d->hlsl_options->screen_shadow_mask_v_size = options.screen_shadow_mask_v_size(); + d3d->hlsl_options->screen_curvature = options.screen_curvature(); + d3d->hlsl_options->screen_pincushion = options.screen_pincushion(); + d3d->hlsl_options->screen_scanline_alpha = options.screen_scanline_amount(); + d3d->hlsl_options->screen_scanline_scale = options.screen_scanline_scale(); + d3d->hlsl_options->screen_scanline_height = options.screen_scanline_height(); + d3d->hlsl_options->screen_scanline_bright_scale = options.screen_scanline_bright_scale(); + d3d->hlsl_options->screen_scanline_bright_offset = options.screen_scanline_bright_offset(); + d3d->hlsl_options->screen_scanline_offset = options.screen_scanline_offset(); + d3d->hlsl_options->screen_defocus_x = options.screen_defocus_x(); + d3d->hlsl_options->screen_defocus_y = options.screen_defocus_y(); + d3d->hlsl_options->screen_red_converge_x = options.screen_red_converge_x(); + d3d->hlsl_options->screen_red_converge_y = options.screen_red_converge_y(); + d3d->hlsl_options->screen_green_converge_x = options.screen_green_converge_x(); + d3d->hlsl_options->screen_green_converge_y = options.screen_green_converge_y(); + d3d->hlsl_options->screen_blue_converge_x = options.screen_blue_converge_x(); + d3d->hlsl_options->screen_blue_converge_y = options.screen_blue_converge_y(); + d3d->hlsl_options->screen_red_radial_converge_x = options.screen_red_radial_converge_x(); + d3d->hlsl_options->screen_red_radial_converge_y = options.screen_red_radial_converge_y(); + d3d->hlsl_options->screen_green_radial_converge_x = options.screen_green_radial_converge_x(); + d3d->hlsl_options->screen_green_radial_converge_y = options.screen_green_radial_converge_y(); + d3d->hlsl_options->screen_blue_radial_converge_x = options.screen_blue_radial_converge_x(); + d3d->hlsl_options->screen_blue_radial_converge_y = options.screen_blue_radial_converge_y(); + d3d->hlsl_options->screen_red_from_red = options.screen_red_from_red(); + d3d->hlsl_options->screen_red_from_green = options.screen_red_from_green(); + d3d->hlsl_options->screen_red_from_blue = options.screen_red_from_blue(); + d3d->hlsl_options->screen_green_from_red = options.screen_green_from_red(); + d3d->hlsl_options->screen_green_from_green = options.screen_green_from_green(); + d3d->hlsl_options->screen_green_from_blue = options.screen_green_from_blue(); + d3d->hlsl_options->screen_blue_from_red = options.screen_blue_from_red(); + d3d->hlsl_options->screen_blue_from_green = options.screen_blue_from_green(); + d3d->hlsl_options->screen_blue_from_blue = options.screen_blue_from_blue(); + d3d->hlsl_options->screen_red_offset = options.screen_red_offset(); + d3d->hlsl_options->screen_green_offset = options.screen_green_offset(); + d3d->hlsl_options->screen_blue_offset = options.screen_blue_offset(); + d3d->hlsl_options->screen_red_scale = options.screen_red_scale(); + d3d->hlsl_options->screen_green_scale = options.screen_green_scale(); + d3d->hlsl_options->screen_blue_scale = options.screen_blue_scale(); + d3d->hlsl_options->screen_red_power = options.screen_red_power(); + d3d->hlsl_options->screen_green_power = options.screen_green_power(); + d3d->hlsl_options->screen_blue_power = options.screen_blue_power(); + d3d->hlsl_options->screen_red_floor = options.screen_red_floor(); + d3d->hlsl_options->screen_green_floor = options.screen_green_floor(); + d3d->hlsl_options->screen_blue_floor = options.screen_blue_floor(); + d3d->hlsl_options->screen_red_phosphor_life = options.screen_red_phosphor(); + d3d->hlsl_options->screen_green_phosphor_life = options.screen_green_phosphor(); + d3d->hlsl_options->screen_blue_phosphor_life = options.screen_blue_phosphor(); + d3d->hlsl_options->screen_saturation = options.screen_saturation(); + } + else + { + d3d->hlsl_options = &g_d3d_hlsl_presets[d3d->hlsl_preset]; + } slider_list = init_slider_list(d3d); } @@ -1713,30 +1952,6 @@ static void device_delete_resources(d3d_info *d3d) (*d3dintf->texture.release)(tex->d3dtex); if (tex->d3dsurface != NULL) (*d3dintf->surface.release)(tex->d3dsurface); - if (tex->d3dtexture0 != NULL) - (*d3dintf->texture.release)(tex->d3dtexture0); - if (tex->d3dtexture1 != NULL) - (*d3dintf->texture.release)(tex->d3dtexture1); - if (tex->d3dtexture2 != NULL) - (*d3dintf->texture.release)(tex->d3dtexture2); - if (tex->d3dtexture3 != NULL) - (*d3dintf->texture.release)(tex->d3dtexture3); - if (tex->d3dtexture4 != NULL) - (*d3dintf->texture.release)(tex->d3dtexture4); - if (tex->d3dsmalltexture0 != NULL) - (*d3dintf->texture.release)(tex->d3dsmalltexture0); - if (tex->d3dtarget0 != NULL) - (*d3dintf->surface.release)(tex->d3dtarget0); - if (tex->d3dtarget1 != NULL) - (*d3dintf->surface.release)(tex->d3dtarget1); - if (tex->d3dtarget2 != NULL) - (*d3dintf->surface.release)(tex->d3dtarget2); - if (tex->d3dtarget3 != NULL) - (*d3dintf->surface.release)(tex->d3dtarget3); - if (tex->d3dtarget4 != NULL) - (*d3dintf->surface.release)(tex->d3dtarget4); - if (tex->d3dsmalltarget0 != NULL) - (*d3dintf->surface.release)(tex->d3dsmalltarget0); global_free(tex); } @@ -1758,6 +1973,11 @@ static void device_delete_resources(d3d_info *d3d) (*d3dintf->effect.release)(d3d->post_effect); d3d->post_effect = NULL; } + if(d3d->prescale_effect != NULL) + { + (*d3dintf->effect.release)(d3d->prescale_effect); + d3d->prescale_effect = NULL; + } if(d3d->pincushion_effect != NULL) { (*d3dintf->effect.release)(d3d->pincushion_effect); @@ -1796,16 +2016,110 @@ static void device_delete_resources(d3d_info *d3d) for(int index = 0; index < 9; index++) { - if(d3d->last_d3dtexture[index] != NULL) + if (d3d->hlslprescaletexture0[index] != NULL) { - (*d3dintf->texture.release)(d3d->last_d3dtexture[index]); - d3d->last_d3dtexture[index] = NULL; + (*d3dintf->texture.release)(d3d->hlslprescaletexture0[index]); + d3d->hlslprescaletexture0[index] = NULL; } - if(d3d->last_d3dtarget[index] != NULL) + if (d3d->hlsltexture0[index] != NULL) { - (*d3dintf->surface.release)(d3d->last_d3dtarget[index]); - d3d->last_d3dtarget[index] = NULL; + (*d3dintf->texture.release)(d3d->hlsltexture0[index]); + d3d->hlsltexture0[index] = NULL; } + if (d3d->hlsltexture1[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlsltexture1[index]); + d3d->hlsltexture1[index] = NULL; + } + if (d3d->hlsltexture2[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlsltexture2[index]); + d3d->hlsltexture2[index] = NULL; + } + if (d3d->hlsltexture3[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlsltexture3[index]); + d3d->hlsltexture3[index] = NULL; + } + if (d3d->hlsltexture4[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlsltexture4[index]); + d3d->hlsltexture4[index] = NULL; + } + if (d3d->hlslsmalltexture0[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlslsmalltexture0[index]); + d3d->hlslsmalltexture0[index] = NULL; + } + if (d3d->hlslprescaletarget0[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlslprescaletarget0[index]); + d3d->hlslprescaletarget0[index] = NULL; + } + if (d3d->hlsltarget0[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlsltarget0[index]); + d3d->hlsltarget0[index] = NULL; + } + if (d3d->hlsltarget1[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlsltarget1[index]); + d3d->hlsltarget1[index] = NULL; + } + if (d3d->hlsltarget2[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlsltarget2[index]); + d3d->hlsltarget2[index] = NULL; + } + if (d3d->hlsltarget3[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlsltarget3[index]); + d3d->hlsltarget3[index] = NULL; + } + if (d3d->hlsltarget4[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlsltarget4[index]); + d3d->hlsltarget4[index] = NULL; + } + if (d3d->hlslsmalltarget0[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlslsmalltarget0[index]); + d3d->hlslsmalltarget0[index] = NULL; + } + if(d3d->last_hlsltexture[index] != NULL) + { + (*d3dintf->texture.release)(d3d->last_hlsltexture[index]); + d3d->last_hlsltexture[index] = NULL; + } + if(d3d->last_hlsltarget[index] != NULL) + { + (*d3dintf->surface.release)(d3d->last_hlsltarget[index]); + d3d->last_hlsltarget[index] = NULL; + } + } + + if(d3d->hlsl_avi_copy_texture != NULL) + { + (*d3dintf->texture.release)(d3d->hlsl_avi_copy_texture); + d3d->hlsl_avi_copy_texture = NULL; + } + + if(d3d->hlsl_avi_copy_surface != NULL) + { + (*d3dintf->surface.release)(d3d->hlsl_avi_copy_surface); + d3d->hlsl_avi_copy_surface = NULL; + } + + if(d3d->hlsl_avi_final_texture != NULL) + { + (*d3dintf->texture.release)(d3d->hlsl_avi_final_texture); + d3d->hlsl_avi_final_texture = NULL; + } + + if(d3d->hlsl_avi_final_target != NULL) + { + (*d3dintf->surface.release)(d3d->hlsl_avi_final_target); + d3d->hlsl_avi_final_target = NULL; } if(d3d->hlsl_options != NULL) @@ -1846,6 +2160,10 @@ static int device_verify_caps(d3d_info *d3d, win_window_info *window) d3d->hlsl_enable = downcast(window->machine().options()).d3d_hlsl_enable() && d3dintf->post_fx_available; d3d->yiq_enable = downcast(window->machine().options()).screen_yiq_enable(); + d3d->hlsl_prescale = downcast(window->machine().options()).d3d_hlsl_prescale(); + d3d->hlsl_prescale_size = downcast(window->machine().options()).d3d_hlsl_prescale_size(); + d3d->hlsl_preset = downcast(window->machine().options()).d3d_hlsl_preset(); + result = (*d3dintf->d3d.get_caps_dword)(d3dintf, d3d->adapter, D3DDEVTYPE_HAL, CAPS_MAX_PS30_INSN_SLOTS, &tempcaps); if (result != D3D_OK) mame_printf_verbose("Direct3D Error %08X during get_caps_dword call\n", (int)result); if(tempcaps < 512 && d3d->hlsl_enable) @@ -2610,9 +2928,10 @@ static void primitive_flush_pending(d3d_info *d3d) vertnum = 0; } + bool screen_encountered[9] = { false }; + d3d_options *options = d3d->hlsl_options; - int cur_render_screen = 0; // now do the polys for (polynum = 0; polynum < d3d->numpolys; polynum++) { @@ -2625,6 +2944,9 @@ static void primitive_flush_pending(d3d_info *d3d) // set filtering if different if (poly->texture != NULL) { + screen_encountered[poly->texture->target_index] = true; + d3d->target_in_use[poly->texture->target_index] = poly->texture; + newfilter = FALSE; if (PRIMFLAG_GET_SCREENTEX(poly->flags)) newfilter = video_config.filter; @@ -2664,6 +2986,7 @@ static void primitive_flush_pending(d3d_info *d3d) (*d3dintf->effect.set_float)(curr_effect, "ShadowHeight", d3d->shadow_texture == NULL ? 1.0f : (float)d3d->shadow_texture->rawheight); (*d3dintf->effect.set_float)(curr_effect, "ScanlineAmount", options->screen_scanline_alpha); (*d3dintf->effect.set_float)(curr_effect, "ScanlineScale", options->screen_scanline_scale); + (*d3dintf->effect.set_float)(curr_effect, "ScanlineHeight", options->screen_scanline_height); (*d3dintf->effect.set_float)(curr_effect, "ScanlineBrightScale", options->screen_scanline_bright_scale); (*d3dintf->effect.set_float)(curr_effect, "ScanlineBrightOffset", options->screen_scanline_bright_offset); (*d3dintf->effect.set_float)(curr_effect, "ScanlineOffset", (poly->texture->cur_frame == 0) ? 0.0f : options->screen_scanline_offset); @@ -2688,6 +3011,8 @@ static void primitive_flush_pending(d3d_info *d3d) if(PRIMFLAG_GET_SCREENTEX(d3d->last_texture_flags) && poly->texture != NULL) { + d3d->target_use_count[poly->texture->target_index] = 60; + if(d3d->yiq_enable) { /* Convert our signal into YIQ */ @@ -2699,13 +3024,16 @@ static void primitive_flush_pending(d3d_info *d3d) (*d3dintf->effect.set_float)(curr_effect, "HeightRatio", 1.0f / (poly->texture->vstop - poly->texture->vstart)); (*d3dintf->effect.set_float)(curr_effect, "TargetWidth", (float)d3d->width); (*d3dintf->effect.set_float)(curr_effect, "TargetHeight", (float)d3d->height); - (*d3dintf->effect.set_float)(curr_effect, "WValue", winoptions.screen_yiq_w()); + (*d3dintf->effect.set_float)(curr_effect, "CCValue", winoptions.screen_yiq_cc()); (*d3dintf->effect.set_float)(curr_effect, "AValue", winoptions.screen_yiq_a()); - (*d3dintf->effect.set_float)(curr_effect, "BValue", (float)poly->texture->cur_frame * winoptions.screen_yiq_b()); - (*d3dintf->effect.set_float)(curr_effect, "FscScale", winoptions.screen_yiq_fsc_scale()); - (*d3dintf->effect.set_float)(curr_effect, "FscValue", winoptions.screen_yiq_fsc()); + (*d3dintf->effect.set_float)(curr_effect, "BValue", (poly->texture->cur_frame == 2) ? 0.0f : ((float)poly->texture->cur_frame * winoptions.screen_yiq_b())); + (*d3dintf->effect.set_float)(curr_effect, "PValue", winoptions.screen_yiq_p()); + (*d3dintf->effect.set_float)(curr_effect, "YFreqResponse", winoptions.screen_yiq_y()); + (*d3dintf->effect.set_float)(curr_effect, "IFreqResponse", winoptions.screen_yiq_i()); + (*d3dintf->effect.set_float)(curr_effect, "QFreqResponse", winoptions.screen_yiq_q()); + (*d3dintf->effect.set_float)(curr_effect, "ScanTime", winoptions.screen_yiq_scan_time()); - result = (*d3dintf->device.set_render_target)(d3d->device, 0, poly->texture->d3dtarget4); + result = (*d3dintf->device.set_render_target)(d3d->device, 0, d3d->hlsltarget4[poly->texture->target_index]); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); result = (*d3dintf->device.clear)(d3d->device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); @@ -2727,7 +3055,7 @@ static void primitive_flush_pending(d3d_info *d3d) /* Convert our signal from YIQ */ curr_effect = d3d->yiq_decode_effect; - (*d3dintf->effect.set_texture)(curr_effect, "Composite", poly->texture->d3dtexture4); + (*d3dintf->effect.set_texture)(curr_effect, "Composite", d3d->hlsltexture4[poly->texture->target_index]); (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", poly->texture->d3dfinaltex); (*d3dintf->effect.set_float)(curr_effect, "RawWidth", (float)poly->texture->rawwidth); (*d3dintf->effect.set_float)(curr_effect, "RawHeight", (float)poly->texture->rawheight); @@ -2735,12 +3063,17 @@ static void primitive_flush_pending(d3d_info *d3d) (*d3dintf->effect.set_float)(curr_effect, "HeightRatio", 1.0f / (poly->texture->vstop - poly->texture->vstart)); (*d3dintf->effect.set_float)(curr_effect, "TargetWidth", (float)d3d->width); (*d3dintf->effect.set_float)(curr_effect, "TargetHeight", (float)d3d->height); - (*d3dintf->effect.set_float)(curr_effect, "WValue", winoptions.screen_yiq_w()); + (*d3dintf->effect.set_float)(curr_effect, "CCValue", winoptions.screen_yiq_cc()); (*d3dintf->effect.set_float)(curr_effect, "AValue", winoptions.screen_yiq_a()); - (*d3dintf->effect.set_float)(curr_effect, "BValue", (float)poly->texture->cur_frame * winoptions.screen_yiq_b()); - (*d3dintf->effect.set_float)(curr_effect, "FscValue", winoptions.screen_yiq_fsc()); + (*d3dintf->effect.set_float)(curr_effect, "BValue", (poly->texture->cur_frame == 2) ? 0.0f : ((float)poly->texture->cur_frame * winoptions.screen_yiq_b())); + (*d3dintf->effect.set_float)(curr_effect, "OValue", winoptions.screen_yiq_o()); + (*d3dintf->effect.set_float)(curr_effect, "PValue", winoptions.screen_yiq_p()); + (*d3dintf->effect.set_float)(curr_effect, "YFreqResponse", winoptions.screen_yiq_y()); + (*d3dintf->effect.set_float)(curr_effect, "IFreqResponse", winoptions.screen_yiq_i()); + (*d3dintf->effect.set_float)(curr_effect, "QFreqResponse", winoptions.screen_yiq_q()); + (*d3dintf->effect.set_float)(curr_effect, "ScanTime", winoptions.screen_yiq_scan_time()); - result = (*d3dintf->device.set_render_target)(d3d->device, 0, poly->texture->d3dtarget3); + result = (*d3dintf->device.set_render_target)(d3d->device, 0, d3d->hlsltarget3[poly->texture->target_index]); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); result = (*d3dintf->device.clear)(d3d->device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); @@ -2761,7 +3094,7 @@ static void primitive_flush_pending(d3d_info *d3d) curr_effect = d3d->color_effect; - (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", poly->texture->d3dtexture3); + (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", d3d->hlsltexture3[poly->texture->target_index]); } curr_effect = d3d->color_effect; @@ -2797,7 +3130,7 @@ static void primitive_flush_pending(d3d_info *d3d) (*d3dintf->effect.set_float)(curr_effect, "BluFloor", options->screen_blue_floor); (*d3dintf->effect.set_float)(curr_effect, "Saturation", options->screen_saturation); - result = (*d3dintf->device.set_render_target)(d3d->device, 0, poly->texture->d3dsmalltarget0); + result = (*d3dintf->device.set_render_target)(d3d->device, 0, d3d->hlslsmalltarget0[poly->texture->target_index]); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); result = (*d3dintf->device.clear)(d3d->device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); @@ -2816,9 +3149,48 @@ static void primitive_flush_pending(d3d_info *d3d) (*d3dintf->effect.end)(curr_effect); + /* Pre-scaling pass (if enabled) */ + if(d3d->hlsl_prescale) + { + curr_effect = d3d->prescale_effect; + (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", d3d->hlslsmalltexture0[poly->texture->target_index]); + + (*d3dintf->effect.set_float)(curr_effect, "TargetWidth", (float)d3d->width); + (*d3dintf->effect.set_float)(curr_effect, "TargetHeight", (float)d3d->height); + (*d3dintf->effect.set_float)(curr_effect, "RawWidth", (float)poly->texture->rawwidth); + (*d3dintf->effect.set_float)(curr_effect, "RawHeight", (float)poly->texture->rawheight); + (*d3dintf->effect.set_float)(curr_effect, "WidthRatio", 1.0f / (poly->texture->ustop - poly->texture->ustart)); + (*d3dintf->effect.set_float)(curr_effect, "HeightRatio", 1.0f / (poly->texture->vstop - poly->texture->vstart)); + + (*d3dintf->effect.begin)(curr_effect, &num_passes, 0); + + result = (*d3dintf->device.set_render_target)(d3d->device, 0, d3d->hlslprescaletarget0[poly->texture->target_index]); + if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); + result = (*d3dintf->device.clear)(d3d->device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); + if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result); + + for (UINT pass = 0; pass < num_passes; pass++) + { + (*d3dintf->effect.begin_pass)(curr_effect, pass); + // add the primitives + result = (*d3dintf->device.draw_primitive)(d3d->device, poly->type, 0, poly->count); + if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device draw_primitive call\n", (int)result); + (*d3dintf->effect.end_pass)(curr_effect); + } + + (*d3dintf->effect.end)(curr_effect); + + curr_effect = d3d->deconverge_effect; + (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", d3d->hlslprescaletexture0[poly->texture->target_index]); + } + else + { + curr_effect = d3d->deconverge_effect; + (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", d3d->hlslsmalltexture0[poly->texture->target_index]); + } + /* Deconverge pass */ curr_effect = d3d->deconverge_effect; - (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", poly->texture->d3dsmalltexture0); (*d3dintf->effect.set_float)(curr_effect, "TargetWidth", (float)d3d->width); (*d3dintf->effect.set_float)(curr_effect, "TargetHeight", (float)d3d->height); @@ -2841,7 +3213,7 @@ static void primitive_flush_pending(d3d_info *d3d) (*d3dintf->effect.begin)(curr_effect, &num_passes, 0); - result = (*d3dintf->device.set_render_target)(d3d->device, 0, poly->texture->d3dtarget2); + result = (*d3dintf->device.set_render_target)(d3d->device, 0, d3d->hlsltarget2[poly->texture->target_index]); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call 6\n", (int)result); result = (*d3dintf->device.clear)(d3d->device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result); @@ -2865,7 +3237,7 @@ static void primitive_flush_pending(d3d_info *d3d) /* Defocus pass 1 */ curr_effect = d3d->focus_effect; - (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", poly->texture->d3dtexture2); + (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", d3d->hlsltexture2[poly->texture->target_index]); (*d3dintf->effect.set_float)(curr_effect, "TargetWidth", (float)d3d->width); (*d3dintf->effect.set_float)(curr_effect, "TargetHeight", (float)d3d->height); @@ -2879,7 +3251,7 @@ static void primitive_flush_pending(d3d_info *d3d) (*d3dintf->effect.begin)(curr_effect, &num_passes, 0); - result = (*d3dintf->device.set_render_target)(d3d->device, 0, poly->texture->d3dtarget0); + result = (*d3dintf->device.set_render_target)(d3d->device, 0, d3d->hlsltarget0[poly->texture->target_index]); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call 6\n", (int)result); result = (*d3dintf->device.clear)(d3d->device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result); @@ -2897,7 +3269,7 @@ static void primitive_flush_pending(d3d_info *d3d) /* Defocus pass 2 */ - (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", poly->texture->d3dtexture0); + (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", d3d->hlsltexture0[poly->texture->target_index]); (*d3dintf->effect.set_float)(curr_effect, "TargetWidth", (float)d3d->width); (*d3dintf->effect.set_float)(curr_effect, "TargetHeight", (float)d3d->height); @@ -2911,7 +3283,7 @@ static void primitive_flush_pending(d3d_info *d3d) (*d3dintf->effect.begin)(curr_effect, &num_passes, 0); - result = (*d3dintf->device.set_render_target)(d3d->device, 0, poly->texture->d3dtarget1); + result = (*d3dintf->device.set_render_target)(d3d->device, 0, d3d->hlsltarget1[poly->texture->target_index]); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call 7\n", (int)result); for (UINT pass = 0; pass < num_passes; pass++) @@ -2939,10 +3311,10 @@ static void primitive_flush_pending(d3d_info *d3d) (*d3dintf->effect.set_float)(curr_effect, "GreenPhosphor", options->screen_green_phosphor_life); (*d3dintf->effect.set_float)(curr_effect, "BluePhosphor", options->screen_blue_phosphor_life); - (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", focus_enable ? poly->texture->d3dtexture1 : poly->texture->d3dtexture2); - (*d3dintf->effect.set_texture)(curr_effect, "LastPass", d3d->last_d3dtexture[cur_render_screen]); + (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", focus_enable ? d3d->hlsltexture1[poly->texture->target_index] : d3d->hlsltexture2[poly->texture->target_index]); + (*d3dintf->effect.set_texture)(curr_effect, "LastPass", d3d->last_hlsltexture[poly->texture->target_index]); - result = (*d3dintf->device.set_render_target)(d3d->device, 0, poly->texture->d3dtarget0); + result = (*d3dintf->device.set_render_target)(d3d->device, 0, d3d->hlsltarget0[poly->texture->target_index]); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call 4\n", (int)result); result = (*d3dintf->device.clear)(d3d->device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result); @@ -2965,10 +3337,10 @@ static void primitive_flush_pending(d3d_info *d3d) (*d3dintf->effect.set_float)(curr_effect, "FixedAlpha", 1.0f); - (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", focus_enable ? poly->texture->d3dtexture1 : poly->texture->d3dtexture2); - (*d3dintf->effect.set_texture)(curr_effect, "LastPass", focus_enable ? poly->texture->d3dtexture1 : poly->texture->d3dtexture2); + (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", focus_enable ? d3d->hlsltexture1[poly->texture->target_index] : d3d->hlsltexture2[poly->texture->target_index]); + (*d3dintf->effect.set_texture)(curr_effect, "LastPass", focus_enable ? d3d->hlsltexture1[poly->texture->target_index] : d3d->hlsltexture2[poly->texture->target_index]); - result = (*d3dintf->device.set_render_target)(d3d->device, 0, d3d->last_d3dtarget[cur_render_screen++]); + result = (*d3dintf->device.set_render_target)(d3d->device, 0, d3d->last_hlsltarget[poly->texture->target_index]); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call 5\n", (int)result); result = (*d3dintf->device.clear)(d3d->device, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0); if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device clear call\n", (int)result); @@ -2986,13 +3358,62 @@ static void primitive_flush_pending(d3d_info *d3d) (*d3dintf->effect.end)(curr_effect); + /* Scanlines and shadow mask, at high res for AVI logging*/ + if(d3d->hlsl_avi_file != NULL) + { + curr_effect = d3d->post_effect; + + (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", d3d->hlsltexture0[poly->texture->target_index]); + + result = (*d3dintf->device.set_render_target)(d3d->device, 0, d3d->hlsl_avi_final_target); + if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); + + (*d3dintf->effect.begin)(curr_effect, &num_passes, 0); + + for (UINT pass = 0; pass < num_passes; pass++) + { + (*d3dintf->effect.begin_pass)(curr_effect, pass); + // add the primitives + result = (*d3dintf->device.draw_primitive)(d3d->device, poly->type, vertnum, poly->count); + if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device draw_primitive call\n", (int)result); + (*d3dintf->effect.end_pass)(curr_effect); + } + + (*d3dintf->effect.end)(curr_effect); + } + + if(d3d->hlsl_render_snap) + { + curr_effect = d3d->post_effect; + + (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", d3d->hlsltexture0[poly->texture->target_index]); + + result = (*d3dintf->device.set_render_target)(d3d->device, 0, d3d->hlsl_snap_target); + if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); + + (*d3dintf->effect.begin)(curr_effect, &num_passes, 0); + + for (UINT pass = 0; pass < num_passes; pass++) + { + (*d3dintf->effect.begin_pass)(curr_effect, pass); + // add the primitives + result = (*d3dintf->device.draw_primitive)(d3d->device, poly->type, vertnum, poly->count); + if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device draw_primitive call\n", (int)result); + (*d3dintf->effect.end_pass)(curr_effect); + } + + (*d3dintf->effect.end)(curr_effect); + + d3d->hlsl_snap_rendered = true; + } + /* Scanlines and shadow mask */ curr_effect = d3d->post_effect; - (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", poly->texture->d3dtexture0); + (*d3dintf->effect.set_texture)(curr_effect, "Diffuse", d3d->hlsltexture0[poly->texture->target_index]); result = (*d3dintf->device.set_render_target)(d3d->device, 0, backbuffer); - if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call 5\n", (int)result); + if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during device set_render_target call\n", (int)result); (*d3dintf->effect.begin)(curr_effect, &num_passes, 0); @@ -3053,12 +3474,428 @@ static void primitive_flush_pending(d3d_info *d3d) (*d3dintf->surface.release)(backbuffer); } + // Unregister any registered targets we didn't traverse in the past frame. A resolution change must + // have occurred. + for(int index = 0; index < 9 && d3d->hlsl_enable && d3dintf->post_fx_available; index++) + { + if(!screen_encountered[index] && d3d->hlslsmalltarget0[index] != NULL) + { + if(d3d->target_use_count[index] > 0) + { + d3d->target_use_count[index]--; + } + else + { + // free all textures + if(d3d->target_in_use[index] != NULL) + { + texture_info *tex = d3d->target_in_use[index]; + if(d3d->texlist == tex) + { + d3d->texlist = tex->next; + if(d3d->texlist != NULL) + { + d3d->texlist->prev = NULL; + } + } + else + { + if(tex->next != NULL) + { + tex->next->prev = tex->prev; + } + if(tex->prev != NULL) + { + tex->prev->next = tex->next; + } + } + + if (tex->d3dfinaltex != NULL) + (*d3dintf->texture.release)(tex->d3dfinaltex); + if (tex->d3dtex != NULL && tex->d3dtex != tex->d3dfinaltex) + (*d3dintf->texture.release)(tex->d3dtex); + if (tex->d3dsurface != NULL) + (*d3dintf->surface.release)(tex->d3dsurface); + global_free(tex); + } + + if (d3d->hlslprescaletexture0[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlslprescaletexture0[index]); + d3d->hlslprescaletexture0[index] = NULL; + } + if (d3d->hlsltexture0[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlsltexture0[index]); + d3d->hlsltexture0[index] = NULL; + } + if (d3d->hlsltexture1[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlsltexture1[index]); + d3d->hlsltexture1[index] = NULL; + } + if (d3d->hlsltexture2[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlsltexture2[index]); + d3d->hlsltexture2[index] = NULL; + } + if (d3d->hlsltexture3[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlsltexture3[index]); + d3d->hlsltexture3[index] = NULL; + } + if (d3d->hlsltexture4[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlsltexture4[index]); + d3d->hlsltexture4[index] = NULL; + } + if (d3d->hlslsmalltexture0[index] != NULL) + { + (*d3dintf->texture.release)(d3d->hlslsmalltexture0[index]); + d3d->hlslsmalltexture0[index] = NULL; + } + if (d3d->hlslprescaletarget0[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlslprescaletarget0[index]); + d3d->hlslprescaletarget0[index] = NULL; + } + if (d3d->hlsltarget0[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlsltarget0[index]); + d3d->hlsltarget0[index] = NULL; + } + if (d3d->hlsltarget1[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlsltarget1[index]); + d3d->hlsltarget1[index] = NULL; + } + if (d3d->hlsltarget2[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlsltarget2[index]); + d3d->hlsltarget2[index] = NULL; + } + if (d3d->hlsltarget3[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlsltarget3[index]); + d3d->hlsltarget3[index] = NULL; + } + if (d3d->hlsltarget4[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlsltarget4[index]); + d3d->hlsltarget4[index] = NULL; + } + if (d3d->hlslsmalltarget0[index] != NULL) + { + (*d3dintf->surface.release)(d3d->hlslsmalltarget0[index]); + d3d->hlslsmalltarget0[index] = NULL; + } + if(d3d->last_hlsltexture[index] != NULL) + { + (*d3dintf->texture.release)(d3d->last_hlsltexture[index]); + d3d->last_hlsltexture[index] = NULL; + } + if(d3d->last_hlsltarget[index] != NULL) + { + (*d3dintf->surface.release)(d3d->last_hlsltarget[index]); + d3d->last_hlsltarget[index] = NULL; + } + d3d->target_use_count[index] = 0; + } + } + } + // reset the vertex count d3d->numverts = 0; d3d->numpolys = 0; } +//============================================================ +// hlsl_avi_update_snap +//============================================================ + +static void hlsl_avi_update_snap(d3d_info *d3d, d3d_surface *surface) +{ + D3DLOCKED_RECT rect; + + // if we don't have a bitmap, or if it's not the right size, allocate a new one + if (d3d->hlsl_avi_snap == NULL || (int)((float)d3d->width * d3d->oversample_x) != d3d->hlsl_avi_snap->width || (int)((float)d3d->height * d3d->oversample_y) != d3d->hlsl_avi_snap->height) + { + if (d3d->hlsl_avi_snap != NULL) + { + auto_free(d3d->window->machine(), d3d->hlsl_avi_snap); + } + d3d->hlsl_avi_snap = auto_alloc(d3d->window->machine(), bitmap_t((int)((float)d3d->width * d3d->oversample_x), (int)((float)d3d->height * d3d->oversample_y), BITMAP_FORMAT_RGB32)); + } + + // copy the texture + HRESULT result = (*d3dintf->device.get_render_target_data)(d3d->device, surface, d3d->hlsl_avi_copy_surface); + if (result != D3D_OK) + { + printf("Couldn't copy (%08x)\n", (UINT32)result); + return; + } + + // lock the texture + result = (*d3dintf->surface.lock_rect)(d3d->hlsl_avi_copy_surface, &rect, NULL, D3DLOCK_DISCARD); + if (result != D3D_OK) + { + printf("Couldn't lock (%08x)\n", (UINT32)result); + return; + } + + // loop over Y + for (int srcy = 0; srcy < (int)((float)d3d->height * d3d->oversample_y); srcy++) + { + BYTE *src = (BYTE *)rect.pBits + srcy * rect.Pitch; + BYTE *dst = (BYTE *)d3d->hlsl_avi_snap->base + srcy * d3d->hlsl_avi_snap->rowpixels * 4; + + for(int x = 0; x < (int)((float)d3d->width * d3d->oversample_x); x++) + { + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + } + } + + // unlock + result = (*d3dintf->surface.unlock_rect)(d3d->hlsl_avi_copy_surface); + if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during texture unlock_rect call\n", (int)result); +} + + + +//============================================================ +// hlsl_render_snapshot +//============================================================ + +static void hlsl_render_snapshot(d3d_info *d3d, d3d_surface *surface) +{ + D3DLOCKED_RECT rect; + + d3d->hlsl_render_snap = false; + + // if we don't have a bitmap, or if it's not the right size, allocate a new one + if (d3d->hlsl_avi_snap == NULL || d3d->hlsl_snap_width != (d3d->hlsl_avi_snap->width / 2) || d3d->hlsl_snap_height != (d3d->hlsl_avi_snap->height / 2)) + { + if (d3d->hlsl_avi_snap != NULL) + { + auto_free(d3d->window->machine(), d3d->hlsl_avi_snap); + } + d3d->hlsl_avi_snap = auto_alloc(d3d->window->machine(), bitmap_t(d3d->hlsl_snap_width / 2, d3d->hlsl_snap_height / 2, BITMAP_FORMAT_RGB32)); + } + + // copy the texture + HRESULT result = (*d3dintf->device.get_render_target_data)(d3d->device, surface, d3d->hlsl_snap_copy_target); + if (result != D3D_OK) + { + printf("Couldn't copy (%08x)\n", (UINT32)result); + return; + } + + // lock the texture + result = (*d3dintf->surface.lock_rect)(d3d->hlsl_snap_copy_target, &rect, NULL, D3DLOCK_DISCARD); + if (result != D3D_OK) + { + printf("Couldn't lock (%08x)\n", (UINT32)result); + return; + } + + for(int cy = 0; cy < 2; cy++) + { + for(int cx = 0; cx < 2; cx++) + { + // loop over Y + for (int srcy = 0; srcy < d3d->hlsl_snap_height / 2; srcy++) + { + int toty = (srcy + cy * (d3d->hlsl_snap_height / 2)); + int totx = cx * (d3d->hlsl_snap_width / 2); + BYTE *src = (BYTE *)rect.pBits + toty * rect.Pitch + totx * 4; + BYTE *dst = (BYTE *)d3d->hlsl_avi_snap->base + srcy * d3d->hlsl_avi_snap->rowpixels * 4; + + for(int x = 0; x < d3d->hlsl_snap_width / 2; x++) + { + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + } + } + + int idx = cy * 2 + cx; + + emu_file file(d3d->window->machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); + file_error filerr = open_next(d3d, file, "png", idx); + if (filerr != FILERR_NONE) + return; + + // add two text entries describing the image + astring text1(APPNAME, " ", build_version); + astring text2(d3d->window->machine().system().manufacturer, " ", d3d->window->machine().system().description); + png_info pnginfo = { 0 }; + png_add_text(&pnginfo, "Software", text1); + png_add_text(&pnginfo, "System", text2); + + // now do the actual work + png_error error = png_write_bitmap(file, &pnginfo, d3d->hlsl_avi_snap, 1 << 24, NULL); + if (error != PNGERR_NONE) + mame_printf_error("Error generating PNG for HLSL snapshot: png_error = %d\n", error); + + // free any data allocated + png_free(&pnginfo); + } + } + + // unlock + result = (*d3dintf->surface.unlock_rect)(d3d->hlsl_snap_copy_target); + if (result != D3D_OK) mame_printf_verbose("Direct3D: Error %08X during texture unlock_rect call\n", (int)result); + + if(d3d->hlsl_snap_texture != NULL) + { + (*d3dintf->texture.release)(d3d->hlsl_snap_texture); + d3d->hlsl_snap_texture = NULL; + } + + if(d3d->hlsl_snap_target != NULL) + { + (*d3dintf->surface.release)(d3d->hlsl_snap_target); + d3d->hlsl_snap_target = NULL; + } + + if(d3d->hlsl_snap_copy_texture != NULL) + { + (*d3dintf->texture.release)(d3d->hlsl_snap_copy_texture); + d3d->hlsl_snap_copy_texture = NULL; + } + + if(d3d->hlsl_snap_copy_target != NULL) + { + (*d3dintf->surface.release)(d3d->hlsl_snap_copy_target); + d3d->hlsl_snap_copy_target = NULL; + } +} + + +//============================================================ +// hlsl_record_texture +//============================================================ + +static void hlsl_record_texture(d3d_info *d3d, d3d_surface *surface) +{ + // ignore if nothing to do + if (d3d->hlsl_avi_file == NULL || surface == NULL) + { + return; + } + + // get the current time + attotime curtime = d3d->window->machine().time(); + + hlsl_avi_update_snap(d3d, surface); + + // loop until we hit the right time + while (d3d->hlsl_avi_next_frame_time <= curtime) + { + // handle an AVI recording + // write the next frame + avi_error avierr = avi_append_video_frame_rgb32(d3d->hlsl_avi_file, d3d->hlsl_avi_snap); + if (avierr != AVIERR_NONE) + { + end_hlsl_avi_recording(d3d); + return; + } + + // advance time + d3d->hlsl_avi_next_frame_time += d3d->hlsl_avi_frame_period; + d3d->hlsl_avi_frame++; + } +} + + +//============================================================ +// end_hlsl_avi_recording +//============================================================ + +static void end_hlsl_avi_recording(d3d_info *d3d) +{ + if(d3d->hlsl_avi_file != NULL) + { + avi_close(d3d->hlsl_avi_file); + } + d3d->hlsl_avi_file = NULL; + d3d->hlsl_avi_frame = 0; +} + + +//============================================================ +// begin_hlsl_avi_recording +//============================================================ + +static void begin_hlsl_avi_recording(d3d_info *d3d, const char *name) +{ + // stop any existing recording + end_hlsl_avi_recording(d3d); + + // reset the state + d3d->hlsl_avi_frame = 0; + d3d->hlsl_avi_next_frame_time = d3d->window->machine().time(); + + // build up information about this new movie + avi_movie_info info; + info.video_format = 0; + info.video_timescale = 1000 * ((d3d->window->machine().primary_screen != NULL) ? ATTOSECONDS_TO_HZ(d3d->window->machine().primary_screen->frame_period().attoseconds) : screen_device::DEFAULT_FRAME_RATE); + info.video_sampletime = 1000; + info.video_numsamples = 0; + info.video_width = d3d->width * d3d->oversample_x; + info.video_height = d3d->height * d3d->oversample_y; + info.video_depth = 24; + + info.audio_format = 0; + info.audio_timescale = d3d->window->machine().sample_rate(); + info.audio_sampletime = 1; + info.audio_numsamples = 0; + info.audio_channels = 2; + info.audio_samplebits = 16; + info.audio_samplerate = d3d->window->machine().sample_rate(); + + // create a new temporary movie file + file_error filerr; + astring fullpath; + { + emu_file tempfile(d3d->window->machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); + if (name != NULL) + { + filerr = tempfile.open(name); + } + else + { + filerr = open_next(d3d, tempfile, "avi", 0); + } + + // compute the frame time + { + d3d->hlsl_avi_frame_period = attotime::from_seconds(1000) / info.video_timescale; + } + + // if we succeeded, make a copy of the name and create the real file over top + if (filerr == FILERR_NONE) + { + fullpath = tempfile.fullpath(); + } + } + + if (filerr == FILERR_NONE) + { + // create the file and free the string + avi_error avierr = avi_create(fullpath, &info, &d3d->hlsl_avi_file); + if (avierr != AVIERR_NONE) + { + mame_printf_error("Error creating AVI: %s\n", avi_error_string(avierr)); + } + } +} + //============================================================ // texture_create @@ -3082,9 +3919,6 @@ static texture_info *texture_create(d3d_info *d3d, const render_texinfo *texsour // compute the size texture_compute_size(d3d, texsource->width, texsource->height, texture); - d3d->oversample_x = downcast(d3d->window->machine().options()).screen_oversample_x(); - d3d->oversample_y = downcast(d3d->window->machine().options()).screen_oversample_y(); - // non-screen textures are easy if (!PRIMFLAG_GET_SCREENTEX(flags)) { @@ -3143,42 +3977,56 @@ static texture_info *texture_create(d3d_info *d3d, const render_texinfo *texsour if(d3d->hlsl_enable && d3dintf->post_fx_available) { - result = (*d3dintf->device.create_texture)(d3d->device, (int)(d3d->width * d3d->oversample_x), (int)(d3d->height * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture->d3dtexture0); + int idx = d3d->registered_targets; + + result = (*d3dintf->device.create_texture)(d3d->device, (int)(d3d->width * d3d->oversample_x), (int)(d3d->height * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlsltexture0[idx]); if (result != D3D_OK) goto error; - (*d3dintf->texture.get_surface_level)(texture->d3dtexture0, 0, &texture->d3dtarget0); + (*d3dintf->texture.get_surface_level)(d3d->hlsltexture0[idx], 0, &d3d->hlsltarget0[idx]); - result = (*d3dintf->device.create_texture)(d3d->device, (int)(d3d->width * d3d->oversample_x), (int)(d3d->height * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->last_d3dtexture[d3d->registered_targets]); + result = (*d3dintf->device.create_texture)(d3d->device, (int)(d3d->width * d3d->oversample_x), (int)(d3d->height * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->last_hlsltexture[idx]); if (result != D3D_OK) goto error; - (*d3dintf->texture.get_surface_level)(d3d->last_d3dtexture[d3d->registered_targets], 0, &d3d->last_d3dtarget[d3d->registered_targets]); + (*d3dintf->texture.get_surface_level)(d3d->last_hlsltexture[idx], 0, &d3d->last_hlsltarget[idx]); - result = (*d3dintf->device.create_texture)(d3d->device, (int)(d3d->width * d3d->oversample_x), (int)(d3d->height * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture->d3dtexture1); + result = (*d3dintf->device.create_texture)(d3d->device, (int)(d3d->width * d3d->oversample_x), (int)(d3d->height * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlsltexture1[idx]); if (result != D3D_OK) goto error; - (*d3dintf->texture.get_surface_level)(texture->d3dtexture1, 0, &texture->d3dtarget1); + (*d3dintf->texture.get_surface_level)(d3d->hlsltexture1[idx], 0, &d3d->hlsltarget1[idx]); - result = (*d3dintf->device.create_texture)(d3d->device, (int)(d3d->width * d3d->oversample_x), (int)(d3d->height * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture->d3dtexture2); + result = (*d3dintf->device.create_texture)(d3d->device, (int)(d3d->width * d3d->oversample_x), (int)(d3d->height * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlsltexture2[idx]); if (result != D3D_OK) goto error; - (*d3dintf->texture.get_surface_level)(texture->d3dtexture2, 0, &texture->d3dtarget2); + (*d3dintf->texture.get_surface_level)(d3d->hlsltexture2[idx], 0, &d3d->hlsltarget2[idx]); - result = (*d3dintf->device.create_texture)(d3d->device, texture->rawwidth, texture->rawheight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture->d3dtexture3); + result = (*d3dintf->device.create_texture)(d3d->device, texture->rawwidth, texture->rawheight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlsltexture3[idx]); if (result != D3D_OK) goto error; - (*d3dintf->texture.get_surface_level)(texture->d3dtexture3, 0, &texture->d3dtarget3); + (*d3dintf->texture.get_surface_level)(d3d->hlsltexture3[idx], 0, &d3d->hlsltarget3[idx]); - result = (*d3dintf->device.create_texture)(d3d->device, texture->rawwidth, texture->rawheight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture->d3dtexture4); + result = (*d3dintf->device.create_texture)(d3d->device, texture->rawwidth, texture->rawheight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlsltexture4[idx]); if (result != D3D_OK) goto error; - (*d3dintf->texture.get_surface_level)(texture->d3dtexture4, 0, &texture->d3dtarget4); + (*d3dintf->texture.get_surface_level)(d3d->hlsltexture4[idx], 0, &d3d->hlsltarget4[idx]); - result = (*d3dintf->device.create_texture)(d3d->device, texture->rawwidth, texture->rawheight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture->d3dsmalltexture0); + int scale = 1; + if(d3d->hlsl_prescale) scale = d3d->hlsl_prescale_size; + + result = (*d3dintf->device.create_texture)(d3d->device, texture->rawwidth * scale, texture->rawheight * scale, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlslsmalltexture0[idx]); if (result != D3D_OK) goto error; - (*d3dintf->texture.get_surface_level)(texture->d3dsmalltexture0, 0, &texture->d3dsmalltarget0); + (*d3dintf->texture.get_surface_level)(d3d->hlslsmalltexture0[idx], 0, &d3d->hlslsmalltarget0[idx]); + result = (*d3dintf->device.create_texture)(d3d->device, texture->rawwidth * scale, texture->rawheight * scale, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlslprescaletexture0[idx]); + if (result != D3D_OK) + goto error; + (*d3dintf->texture.get_surface_level)(d3d->hlslprescaletexture0[idx], 0, &d3d->hlslprescaletarget0[idx]); + + texture->target_index = d3d->registered_targets; + d3d->target_use_count[texture->target_index] = 60; + d3d->target_in_use[texture->target_index] = texture; d3d->registered_targets++; + d3d->registered_targets %= 9; } break; @@ -3221,41 +4069,56 @@ static texture_info *texture_create(d3d_info *d3d, const render_texinfo *texsour { if(d3d->hlsl_enable && d3dintf->post_fx_available) { - result = (*d3dintf->device.create_texture)(d3d->device, (int)(scwidth * d3d->oversample_x), (int)(scheight * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture->d3dtexture0); - if (result != D3D_OK) - goto error; - (*d3dintf->texture.get_surface_level)(texture->d3dtexture0, 0, &texture->d3dtarget0); + int idx = d3d->registered_targets; - result = (*d3dintf->device.create_texture)(d3d->device, (int)(scwidth * d3d->oversample_x), (int)(scheight * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->last_d3dtexture[d3d->registered_targets]); + result = (*d3dintf->device.create_texture)(d3d->device, (int)(scwidth * d3d->oversample_x), (int)(scheight * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlsltexture0[idx]); if (result != D3D_OK) goto error; - (*d3dintf->texture.get_surface_level)(d3d->last_d3dtexture[d3d->registered_targets], 0, &d3d->last_d3dtarget[d3d->registered_targets]); + (*d3dintf->texture.get_surface_level)(d3d->hlsltexture0[idx], 0, &d3d->hlsltarget0[idx]); + + result = (*d3dintf->device.create_texture)(d3d->device, (int)(scwidth * d3d->oversample_x), (int)(scheight * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->last_hlsltexture[idx]); + if (result != D3D_OK) + goto error; + (*d3dintf->texture.get_surface_level)(d3d->last_hlsltexture[idx], 0, &d3d->last_hlsltarget[idx]); + + result = (*d3dintf->device.create_texture)(d3d->device, (int)(scwidth * d3d->oversample_x), (int)(scheight * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlsltexture1[idx]); + if (result != D3D_OK) + goto error; + (*d3dintf->texture.get_surface_level)(d3d->hlsltexture1[idx], 0, &d3d->hlsltarget1[idx]); + + result = (*d3dintf->device.create_texture)(d3d->device, (int)(scwidth * d3d->oversample_x), (int)(scheight * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlsltexture2[idx]); + if (result != D3D_OK) + goto error; + (*d3dintf->texture.get_surface_level)(d3d->hlsltexture2[idx], 0, &d3d->hlsltarget2[idx]); + + result = (*d3dintf->device.create_texture)(d3d->device, (int)(scwidth * d3d->oversample_x), (int)(scheight * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlsltexture3[idx]); + if (result != D3D_OK) + goto error; + (*d3dintf->texture.get_surface_level)(d3d->hlsltexture3[idx], 0, &d3d->hlsltarget3[idx]); + + result = (*d3dintf->device.create_texture)(d3d->device, (int)(scwidth * d3d->oversample_x), (int)(scheight * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlsltexture4[idx]); + if (result != D3D_OK) + goto error; + (*d3dintf->texture.get_surface_level)(d3d->hlsltexture4[idx], 0, &d3d->hlsltarget4[idx]); + + int scale = 1; + if(d3d->hlsl_prescale) scale = d3d->hlsl_prescale_size; + + result = (*d3dintf->device.create_texture)(d3d->device, scwidth * scale, scheight * scale, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlslsmalltexture0[idx]); + if (result != D3D_OK) + goto error; + (*d3dintf->texture.get_surface_level)(d3d->hlslsmalltexture0[idx], 0, &d3d->hlslsmalltarget0[idx]); + + result = (*d3dintf->device.create_texture)(d3d->device, scwidth * scale, scheight * scale, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d->hlslprescaletexture0[idx]); + if (result != D3D_OK) + goto error; + (*d3dintf->texture.get_surface_level)(d3d->hlslprescaletexture0[idx], 0, &d3d->hlslprescaletarget0[idx]); + + texture->target_index = d3d->registered_targets; + d3d->target_use_count[texture->target_index] = 60; + d3d->target_in_use[texture->target_index] = texture; d3d->registered_targets++; - - result = (*d3dintf->device.create_texture)(d3d->device, (int)(scwidth * d3d->oversample_x), (int)(scheight * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture->d3dtexture1); - if (result != D3D_OK) - goto error; - (*d3dintf->texture.get_surface_level)(texture->d3dtexture1, 0, &texture->d3dtarget1); - - result = (*d3dintf->device.create_texture)(d3d->device, (int)(scwidth * d3d->oversample_x), (int)(scheight * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture->d3dtexture2); - if (result != D3D_OK) - goto error; - (*d3dintf->texture.get_surface_level)(texture->d3dtexture2, 0, &texture->d3dtarget2); - - result = (*d3dintf->device.create_texture)(d3d->device, (int)(scwidth * d3d->oversample_x), (int)(scheight * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture->d3dtexture3); - if (result != D3D_OK) - goto error; - (*d3dintf->texture.get_surface_level)(texture->d3dtexture3, 0, &texture->d3dtarget3); - - result = (*d3dintf->device.create_texture)(d3d->device, (int)(scwidth * d3d->oversample_x), (int)(scheight * d3d->oversample_y), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture->d3dtexture4); - if (result != D3D_OK) - goto error; - (*d3dintf->texture.get_surface_level)(texture->d3dtexture4, 0, &texture->d3dtarget4); - - result = (*d3dintf->device.create_texture)(d3d->device, scwidth, scheight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture->d3dsmalltexture0); - if (result != D3D_OK) - goto error; - (*d3dintf->texture.get_surface_level)(texture->d3dsmalltexture0, 0, &texture->d3dsmalltarget0); + d3d->registered_targets %= 9; } break; } @@ -3269,6 +4132,9 @@ static texture_info *texture_create(d3d_info *d3d, const render_texinfo *texsour texture_set_data(d3d, texture, texsource, flags); // add us to the texture list + if(d3d->texlist != NULL) + d3d->texlist->prev = texture; + texture->prev = NULL; texture->next = d3d->texlist; d3d->texlist = texture; return texture; @@ -4022,3 +4888,130 @@ static void texture_update(d3d_info *d3d, const render_primitive *prim) texture->texinfo.seqid = prim->texture.seqid; } } + + +// NOTE: The function below is taken directly from src/emu/video.c and should likely be moved into a global helper function. +//------------------------------------------------- +// open_next - open the next non-existing file of +// type filetype according to our numbering +// scheme +//------------------------------------------------- + +static file_error open_next(d3d_info *d3d, emu_file &file, const char *extension, int idx) +{ + UINT32 origflags = file.openflags(); + + // handle defaults + const char *snapname = d3d->window->machine().options().snap_name(); + + if (snapname == NULL || snapname[0] == 0) + snapname = "%g/%i"; + astring snapstr(snapname); + + // strip any extension in the provided name + int index = snapstr.rchr(0, '.'); + if (index != -1) + snapstr.substr(0, index); + + // handle %d in the template (for image devices) + astring snapdev("%d_"); + int pos = snapstr.find(0, snapdev); + + if (pos != -1) + { + // if more %d are found, revert to default and ignore them all + if (snapstr.find(pos + 3, snapdev) != -1) + snapstr.cpy("%g/%i"); + // else if there is a single %d, try to create the correct snapname + else + { + int name_found = 0; + + // find length of the device name + int end1 = snapstr.find(pos + 3, "/"); + int end2 = snapstr.find(pos + 3, "%"); + int end = -1; + + if ((end1 != -1) && (end2 != -1)) + end = MIN(end1, end2); + else if (end1 != -1) + end = end1; + else if (end2 != -1) + end = end2; + else + end = snapstr.len(); + + if (end - pos < 3) + fatalerror("Something very wrong is going on!!!"); + + // copy the device name to an astring + astring snapdevname; + snapdevname.cpysubstr(snapstr, pos + 3, end - pos - 3); + + // verify that there is such a device for this system + device_image_interface *image = NULL; + for (bool gotone = d3d->window->machine().devicelist().first(image); gotone; gotone = image->next(image)) + { + // get the device name + astring tempdevname(image->brief_instance_name()); + + if (snapdevname.cmp(tempdevname) == 0) + { + // verify that such a device has an image mounted + if (image->basename() != NULL) + { + astring filename(image->basename()); + + // strip extension + filename.substr(0, filename.rchr(0, '.')); + + // setup snapname and remove the %d_ + snapstr.replace(0, snapdevname, filename); + snapstr.del(pos, 3); + + name_found = 1; + } + } + } + + // or fallback to default + if (name_found == 0) + snapstr.cpy("%g/%i"); + } + } + + // add our own index + // add our own extension + snapstr.cat(".").cat(extension); + + // substitute path and gamename up front + snapstr.replace(0, "/", PATH_SEPARATOR); + snapstr.replace(0, "%g", d3d->window->machine().basename()); + + // determine if the template has an index; if not, we always use the same name + astring fname; + if (snapstr.find(0, "%i") == -1) + fname.cpy(snapstr); + + // otherwise, we scan for the next available filename + else + { + // try until we succeed + astring seqtext; + file.set_openflags(OPEN_FLAG_READ); + for (int seq = 0; ; seq++) + { + // build up the filename + fname.cpy(snapstr).replace(0, "%i", seqtext.format("%04d_%d", seq, idx).cstr()); + + // try to open the file; stop when we fail + file_error filerr = file.open(fname); + if (filerr != FILERR_NONE) + break; + } + } + + // create the final file + file.set_openflags(origflags); + return file.open(fname); +} diff --git a/src/osd/windows/drawdd.c b/src/osd/windows/drawdd.c index d1ea6e481d2..dfab66a6830 100644 --- a/src/osd/windows/drawdd.c +++ b/src/osd/windows/drawdd.c @@ -251,6 +251,8 @@ int drawdd_init(running_machine &machine, win_draw_callbacks *callbacks) callbacks->window_init = drawdd_window_init; callbacks->window_get_primitives = drawdd_window_get_primitives; callbacks->window_draw = drawdd_window_draw; + callbacks->window_save = NULL; + callbacks->window_record = NULL; callbacks->window_destroy = drawdd_window_destroy; mame_printf_verbose("DirectDraw: Using DirectDraw 7\n"); diff --git a/src/osd/windows/drawgdi.c b/src/osd/windows/drawgdi.c index 7a7d8cbf1b0..2be9b026684 100644 --- a/src/osd/windows/drawgdi.c +++ b/src/osd/windows/drawgdi.c @@ -94,6 +94,8 @@ int drawgdi_init(running_machine &machine, win_draw_callbacks *callbacks) callbacks->window_init = drawgdi_window_init; callbacks->window_get_primitives = drawgdi_window_get_primitives; callbacks->window_draw = drawgdi_window_draw; + callbacks->window_save = NULL; + callbacks->window_record = NULL; callbacks->window_destroy = drawgdi_window_destroy; return 0; } diff --git a/src/osd/windows/drawnone.c b/src/osd/windows/drawnone.c index 89c119052a4..c82740f84ac 100644 --- a/src/osd/windows/drawnone.c +++ b/src/osd/windows/drawnone.c @@ -75,6 +75,8 @@ int drawnone_init(running_machine &machine, win_draw_callbacks *callbacks) callbacks->window_init = drawnone_window_init; callbacks->window_get_primitives = drawnone_window_get_primitives; callbacks->window_draw = drawnone_window_draw; + callbacks->window_save = NULL; + callbacks->window_record = NULL; callbacks->window_destroy = drawnone_window_destroy; return 0; } diff --git a/src/osd/windows/input.c b/src/osd/windows/input.c index 0b315aeecd6..512f95e9b08 100644 --- a/src/osd/windows/input.c +++ b/src/osd/windows/input.c @@ -781,6 +781,20 @@ void windows_osd_interface::customize_input_type_list(simple_listname = "Toggle Fullscreen"; entry->defseq[SEQ_TYPE_STANDARD].set(KEYCODE_LALT, KEYCODE_ENTER); break; + + // alt-F12 for fullscreen snap + case IPT_OSD_2: + entry->token = "RENDER_SNAP"; + entry->name = "Take Rendered Snapshot"; + entry->defseq[SEQ_TYPE_STANDARD].set(KEYCODE_LALT, KEYCODE_F12); + break; + + // alt-F11 for fullscreen video + case IPT_OSD_3: + entry->token = "RENDER_AVI"; + entry->name = "Record Rendered Video"; + entry->defseq[SEQ_TYPE_STANDARD].set(KEYCODE_LALT, KEYCODE_F11); + break; } } diff --git a/src/osd/windows/video.c b/src/osd/windows/video.c index cbe434f0c20..68b2f022a49 100644 --- a/src/osd/windows/video.c +++ b/src/osd/windows/video.c @@ -364,6 +364,14 @@ static void check_osd_inputs(running_machine &machine) // check for toggling fullscreen mode if (ui_input_pressed(machine, IPT_OSD_1)) winwindow_toggle_full_screen(); + + // check for taking fullscreen snap + if (ui_input_pressed(machine, IPT_OSD_2)) + winwindow_take_snap(); + + // check for taking fullscreen video + if (ui_input_pressed(machine, IPT_OSD_3)) + winwindow_take_video(); } diff --git a/src/osd/windows/window.c b/src/osd/windows/window.c index d92ee5d05e5..2fbacb8b780 100644 --- a/src/osd/windows/window.c +++ b/src/osd/windows/window.c @@ -498,6 +498,52 @@ void winwindow_dispatch_message(running_machine &machine, MSG *message) +//============================================================ +// winwindow_take_snap +// (main thread) +//============================================================ + +void winwindow_take_snap(void) +{ + if (draw.window_record == NULL) + return; + + win_window_info *window; + + assert(GetCurrentThreadId() == main_threadid); + + // iterate over windows and request a snap + for (window = win_window_list; window != NULL; window = window->next) + { + (*draw.window_save)(window); + } +} + + + +//============================================================ +// winwindow_take_video +// (main thread) +//============================================================ + +void winwindow_take_video(void) +{ + if (draw.window_record == NULL) + return; + + win_window_info *window; + + assert(GetCurrentThreadId() == main_threadid); + + // iterate over windows and request a snap + for (window = win_window_list; window != NULL; window = window->next) + { + (*draw.window_record)(window); + } +} + + + //============================================================ // winwindow_toggle_full_screen // (main thread) diff --git a/src/osd/windows/window.h b/src/osd/windows/window.h index 13d76a6d54d..8b12c38f291 100644 --- a/src/osd/windows/window.h +++ b/src/osd/windows/window.h @@ -122,6 +122,8 @@ struct _win_draw_callbacks int (*window_init)(win_window_info *window); render_primitive_list *(*window_get_primitives)(win_window_info *window); int (*window_draw)(win_window_info *window, HDC dc, int update); + void (*window_save)(win_window_info *window); + void (*window_record)(win_window_info *window); void (*window_destroy)(win_window_info *window); }; @@ -155,6 +157,8 @@ LRESULT CALLBACK winwindow_video_window_proc(HWND wnd, UINT message, WPARAM wpar extern LRESULT CALLBACK winwindow_video_window_proc_ui(HWND wnd, UINT message, WPARAM wparam, LPARAM lparam); void winwindow_toggle_full_screen(void); +void winwindow_take_snap(void); +void winwindow_take_video(void); void winwindow_process_events_periodic(running_machine &machine); void winwindow_process_events(running_machine &machine, int ingame); diff --git a/src/osd/windows/winmain.c b/src/osd/windows/winmain.c index e78d1aa57d2..c1e75aa3d1a 100644 --- a/src/osd/windows/winmain.c +++ b/src/osd/windows/winmain.c @@ -328,9 +328,15 @@ const options_entry windows_options::s_option_entries[] = // post-processing options { NULL, NULL, OPTION_HEADER, "DIRECT3D POST-PROCESSING OPTIONS" }, - { WINOPTION_HLSL_ENABLE";hlsl", "0", OPTION_BOOLEAN, "enable HLSL post-processing (PS3.0 required)" }, - { WINOPTION_HLSLPATH, "hlsl", OPTION_STRING, "path to hlsl files" }, - { WINOPTION_SHADOW_MASK_ALPHA";fs_shadwa(0.0-1.0)", "0.0", OPTION_FLOAT, "shadow mask alpha-blend value (1.0 is fully blended, 0.0 is no mask)" }, + { WINOPTION_HLSL_ENABLE";hlsl", "0", OPTION_BOOLEAN, "enable HLSL post-processing (PS3.0 required)" }, + { WINOPTION_HLSLPATH, "hlsl", OPTION_STRING, "path to hlsl files" }, + { WINOPTION_HLSL_PRESCALE";hlsl_prescale", "0", OPTION_BOOLEAN, "enable HLSL scaling pre-pass (for 'x' filters)" }, + { WINOPTION_HLSL_PRESCALE_SIZE, "2", OPTION_INTEGER, "HLSL scaling pre-pass factor (usually 2 or 3)" }, + { WINOPTION_HLSL_PRESET";(-1-5)", "-1", OPTION_INTEGER, "HLSL preset to use (0-5)" }, + { WINOPTION_HLSL_WRITE, NULL, OPTION_STRING, "enable HLSL AVI writing (huge disk bandwidth suggested)" }, + { WINOPTION_HLSL_SNAP_WIDTH, "2048", OPTION_STRING, "HLSL upscaled-snapshot width" }, + { WINOPTION_HLSL_SNAP_HEIGHT, "1536", OPTION_STRING, "HLSL upscaled-snapshot height" }, + { WINOPTION_SHADOW_MASK_ALPHA";fs_shadwa(0.0-1.0)", "0.0", OPTION_FLOAT, "shadow mask alpha-blend value (1.0 is fully blended, 0.0 is no mask)" }, { WINOPTION_SHADOW_MASK_TEXTURE";fs_shadwt(0.0-1.0)", "aperture.png", OPTION_STRING, "shadow mask texture name" }, { WINOPTION_SHADOW_MASK_COUNT_X";fs_shadww", "640", OPTION_INTEGER, "shadow mask width, in phosphor dots" }, { WINOPTION_SHADOW_MASK_COUNT_Y";fs_shadwh", "480", OPTION_INTEGER, "shadow mask height, in phosphor dots" }, @@ -345,6 +351,7 @@ const options_entry windows_options::s_option_entries[] = { WINOPTION_PINCUSHION";fs_pin(0.0-4.0)", "0.0", OPTION_FLOAT, "pincushion amount" }, { WINOPTION_SCANLINE_AMOUNT";fs_scanam(0.0-4.0)", "0.0", OPTION_FLOAT, "overall alpha scaling value for scanlines" }, { WINOPTION_SCANLINE_SCALE";fs_scansc(0.0-4.0)", "1.0", OPTION_FLOAT, "overall height scaling value for scanlines" }, + { WINOPTION_SCANLINE_HEIGHT";fs_scanh(0.0-4.0)", "0.5", OPTION_FLOAT, "individual height scaling value for scanlines" }, { WINOPTION_SCANLINE_BRIGHT_SCALE";fs_scanbs(0.0-1.0)", "1.0", OPTION_FLOAT, "overall brightness scaling value for scanlines (multiplicative)" }, { WINOPTION_SCANLINE_BRIGHT_OFFSET";fs_scanbo(0.0-1.0)", "0.6", OPTION_FLOAT, "overall brightness offset value for scanlines (additive)" }, { WINOPTION_SCANLINE_OFFSET";fs_scanjt(0.0-4.0)", "0.0", OPTION_FLOAT, "overall interlace jitter scaling value for scanlines" }, @@ -396,12 +403,16 @@ const options_entry windows_options::s_option_entries[] = { WINOPTION_BLUE_PHOSPHOR";fs_grnpho(0.0-1.0)", "0.0", OPTION_FLOAT, "blue phosphorescence decay rate (0.0 is instant, 1.0 is forever)" }, /* NTSC simulation below this line */ { WINOPTION_YIQ_ENABLE";yiq", "0", OPTION_BOOLEAN, "enable YIQ-space HLSL post-processing" }, - { WINOPTION_YIQ_WVALUE";yiqw", "4.1187867", OPTION_FLOAT, "W value for YIQ signal processing" }, - { WINOPTION_YIQ_AVALUE";yiqa", "0.5", OPTION_FLOAT, "A value for YIQ signal processing" }, - { WINOPTION_YIQ_BVALUE";yiqb", "0.5", OPTION_FLOAT, "B value for YIQ signal processing" }, - { WINOPTION_YIQ_FSCVALUE";yiqfsc", "1.5", OPTION_FLOAT, "Fsc value for YIQ signal processing" }, - { WINOPTION_YIQ_FSCSCALE";yiqfscs", "1.0", OPTION_FLOAT, "Incoming Fsc scaling value for YIQ signal processing" }, - { WINOPTION_YIQ_PHASE_COUNT";yiqp", "2", OPTION_INTEGER, "Phase Count value for YIQ signal processing" }, + { WINOPTION_YIQ_CCVALUE";yiqcc", "3.59754545",OPTION_FLOAT, "Color Carrier frequency for NTSC signal processing" }, + { WINOPTION_YIQ_AVALUE";yiqa", "0.5", OPTION_FLOAT, "A value for NTSC signal processing" }, + { WINOPTION_YIQ_BVALUE";yiqb", "0.5", OPTION_FLOAT, "B value for NTSC signal processing" }, + { WINOPTION_YIQ_OVALUE";yiqo", "0.0", OPTION_FLOAT, "Outgoing Color Carrier phase offset for NTSC signal processing" }, + { WINOPTION_YIQ_PVALUE";yiqp", "1.0", OPTION_FLOAT, "Incoming Pixel Clock scaling value for NTSC signal processing" }, + { WINOPTION_YIQ_YVALUE";yiqy", "3.0", OPTION_FLOAT, "Y filter cutoff frequency for NTSC signal processing" }, + { WINOPTION_YIQ_IVALUE";yiqi", "1.2", OPTION_FLOAT, "I filter cutoff frequency for NTSC signal processing" }, + { WINOPTION_YIQ_QVALUE";yiqq", "0.6", OPTION_FLOAT, "Q filter cutoff frequency for NTSC signal processing" }, + { WINOPTION_YIQ_SCAN_TIME";yiqsc", "52.6", OPTION_FLOAT, "Horizontal scanline duration for NTSC signal processing (in usec)" }, + { WINOPTION_YIQ_PHASE_COUNT";yiqp", "2", OPTION_INTEGER, "Phase Count value for NTSC signal processing" }, // per-window options { NULL, NULL, OPTION_HEADER, "PER-WINDOW VIDEO OPTIONS" }, diff --git a/src/osd/windows/winmain.h b/src/osd/windows/winmain.h index 456f6e5c3fc..0040ff91c29 100644 --- a/src/osd/windows/winmain.h +++ b/src/osd/windows/winmain.h @@ -81,6 +81,12 @@ // core post-processing options #define WINOPTION_HLSL_ENABLE "hlsl_enable" #define WINOPTION_HLSLPATH "hlslpath" +#define WINOPTION_HLSL_PRESCALE "hlsl_prescale" +#define WINOPTION_HLSL_PRESCALE_SIZE "hlsl_prescale_size" +#define WINOPTION_HLSL_PRESET "hlsl_preset" +#define WINOPTION_HLSL_WRITE "hlsl_write" +#define WINOPTION_HLSL_SNAP_WIDTH "hlsl_snap_width" +#define WINOPTION_HLSL_SNAP_HEIGHT "hlsl_snap_height" #define WINOPTION_SHADOW_MASK_ALPHA "shadow_mask_alpha" #define WINOPTION_SHADOW_MASK_TEXTURE "shadow_mask_texture" #define WINOPTION_SHADOW_MASK_COUNT_X "shadow_mask_x_count" @@ -95,6 +101,7 @@ #define WINOPTION_OVERSAMPLE_Y "oversample_y" #define WINOPTION_SCANLINE_AMOUNT "scanline_alpha" #define WINOPTION_SCANLINE_SCALE "scanline_size" +#define WINOPTION_SCANLINE_HEIGHT "scanline_height" #define WINOPTION_SCANLINE_BRIGHT_SCALE "scanline_bright_scale" #define WINOPTION_SCANLINE_BRIGHT_OFFSET "scanline_bright_offset" #define WINOPTION_SCANLINE_OFFSET "scanline_jitter" @@ -138,11 +145,15 @@ #define WINOPTION_BLUE_PHOSPHOR "blue_phosphor_life" #define WINOPTION_SATURATION "saturation" #define WINOPTION_YIQ_ENABLE "yiq_enable" -#define WINOPTION_YIQ_WVALUE "yiq_w" +#define WINOPTION_YIQ_CCVALUE "yiq_cc" #define WINOPTION_YIQ_AVALUE "yiq_a" #define WINOPTION_YIQ_BVALUE "yiq_b" -#define WINOPTION_YIQ_FSCVALUE "yiq_fsc" -#define WINOPTION_YIQ_FSCSCALE "yiq_fsc_scale" +#define WINOPTION_YIQ_OVALUE "yiq_o" +#define WINOPTION_YIQ_PVALUE "yiq_p" +#define WINOPTION_YIQ_YVALUE "yiq_y" +#define WINOPTION_YIQ_IVALUE "yiq_i" +#define WINOPTION_YIQ_QVALUE "yiq_q" +#define WINOPTION_YIQ_SCAN_TIME "yiq_scan_time" #define WINOPTION_YIQ_PHASE_COUNT "yiq_phase_count" // per-window options @@ -210,16 +221,23 @@ public: // core post-processing options const char *screen_post_fx_dir() const { return value(WINOPTION_HLSLPATH); } bool d3d_hlsl_enable() const { return bool_value(WINOPTION_HLSL_ENABLE); } + const char *d3d_hlsl_write() const { return value(WINOPTION_HLSL_WRITE); } + bool d3d_hlsl_prescale() const { return bool_value(WINOPTION_HLSL_PRESCALE); } + int d3d_hlsl_prescale_size() const { return int_value(WINOPTION_HLSL_PRESCALE_SIZE); } + int d3d_hlsl_preset() const { return int_value(WINOPTION_HLSL_PRESET); } + int d3d_snap_width() const { return int_value(WINOPTION_HLSL_SNAP_WIDTH); } + int d3d_snap_height() const { return int_value(WINOPTION_HLSL_SNAP_HEIGHT); } float screen_shadow_mask_alpha() const { return float_value(WINOPTION_SHADOW_MASK_ALPHA); } const char *screen_shadow_mask_texture() const { return value(WINOPTION_SHADOW_MASK_TEXTURE); } - float screen_shadow_mask_count_x() const { return float_value(WINOPTION_SHADOW_MASK_COUNT_X); } - float screen_shadow_mask_count_y() const { return float_value(WINOPTION_SHADOW_MASK_COUNT_Y); } + int screen_shadow_mask_count_x() const { return int_value(WINOPTION_SHADOW_MASK_COUNT_X); } + int screen_shadow_mask_count_y() const { return int_value(WINOPTION_SHADOW_MASK_COUNT_Y); } float screen_shadow_mask_u_size() const { return float_value(WINOPTION_SHADOW_MASK_USIZE); } float screen_shadow_mask_v_size() const { return float_value(WINOPTION_SHADOW_MASK_VSIZE); } float screen_oversample_x() const { return float_value(WINOPTION_OVERSAMPLE_X); } float screen_oversample_y() const { return float_value(WINOPTION_OVERSAMPLE_Y); } float screen_scanline_amount() const { return float_value(WINOPTION_SCANLINE_AMOUNT); } float screen_scanline_scale() const { return float_value(WINOPTION_SCANLINE_SCALE); } + float screen_scanline_height() const { return float_value(WINOPTION_SCANLINE_HEIGHT); } float screen_scanline_bright_scale() const { return float_value(WINOPTION_SCANLINE_BRIGHT_SCALE); } float screen_scanline_bright_offset() const { return float_value(WINOPTION_SCANLINE_BRIGHT_OFFSET); } float screen_scanline_offset() const { return float_value(WINOPTION_SCANLINE_OFFSET); } @@ -251,11 +269,15 @@ public: float screen_blue_from_green() const { return float_value(WINOPTION_BLUE_MATRIX_G); } float screen_blue_from_blue() const { return float_value(WINOPTION_BLUE_MATRIX_B); } bool screen_yiq_enable() const { return bool_value(WINOPTION_YIQ_ENABLE); } - float screen_yiq_w() const { return float_value(WINOPTION_YIQ_WVALUE); } + float screen_yiq_cc() const { return float_value(WINOPTION_YIQ_CCVALUE); } float screen_yiq_a() const { return float_value(WINOPTION_YIQ_AVALUE); } float screen_yiq_b() const { return float_value(WINOPTION_YIQ_BVALUE); } - float screen_yiq_fsc() const { return float_value(WINOPTION_YIQ_FSCVALUE); } - float screen_yiq_fsc_scale() const { return float_value(WINOPTION_YIQ_FSCSCALE); } + float screen_yiq_o() const { return float_value(WINOPTION_YIQ_OVALUE); } + float screen_yiq_p() const { return float_value(WINOPTION_YIQ_PVALUE); } + float screen_yiq_y() const { return float_value(WINOPTION_YIQ_YVALUE); } + float screen_yiq_i() const { return float_value(WINOPTION_YIQ_IVALUE); } + float screen_yiq_q() const { return float_value(WINOPTION_YIQ_QVALUE); } + float screen_yiq_scan_time() const { return float_value(WINOPTION_YIQ_SCAN_TIME); } int screen_yiq_phase_count() const { return int_value(WINOPTION_YIQ_PHASE_COUNT); } float screen_red_offset() const { return float_value(WINOPTION_RED_OFFSET); } float screen_green_offset() const { return float_value(WINOPTION_GREEN_OFFSET); }