Replace D3D9 IGL impl with a D3D11 IGL impl

This commit is contained in:
CasualPokePlayer 2024-05-14 01:37:59 -07:00
parent 0122dec099
commit e293e02369
33 changed files with 1826 additions and 1290 deletions

View File

@ -1,23 +1,25 @@
void main_vertex void main_vertex
( (
float4 position : POSITION, float4 position : POSITION,
float2 tex : TEXCOORD0, float2 tex : TEXCOORD0,
uniform float4x4 modelViewProj, uniform float4x4 modelViewProj,
out float4 oPosition : POSITION, out float4 oPosition : POSITION,
out float2 oTexcoord : TEXCOORD0 out float2 oTex0 : TEXCOORD0,
out float oTex1 : TEXCOORD1
) )
{ {
oPosition = mul(modelViewProj, position); oPosition = mul(modelViewProj, position);
oTexcoord = tex; oTex0 = tex;
oTex1 = position.y;
} }
uniform float uIntensity; uniform float uIntensity;
float4 main_fragment (in float2 texcoord : TEXCOORD0, in float2 wpos : VPOS, uniform sampler2D s_p : TEXUNIT0) : COLOR float4 main_fragment (in float4 vpos : POSITION, in float2 tex0 : TEXCOORD0, in float tex1 : TEXCOORD1, uniform sampler2D s_p : TEXUNIT0) : COLOR
{ {
float4 temp = tex2D(s_p,texcoord); float4 temp = tex2D(s_p, tex0);
if(floor(wpos.y/2) != floor(wpos.y)/2) temp.rgb *= uIntensity; if (floor(tex1 / 2) != floor(tex1) / 2) temp.rgb *= uIntensity;
return temp; return temp;
} }

View File

@ -46,13 +46,14 @@ struct input
float2 video_size; float2 video_size;
float2 texture_size; float2 texture_size;
float2 output_size; float2 output_size;
float frame_count; float frame_count;
float frame_direction; float frame_direction;
float frame_rotation; float frame_rotation;
}; };
struct out_vertex { struct out_vertex
{
float2 texCoord : TEXCOORD0; float2 texCoord : TEXCOORD0;
float4 t1 : TEXCOORD1; float4 t1 : TEXCOORD1;
float4 t2 : TEXCOORD2; float4 t2 : TEXCOORD2;
@ -65,26 +66,29 @@ struct out_vertex {
}; };
/* VERTEX_SHADER */ /* VERTEX_SHADER */
out_vertex main_vertex void main_vertex
( (
float4 position : POSITION, float4 position : POSITION,
out float4 oPosition : POSITION,
float2 texCoord1 : TEXCOORD0, float2 texCoord1 : TEXCOORD0,
uniform float4x4 modelViewProj, uniform float4x4 modelViewProj,
uniform input IN uniform input IN,
out float4 oPosition : POSITION,
out out_vertex oVAR
) )
{ {
float2 ps = float2(1.0/IN.texture_size.x, 1.0/IN.texture_size.y); float2 ps = float2(1.0/IN.texture_size.x, 1.0/IN.texture_size.y);
float dx = ps.x; float dx = ps.x;
float dy = ps.y; float dy = ps.y;
oPosition = mul(modelViewProj, position); oPosition = mul(modelViewProj, position);
// This line fix a bug in ATI cards. // This line fix a bug in ATI cards.
float2 tex = texCoord1 + float2(0.0000001, 0.0000001); float2 tex = texCoord1 + float2(0.0000001, 0.0000001);
out_vertex OUT = { out_vertex OUT =
{
tex, tex,
float4(tex,tex) + float4( -dx, -dy, 0.0, -dy), float4(tex,tex) + float4( -dx, -dy, 0.0, -dy),
float4(tex,tex) + float4( dx, -dy, 2.0*dx, -dy), float4(tex,tex) + float4( dx, -dy, 2.0*dx, -dy),
@ -96,57 +100,54 @@ out_vertex main_vertex
tex + float2(2.0*dx, 2.0*dy) tex + float2(2.0*dx, 2.0*dy)
}; };
oVAR = OUT;
return OUT;
} }
float4 main_fragment(in out_vertex VAR, uniform sampler2D s_p : TEXUNIT0, uniform input IN) : COLOR float4 main_fragment(in float4 vpos : POSITION, in out_vertex VAR, uniform sampler2D s_p : TEXUNIT0, uniform input IN) : COLOR
{ {
float2 fp = frac(VAR.texCoord*IN.texture_size);
float2 fp = frac(VAR.texCoord*IN.texture_size); float3 c00 = tex2D(s_p, VAR.t1.xy).xyz;
float3 c00 = tex2D(s_p, VAR.t1.xy).xyz; float3 c01 = tex2D(s_p, VAR.t1.zw).xyz;
float3 c01 = tex2D(s_p, VAR.t1.zw).xyz; float3 c02 = tex2D(s_p, VAR.t2.xy).xyz;
float3 c02 = tex2D(s_p, VAR.t2.xy).xyz; float3 c03 = tex2D(s_p, VAR.t2.zw).xyz;
float3 c03 = tex2D(s_p, VAR.t2.zw).xyz; float3 c10 = tex2D(s_p, VAR.t3.xy).xyz;
float3 c10 = tex2D(s_p, VAR.t3.xy).xyz; float3 c11 = tex2D(s_p, VAR.texCoord).xyz;
float3 c11 = tex2D(s_p, VAR.texCoord).xyz; float3 c12 = tex2D(s_p, VAR.t3.zw).xyz;
float3 c12 = tex2D(s_p, VAR.t3.zw).xyz; float3 c13 = tex2D(s_p, VAR.t4.xy).xyz;
float3 c13 = tex2D(s_p, VAR.t4.xy).xyz; float3 c20 = tex2D(s_p, VAR.t4.zw).xyz;
float3 c20 = tex2D(s_p, VAR.t4.zw).xyz; float3 c21 = tex2D(s_p, VAR.t5.xy).xyz;
float3 c21 = tex2D(s_p, VAR.t5.xy).xyz; float3 c22 = tex2D(s_p, VAR.t5.zw).xyz;
float3 c22 = tex2D(s_p, VAR.t5.zw).xyz; float3 c23 = tex2D(s_p, VAR.t6.xy).xyz;
float3 c23 = tex2D(s_p, VAR.t6.xy).xyz; float3 c30 = tex2D(s_p, VAR.t6.zw).xyz;
float3 c30 = tex2D(s_p, VAR.t6.zw).xyz; float3 c31 = tex2D(s_p, VAR.t7.xy).xyz;
float3 c31 = tex2D(s_p, VAR.t7.xy).xyz; float3 c32 = tex2D(s_p, VAR.t7.zw).xyz;
float3 c32 = tex2D(s_p, VAR.t7.zw).xyz; float3 c33 = tex2D(s_p, VAR.t8.xy).xyz;
float3 c33 = tex2D(s_p, VAR.t8.xy).xyz;
float4x4 red_matrix = float4x4(c00.x, c01.x, c02.x, c03.x, float4x4 red_matrix = float4x4(c00.x, c01.x, c02.x, c03.x,
c10.x, c11.x, c12.x, c13.x, c10.x, c11.x, c12.x, c13.x,
c20.x, c21.x, c22.x, c23.x, c20.x, c21.x, c22.x, c23.x,
c30.x, c31.x, c32.x, c33.x); c30.x, c31.x, c32.x, c33.x);
float4x4 green_matrix = float4x4(c00.y, c01.y, c02.y, c03.y, float4x4 green_matrix = float4x4(c00.y, c01.y, c02.y, c03.y,
c10.y, c11.y, c12.y, c13.y, c10.y, c11.y, c12.y, c13.y,
c20.y, c21.y, c22.y, c23.y, c20.y, c21.y, c22.y, c23.y,
c30.y, c31.y, c32.y, c33.y); c30.y, c31.y, c32.y, c33.y);
float4x4 blue_matrix = float4x4(c00.z, c01.z, c02.z, c03.z, float4x4 blue_matrix = float4x4(c00.z, c01.z, c02.z, c03.z,
c10.z, c11.z, c12.z, c13.z, c10.z, c11.z, c12.z, c13.z,
c20.z, c21.z, c22.z, c23.z, c20.z, c21.z, c22.z, c23.z,
c30.z, c31.z, c32.z, c33.z); c30.z, c31.z, c32.z, c33.z);
float4x1 invX_Px = mul(invX, float4x1(fp.x*fp.x*fp.x, fp.x*fp.x, fp.x, 1.0)); float4x1 invX_Px = mul(invX, float4x1(fp.x*fp.x*fp.x, fp.x*fp.x, fp.x, 1.0));
float1x4 Py_invY = mul(float1x4(fp.y*fp.y*fp.y, fp.y*fp.y, fp.y, 1.0), invY); float1x4 Py_invY = mul(float1x4(fp.y*fp.y*fp.y, fp.y*fp.y, fp.y, 1.0), invY);
float red = mul(Py_invY, mul( red_matrix, invX_Px)); float red = mul(Py_invY, mul( red_matrix, invX_Px));
float green = mul(Py_invY, mul(green_matrix, invX_Px)); float green = mul(Py_invY, mul(green_matrix, invX_Px));
float blue = mul(Py_invY, mul( blue_matrix, invX_Px)); float blue = mul(Py_invY, mul( blue_matrix, invX_Px));
return float4(red, green, blue, 1.0); return float4(red, green, blue, 1.0);
} }

View File

@ -33,35 +33,32 @@ http://www.gnu.org/copyleft/gpl.html
/* Default Vertex shader */ /* Default Vertex shader */
void main_vertex void main_vertex
( (
float4 position : POSITION, float4 position : POSITION,
//float4 color : COLOR, float2 texCoord1 : TEXCOORD0,
float2 texCoord1 : TEXCOORD0,
uniform float4x4 modelViewProj, uniform float4x4 modelViewProj,
out float4 oPosition : POSITION, out float4 oPosition : POSITION,
//out float4 oColor : COLOR, out float2 otexCoord : TEXCOORD
out float2 otexCoord : TEXCOORD )
)
{ {
oPosition = mul(modelViewProj, position); oPosition = mul(modelViewProj, position);
//oColor = color; otexCoord = texCoord1;
otexCoord = texCoord1;
} }
struct output struct output
{ {
float4 color : COLOR; float4 color : COLOR;
}; };
struct input struct input
{ {
float2 video_size; float2 video_size;
float2 texture_size; float2 texture_size;
float2 output_size; float2 output_size;
float frame_count; float frame_count;
float frame_direction; float frame_direction;
float frame_rotation; float frame_rotation;
}; };
float weight(float x) float weight(float x)
@ -123,11 +120,11 @@ float3 line_run(float ypos, float4 xpos, float4 linetaps, uniform sampler2D s_p)
} }
output main_fragment (float2 tex : TEXCOORD0, uniform input IN, uniform sampler2D s_p : TEXUNIT0) output main_fragment (in float4 vpos : POSITION, float2 tex : TEXCOORD0, uniform input IN, uniform sampler2D s_p : TEXUNIT0)
{ {
float2 stepxy = float2(1.0/IN.texture_size.x, 1.0/IN.texture_size.y); float2 stepxy = float2(1.0/IN.texture_size.x, 1.0/IN.texture_size.y);
float2 pos = tex.xy + stepxy * 0.5; float2 pos = tex.xy + stepxy * 0.5;
float2 f = frac(pos / stepxy); float2 f = frac(pos / stepxy);
float4 linetaps = weight4(1.0 - f.x); float4 linetaps = weight4(1.0 - f.x);
float4 columntaps = weight4(1.0 - f.y); float4 columntaps = weight4(1.0 - f.y);
@ -140,12 +137,11 @@ output main_fragment (float2 tex : TEXCOORD0, uniform input IN, uniform sampler2
float4 xpos = float4(xystart.x, xystart.x + stepxy.x, xystart.x + stepxy.x * 2.0, xystart.x + stepxy.x * 3.0); float4 xpos = float4(xystart.x, xystart.x + stepxy.x, xystart.x + stepxy.x * 2.0, xystart.x + stepxy.x * 3.0);
// final sum and weight normalization // final sum and weight normalization
output OUT; output OUT;
OUT.color = float4(line_run(xystart.y , xpos, linetaps, s_p) * columntaps.r + OUT.color = float4(line_run(xystart.y , xpos, linetaps, s_p) * columntaps.r +
line_run(xystart.y + stepxy.y , xpos, linetaps, s_p) * columntaps.g + line_run(xystart.y + stepxy.y , xpos, linetaps, s_p) * columntaps.g +
line_run(xystart.y + stepxy.y * 2.0, xpos, linetaps, s_p) * columntaps.b + line_run(xystart.y + stepxy.y * 2.0, xpos, linetaps, s_p) * columntaps.b +
line_run(xystart.y + stepxy.y * 3.0, xpos, linetaps, s_p) * columntaps.a,1); line_run(xystart.y + stepxy.y * 3.0, xpos, linetaps, s_p) * columntaps.a,1);
return OUT; return OUT;
} }

View File

@ -9,16 +9,17 @@
void main_vertex void main_vertex
( (
float4 position : POSITION, float4 position : POSITION,
out float4 oPosition : POSITION, float2 tex : TEXCOORD,
uniform float4x4 modelViewProj,
float2 tex : TEXCOORD, uniform float4x4 modelViewProj,
out float2 oTex : TEXCOORD
out float4 oPosition : POSITION,
out float2 oTex : TEXCOORD
) )
{ {
oPosition = mul(modelViewProj, position); oPosition = mul(modelViewProj, position);
oTex = tex; oTex = tex;
} }
// Tweakables. // Tweakables.
@ -34,7 +35,7 @@ float3 grayscale(float3 col)
return float3(v,v,v); return float3(v,v,v);
} }
float4 main_fragment(float2 tex : TEXCOORD, uniform sampler2D s0 : TEXUNIT0) : COLOR float4 main_fragment(in float4 vpos : POSITION, in float2 tex : TEXCOORD, uniform sampler2D s0 : TEXUNIT0) : COLOR
{ {
float3 res = tex2D(s0, tex).xyz; float3 res = tex2D(s0, tex).xyz;
res = lerp(grayscale(res), res, saturation); // Apply saturation res = lerp(grayscale(res), res, saturation); // Apply saturation

View File

@ -1,51 +1,51 @@
struct tex_coords struct tex_coords
{ {
float2 c00 : TEXCOORD0; float2 c00 : TEXCOORD0;
float2 c01 : TEXCOORD1; float2 c01 : TEXCOORD1;
float2 c02 : TEXCOORD2; float2 c02 : TEXCOORD2;
float2 c10 : TEXCOORD3; float2 c10 : TEXCOORD3;
float2 c11 : TEXCOORD4; float2 c11 : TEXCOORD4;
float2 c12 : TEXCOORD5; float2 c12 : TEXCOORD5;
float2 c20 : TEXCOORD6; float2 c20 : TEXCOORD6;
float2 c21 : TEXCOORD7; float2 c21 : TEXCOORD7;
float2 c22 : COLOR0; float2 c22 : COLOR0;
}; };
struct input struct input
{ {
float2 video_size; float2 video_size;
float2 texture_size; float2 texture_size;
float2 output_size; float2 output_size;
}; };
void main_vertex void main_vertex
( (
float4 position : POSITION, float4 position : POSITION,
out float4 oPosition : POSITION, float2 tex : TEXCOORD0,
uniform float4x4 modelViewProj,
float2 tex : TEXCOORD0, uniform float4x4 modelViewProj,
uniform input IN,
uniform input IN, out float4 oPosition : POSITION,
out tex_coords coords out tex_coords coords
) )
{ {
oPosition = mul(modelViewProj, position); oPosition = mul(modelViewProj, position);
float2 texsize = IN.texture_size; float2 texsize = IN.texture_size;
float2 delta = 0.5 / texsize; float2 delta = 0.5 / texsize;
float dx = delta.x; float dx = delta.x;
float dy = delta.y; float dy = delta.y;
coords.c00 = tex + float2(-dx, -dy); coords.c00 = tex + float2(-dx, -dy);
coords.c01 = tex + float2(-dx, 0.0); coords.c01 = tex + float2(-dx, 0.0);
coords.c02 = tex + float2(-dx, dy); coords.c02 = tex + float2(-dx, dy);
coords.c10 = tex + float2(0.0, -dy); coords.c10 = tex + float2(0.0, -dy);
coords.c11 = tex + float2(0.0, 0.0); coords.c11 = tex + float2(0.0, 0.0);
coords.c12 = tex + float2(0.0, dy); coords.c12 = tex + float2(0.0, dy);
coords.c20 = tex + float2(dx, -dy); coords.c20 = tex + float2(dx, -dy);
coords.c21 = tex + float2(dx, 0); coords.c21 = tex + float2(dx, 0);
coords.c22 = tex + float2(dx, dy); coords.c22 = tex + float2(dx, dy);
} }
static const float mx = 0.325; // start smoothing wt. static const float mx = 0.325; // start smoothing wt.
@ -54,40 +54,40 @@ static const float max_w = 0.25; // max filter weigth
static const float min_w = -0.05; // min filter weigth static const float min_w = -0.05; // min filter weigth
static const float lum_add = 0.25; // effects smoothing static const float lum_add = 0.25; // effects smoothing
float4 main_fragment (in tex_coords co, uniform sampler2D s_p : TEXUNIT0) : COLOR float4 main_fragment (in float4 vpos : POSITION, in tex_coords co, uniform sampler2D s_p : TEXUNIT0) : COLOR
{ {
float3 c00 = tex2D(s_p, co.c00).xyz; float3 c00 = tex2D(s_p, co.c00).xyz;
float3 c01 = tex2D(s_p, co.c01).xyz; float3 c01 = tex2D(s_p, co.c01).xyz;
float3 c02 = tex2D(s_p, co.c02).xyz; float3 c02 = tex2D(s_p, co.c02).xyz;
float3 c10 = tex2D(s_p, co.c10).xyz; float3 c10 = tex2D(s_p, co.c10).xyz;
float3 c11 = tex2D(s_p, co.c11).xyz; float3 c11 = tex2D(s_p, co.c11).xyz;
float3 c12 = tex2D(s_p, co.c12).xyz; float3 c12 = tex2D(s_p, co.c12).xyz;
float3 c20 = tex2D(s_p, co.c20).xyz; float3 c20 = tex2D(s_p, co.c20).xyz;
float3 c21 = tex2D(s_p, co.c21).xyz; float3 c21 = tex2D(s_p, co.c21).xyz;
float3 c22 = tex2D(s_p, co.c22).xyz; float3 c22 = tex2D(s_p, co.c22).xyz;
float3 dt = float3(1.0,1.0,1.0); float3 dt = float3(1.0,1.0,1.0);
float md1 = dot(abs(c00 - c22), dt); float md1 = dot(abs(c00 - c22), dt);
float md2 = dot(abs(c02 - c20), dt); float md2 = dot(abs(c02 - c20), dt);
float w1 = dot(abs(c22 - c11), dt) * md2; float w1 = dot(abs(c22 - c11), dt) * md2;
float w2 = dot(abs(c02 - c11), dt) * md1; float w2 = dot(abs(c02 - c11), dt) * md1;
float w3 = dot(abs(c00 - c11), dt) * md2; float w3 = dot(abs(c00 - c11), dt) * md2;
float w4 = dot(abs(c20 - c11), dt) * md1; float w4 = dot(abs(c20 - c11), dt) * md1;
float t1 = w1 + w3; float t1 = w1 + w3;
float t2 = w2 + w4; float t2 = w2 + w4;
float ww = max(t1, t2) + 0.0001; float ww = max(t1, t2) + 0.0001;
c11 = (w1 * c00 + w2 * c20 + w3 * c22 + w4 * c02 + ww * c11) / (t1 + t2 + ww); c11 = (w1 * c00 + w2 * c20 + w3 * c22 + w4 * c02 + ww * c11) / (t1 + t2 + ww);
float lc1 = k / (0.12 * dot(c10 + c12 + c11, dt) + lum_add); float lc1 = k / (0.12 * dot(c10 + c12 + c11, dt) + lum_add);
float lc2 = k / (0.12 * dot(c01 + c21 + c11, dt) + lum_add); float lc2 = k / (0.12 * dot(c01 + c21 + c11, dt) + lum_add);
w1 = clamp(lc1 * dot(abs(c11 - c10), dt) + mx, min_w, max_w); w1 = clamp(lc1 * dot(abs(c11 - c10), dt) + mx, min_w, max_w);
w2 = clamp(lc2 * dot(abs(c11 - c21), dt) + mx, min_w, max_w); w2 = clamp(lc2 * dot(abs(c11 - c21), dt) + mx, min_w, max_w);
w3 = clamp(lc1 * dot(abs(c11 - c12), dt) + mx, min_w, max_w); w3 = clamp(lc1 * dot(abs(c11 - c12), dt) + mx, min_w, max_w);
w4 = clamp(lc2 * dot(abs(c11 - c01), dt) + mx, min_w, max_w); w4 = clamp(lc2 * dot(abs(c11 - c01), dt) + mx, min_w, max_w);
return float4(w1 * c10 + w2 * c21 + w3 * c12 + w4 * c01 + (1.0 - w1 - w2 - w3 - w4) * c11, 1.0); return float4(w1 * c10 + w2 * c21 + w3 * c12 + w4 * c01 + (1.0 - w1 - w2 - w3 - w4) * c11, 1.0);
} }

View File

@ -1,4 +1,3 @@
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
//// ////
@ -9,26 +8,25 @@
struct input struct input
{ {
float2 video_size; float2 video_size;
float2 texture_size; float2 texture_size;
float2 output_size; float2 output_size;
}; };
void main_vertex void main_vertex
( (
float4 position : POSITION, float4 position : POSITION,
out float4 oPosition : POSITION, float2 tex : TEXCOORD0,
uniform float4x4 modelViewProj,
float2 tex : TEXCOORD, uniform float4x4 modelViewProj,
uniform input IN,
uniform input IN, out float4 oPosition : POSITION,
out float2 oTexcoord : TEXCOORD, out float2 oTexcoord : TEXCOORD0,
out float2 oFakeResolution : TEXCOORD1 out float2 oFakeResolution : TEXCOORD1
) )
{ {
oPosition = mul(modelViewProj, position); oPosition = mul(modelViewProj, position);
oTexcoord = tex; oTexcoord = tex;
oFakeResolution = IN.texture_size; oFakeResolution = IN.texture_size;
} }
@ -39,105 +37,112 @@ void main_vertex
//// EFFECT CONSTANTS : TWEAK THEM! //// EFFECT CONSTANTS : TWEAK THEM!
//// ////
// Size of the border effect // Size of the border effect
static const float2 OverscanMaskHardness = {12.0f ,12.0f }; static const float2 OverscanMaskHardness = {12.0f ,12.0f };
// Attenuation of the border effect // Attenuation of the border effect
static const float OverscanMaskPower = 4.0f; static const float OverscanMaskPower = 4.0f;
// Intensity of the border effect // Intensity of the border effect
static const float OverscanIntensity = 0.96f; static const float OverscanIntensity = 0.96f;
// Intensity of the TV Corners (round-ness) deformation
static const float TVDeformInstensity = 0.02f;
// How much R, G and B are offset : default is -0.333 pixels in fake-pixel-space
static const float ColorFringeIntensity = -0.666;
// How much luminosity is output by a fake-pixel
static const float FakePixelMaskGain = 0.75f;
// How much luminosity is output between fake-pixels (adds to the fake-pixel value)
static const float FakePixelMaskOffset = 0.55f;
// How sharp will appear the pixels (Horizontal Sharpness, Vertical Sharpness A.K.A Scanlines)
static const float2 FakePixelMaskPower = {0.150f ,2.0f };
// Scanline Off Sync (Slides one line out of two)
static const float ScanlineOffSync = 0.25;
// Base Brightness
static const float BaseBrightness = 0.55f;
// How much the Fake-Pixel effect is Active (0.0 = normal image, 1.0 = full FakePixel Effect)
static const float FakePixelEffectBlend = 0.95f;
// Ghost Sampling : enable define to activate // Intensity of the TV Corners (round-ness) deformation
#define GHOST_SAMPLING; static const float TVDeformInstensity = 0.02f;
static const float GhostLatencyIntensity = 0.03f;
// Number of samples (higer is slower)
static const int GhostNumSamples = 32;
// Latency of the RGB Signal (per-signal, in screen width percentage)
static const float3 SignalLatencyRGB = {0.184f,0.08f,0.0624f};
// Attenuation of the ghosting latency
static const float SignalLatencyAttenuation = 1.0f;
// Bloom : enable define to activate // How much R, G and B are offset : default is -0.333 pixels in fake-pixel-space
#define BLOOM; static const float ColorFringeIntensity = -0.666;
static const float BloomIntensity = 0.75f; // How much luminosity is output by a fake-pixel
static const float BloomExponent = 1.00f; static const float FakePixelMaskGain = 0.75f;
static const float BloomWeights[5][5] = // How much luminosity is output between fake-pixels (adds to the fake-pixel value)
{ static const float FakePixelMaskOffset = 0.55f;
{0.003765, 0.015019, 0.023792, 0.015019, 0.003765}, // How sharp will appear the pixels (Horizontal Sharpness, Vertical Sharpness A.K.A Scanlines)
{0.015019, 0.059912, 0.094907, 0.059912, 0.015019}, static const float2 FakePixelMaskPower = {0.150f ,2.0f };
{0.023792, 0.094907, 0.150342, 0.094907, 0.023792}, // Scanline Off Sync (Slides one line out of two)
{0.015019, 0.059912, 0.094907, 0.059912, 0.015019}, static const float ScanlineOffSync = 0.25;
{0.003765, 0.015019, 0.023792, 0.015019, 0.003765} // Base Brightness
}; static const float BaseBrightness = 0.55f;
static const float BloomPositions[5] = { -2, -1, 0 , 1 , 2};
// How much the Fake-Pixel effect is Active (0.0 = normal image, 1.0 = full FakePixel Effect)
static const float FakePixelEffectBlend = 0.95f;
// Ghost Sampling : enable define to activate
#define GHOST_SAMPLING;
static const float GhostLatencyIntensity = 0.03f;
// Number of samples (higer is slower)
static const int GhostNumSamples = 32;
// Latency of the RGB Signal (per-signal, in screen width percentage)
static const float3 SignalLatencyRGB = {0.184f,0.08f,0.0624f};
// Attenuation of the ghosting latency
static const float SignalLatencyAttenuation = 1.0f;
// Bloom : enable define to activate
#define BLOOM;
static const float BloomIntensity = 0.75f;
static const float BloomExponent = 1.00f;
static const float BloomWeights[5][5] =
{
{0.003765, 0.015019, 0.023792, 0.015019, 0.003765},
{0.015019, 0.059912, 0.094907, 0.059912, 0.015019},
{0.023792, 0.094907, 0.150342, 0.094907, 0.023792},
{0.015019, 0.059912, 0.094907, 0.059912, 0.015019},
{0.003765, 0.015019, 0.023792, 0.015019, 0.003765}
};
static const float BloomPositions[5] = { -2, -1, 0 , 1 , 2};
//// ////
//// ////
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
float expow(float value, float exponent) { float expow(float value, float exponent)
{
return lerp(1.0f,pow(value,max(exponent,1.0f)),saturate(exponent)); return lerp(1.0f,pow(value,max(exponent,1.0f)),saturate(exponent));
} }
//the code that calls expow() carefully builds float2 for some reason and calls this only to have it implicitly thrown away (which is a warning) //the code that calls expow() carefully builds float2 for some reason and calls this only to have it implicitly thrown away (which is a warning)
//so this was added to get rid of the warning //so this was added to get rid of the warning
float expow(float2 value, float2 exponent) { float expow(float2 value, float2 exponent)
{
return lerp(1.0f,pow(value,max(exponent,1.0f)),saturate(exponent)).x; return lerp(1.0f,pow(value,max(exponent,1.0f)),saturate(exponent)).x;
} }
// MultiSampling for ghosting effect // MultiSampling for ghosting effect
float3 GhostSample(sampler2D s, float2 t, float latency) { float3 GhostSample(sampler2D s, float2 t, float latency)
{
float3 Out = tex2D(s,t); float3 Out = tex2D(s,t);
float Weight = 1.0f; float Weight = 1.0f;
float2 Direction = float2(-latency,0.0f); float2 Direction = float2(-latency,0.0f);
for(int i=1; i < GhostNumSamples; i++) {
float curweight = pow(1.0f-((float)i/GhostNumSamples),1.0f/SignalLatencyAttenuation);
for(int i=1; i < GhostNumSamples; i++)
{
float curweight = pow(1.0f-((float)i/GhostNumSamples),1.0f/SignalLatencyAttenuation);
Out += GhostLatencyIntensity * curweight * tex2D(s,saturate(t+(1.0f-curweight)*Direction)).xyz; Out += GhostLatencyIntensity * curweight * tex2D(s,saturate(t+(1.0f-curweight)*Direction)).xyz;
Weight += GhostLatencyIntensity * curweight; Weight += GhostLatencyIntensity * curweight;
} }
return Out/Weight; return Out/Weight;
} }
// MultiSampling for ghosting effect // MultiSampling for ghosting effect
float3 Bloom(sampler2D s, float2 t, float2 r) { float3 Bloom(sampler2D s, float2 t, float2 r)
{
float3 Out = float3(0,0,0); float3 Out = float3(0,0,0);
for(int j = 0; j < 5; j++) for(int j = 0; j < 5; j++)
{
for(int i = 0; i < 5; i++) for(int i = 0; i < 5; i++)
{ {
float2 offset = float2(BloomPositions[i],BloomPositions[j]) / r; float2 offset = float2(BloomPositions[i],BloomPositions[j]) / r;
Out += tex2D(s, t + offset).rgb * BloomWeights[i][j]; Out += tex2D(s, t + offset).rgb * BloomWeights[i][j];
} }
}
return pow(Out, BloomExponent) * BloomIntensity; return pow(Out, BloomExponent) * BloomIntensity;
} }
// Compositing of the TV Emulation // Compositing of the TV Emulation
float3 TVEffect(float2 in_Position, float2 FakeResolution, sampler2D Texture, float Time) { float3 TVEffect(float2 in_Position, float2 FakeResolution, sampler2D Texture, float Time)
{
// TV Deformation // TV Deformation
float2 ScreenPos = in_Position + dot(in_Position-0.5f,in_Position-0.5f)*(in_Position-0.5f)* TVDeformInstensity; float2 ScreenPos = in_Position + dot(in_Position-0.5f,in_Position-0.5f)*(in_Position-0.5f)* TVDeformInstensity;
@ -147,9 +152,11 @@ float3 TVEffect(float2 in_Position, float2 FakeResolution, sampler2D Texture, fl
// Sampling 3 Images biased to simulate TV RGB Offset // Sampling 3 Images biased to simulate TV RGB Offset
#ifdef GHOST_SAMPLING #ifdef GHOST_SAMPLING
float3 latencyweight = float3(0.0f,0.0f,0.0f); float3 latencyweight = float3(0.0f,0.0f,0.0f);
for(int i=1; i < GhostNumSamples; i++) { for(int i=1; i < GhostNumSamples; i++)
{
latencyweight += tex2D(Texture, ScreenPos + float2(1.0f/FakeResolution.x,0.0f)).xyz; latencyweight += tex2D(Texture, ScreenPos + float2(1.0f/FakeResolution.x,0.0f)).xyz;
} }
float3 LatencyRGB = SignalLatencyRGB * (1.0-(latencyweight/GhostNumSamples)); float3 LatencyRGB = SignalLatencyRGB * (1.0-(latencyweight/GhostNumSamples));
float3 SMP_Red = GhostSample(Texture, (ScreenPos),LatencyRGB.x).xyz; float3 SMP_Red = GhostSample(Texture, (ScreenPos),LatencyRGB.x).xyz;
@ -183,24 +190,22 @@ float3 TVEffect(float2 in_Position, float2 FakeResolution, sampler2D Texture, fl
float PixelMaskB = expow(saturate(4*frac(ScreenPos.x*FakeResolution.x+float2(ColorFringeIntensity*2.0f,0.0f))*(1.0f-frac(ScreenPos.x*FakeResolution.x+float2(ColorFringeIntensity*2.0f,0.0f)))),FakePixelMaskPower.x); float PixelMaskB = expow(saturate(4*frac(ScreenPos.x*FakeResolution.x+float2(ColorFringeIntensity*2.0f,0.0f))*(1.0f-frac(ScreenPos.x*FakeResolution.x+float2(ColorFringeIntensity*2.0f,0.0f)))),FakePixelMaskPower.x);
float PixelMaskScanline = pow(saturate(4*frac(ScreenPos.y*FakeResolution.y)*(1.0f-frac(ScreenPos.y*FakeResolution.y))),FakePixelMaskPower.y); float PixelMaskScanline = pow(saturate(4*frac(ScreenPos.y*FakeResolution.y)*(1.0f-frac(ScreenPos.y*FakeResolution.y))),FakePixelMaskPower.y);
float3 PixelRGB = float3 ( float3 PixelRGB = float3(((PixelMaskR*PixelMaskScanline * FakePixelMaskGain)+FakePixelMaskOffset) * SMP_Red.x,
((PixelMaskR*PixelMaskScanline * FakePixelMaskGain)+FakePixelMaskOffset) * SMP_Red.x , ((PixelMaskG*PixelMaskScanline * FakePixelMaskGain)+FakePixelMaskOffset) * SMP_Green.y,
((PixelMaskG*PixelMaskScanline * FakePixelMaskGain)+FakePixelMaskOffset) * SMP_Green.y , ((PixelMaskB*PixelMaskScanline * FakePixelMaskGain)+FakePixelMaskOffset) * SMP_Blue.z);
((PixelMaskB*PixelMaskScanline * FakePixelMaskGain)+FakePixelMaskOffset) * SMP_Blue.z
);
// Non-Pixelated Image // Non-Pixelated Image
float3 ImageRGB = tex2D(Texture, ScreenPos).xyz; float3 ImageRGB = tex2D(Texture, ScreenPos).xyz;
return lerp(ImageRGB, PixelRGB, FakePixelEffectBlend) * mask; return lerp(ImageRGB, PixelRGB, FakePixelEffectBlend) * mask;
//return float3(PixelMaskR*PixelMaskScanline,PixelMaskG*PixelMaskScanline,PixelMaskB*PixelMaskScanline); //return float3(PixelMaskR*PixelMaskScanline,PixelMaskG*PixelMaskScanline,PixelMaskB*PixelMaskScanline);
} }
float4 main_fragment float4 main_fragment
( (
in float2 TexCoord : TEXCOORD, in float4 vpos : POSITION,
in float2 TexCoord : TEXCOORD0,
in float2 FakeResolution : TEXCOORD1, in float2 FakeResolution : TEXCOORD1,
in float2 wpos : WPOS,
uniform sampler2D s_p : TEXUNIT0, uniform sampler2D s_p : TEXUNIT0,
uniform float Time uniform float Time
) : COLOR ) : COLOR

View File

@ -18,7 +18,6 @@
<PackageVersion Include="PolySharp" Version="1.14.1" /> <PackageVersion Include="PolySharp" Version="1.14.1" />
<PackageVersion Include="ppy.SDL2-CS" Version="1.0.630-alpha" /> <!-- last version with .NET Standard 2.0 support --> <PackageVersion Include="ppy.SDL2-CS" Version="1.0.630-alpha" /> <!-- last version with .NET Standard 2.0 support -->
<PackageVersion Include="SharpCompress" Version="0.31.0" /><!-- can't update any further or .gz stops being detected as archive --> <PackageVersion Include="SharpCompress" Version="0.31.0" /><!-- can't update any further or .gz stops being detected as archive -->
<PackageVersion Include="SharpDX.Direct3D9" Version="4.2.0" />
<PackageVersion Include="Silk.NET.OpenAL" Version="2.21.0" /> <PackageVersion Include="Silk.NET.OpenAL" Version="2.21.0" />
<PackageVersion Include="Silk.NET.OpenAL.Extensions.Creative" Version="2.21.0" /> <PackageVersion Include="Silk.NET.OpenAL.Extensions.Creative" Version="2.21.0" />
<PackageVersion Include="Silk.NET.OpenAL.Extensions.Enumeration" Version="2.21.0" /> <PackageVersion Include="Silk.NET.OpenAL.Extensions.Enumeration" Version="2.21.0" />
@ -34,6 +33,8 @@
<PackageVersion Include="System.Reflection.Emit" Version="4.7.0" /> <PackageVersion Include="System.Reflection.Emit" Version="4.7.0" />
<PackageVersion Include="System.Resources.Extensions" Version="7.0.0" /> <PackageVersion Include="System.Resources.Extensions" Version="7.0.0" />
<PackageVersion Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" /> <PackageVersion Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
<PackageVersion Include="Vortice.Direct3D11" Version="2.4.2" /> <!-- last version with .NET Standard 2.0 support -->
<PackageVersion Include="Vortice.D3DCompiler" Version="2.4.2" /> <!-- last version with .NET Standard 2.0 support -->
<PackageVersion Include="Vortice.MediaFoundation" Version="2.4.2" /> <!-- last version with .NET Standard 2.0 support --> <PackageVersion Include="Vortice.MediaFoundation" Version="2.4.2" /> <!-- last version with .NET Standard 2.0 support -->
<PackageVersion Include="Vortice.XAudio2" Version="2.4.2" /> <!-- last version with .NET Standard 2.0 support --> <PackageVersion Include="Vortice.XAudio2" Version="2.4.2" /> <!-- last version with .NET Standard 2.0 support -->
</ItemGroup> </ItemGroup>

View File

@ -4,6 +4,6 @@ namespace BizHawk.Bizware.BizwareGL
{ {
OpenGL = 0, OpenGL = 0,
GdiPlus = 1, GdiPlus = 1,
D3D9 = 2 D3D11 = 2,
} }
} }

View File

@ -9,7 +9,7 @@ namespace BizHawk.Bizware.BizwareGL
/// <summary> /// <summary>
/// This is a wrapper over OpenGL and direct3d to give a uniform interface /// This is a wrapper over OpenGL and direct3d to give a uniform interface
/// TODO - This really needs to be split up into an internal and a user interface. so many of the functions are made to support the smart wrappers /// TODO - This really needs to be split up into an internal and a user interface. so many of the functions are made to support the smart wrappers
/// Maybe make a method that returns an interface used for advanced methods (and IGL_TK could implement that as well and just "return this:") /// Maybe make a method that returns an interface used for advanced methods (and IGL_OpenGL could implement that as well and just "return this:")
/// ///
/// NOTE: THIS SHOULD NOT BE ASSUMED TO BE THREAD SAFE! Make a new IGL if you want to use it in a new thread. I hope that will work... /// NOTE: THIS SHOULD NOT BE ASSUMED TO BE THREAD SAFE! Make a new IGL if you want to use it in a new thread. I hope that will work...
/// </summary> /// </summary>

View File

@ -29,6 +29,12 @@ namespace BizHawk.Bizware.BizwareGL
if (!Pipeline.Available) if (!Pipeline.Available)
{ {
// make sure we release the vertex shader if it was compiled ok
if (vs.Available)
{
vs.Release();
}
Available = false; Available = false;
return; return;
} }

View File

@ -3,15 +3,15 @@ using System.Windows.Forms;
namespace BizHawk.Bizware.Graphics.Controls namespace BizHawk.Bizware.Graphics.Controls
{ {
internal sealed class D3D9Control : GraphicsControl internal sealed class D3D11Control : GraphicsControl
{ {
private readonly Func<D3D9SwapChain.ControlParameters, D3D9SwapChain> _createSwapChain; private readonly Func<D3D11SwapChain.ControlParameters, D3D11SwapChain> _createSwapChain;
private D3D9SwapChain _swapChain; private D3D11SwapChain _swapChain;
private bool Vsync; private bool Vsync, AllowsTearing;
private D3D9SwapChain.ControlParameters ControlParameters => new(Handle, Width, Height, Vsync); private D3D11SwapChain.ControlParameters ControlParameters => new(Handle, Width, Height, Vsync, AllowsTearing);
public D3D9Control(Func<D3D9SwapChain.ControlParameters, D3D9SwapChain> createSwapChain) public D3D11Control(Func<D3D11SwapChain.ControlParameters, D3D11SwapChain> createSwapChain)
{ {
_createSwapChain = createSwapChain; _createSwapChain = createSwapChain;
@ -41,14 +41,11 @@ namespace BizHawk.Bizware.Graphics.Controls
_swapChain.Refresh(ControlParameters); _swapChain.Refresh(ControlParameters);
} }
public override void AllowTearing(bool state)
=> AllowsTearing = state;
public override void SetVsync(bool state) public override void SetVsync(bool state)
{ => Vsync = state;
if (Vsync != state)
{
Vsync = state;
_swapChain.Refresh(ControlParameters);
}
}
public override void Begin() public override void Begin()
=> _swapChain.SetBackBuffer(); => _swapChain.SetBackBuffer();

View File

@ -27,6 +27,11 @@ namespace BizHawk.Bizware.Graphics.Controls
/// </summary> /// </summary>
private GDIPlusRenderTarget RenderTarget { get; } private GDIPlusRenderTarget RenderTarget { get; }
public override void AllowTearing(bool state)
{
// not controllable
}
public override void SetVsync(bool state) public override void SetVsync(bool state)
{ {
// not really supported now... // not really supported now...

View File

@ -68,6 +68,11 @@ namespace BizHawk.Bizware.Graphics.Controls
} }
} }
public override void AllowTearing(bool state)
{
// not controllable
}
public override void SetVsync(bool state) public override void SetVsync(bool state)
{ {
MakeContextCurrent(); MakeContextCurrent();

View File

@ -4,6 +4,12 @@ namespace BizHawk.Bizware.Graphics.Controls
{ {
public abstract class GraphicsControl : Control public abstract class GraphicsControl : Control
{ {
/// <summary>
/// Allows the control to tear when out of vsync
/// Only relevant for D3D11Control currently
/// </summary>
public abstract void AllowTearing(bool state);
/// <summary> /// <summary>
/// Sets whether presentation operations on this control will vsync /// Sets whether presentation operations on this control will vsync
/// </summary> /// </summary>

View File

@ -14,7 +14,7 @@ namespace BizHawk.Bizware.Graphics.Controls
GraphicsControl ret = gl switch GraphicsControl ret = gl switch
{ {
IGL_OpenGL => new OpenGLControl(), IGL_OpenGL => new OpenGLControl(),
IGL_D3D9 d3d9 => new D3D9Control(d3d9.CreateSwapChain), IGL_D3D11 d3d11 => new D3D11Control(d3d11.CreateSwapChain),
IGL_GDIPlus gdiPlus => new GDIPlusControl(gdiPlus.CreateControlRenderTarget), IGL_GDIPlus gdiPlus => new GDIPlusControl(gdiPlus.CreateControlRenderTarget),
_ => throw new InvalidOperationException() _ => throw new InvalidOperationException()
}; };

View File

@ -9,8 +9,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Silk.NET.OpenGL.Legacy" /> <PackageReference Include="Silk.NET.OpenGL.Legacy" />
<PackageReference Include="SharpDX.Direct3D9" />
<PackageReference Include="ppy.SDL2-CS" ExcludeAssets="native;contentFiles" /> <PackageReference Include="ppy.SDL2-CS" ExcludeAssets="native;contentFiles" />
<PackageReference Include="Vortice.Direct3D11" />
<PackageReference Include="Vortice.D3DCompiler" />
<ProjectReference Include="$(ProjectDir)../BizHawk.Bizware.BizwareGL/BizHawk.Bizware.BizwareGL.csproj" /> <ProjectReference Include="$(ProjectDir)../BizHawk.Bizware.BizwareGL/BizHawk.Bizware.BizwareGL.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,130 @@
using System;
using Vortice.Direct3D11;
using Vortice.DXGI;
using DXGIResultCode = Vortice.DXGI.ResultCode;
namespace BizHawk.Bizware.Graphics
{
public sealed class D3D11SwapChain : IDisposable
{
public readonly struct ControlParameters
{
public readonly IntPtr Handle;
public readonly int Width;
public readonly int Height;
public readonly bool Vsync;
public readonly bool AllowsTearing;
public ControlParameters(IntPtr handle, int width, int height, bool vsync, bool allowsTearing)
{
Handle = handle;
Width = Math.Max(width, 1);
Height = Math.Max(height, 1);
Vsync = vsync;
AllowsTearing = allowsTearing;
}
}
internal class SwapChainResources : IDisposable
{
public ID3D11Device Device;
public ID3D11DeviceContext Context;
public ID3D11Texture2D BackBufferTexture;
public ID3D11RenderTargetView RTV;
public IDXGISwapChain1 SwapChain;
public bool AllowsTearing;
public void Dispose()
{
// Device/Context not owned by this class
Device = null;
Context = null;
RTV?.Dispose();
RTV = null;
BackBufferTexture?.Dispose();
BackBufferTexture = null;
SwapChain?.Dispose();
SwapChain = null;
}
}
private static readonly SharpGen.Runtime.Result D3DDDIERR_DEVICEREMOVED = new(2289436784UL);
private readonly SwapChainResources _resources;
private readonly Action<ControlParameters> _resetDeviceCallback;
private ID3D11Device Device => _resources.Device;
private ID3D11DeviceContext Context => _resources.Context;
private ID3D11Texture2D BackBufferTexture => _resources.BackBufferTexture;
private ID3D11RenderTargetView RTV => _resources.RTV;
private IDXGISwapChain1 SwapChain => _resources.SwapChain;
private bool AllowsTearing => _resources.AllowsTearing;
internal D3D11SwapChain(SwapChainResources resources, Action<ControlParameters> resetDeviceCallback)
{
_resources = resources;
_resetDeviceCallback = resetDeviceCallback;
}
public void Dispose()
=> _resources.Dispose();
public void SetBackBuffer()
=> Context.OMSetRenderTargets(RTV);
public void PresentBuffer(ControlParameters cp)
{
SetBackBuffer();
PresentFlags presentFlags;
if (cp.Vsync)
{
presentFlags = PresentFlags.None;
}
else
{
presentFlags = cp.AllowsTearing && AllowsTearing ? PresentFlags.AllowTearing : PresentFlags.DoNotWait;
}
var result = SwapChain.Present(cp.Vsync ? 1 : 0, presentFlags);
if (result == DXGIResultCode.DeviceReset
|| result == DXGIResultCode.DeviceRemoved
|| result == D3DDDIERR_DEVICEREMOVED)
{
_resetDeviceCallback(cp);
}
}
public void Refresh(ControlParameters cp)
{
// must be released in order to resize these buffers
RTV.Dispose();
_resources.RTV = null;
BackBufferTexture.Dispose();
_resources.BackBufferTexture = null;
var result = SwapChain.ResizeBuffers(
bufferCount: 2,
cp.Width,
cp.Height,
Format.B8G8R8A8_UNorm,
AllowsTearing ? SwapChainFlags.AllowTearing : SwapChainFlags.None);
if (result == DXGIResultCode.DeviceReset
|| result == DXGIResultCode.DeviceRemoved
|| result == D3DDDIERR_DEVICEREMOVED)
{
_resetDeviceCallback(cp);
}
else
{
result.CheckError();
_resources.BackBufferTexture = SwapChain.GetBuffer<ID3D11Texture2D>(0);
var rtvd = new RenderTargetViewDescription(RenderTargetViewDimension.Texture2D, Format.B8G8R8A8_UNorm);
_resources.RTV = Device.CreateRenderTargetView(BackBufferTexture, rtvd);
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,76 +0,0 @@
using System;
using SharpDX;
using SharpDX.Direct3D9;
namespace BizHawk.Bizware.Graphics
{
public sealed class D3D9SwapChain : IDisposable
{
public readonly struct ControlParameters
{
public readonly IntPtr Handle;
public readonly int Width;
public readonly int Height;
public readonly bool Vsync;
public ControlParameters(IntPtr handle, int width, int height, bool vsync)
{
Handle = handle;
Width = Math.Max(width, 1);
Height = Math.Max(height, 1);
Vsync = vsync;
}
}
private const int D3DERR_DEVICELOST = unchecked((int)0x88760868);
private readonly Device _device;
private readonly Func<ControlParameters, SwapChain> _resetDeviceCallback;
private readonly Func<ControlParameters, SwapChain> _resetSwapChainCallback;
private SwapChain _swapChain;
internal D3D9SwapChain(Device device, SwapChain swapChain,
Func<ControlParameters, SwapChain> resetDeviceCallback, Func<ControlParameters, SwapChain> resetSwapChainCallback)
{
_device = device;
_swapChain = swapChain;
_resetDeviceCallback = resetDeviceCallback;
_resetSwapChainCallback = resetSwapChainCallback;
}
public void Dispose()
{
_swapChain?.Dispose();
_swapChain = null;
}
public void SetBackBuffer()
{
using var surface = _swapChain.GetBackBuffer(0);
_device.SetRenderTarget(0, surface);
_device.DepthStencilSurface = null;
}
public void PresentBuffer(ControlParameters cp)
{
SetBackBuffer();
try
{
_swapChain.Present(Present.None);
}
catch (SharpDXException ex)
{
if (ex.ResultCode.Code == D3DERR_DEVICELOST)
{
_swapChain = _resetDeviceCallback(cp);
}
}
}
public void Refresh(ControlParameters cp)
=> _swapChain = _resetSwapChainCallback(cp);
}
}

View File

@ -1,839 +0,0 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using BizHawk.Bizware.BizwareGL;
using BizHawk.Common;
using BizHawk.Common.StringExtensions;
using SharpDX.Direct3D9;
using static SDL2.SDL;
// todo - do a better job selecting shader model? base on caps somehow? try several and catch compilation exceptions (yuck, exceptions)
namespace BizHawk.Bizware.Graphics
{
/// <summary>
/// Direct3D9 implementation of the BizwareGL.IGL interface
/// </summary>
public sealed class IGL_D3D9 : IGL
{
public EDispMethod DispMethodEnum => EDispMethod.D3D9;
private const int D3DERR_DEVICENOTRESET = unchecked((int)0x88760869);
private Device _device;
private SwapChain _controlSwapchain;
private IntPtr _offscreenSdl2Window;
private IntPtr OffscreenNativeWindow;
// rendering state
private Pipeline _currPipeline;
// misc state
private readonly HashSet<RenderTarget> _renderTargets = new();
public string API => "D3D9";
static IGL_D3D9()
{
if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
throw new($"Failed to init SDL video, SDL error: {SDL_GetError()}");
}
}
public IGL_D3D9()
{
if (OSTailoredCode.IsUnixHost)
{
throw new NotSupportedException("D3D9 is Windows only");
}
// make an 'offscreen context' so we can at least do things without having to create a window
_offscreenSdl2Window = SDL_CreateWindow(null, 0, 0, 1, 1, SDL_WindowFlags.SDL_WINDOW_HIDDEN);
if (_offscreenSdl2Window == IntPtr.Zero)
{
throw new($"Failed to create offscreen SDL window, SDL error: {SDL_GetError()}");
}
// get the native window handle
var wminfo = default(SDL_SysWMinfo);
SDL_GetVersion(out wminfo.version);
SDL_GetWindowWMInfo(_offscreenSdl2Window, ref wminfo);
if (wminfo.subsystem != SDL_SYSWM_TYPE.SDL_SYSWM_WINDOWS)
{
throw new($"SDL_SysWMinfo did not report SDL_SYSWM_WINDOWS? Something went wrong... SDL error: {SDL_GetError()}");
}
OffscreenNativeWindow = wminfo.info.win.window;
CreateDevice();
}
public void AlternateVsyncPass(int pass)
{
while (true)
{
var status = _device.GetRasterStatus(0);
if (status.InVBlank && pass == 0) return; // wait for vblank to begin
if (!status.InVBlank && pass == 1) return; // wait for vblank to end
// STOP! think you can use System.Threading.SpinWait? No, it's way too slow.
// (on my system, the vblank is something like 24 of 1074 scanlines @ 60hz ~= 0.35ms which is an awfully small window to nail)
}
}
private void CreateDevice()
{
// this object is only used for creating a device, it's not needed afterwards
using var d3d9 = new Direct3D();
var pp = MakePresentParameters();
var flags = (d3d9.GetDeviceCaps(0, DeviceType.Hardware).DeviceCaps & DeviceCaps.HWTransformAndLight) != 0
? CreateFlags.HardwareVertexProcessing
: CreateFlags.SoftwareVertexProcessing;
flags |= CreateFlags.FpuPreserve;
_device = new(d3d9, 0, DeviceType.Hardware, pp.DeviceWindowHandle, flags, pp);
}
private PresentParameters MakePresentParameters()
{
return new()
{
BackBufferCount = 1,
SwapEffect = SwapEffect.Discard,
DeviceWindowHandle = OffscreenNativeWindow,
Windowed = true,
PresentationInterval = PresentInterval.Immediate,
};
}
private static PresentParameters MakePresentParameters(D3D9SwapChain.ControlParameters cp)
{
return new()
{
BackBufferWidth = cp.Width,
BackBufferHeight = cp.Height,
BackBufferFormat = Format.X8R8G8B8,
BackBufferCount = 2,
SwapEffect = SwapEffect.Discard,
DeviceWindowHandle = cp.Handle,
Windowed = true,
PresentationInterval = cp.Vsync ? PresentInterval.One : PresentInterval.Immediate
};
}
private SwapChain ResetDevice(D3D9SwapChain.ControlParameters cp)
{
SuspendRenderTargets();
_controlSwapchain.Dispose();
var pp = MakePresentParameters();
while (true)
{
var result = _device.TestCooperativeLevel();
if (result.Success)
{
break;
}
if (result.Code == D3DERR_DEVICENOTRESET)
{
try
{
_device.Reset(pp);
break;
}
catch
{
// ignored
}
}
Thread.Sleep(100);
}
ResumeRenderTargets();
pp = MakePresentParameters(cp);
_controlSwapchain = new(_device, pp);
return _controlSwapchain;
}
private SwapChain ResetSwapChain(D3D9SwapChain.ControlParameters cp)
{
_controlSwapchain.Dispose();
var pp = MakePresentParameters(cp);
_controlSwapchain = new(_device, pp);
return _controlSwapchain;
}
public D3D9SwapChain CreateSwapChain(D3D9SwapChain.ControlParameters cp)
{
if (_controlSwapchain != null)
{
throw new InvalidOperationException($"{nameof(IGL_D3D9)} can only have 1 control swap chain");
}
var pp = MakePresentParameters(cp);
_controlSwapchain = new(_device, pp);
return new(_device, _controlSwapchain, ResetDevice, ResetSwapChain);
}
public void Dispose()
{
if (_device != null)
{
_device.Dispose();
_device = null;
}
if (_offscreenSdl2Window != IntPtr.Zero)
{
SDL_DestroyWindow(_offscreenSdl2Window);
_offscreenSdl2Window = OffscreenNativeWindow = IntPtr.Zero;
}
_controlSwapchain = null;
}
public void ClearColor(Color color)
=> _device.Clear(ClearFlags.Target, color.ToSharpDXColor(), 0.0f, 0);
public void FreeTexture(Texture2d tex)
{
var tw = (TextureWrapper)tex.Opaque;
tw.Texture.Dispose();
}
private class ShaderWrapper // Disposable fields cleaned up by Internal_FreeShader
{
public ShaderBytecode Bytecode;
public VertexShader VS;
public PixelShader PS;
public Shader IGLShader;
}
/// <exception cref="InvalidOperationException"><paramref name="required"/> is <see langword="true"/> and compilation error occurred</exception>
public Shader CreateFragmentShader(string source, string entry, bool required)
{
try
{
var sw = new ShaderWrapper();
// ShaderFlags.EnableBackwardsCompatibility - used this once upon a time (please leave a note about why)
var result = ShaderBytecode.Compile(
shaderSource: source,
entryPoint: entry,
profile: "ps_3_0",
shaderFlags: ShaderFlags.UseLegacyD3DX9_31Dll);
sw.PS = new(_device, result);
sw.Bytecode = result;
var s = new Shader(this, sw, true);
sw.IGLShader = s;
return s;
}
catch (Exception ex)
{
if (required)
{
throw;
}
return new(this, null, false) { Errors = ex.ToString() };
}
}
/// <exception cref="InvalidOperationException"><paramref name="required"/> is <see langword="true"/> and compilation error occurred</exception>
public Shader CreateVertexShader(string source, string entry, bool required)
{
try
{
var sw = new ShaderWrapper();
var result = ShaderBytecode.Compile(
shaderSource: source,
entryPoint: entry,
profile: "vs_3_0",
shaderFlags: ShaderFlags.UseLegacyD3DX9_31Dll);
sw.VS = new(_device, result);
sw.Bytecode = result;
var s = new Shader(this, sw, true);
sw.IGLShader = s;
return s;
}
catch (Exception ex)
{
if (required)
{
throw;
}
return new(this, null, false) { Errors = ex.ToString() };
}
}
public void EnableBlending()
{
_device.SetRenderState(RenderState.AlphaBlendEnable, true);
_device.SetRenderState(RenderState.SeparateAlphaBlendEnable, true);
_device.SetRenderState(RenderState.BlendOperation, BlendOperation.Add);
_device.SetRenderState(RenderState.SourceBlend, Blend.SourceAlpha);
_device.SetRenderState(RenderState.DestinationBlend, Blend.InverseSourceAlpha);
_device.SetRenderState(RenderState.BlendOperationAlpha, BlendOperation.Add);
_device.SetRenderState(RenderState.SourceBlendAlpha, Blend.One);
_device.SetRenderState(RenderState.DestinationBlendAlpha, Blend.Zero);
}
public void DisableBlending()
=> _device.SetRenderState(RenderState.AlphaBlendEnable, false);
/// <exception cref="InvalidOperationException">
/// <paramref name="required"/> is <see langword="true"/> and either <paramref name="vertexShader"/> or <paramref name="fragmentShader"/> is unavailable (their <see cref="Shader.Available"/> property is <see langword="false"/>), or
/// one of <paramref name="vertexLayout"/>'s items has an unsupported value in <see cref="VertexLayout.LayoutItem.AttribType"/>, <see cref="VertexLayout.LayoutItem.Components"/>, or <see cref="VertexLayout.LayoutItem.Usage"/>
/// </exception>
public Pipeline CreatePipeline(VertexLayout vertexLayout, Shader vertexShader, Shader fragmentShader, bool required, string memo)
{
if (!vertexShader.Available || !fragmentShader.Available)
{
var errors = $"Vertex Shader:\r\n {vertexShader.Errors} \r\n-------\r\nFragment Shader:\r\n{fragmentShader.Errors}";
if (required)
{
throw new InvalidOperationException($"Couldn't build required GL pipeline:\r\n{errors}");
}
return new(this, null, false, null, null, null) { Errors = errors };
}
var ves = new VertexElement[vertexLayout.Items.Count + 1];
var stride = 0;
foreach (var (i, item) in vertexLayout.Items)
{
DeclarationType declType;
// ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault
switch (item.AttribType)
{
case VertexAttribPointerType.Float:
declType = item.Components switch
{
1 => DeclarationType.Float1,
2 => DeclarationType.Float2,
3 => DeclarationType.Float3,
4 => DeclarationType.Float4,
_ => throw new InvalidOperationException()
};
stride += 4 * item.Components;
break;
default:
throw new NotSupportedException();
}
DeclarationUsage usage;
byte usageIndex = 0;
// ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault
switch (item.Usage)
{
case AttribUsage.Position:
usage = DeclarationUsage.Position;
break;
case AttribUsage.Texcoord0:
usage = DeclarationUsage.TextureCoordinate;
break;
case AttribUsage.Texcoord1:
usage = DeclarationUsage.TextureCoordinate;
usageIndex = 1;
break;
case AttribUsage.Color0:
usage = DeclarationUsage.Color;
break;
default:
throw new NotSupportedException();
}
ves[i] = new(0, (short)item.Offset, declType, DeclarationMethod.Default, usage, usageIndex);
}
// must be placed at the end
ves[vertexLayout.Items.Count] = VertexElement.VertexDeclarationEnd;
var pw = new PipelineWrapper
{
VertexDeclaration = new(_device, ves),
VertexShader = (ShaderWrapper)vertexShader.Opaque,
FragmentShader = (ShaderWrapper)fragmentShader.Opaque,
VertexStride = stride
};
// scan uniforms from reflection
var uniforms = new List<UniformInfo>();
var vsct = pw.VertexShader.Bytecode.ConstantTable;
var psct = pw.FragmentShader.Bytecode.ConstantTable;
foreach (var ct in new[] { vsct, psct })
{
var todo = new Queue<(string, EffectHandle)>();
var n = ct.Description.Constants;
for (var i = 0; i < n; i++)
{
var handle = ct.GetConstant(null, i);
todo.Enqueue((string.Empty, handle));
}
while (todo.Count != 0)
{
var (prefix, handle) = todo.Dequeue();
var descr = ct.GetConstantDescription(handle);
// Console.WriteLine($"D3D UNIFORM: {descr.Name}");
if (descr.StructMembers != 0)
{
var newPrefix = $"{prefix}{descr.Name}.";
for (var j = 0; j < descr.StructMembers; j++)
{
var subHandle = ct.GetConstant(handle, j);
todo.Enqueue((newPrefix, subHandle));
}
continue;
}
var ui = new UniformInfo();
var uw = new UniformWrapper();
ui.Opaque = uw;
var name = prefix + descr.Name;
// uniforms done through the entry point signature have $ in their names which isn't helpful, so get rid of that
name = name.RemovePrefix('$');
ui.Name = name;
uw.EffectHandle = handle;
uw.CT = ct;
if (descr.Type == ParameterType.Sampler2D)
{
ui.IsSampler = true;
ui.SamplerIndex = descr.RegisterIndex;
}
uniforms.Add(ui);
}
}
return new(this, pw, true, vertexLayout, uniforms, memo);
}
public void FreePipeline(Pipeline pipeline)
{
// unavailable pipelines will have no opaque
if (pipeline.Opaque is not PipelineWrapper pw)
{
return;
}
pw.VertexDeclaration.Dispose();
pw.FragmentShader.IGLShader.Release();
pw.VertexShader.IGLShader.Release();
}
public void Internal_FreeShader(Shader shader)
{
var sw = (ShaderWrapper)shader.Opaque;
sw.Bytecode.Dispose();
sw.PS?.Dispose();
sw.VS?.Dispose();
}
private class UniformWrapper
{
public EffectHandle EffectHandle;
public ConstantTable CT;
}
private class PipelineWrapper // Disposable fields cleaned up by FreePipeline
{
public VertexDeclaration VertexDeclaration;
public ShaderWrapper VertexShader, FragmentShader;
public int VertexStride;
}
private class TextureWrapper
{
public Texture Texture;
public TextureAddress WrapClamp = TextureAddress.Clamp;
public TextureFilter MinFilter = TextureFilter.Point, MagFilter = TextureFilter.Point;
}
public VertexLayout CreateVertexLayout()
=> new(this, null);
public void Internal_FreeVertexLayout(VertexLayout layout)
{
}
public void BindPipeline(Pipeline pipeline)
{
_currPipeline = pipeline;
if (pipeline == null)
{
// unbind? i don't know
return;
}
var pw = (PipelineWrapper)pipeline.Opaque;
_device.PixelShader = pw.FragmentShader.PS;
_device.VertexShader = pw.VertexShader.VS;
_device.VertexDeclaration = pw.VertexDeclaration;
}
public void SetPipelineUniform(PipelineUniform uniform, bool value)
{
foreach (var ui in uniform.UniformInfos)
{
var uw = (UniformWrapper)ui.Opaque;
uw.CT.SetValue(_device, uw.EffectHandle, value);
}
}
public void SetPipelineUniformMatrix(PipelineUniform uniform, Matrix4x4 mat, bool transpose)
=> SetPipelineUniformMatrix(uniform, ref mat, transpose);
public void SetPipelineUniformMatrix(PipelineUniform uniform, ref Matrix4x4 mat, bool transpose)
{
foreach (var ui in uniform.UniformInfos)
{
var uw = (UniformWrapper)ui.Opaque;
uw.CT.SetValue(_device, uw.EffectHandle, mat.ToSharpDXMatrix(!transpose));
}
}
public void SetPipelineUniform(PipelineUniform uniform, Vector4 value)
{
foreach (var ui in uniform.UniformInfos)
{
var uw = (UniformWrapper)ui.Opaque;
uw.CT.SetValue(_device, uw.EffectHandle, value.ToSharpDXVector4());
}
}
public void SetPipelineUniform(PipelineUniform uniform, Vector2 value)
{
foreach (var ui in uniform.UniformInfos)
{
var uw = (UniformWrapper)ui.Opaque;
uw.CT.SetValue(_device, uw.EffectHandle, value.ToSharpDXVector2());
}
}
public void SetPipelineUniform(PipelineUniform uniform, float value)
{
foreach (var ui in uniform.UniformInfos)
{
var uw = (UniformWrapper)ui.Opaque;
uw.CT.SetValue(_device, uw.EffectHandle, value);
}
}
public void SetPipelineUniform(PipelineUniform uniform, Vector4[] values)
{
var v = Array.ConvertAll(values, v => v.ToSharpDXVector4());
foreach (var ui in uniform.UniformInfos)
{
var uw = (UniformWrapper)ui.Opaque;
uw.CT.SetValue(_device, uw.EffectHandle, v);
}
}
public void SetPipelineUniformSampler(PipelineUniform uniform, Texture2d tex)
{
if (uniform.Owner == null)
{
return; // uniform was optimized out
}
var tw = (TextureWrapper)tex.Opaque;
foreach (var ui in uniform.UniformInfos)
{
if (!ui.IsSampler)
{
throw new InvalidOperationException("Uniform was not a texture/sampler");
}
_device.SetTexture(ui.SamplerIndex, tw.Texture);
_device.SetSamplerState(ui.SamplerIndex, SamplerState.AddressU, (int)tw.WrapClamp);
_device.SetSamplerState(ui.SamplerIndex, SamplerState.AddressV, (int)tw.WrapClamp);
_device.SetSamplerState(ui.SamplerIndex, SamplerState.MinFilter, (int)tw.MinFilter);
_device.SetSamplerState(ui.SamplerIndex, SamplerState.MagFilter, (int)tw.MagFilter);
}
}
public void SetTextureWrapMode(Texture2d tex, bool clamp)
{
var tw = (TextureWrapper)tex.Opaque;
tw.WrapClamp = clamp ? TextureAddress.Clamp : TextureAddress.Wrap;
}
public void SetMinFilter(Texture2d texture, TextureMinFilter minFilter)
=> ((TextureWrapper)texture.Opaque).MinFilter = minFilter == TextureMinFilter.Linear
? TextureFilter.Linear
: TextureFilter.Point;
public void SetMagFilter(Texture2d texture, TextureMagFilter magFilter)
=> ((TextureWrapper)texture.Opaque).MagFilter = magFilter == TextureMagFilter.Linear
? TextureFilter.Linear
: TextureFilter.Point;
public Texture2d LoadTexture(Bitmap bitmap)
{
using var bmp = new BitmapBuffer(bitmap, new());
return LoadTexture(bmp);
}
public Texture2d LoadTexture(Stream stream)
{
using var bmp = new BitmapBuffer(stream, new());
return LoadTexture(bmp);
}
public Texture2d CreateTexture(int width, int height)
{
var tex = new Texture(_device, width, height, 1, Usage.None, Format.A8R8G8B8, Pool.Managed);
var tw = new TextureWrapper { Texture = tex };
var ret = new Texture2d(this, tw, width, height);
return ret;
}
public Texture2d WrapGLTexture2d(IntPtr glTexId, int width, int height)
{
// only used for OpenGL
return null;
}
/// <exception cref="InvalidOperationException">GDI+ call returned unexpected data</exception>
public unsafe void LoadTextureData(Texture2d tex, BitmapBuffer bmp)
{
var tw = (TextureWrapper)tex.Opaque;
var bmpData = bmp.LockBits();
try
{
var dr = tw.Texture.LockRectangle(0, LockFlags.None);
// TODO - do we need to handle odd sizes, weird pitches here?
if (bmp.Width * 4 != bmpData.Stride || bmpData.Stride != dr.Pitch)
{
throw new InvalidOperationException();
}
var srcSpan = new ReadOnlySpan<byte>(bmpData.Scan0.ToPointer(), bmpData.Stride * bmp.Height);
var dstSpan = new Span<byte>(dr.DataPointer.ToPointer(), dr.Pitch * bmp.Height);
srcSpan.CopyTo(dstSpan);
}
finally
{
tw.Texture.UnlockRectangle(0);
bmp.UnlockBits(bmpData);
}
}
public Texture2d LoadTexture(BitmapBuffer bmp)
{
var ret = CreateTexture(bmp.Width, bmp.Height);
LoadTextureData(ret, bmp);
return ret;
}
/// <exception cref="InvalidOperationException">Vortice call returned unexpected data</exception>
public BitmapBuffer ResolveTexture2d(Texture2d tex)
{
// TODO - lazy create and cache resolving target in RT
using var target = new Texture(_device, tex.IntWidth, tex.IntHeight, 1, Usage.None, Format.A8R8G8B8, Pool.SystemMemory);
var tw = (TextureWrapper)tex.Opaque;
using var rtSurf = tw.Texture.GetSurfaceLevel(0);
using var dstSurf = target.GetSurfaceLevel(0);
_device.GetRenderTargetData(rtSurf, dstSurf);
try
{
var dr = target.LockRectangle(0, LockFlags.ReadOnly);
if (dr.Pitch != tex.IntWidth * 4)
{
throw new InvalidOperationException();
}
var pixels = new int[tex.IntWidth * tex.IntHeight];
Marshal.Copy(dr.DataPointer, pixels, 0, tex.IntWidth * tex.IntHeight);
return new(tex.IntWidth, tex.IntHeight, pixels);
}
finally
{
target.UnlockRectangle(0);
}
}
public Texture2d LoadTexture(string path)
{
using var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
return LoadTexture(fs);
}
public Matrix4x4 CreateGuiProjectionMatrix(int w, int h)
{
return CreateGuiProjectionMatrix(new(w, h));
}
public Matrix4x4 CreateGuiViewMatrix(int w, int h, bool autoFlip)
{
return CreateGuiViewMatrix(new(w, h), autoFlip);
}
public Matrix4x4 CreateGuiProjectionMatrix(Size dims)
{
var ret = Matrix4x4.Identity;
ret.M11 = 2.0f / dims.Width;
ret.M22 = 2.0f / dims.Height;
return ret;
}
public Matrix4x4 CreateGuiViewMatrix(Size dims, bool autoFlip)
{
var ret = Matrix4x4.Identity;
ret.M22 = -1.0f;
ret.M41 = -dims.Width * 0.5f - 0.5f;
ret.M42 = dims.Height * 0.5f + 0.5f;
// auto-flipping isn't needed on D3D
return ret;
}
public void SetViewport(int x, int y, int width, int height)
{
_device.Viewport = new() { X = x, Y = y, Width = width, Height = height, MinDepth = 0, MaxDepth = 1 };
_device.ScissorRect = new(x, y, x + width, y + height);
}
public void SetViewport(int width, int height)
{
SetViewport(0, 0, width, height);
}
public void SetViewport(Size size)
{
SetViewport(size.Width, size.Height);
}
public void FreeRenderTarget(RenderTarget rt)
{
var tw = (TextureWrapper)rt.Texture2d.Opaque;
tw.Texture.Dispose();
tw.Texture = null;
_renderTargets.Remove(rt);
}
public RenderTarget CreateRenderTarget(int w, int h)
{
var tw = new TextureWrapper { Texture = CreateRenderTargetTexture(w, h) };
var tex = new Texture2d(this, tw, w, h);
var rt = new RenderTarget(this, tw, tex);
_renderTargets.Add(rt);
return rt;
}
private Texture CreateRenderTargetTexture(int w, int h)
=> new(_device, w, h, 1, Usage.RenderTarget, Format.A8R8G8B8, Pool.Default);
private void SuspendRenderTargets()
{
foreach (var tw in _renderTargets.Select(tex => (TextureWrapper)tex.Opaque))
{
tw.Texture.Dispose();
tw.Texture = null;
}
}
private void ResumeRenderTargets()
{
foreach (var rt in _renderTargets)
{
var tw = (TextureWrapper)rt.Opaque;
tw.Texture = CreateRenderTargetTexture(rt.Texture2d.IntWidth, rt.Texture2d.IntHeight);
}
}
public void BindRenderTarget(RenderTarget rt)
{
if (rt == null)
{
using var bb = _controlSwapchain.GetBackBuffer(0);
_device.SetRenderTarget(0, bb);
_device.DepthStencilSurface = null;
return;
}
// dispose doesn't seem necessary for reset here...
var tw = (TextureWrapper)rt.Opaque;
using var texSurface = tw.Texture.GetSurfaceLevel(0);
_device.SetRenderTarget(0, texSurface);
_device.DepthStencilSurface = null;
}
private delegate void DrawPrimitiveUPDelegate(Device device, PrimitiveType primitiveType, int primitiveCount, IntPtr vertexStreamZeroDataRef, int vertexStreamZeroStride);
private static readonly Lazy<DrawPrimitiveUPDelegate> _drawPrimitiveUP = new(() =>
{
var mi = typeof(Device).GetMethod("DrawPrimitiveUP", BindingFlags.Instance | BindingFlags.NonPublic);
return (DrawPrimitiveUPDelegate)Delegate.CreateDelegate(typeof(DrawPrimitiveUPDelegate), mi!);
});
private void DrawPrimitiveUP(PrimitiveType primitiveType, int primitiveCount, IntPtr vertexStreamZeroDataRef, int vertexStreamZeroStride)
=> _drawPrimitiveUP.Value(_device, primitiveType, primitiveCount, vertexStreamZeroDataRef, vertexStreamZeroStride);
public void Draw(IntPtr data, int count)
{
var pw = (PipelineWrapper)_currPipeline.Opaque;
// this is stupid, sharpdx only public exposes DrawUserPrimatives
// why is this bad? it takes in an array of T
// and uses the size of T to determine stride
// since stride for us is just completely variable, this is no good
// DrawPrimitiveUP is internal so we have to use this hack to use it directly
DrawPrimitiveUP(PrimitiveType.TriangleStrip, count - 2, data, pw.VertexStride);
}
public void BeginScene()
{
_device.BeginScene();
_device.SetRenderState(RenderState.CullMode, Cull.None);
_device.SetRenderState(RenderState.ZEnable, false);
_device.SetRenderState(RenderState.ZWriteEnable, false);
_device.SetRenderState(RenderState.Lighting, false);
}
public void EndScene()
=> _device.EndScene();
}
}

View File

@ -1,37 +0,0 @@
using System.Drawing;
using System.Numerics;
using SharpDX.Mathematics.Interop;
namespace BizHawk.Bizware.Graphics
{
internal static class SharpDXExtensions
{
// SharpDX RawMatrix and Numerics Matrix4x4 are identical in structure
public static RawMatrix ToSharpDXMatrix(this Matrix4x4 m, bool transpose)
{
// Transpose call could be inlined to reduce 2 sets of copies to 1
if (transpose)
{
m = Matrix4x4.Transpose(m);
}
return new()
{
M11 = m.M11, M12 = m.M12, M13 = m.M13, M14 = m.M14,
M21 = m.M21, M22 = m.M22, M23 = m.M23, M24 = m.M24,
M31 = m.M31, M32 = m.M32, M33 = m.M33, M34 = m.M34,
M41 = m.M41, M42 = m.M42, M43 = m.M43, M44 = m.M44
};
}
public static RawVector2 ToSharpDXVector2(this Vector2 v)
=> new(v.X, v.Y);
public static RawVector4 ToSharpDXVector4(this Vector4 v)
=> new(v.X, v.Y, v.Z, v.W);
public static RawColorBGRA ToSharpDXColor(this Color c)
=> new(c.B, c.G, c.R, c.A);
}
}

View File

@ -31,15 +31,18 @@ namespace BizHawk.Bizware.Graphics
string psProgram, vsProgram; string psProgram, vsProgram;
if (owner.API == "D3D9") switch (owner.API)
{ {
vsProgram = DefaultShader_d3d9; case "D3D11":
psProgram = DefaultShader_d3d9; vsProgram = DefaultShader_d3d9;
} psProgram = DefaultShader_d3d9;
else break;
{ case "OPENGL":
vsProgram = DefaultVertexShader_gl; vsProgram = DefaultVertexShader_gl;
psProgram = DefaultPixelShader_gl; psProgram = DefaultPixelShader_gl;
break;
default:
throw new InvalidOperationException();
} }
var vs = Owner.CreateVertexShader(vsProgram, "vsmain", true); var vs = Owner.CreateVertexShader(vsProgram, "vsmain", true);
@ -177,7 +180,6 @@ namespace BizHawk.Bizware.Graphics
SetModulateColorWhite(); SetModulateColorWhite();
} }
public void Flush() public void Flush()
{ {
// no batching, nothing to do here yet // no batching, nothing to do here yet
@ -381,6 +383,56 @@ namespace BizHawk.Bizware.Graphics
// shaders are hand-coded for each platform to make sure they stay as fast as possible // shaders are hand-coded for each platform to make sure they stay as fast as possible
#if false // this doesn't work for reasons unknown (TODO make this work)
public const string DefaultShader_d3d11 = @"
//vertex shader uniforms
float4x4 um44Modelview, um44Projection;
float4 uModulateColor;
//pixel shader uniforms
bool uSamplerEnable;
Texture2D texture0, texture1;
SamplerState uSampler0 = sampler_state { Texture = (texture0); };
struct VS_INPUT
{
float2 aPosition : POSITION;
float2 aTexcoord : TEXCOORD0;
float4 aColor : TEXCOORD1;
};
struct VS_OUTPUT
{
float4 vPosition : SV_POSITION;
float2 vTexcoord0 : TEXCOORD0;
float4 vCornerColor : COLOR0;
};
struct PS_INPUT
{
float4 vPosition : SV_POSITION;
float2 vTexcoord0 : TEXCOORD0;
float4 vCornerColor : COLOR0;
};
VS_OUTPUT vsmain(VS_INPUT src)
{
VS_OUTPUT dst;
dst.vPosition = float4(src.aPosition,0,1);
dst.vTexcoord0 = src.aTexcoord;
dst.vCornerColor = src.aColor;
return dst;
}
float4 psmain(PS_INPUT src) : SV_TARGET
{
float4 temp = src.vCornerColor;
temp *= texture0.Sample(uSampler0,src.vTexcoord0);
return temp;
}
";
#endif
public const string DefaultShader_d3d9 = @" public const string DefaultShader_d3d9 = @"
//vertex shader uniforms //vertex shader uniforms
float4x4 um44Modelview, um44Projection; float4x4 um44Modelview, um44Projection;
@ -407,6 +459,7 @@ struct VS_OUTPUT
struct PS_INPUT struct PS_INPUT
{ {
float4 vPosition : POSITION;
float2 vTexcoord0 : TEXCOORD0; float2 vTexcoord0 : TEXCOORD0;
float4 vCornerColor : COLOR0; float4 vCornerColor : COLOR0;
}; };

View File

@ -88,7 +88,7 @@ namespace BizHawk.Client.Common
LoadCustomFont(fceux); LoadCustomFont(fceux);
} }
if (dispMethod is EDispMethod.OpenGL or EDispMethod.D3D9) if (dispMethod is EDispMethod.OpenGL or EDispMethod.D3D11)
{ {
var fiHq2x = new FileInfo(Path.Combine(PathUtils.ExeDirectoryPath, "Shaders/BizHawk/hq2x.cgp")); var fiHq2x = new FileInfo(Path.Combine(PathUtils.ExeDirectoryPath, "Shaders/BizHawk/hq2x.cgp"));
if (fiHq2x.Exists) if (fiHq2x.Exists)
@ -102,7 +102,7 @@ namespace BizHawk.Client.Common
using var stream = fiScanlines.OpenRead(); using var stream = fiScanlines.OpenRead();
_shaderChainScanlines = new(_gl, new(stream), Path.Combine(PathUtils.ExeDirectoryPath, "Shaders/BizHawk")); _shaderChainScanlines = new(_gl, new(stream), Path.Combine(PathUtils.ExeDirectoryPath, "Shaders/BizHawk"));
} }
var bicubicPath = dispMethod == EDispMethod.D3D9 ? "Shaders/BizHawk/bicubic-normal.cgp" : "Shaders/BizHawk/bicubic-fast.cgp"; var bicubicPath = dispMethod is EDispMethod.D3D11 ? "Shaders/BizHawk/bicubic-normal.cgp" : "Shaders/BizHawk/bicubic-fast.cgp";
var fiBicubic = new FileInfo(Path.Combine(PathUtils.ExeDirectoryPath, bicubicPath)); var fiBicubic = new FileInfo(Path.Combine(PathUtils.ExeDirectoryPath, bicubicPath));
if (fiBicubic.Exists) if (fiBicubic.Exists)
{ {

View File

@ -45,7 +45,7 @@ namespace BizHawk.Client.Common.Filters
Passes = preset.Passes.ToArray(); Passes = preset.Passes.ToArray();
Errors = string.Empty; Errors = string.Empty;
if (owner.API is not ("OPENGL" or "D3D9")) if (owner.API is not ("OPENGL" or "D3D11"))
{ {
Errors = $"Unsupported API {owner.API}"; Errors = $"Unsupported API {owner.API}";
return; return;
@ -70,7 +70,7 @@ namespace BizHawk.Client.Common.Filters
path = owner.API switch path = owner.API switch
{ {
"OPENGL" => Path.ChangeExtension(path, ".glsl"), "OPENGL" => Path.ChangeExtension(path, ".glsl"),
"D3D9" => Path.ChangeExtension(path, ".hlsl"), "D3D11" => Path.ChangeExtension(path, ".hlsl"),
_ => throw new InvalidOperationException(), _ => throw new InvalidOperationException(),
}; };
} }

View File

@ -6,10 +6,10 @@ namespace BizHawk.Client.Common
{ {
public static class HostCapabilityDetector public static class HostCapabilityDetector
{ {
private static readonly Lazy<bool> _hasD3D9 = new(() => private static readonly Lazy<bool> _hasD3D11 = new(() =>
{ {
if (OSTailoredCode.IsUnixHost) return false; if (OSTailoredCode.IsUnixHost) return false;
var p = OSTailoredCode.LinkedLibManager.LoadOrZero("d3dx9_43.dll"); var p = OSTailoredCode.LinkedLibManager.LoadOrZero("d3d11.dll");
if (p == IntPtr.Zero) return false; if (p == IntPtr.Zero) return false;
OSTailoredCode.LinkedLibManager.FreeByPtr(p); OSTailoredCode.LinkedLibManager.FreeByPtr(p);
return true; return true;
@ -37,7 +37,7 @@ namespace BizHawk.Client.Common
return false; return false;
}); });
public static bool HasD3D9 => _hasD3D9.Value; public static bool HasD3D11 => _hasD3D11.Value;
public static bool HasXAudio2 => _hasXAudio2.Value; public static bool HasXAudio2 => _hasXAudio2.Value;
} }
} }

View File

@ -186,9 +186,9 @@ namespace BizHawk.Client.Common
public bool VSync { get; set; } public bool VSync { get; set; }
/// <summary> /// <summary>
/// Tries to use an alternate vsync mechanism, for video cards that just can't do it right /// Allows non-vsync'd video to tear, this is needed for VFR monitors reportedly
/// </summary> /// </summary>
public bool DispAlternateVsync { get; set; } public bool DispAllowTearing { get; set; }
// Display options // Display options
public bool DisplayFps { get; set; } public bool DisplayFps { get; set; }
@ -220,7 +220,7 @@ namespace BizHawk.Client.Common
public int DispPrescale { get; set; } = 1; public int DispPrescale { get; set; } = 1;
public EDispMethod DispMethod { get; set; } = HostCapabilityDetector.HasD3D9 && !OSTailoredCode.IsWine ? EDispMethod.D3D9 : EDispMethod.OpenGL; public EDispMethod DispMethod { get; set; } = HostCapabilityDetector.HasD3D11 && !OSTailoredCode.IsWine ? EDispMethod.D3D11 : EDispMethod.OpenGL;
public int DispChromeFrameWindowed { get; set; } = 2; public int DispChromeFrameWindowed { get; set; } = 2;
public bool DispChromeStatusBarWindowed { get; set; } = true; public bool DispChromeStatusBarWindowed { get; set; } = true;

View File

@ -263,7 +263,7 @@
<Compile Update="CustomControls/ViewportPanel.cs" SubType="Component" /> <Compile Update="CustomControls/ViewportPanel.cs" SubType="Component" />
<Compile Update="GraphicsImplementations/GLControlWrapper_SlimDX9.cs" SubType="Component" /> <Compile Update="GraphicsImplementations/GLControlWrapper_SlimDX9.cs" SubType="Component" />
<Compile Update="GraphicsImplementations/GraphicsControl_TK.cs" SubType="UserControl" /> <Compile Update="GraphicsImplementations/GraphicsControl_TK.cs" SubType="UserControl" />
<Compile Update="GraphicsImplementations/RetainedGraphicsControl.cs" SubType="UserControl" /> <Compile Update="GraphicsImplementations/RetainedGraphicsControl.cs" />
<Compile Update="LogWindow.cs" SubType="Form" /> <Compile Update="LogWindow.cs" SubType="Form" />
<Compile Update="LogWindow.Designer.cs" DependentUpon="LogWindow.cs" /> <Compile Update="LogWindow.Designer.cs" DependentUpon="LogWindow.cs" />
<EmbeddedResource Update="LogWindow.resx" DependentUpon="LogWindow.cs" /> <EmbeddedResource Update="LogWindow.resx" DependentUpon="LogWindow.cs" />

View File

@ -57,8 +57,6 @@ namespace BizHawk.Client.EmuHawk
protected override void UpdateSourceDrawingWork(JobInfo job) protected override void UpdateSourceDrawingWork(JobInfo job)
{ {
bool alternateVsync = false;
if (!job.Offscreen) if (!job.Offscreen)
{ {
//apply the vsync setting (should probably try to avoid repeating this) //apply the vsync setting (should probably try to avoid repeating this)
@ -73,12 +71,9 @@ namespace BizHawk.Client.EmuHawk
vsync = false; vsync = false;
//for now, it's assumed that the presentation panel is the main window, but that may not always be true //for now, it's assumed that the presentation panel is the main window, but that may not always be true
if (vsync && GlobalConfig.DispAlternateVsync && GlobalConfig.VSyncThrottle && _gl.DispMethodEnum is EDispMethod.D3D9)
{ // no cost currently to just always call this...
alternateVsync = true; _graphicsControl.AllowTearing(GlobalConfig.DispAllowTearing);
//unset normal vsync if we've chosen the alternate vsync
vsync = false;
}
//TODO - whats so hard about triple buffering anyway? just enable it always, and change api to SetVsync(enable,throttle) //TODO - whats so hard about triple buffering anyway? just enable it always, and change api to SetVsync(enable,throttle)
//maybe even SetVsync(enable,throttlemethod) or just SetVsync(enable,throttle,advanced) //maybe even SetVsync(enable,throttlemethod) or just SetVsync(enable,throttle,advanced)
@ -99,7 +94,6 @@ namespace BizHawk.Client.EmuHawk
// begin rendering on this context // begin rendering on this context
// should this have been done earlier? // should this have been done earlier?
// do i need to check this on an intel video card to see if running excessively is a problem? (it used to be in the FinalTarget command below, shouldn't be a problem) // do i need to check this on an intel video card to see if running excessively is a problem? (it used to be in the FinalTarget command below, shouldn't be a problem)
//GraphicsControl.Begin(); // CRITICAL POINT for yabause+GL
//TODO - auto-create and age these (and dispose when old) //TODO - auto-create and age these (and dispose when old)
int rtCounter = 0; int rtCounter = 0;
@ -119,17 +113,11 @@ namespace BizHawk.Client.EmuHawk
Debug.Assert(inFinalTarget); Debug.Assert(inFinalTarget);
// wait for vsync to begin
if (alternateVsync) ((dynamic) _gl).AlternateVsyncPass(0);
// present and conclude drawing // present and conclude drawing
_graphicsControl.SwapBuffers(); _graphicsControl.SwapBuffers();
// wait for vsync to end
if (alternateVsync) ((dynamic) _gl).AlternateVsyncPass(1);
// nope. don't do this. workaround for slow context switching on intel GPUs. just switch to another context when necessary before doing anything // nope. don't do this. workaround for slow context switching on intel GPUs. just switch to another context when necessary before doing anything
// presentationPanel.GraphicsControl.End(); // _graphicsControl.End();
} }
} }
} }

View File

@ -53,6 +53,9 @@ namespace BizHawk.Client.EmuHawk
_graphicsControl.End(); _graphicsControl.End();
} }
public override void AllowTearing(bool state)
=> _graphicsControl.AllowTearing(state);
public override void SetVsync(bool state) public override void SetVsync(bool state)
=> _graphicsControl.SetVsync(state); => _graphicsControl.SetVsync(state);

View File

@ -207,9 +207,9 @@ namespace BizHawk.Client.EmuHawk
// try to fallback on the faster option on Windows // try to fallback on the faster option on Windows
// if we're on a Unix platform, there's only 1 fallback here... // if we're on a Unix platform, there's only 1 fallback here...
1 when OSTailoredCode.IsUnixHost => (EDispMethod.GdiPlus, "GDI+"), 1 when OSTailoredCode.IsUnixHost => (EDispMethod.GdiPlus, "GDI+"),
1 or 2 when !OSTailoredCode.IsUnixHost => dispMethod == EDispMethod.D3D9 1 or 2 when !OSTailoredCode.IsUnixHost => dispMethod == EDispMethod.D3D11
? (EDispMethod.OpenGL, "OpenGL") ? (EDispMethod.OpenGL, "OpenGL")
: (EDispMethod.D3D9, "Direct3D9"), : (EDispMethod.D3D11, "Direct3D11"),
_ => (EDispMethod.GdiPlus, "GDI+") _ => (EDispMethod.GdiPlus, "GDI+")
}; };
@ -229,7 +229,7 @@ namespace BizHawk.Client.EmuHawk
switch (dispMethod) switch (dispMethod)
{ {
case EDispMethod.D3D9: case EDispMethod.D3D11:
if (OSTailoredCode.IsUnixHost || OSTailoredCode.IsWine) if (OSTailoredCode.IsUnixHost || OSTailoredCode.IsWine)
{ {
// possibly sharing config w/ Windows, assume the user wants the not-slow method (but don't change the config) // possibly sharing config w/ Windows, assume the user wants the not-slow method (but don't change the config)
@ -237,12 +237,12 @@ namespace BizHawk.Client.EmuHawk
} }
try try
{ {
return CheckRenderer(new IGL_D3D9()); return CheckRenderer(new IGL_D3D11());
} }
catch (Exception ex) catch (Exception ex)
{ {
var (method, name) = ChooseFallback(); var (method, name) = ChooseFallback();
new ExceptionBox(new Exception($"Initialization of Direct3D9 Display Method failed; falling back to {name}", ex)).ShowDialog(); new ExceptionBox(new Exception($"Initialization of Direct3D11 Display Method failed; falling back to {name}", ex)).ShowDialog();
return TryInitIGL(initialConfig.DispMethod = method); return TryInitIGL(initialConfig.DispMethod = method);
} }
case EDispMethod.OpenGL: case EDispMethod.OpenGL:

View File

@ -81,9 +81,9 @@
this.label6 = new BizHawk.WinForms.Controls.LocLabelEx(); this.label6 = new BizHawk.WinForms.Controls.LocLabelEx();
this.groupBox3 = new System.Windows.Forms.GroupBox(); this.groupBox3 = new System.Windows.Forms.GroupBox();
this.label13 = new BizHawk.WinForms.Controls.LocLabelEx(); this.label13 = new BizHawk.WinForms.Controls.LocLabelEx();
this.cbAlternateVsync = new System.Windows.Forms.CheckBox(); this.cbAllowTearing = new System.Windows.Forms.CheckBox();
this.label8 = new BizHawk.WinForms.Controls.LocLabelEx(); this.label8 = new BizHawk.WinForms.Controls.LocLabelEx();
this.rbD3D9 = new System.Windows.Forms.RadioButton(); this.rbD3D11 = new System.Windows.Forms.RadioButton();
this.label7 = new BizHawk.WinForms.Controls.LocLabelEx(); this.label7 = new BizHawk.WinForms.Controls.LocLabelEx();
this.rbGDIPlus = new System.Windows.Forms.RadioButton(); this.rbGDIPlus = new System.Windows.Forms.RadioButton();
this.tpMisc = new System.Windows.Forms.TabPage(); this.tpMisc = new System.Windows.Forms.TabPage();
@ -446,7 +446,7 @@
// //
this.label5.Location = new System.Drawing.Point(21, 123); this.label5.Location = new System.Drawing.Point(21, 123);
this.label5.Name = "label5"; this.label5.Name = "label5";
this.label5.Text = " • May malfunction on some systems.\r\n • May have increased performance for OpenGL" + this.label5.Text = " • May malfunction on some systems.\r\n • Will have increased performance for OpenGL" +
"-based emulation cores.\r\n • May have reduced performance on some systems.\r\n"; "-based emulation cores.\r\n • May have reduced performance on some systems.\r\n";
// //
// tabControl1 // tabControl1
@ -633,9 +633,9 @@
// groupBox3 // groupBox3
// //
this.groupBox3.Controls.Add(this.label13); this.groupBox3.Controls.Add(this.label13);
this.groupBox3.Controls.Add(this.cbAlternateVsync); this.groupBox3.Controls.Add(this.cbAllowTearing);
this.groupBox3.Controls.Add(this.label8); this.groupBox3.Controls.Add(this.label8);
this.groupBox3.Controls.Add(this.rbD3D9); this.groupBox3.Controls.Add(this.rbD3D11);
this.groupBox3.Controls.Add(this.label7); this.groupBox3.Controls.Add(this.label7);
this.groupBox3.Controls.Add(this.rbGDIPlus); this.groupBox3.Controls.Add(this.rbGDIPlus);
this.groupBox3.Controls.Add(this.label5); this.groupBox3.Controls.Add(this.label5);
@ -652,34 +652,34 @@
this.label13.Name = "label13"; this.label13.Name = "label13";
this.label13.Text = resources.GetString("label13.Text"); this.label13.Text = resources.GetString("label13.Text");
this.label13.Click += new System.EventHandler(this.Label13_Click); this.label13.Click += new System.EventHandler(this.Label13_Click);
this.label13.DoubleClick += new System.EventHandler(this.Label13_Click); this.label13.DoubleClick += new System.EventHandler(this.Label13_Click);
// //
// cbAlternateVsync // cbAllowTearing
// //
this.cbAlternateVsync.AutoSize = true; this.cbAllowTearing.AutoSize = true;
this.cbAlternateVsync.Location = new System.Drawing.Point(28, 60); this.cbAllowTearing.Location = new System.Drawing.Point(28, 60);
this.cbAlternateVsync.Name = "cbAlternateVsync"; this.cbAllowTearing.Name = "cbAllowTearing";
this.cbAlternateVsync.Size = new System.Drawing.Size(15, 14); this.cbAllowTearing.Size = new System.Drawing.Size(15, 14);
this.cbAlternateVsync.TabIndex = 21; this.cbAllowTearing.TabIndex = 21;
this.cbAlternateVsync.UseVisualStyleBackColor = true; this.cbAllowTearing.UseVisualStyleBackColor = true;
// //
// label8 // label8
// //
this.label8.Location = new System.Drawing.Point(21, 30); this.label8.Location = new System.Drawing.Point(21, 30);
this.label8.Name = "label8"; this.label8.Name = "label8";
this.label8.Text = " • Best compatibility\r\n • May have trouble with OpenGL-based cores (N64)\r\n"; this.label8.Text = " • Best compatibility\r\n • Decreased performance for OpenGL-based cores (NDS, 3DS)\r\n";
// //
// rbD3D9 // rbD3D11
// //
this.rbD3D9.AutoSize = true; this.rbD3D11.AutoSize = true;
this.rbD3D9.Checked = true; this.rbD3D11.Checked = true;
this.rbD3D9.Location = new System.Drawing.Point(6, 10); this.rbD3D11.Location = new System.Drawing.Point(6, 10);
this.rbD3D9.Name = "rbD3D9"; this.rbD3D11.Name = "rbD3D11";
this.rbD3D9.Size = new System.Drawing.Size(73, 17); this.rbD3D11.Size = new System.Drawing.Size(73, 17);
this.rbD3D9.TabIndex = 19; this.rbD3D11.TabIndex = 19;
this.rbD3D9.TabStop = true; this.rbD3D11.TabStop = true;
this.rbD3D9.Text = "Direct3D9"; this.rbD3D11.Text = "Direct3D11";
this.rbD3D9.UseVisualStyleBackColor = true; this.rbD3D11.UseVisualStyleBackColor = true;
// //
// label7 // label7
// //
@ -1050,7 +1050,7 @@
private System.Windows.Forms.RadioButton rbGDIPlus; private System.Windows.Forms.RadioButton rbGDIPlus;
private System.Windows.Forms.TabPage tpMisc; private System.Windows.Forms.TabPage tpMisc;
private BizHawk.WinForms.Controls.LocLabelEx label8; private BizHawk.WinForms.Controls.LocLabelEx label8;
private System.Windows.Forms.RadioButton rbD3D9; private System.Windows.Forms.RadioButton rbD3D11;
private System.Windows.Forms.TabPage tabPage1; private System.Windows.Forms.TabPage tabPage1;
private System.Windows.Forms.CheckBox cbStatusBarWindowed; private System.Windows.Forms.CheckBox cbStatusBarWindowed;
private BizHawk.WinForms.Controls.LocLabelEx label9; private BizHawk.WinForms.Controls.LocLabelEx label9;
@ -1078,7 +1078,7 @@
private System.Windows.Forms.TextBox txtCustomARX; private System.Windows.Forms.TextBox txtCustomARX;
private System.Windows.Forms.CheckBox cbAutoPrescale; private System.Windows.Forms.CheckBox cbAutoPrescale;
private BizHawk.WinForms.Controls.LocLabelEx label13; private BizHawk.WinForms.Controls.LocLabelEx label13;
private System.Windows.Forms.CheckBox cbAlternateVsync; private System.Windows.Forms.CheckBox cbAllowTearing;
private BizHawk.WinForms.Controls.LocLabelEx label1; private BizHawk.WinForms.Controls.LocLabelEx label1;
private System.Windows.Forms.CheckBox cbFullscreenHacks; private System.Windows.Forms.CheckBox cbFullscreenHacks;
private System.Windows.Forms.Button btnDefaults; private System.Windows.Forms.Button btnDefaults;

View File

@ -53,7 +53,7 @@ namespace BizHawk.Client.EmuHawk
cbFullscreenHacks.Checked = _config.DispFullscreenHacks; cbFullscreenHacks.Checked = _config.DispFullscreenHacks;
cbAutoPrescale.Checked = _config.DispAutoPrescale; cbAutoPrescale.Checked = _config.DispAutoPrescale;
cbAlternateVsync.Checked = _config.DispAlternateVsync; cbAllowTearing.Checked = _config.DispAllowTearing;
if (_config.DispSpeedupFeatures == 2) rbDisplayFull.Checked = true; if (_config.DispSpeedupFeatures == 2) rbDisplayFull.Checked = true;
if (_config.DispSpeedupFeatures == 1) rbDisplayMinimal.Checked = true; if (_config.DispSpeedupFeatures == 1) rbDisplayMinimal.Checked = true;
@ -63,7 +63,7 @@ namespace BizHawk.Client.EmuHawk
rbOpenGL.Checked = _config.DispMethod == EDispMethod.OpenGL; rbOpenGL.Checked = _config.DispMethod == EDispMethod.OpenGL;
rbGDIPlus.Checked = _config.DispMethod == EDispMethod.GdiPlus; rbGDIPlus.Checked = _config.DispMethod == EDispMethod.GdiPlus;
rbD3D9.Checked = _config.DispMethod == EDispMethod.D3D9; rbD3D11.Checked = _config.DispMethod == EDispMethod.D3D11;
cbStatusBarWindowed.Checked = _config.DispChromeStatusBarWindowed; cbStatusBarWindowed.Checked = _config.DispChromeStatusBarWindowed;
cbCaptionWindowed.Checked = _config.DispChromeCaptionWindowed; cbCaptionWindowed.Checked = _config.DispChromeCaptionWindowed;
@ -110,11 +110,11 @@ namespace BizHawk.Client.EmuHawk
RefreshAspectRatioOptions(); RefreshAspectRatioOptions();
if (!HostCapabilityDetector.HasD3D9) if (!HostCapabilityDetector.HasD3D11)
{ {
rbD3D9.Enabled = false; rbD3D11.Enabled = false;
rbD3D9.AutoCheck = false; rbD3D11.AutoCheck = false;
cbAlternateVsync.Enabled = false; cbAllowTearing.Enabled = false;
label13.Enabled = false; label13.Enabled = false;
label8.Enabled = false; label8.Enabled = false;
} }
@ -146,7 +146,7 @@ namespace BizHawk.Client.EmuHawk
_config.DispFullscreenHacks = cbFullscreenHacks.Checked; _config.DispFullscreenHacks = cbFullscreenHacks.Checked;
_config.DispAutoPrescale = cbAutoPrescale.Checked; _config.DispAutoPrescale = cbAutoPrescale.Checked;
_config.DispAlternateVsync = cbAlternateVsync.Checked; _config.DispAllowTearing = cbAllowTearing.Checked;
_config.DispChromeStatusBarWindowed = cbStatusBarWindowed.Checked; _config.DispChromeStatusBarWindowed = cbStatusBarWindowed.Checked;
_config.DispChromeCaptionWindowed = cbCaptionWindowed.Checked; _config.DispChromeCaptionWindowed = cbCaptionWindowed.Checked;
@ -228,8 +228,8 @@ namespace BizHawk.Client.EmuHawk
_config.DispMethod = EDispMethod.OpenGL; _config.DispMethod = EDispMethod.OpenGL;
if(rbGDIPlus.Checked) if(rbGDIPlus.Checked)
_config.DispMethod = EDispMethod.GdiPlus; _config.DispMethod = EDispMethod.GdiPlus;
if(rbD3D9.Checked) if(rbD3D11.Checked)
_config.DispMethod = EDispMethod.D3D9; _config.DispMethod = EDispMethod.D3D11;
if (int.TryParse(txtCropLeft.Text, out int dispCropLeft)) if (int.TryParse(txtCropLeft.Text, out int dispCropLeft))
{ {
@ -368,7 +368,7 @@ namespace BizHawk.Client.EmuHawk
private void Label13_Click(object sender, EventArgs e) private void Label13_Click(object sender, EventArgs e)
{ {
cbAlternateVsync.Checked ^= true; cbAllowTearing.Checked ^= true;
} }
private void BtnDefaults_Click(object sender, EventArgs e) private void BtnDefaults_Click(object sender, EventArgs e)

View File

@ -121,9 +121,9 @@
<value>17, 17</value> <value>17, 17</value>
</metadata> </metadata>
<data name="label13.Text" xml:space="preserve"> <data name="label13.Text" xml:space="preserve">
<value>Alternate VSync Method: Some GPUs have problems VSyncing. It seems <value>Allow Tearing: Allows fullscreen to tear when VSync is disabled.
to manifest on full-screen windows. There will be hiccups when throttling This is required for variable frame rate (VFR) monitors to properly work.
to VSync. Use this to try and solve it (busy loop; burns major CPU)</value> Fast forward performance might decrease with tearing allowed.</value>
</data> </data>
<data name="label1.Text" xml:space="preserve"> <data name="label1.Text" xml:space="preserve">
<value>For Windows operating systems &gt;= Vista, with <value>For Windows operating systems &gt;= Vista, with