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
(
float4 position : POSITION,
float2 tex : TEXCOORD0,
float4 position : POSITION,
float2 tex : TEXCOORD0,
uniform float4x4 modelViewProj,
uniform float4x4 modelViewProj,
out float4 oPosition : POSITION,
out float2 oTexcoord : TEXCOORD0
out float4 oPosition : POSITION,
out float2 oTex0 : TEXCOORD0,
out float oTex1 : TEXCOORD1
)
{
oPosition = mul(modelViewProj, position);
oTexcoord = tex;
oTex0 = tex;
oTex1 = position.y;
}
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);
if(floor(wpos.y/2) != floor(wpos.y)/2) temp.rgb *= uIntensity;
float4 temp = tex2D(s_p, tex0);
if (floor(tex1 / 2) != floor(tex1) / 2) temp.rgb *= uIntensity;
return temp;
}

View File

@ -46,13 +46,14 @@ struct input
float2 video_size;
float2 texture_size;
float2 output_size;
float frame_count;
float frame_direction;
float frame_count;
float frame_direction;
float frame_rotation;
};
struct out_vertex {
struct out_vertex
{
float2 texCoord : TEXCOORD0;
float4 t1 : TEXCOORD1;
float4 t2 : TEXCOORD2;
@ -65,26 +66,29 @@ struct out_vertex {
};
/* VERTEX_SHADER */
out_vertex main_vertex
void main_vertex
(
float4 position : POSITION,
out float4 oPosition : POSITION,
float2 texCoord1 : TEXCOORD0,
uniform float4x4 modelViewProj,
uniform input IN
uniform float4x4 modelViewProj,
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);
float dx = ps.x;
float dy = ps.y;
oPosition = mul(modelViewProj, position);
oPosition = mul(modelViewProj, position);
// This line fix a bug in ATI cards.
float2 tex = texCoord1 + float2(0.0000001, 0.0000001);
out_vertex OUT = {
out_vertex OUT =
{
tex,
float4(tex,tex) + float4( -dx, -dy, 0.0, -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)
};
return OUT;
oVAR = 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);
float3 c00 = tex2D(s_p, VAR.t1.xy).xyz;
float3 c01 = tex2D(s_p, VAR.t1.zw).xyz;
float3 c02 = tex2D(s_p, VAR.t2.xy).xyz;
float3 c03 = tex2D(s_p, VAR.t2.zw).xyz;
float3 c10 = tex2D(s_p, VAR.t3.xy).xyz;
float3 c11 = tex2D(s_p, VAR.texCoord).xyz;
float3 c12 = tex2D(s_p, VAR.t3.zw).xyz;
float3 c13 = tex2D(s_p, VAR.t4.xy).xyz;
float3 c20 = tex2D(s_p, VAR.t4.zw).xyz;
float3 c21 = tex2D(s_p, VAR.t5.xy).xyz;
float3 c22 = tex2D(s_p, VAR.t5.zw).xyz;
float3 c23 = tex2D(s_p, VAR.t6.xy).xyz;
float3 c30 = tex2D(s_p, VAR.t6.zw).xyz;
float3 c31 = tex2D(s_p, VAR.t7.xy).xyz;
float3 c32 = tex2D(s_p, VAR.t7.zw).xyz;
float3 c33 = tex2D(s_p, VAR.t8.xy).xyz;
float2 fp = frac(VAR.texCoord*IN.texture_size);
float3 c00 = tex2D(s_p, VAR.t1.xy).xyz;
float3 c01 = tex2D(s_p, VAR.t1.zw).xyz;
float3 c02 = tex2D(s_p, VAR.t2.xy).xyz;
float3 c03 = tex2D(s_p, VAR.t2.zw).xyz;
float3 c10 = tex2D(s_p, VAR.t3.xy).xyz;
float3 c11 = tex2D(s_p, VAR.texCoord).xyz;
float3 c12 = tex2D(s_p, VAR.t3.zw).xyz;
float3 c13 = tex2D(s_p, VAR.t4.xy).xyz;
float3 c20 = tex2D(s_p, VAR.t4.zw).xyz;
float3 c21 = tex2D(s_p, VAR.t5.xy).xyz;
float3 c22 = tex2D(s_p, VAR.t5.zw).xyz;
float3 c23 = tex2D(s_p, VAR.t6.xy).xyz;
float3 c30 = tex2D(s_p, VAR.t6.zw).xyz;
float3 c31 = tex2D(s_p, VAR.t7.xy).xyz;
float3 c32 = tex2D(s_p, VAR.t7.zw).xyz;
float3 c33 = tex2D(s_p, VAR.t8.xy).xyz;
float4x4 red_matrix = float4x4(c00.x, c01.x, c02.x, c03.x,
c10.x, c11.x, c12.x, c13.x,
c20.x, c21.x, c22.x, c23.x,
c30.x, c31.x, c32.x, c33.x);
float4x4 red_matrix = float4x4(c00.x, c01.x, c02.x, c03.x,
c10.x, c11.x, c12.x, c13.x,
c20.x, c21.x, c22.x, c23.x,
c30.x, c31.x, c32.x, c33.x);
float4x4 green_matrix = float4x4(c00.y, c01.y, c02.y, c03.y,
c10.y, c11.y, c12.y, c13.y,
c20.y, c21.y, c22.y, c23.y,
c30.y, c31.y, c32.y, c33.y);
float4x4 green_matrix = float4x4(c00.y, c01.y, c02.y, c03.y,
c10.y, c11.y, c12.y, c13.y,
c20.y, c21.y, c22.y, c23.y,
c30.y, c31.y, c32.y, c33.y);
float4x4 blue_matrix = float4x4(c00.z, c01.z, c02.z, c03.z,
c10.z, c11.z, c12.z, c13.z,
c20.z, c21.z, c22.z, c23.z,
c30.z, c31.z, c32.z, c33.z);
float4x4 blue_matrix = float4x4(c00.z, c01.z, c02.z, c03.z,
c10.z, c11.z, c12.z, c13.z,
c20.z, c21.z, c22.z, c23.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));
float1x4 Py_invY = mul(float1x4(fp.y*fp.y*fp.y, fp.y*fp.y, fp.y, 1.0), invY);
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);
float red = mul(Py_invY, mul( red_matrix, invX_Px));
float green = mul(Py_invY, mul(green_matrix, invX_Px));
float blue = mul(Py_invY, mul( blue_matrix, invX_Px));
float red = mul(Py_invY, mul( red_matrix, invX_Px));
float green = mul(Py_invY, mul(green_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 */
void main_vertex
(
float4 position : POSITION,
//float4 color : COLOR,
float2 texCoord1 : TEXCOORD0,
float4 position : POSITION,
float2 texCoord1 : TEXCOORD0,
uniform float4x4 modelViewProj,
uniform float4x4 modelViewProj,
out float4 oPosition : POSITION,
//out float4 oColor : COLOR,
out float2 otexCoord : TEXCOORD
)
out float4 oPosition : POSITION,
out float2 otexCoord : TEXCOORD
)
{
oPosition = mul(modelViewProj, position);
//oColor = color;
otexCoord = texCoord1;
oPosition = mul(modelViewProj, position);
otexCoord = texCoord1;
}
struct output
{
float4 color : COLOR;
float4 color : COLOR;
};
struct input
{
float2 video_size;
float2 texture_size;
float2 output_size;
float frame_count;
float frame_direction;
float frame_rotation;
float2 video_size;
float2 texture_size;
float2 output_size;
float frame_count;
float frame_direction;
float frame_rotation;
};
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 pos = tex.xy + stepxy * 0.5;
float2 f = frac(pos / stepxy);
float2 stepxy = float2(1.0/IN.texture_size.x, 1.0/IN.texture_size.y);
float2 pos = tex.xy + stepxy * 0.5;
float2 f = frac(pos / stepxy);
float4 linetaps = weight4(1.0 - f.x);
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);
// final sum and weight normalization
output OUT;
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 * 2.0, xpos, linetaps, s_p) * columntaps.b +
line_run(xystart.y + stepxy.y * 3.0, xpos, linetaps, s_p) * columntaps.a,1);
// final sum and weight normalization
output OUT;
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 * 2.0, xpos, linetaps, s_p) * columntaps.b +
line_run(xystart.y + stepxy.y * 3.0, xpos, linetaps, s_p) * columntaps.a,1);
return OUT;
}

View File

@ -9,16 +9,17 @@
void main_vertex
(
float4 position : POSITION,
out float4 oPosition : POSITION,
uniform float4x4 modelViewProj,
float4 position : POSITION,
float2 tex : TEXCOORD,
float2 tex : TEXCOORD,
out float2 oTex : TEXCOORD
uniform float4x4 modelViewProj,
out float4 oPosition : POSITION,
out float2 oTex : TEXCOORD
)
{
oPosition = mul(modelViewProj, position);
oTex = tex;
oPosition = mul(modelViewProj, position);
oTex = tex;
}
// Tweakables.
@ -34,7 +35,7 @@ float3 grayscale(float3 col)
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;
res = lerp(grayscale(res), res, saturation); // Apply saturation

View File

@ -1,51 +1,51 @@
struct tex_coords
{
float2 c00 : TEXCOORD0;
float2 c01 : TEXCOORD1;
float2 c02 : TEXCOORD2;
float2 c10 : TEXCOORD3;
float2 c11 : TEXCOORD4;
float2 c12 : TEXCOORD5;
float2 c20 : TEXCOORD6;
float2 c21 : TEXCOORD7;
float2 c22 : COLOR0;
float2 c00 : TEXCOORD0;
float2 c01 : TEXCOORD1;
float2 c02 : TEXCOORD2;
float2 c10 : TEXCOORD3;
float2 c11 : TEXCOORD4;
float2 c12 : TEXCOORD5;
float2 c20 : TEXCOORD6;
float2 c21 : TEXCOORD7;
float2 c22 : COLOR0;
};
struct input
{
float2 video_size;
float2 texture_size;
float2 output_size;
float2 video_size;
float2 texture_size;
float2 output_size;
};
void main_vertex
(
float4 position : POSITION,
out float4 oPosition : POSITION,
uniform float4x4 modelViewProj,
float4 position : POSITION,
float2 tex : TEXCOORD0,
float2 tex : TEXCOORD0,
uniform float4x4 modelViewProj,
uniform input IN,
uniform input IN,
out tex_coords coords
out float4 oPosition : POSITION,
out tex_coords coords
)
{
oPosition = mul(modelViewProj, position);
oPosition = mul(modelViewProj, position);
float2 texsize = IN.texture_size;
float2 delta = 0.5 / texsize;
float dx = delta.x;
float dy = delta.y;
float2 texsize = IN.texture_size;
float2 delta = 0.5 / texsize;
float dx = delta.x;
float dy = delta.y;
coords.c00 = tex + float2(-dx, -dy);
coords.c01 = tex + float2(-dx, 0.0);
coords.c02 = tex + float2(-dx, dy);
coords.c10 = tex + float2(0.0, -dy);
coords.c11 = tex + float2(0.0, 0.0);
coords.c12 = tex + float2(0.0, dy);
coords.c20 = tex + float2(dx, -dy);
coords.c21 = tex + float2(dx, 0);
coords.c22 = tex + float2(dx, dy);
coords.c00 = tex + float2(-dx, -dy);
coords.c01 = tex + float2(-dx, 0.0);
coords.c02 = tex + float2(-dx, dy);
coords.c10 = tex + float2(0.0, -dy);
coords.c11 = tex + float2(0.0, 0.0);
coords.c12 = tex + float2(0.0, dy);
coords.c20 = tex + float2(dx, -dy);
coords.c21 = tex + float2(dx, 0);
coords.c22 = tex + float2(dx, dy);
}
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 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 c01 = tex2D(s_p, co.c01).xyz;
float3 c02 = tex2D(s_p, co.c02).xyz;
float3 c10 = tex2D(s_p, co.c10).xyz;
float3 c11 = tex2D(s_p, co.c11).xyz;
float3 c12 = tex2D(s_p, co.c12).xyz;
float3 c20 = tex2D(s_p, co.c20).xyz;
float3 c21 = tex2D(s_p, co.c21).xyz;
float3 c22 = tex2D(s_p, co.c22).xyz;
float3 dt = float3(1.0,1.0,1.0);
float3 c00 = tex2D(s_p, co.c00).xyz;
float3 c01 = tex2D(s_p, co.c01).xyz;
float3 c02 = tex2D(s_p, co.c02).xyz;
float3 c10 = tex2D(s_p, co.c10).xyz;
float3 c11 = tex2D(s_p, co.c11).xyz;
float3 c12 = tex2D(s_p, co.c12).xyz;
float3 c20 = tex2D(s_p, co.c20).xyz;
float3 c21 = tex2D(s_p, co.c21).xyz;
float3 c22 = tex2D(s_p, co.c22).xyz;
float3 dt = float3(1.0,1.0,1.0);
float md1 = dot(abs(c00 - c22), dt);
float md2 = dot(abs(c02 - c20), dt);
float md1 = dot(abs(c00 - c22), dt);
float md2 = dot(abs(c02 - c20), dt);
float w1 = dot(abs(c22 - c11), dt) * md2;
float w2 = dot(abs(c02 - c11), dt) * md1;
float w3 = dot(abs(c00 - c11), dt) * md2;
float w4 = dot(abs(c20 - c11), dt) * md1;
float w1 = dot(abs(c22 - c11), dt) * md2;
float w2 = dot(abs(c02 - c11), dt) * md1;
float w3 = dot(abs(c00 - c11), dt) * md2;
float w4 = dot(abs(c20 - c11), dt) * md1;
float t1 = w1 + w3;
float t2 = w2 + w4;
float ww = max(t1, t2) + 0.0001;
float t1 = w1 + w3;
float t2 = w2 + w4;
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 lc2 = k / (0.12 * dot(c01 + c21 + 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);
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);
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);
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);
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);
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
{
float2 video_size;
float2 texture_size;
float2 output_size;
float2 video_size;
float2 texture_size;
float2 output_size;
};
void main_vertex
(
float4 position : POSITION,
out float4 oPosition : POSITION,
uniform float4x4 modelViewProj,
float4 position : POSITION,
float2 tex : TEXCOORD0,
float2 tex : TEXCOORD,
uniform float4x4 modelViewProj,
uniform input IN,
uniform input IN,
out float2 oTexcoord : TEXCOORD,
out float2 oFakeResolution : TEXCOORD1
out float4 oPosition : POSITION,
out float2 oTexcoord : TEXCOORD0,
out float2 oFakeResolution : TEXCOORD1
)
{
oPosition = mul(modelViewProj, position);
oPosition = mul(modelViewProj, position);
oTexcoord = tex;
oFakeResolution = IN.texture_size;
}
@ -39,105 +37,112 @@ void main_vertex
//// EFFECT CONSTANTS : TWEAK THEM!
////
// Size of the border effect
static const float2 OverscanMaskHardness = {12.0f ,12.0f };
// Attenuation of the border effect
static const float OverscanMaskPower = 4.0f;
// Intensity of the border effect
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;
// Size of the border effect
static const float2 OverscanMaskHardness = {12.0f ,12.0f };
// Attenuation of the border effect
static const float OverscanMaskPower = 4.0f;
// Intensity of the border effect
static const float OverscanIntensity = 0.96f;
// Ghost Sampling : enable define to activate
#define GHOST_SAMPLING;
// Intensity of the TV Corners (round-ness) deformation
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
#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};
// 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
#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));
}
//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
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;
}
// 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);
float Weight = 1.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;
Weight += GhostLatencyIntensity * curweight;
}
return Out/Weight;
}
// 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);
for(int j = 0; j < 5; j++)
{
for(int i = 0; i < 5; i++)
{
float2 offset = float2(BloomPositions[i],BloomPositions[j]) / r;
Out += tex2D(s, t + offset).rgb * BloomWeights[i][j];
}
}
return pow(Out, BloomExponent) * BloomIntensity;
}
// 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
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
#ifdef GHOST_SAMPLING
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;
}
}
float3 LatencyRGB = SignalLatencyRGB * (1.0-(latencyweight/GhostNumSamples));
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 PixelMaskScanline = pow(saturate(4*frac(ScreenPos.y*FakeResolution.y)*(1.0f-frac(ScreenPos.y*FakeResolution.y))),FakePixelMaskPower.y);
float3 PixelRGB = float3 (
((PixelMaskR*PixelMaskScanline * FakePixelMaskGain)+FakePixelMaskOffset) * SMP_Red.x ,
((PixelMaskG*PixelMaskScanline * FakePixelMaskGain)+FakePixelMaskOffset) * SMP_Green.y ,
((PixelMaskB*PixelMaskScanline * FakePixelMaskGain)+FakePixelMaskOffset) * SMP_Blue.z
);
float3 PixelRGB = float3(((PixelMaskR*PixelMaskScanline * FakePixelMaskGain)+FakePixelMaskOffset) * SMP_Red.x,
((PixelMaskG*PixelMaskScanline * FakePixelMaskGain)+FakePixelMaskOffset) * SMP_Green.y,
((PixelMaskB*PixelMaskScanline * FakePixelMaskGain)+FakePixelMaskOffset) * SMP_Blue.z);
// Non-Pixelated Image
float3 ImageRGB = tex2D(Texture, ScreenPos).xyz;
return lerp(ImageRGB, PixelRGB, FakePixelEffectBlend) * mask;
//return float3(PixelMaskR*PixelMaskScanline,PixelMaskG*PixelMaskScanline,PixelMaskB*PixelMaskScanline);
}
float4 main_fragment
(
in float2 TexCoord : TEXCOORD,
in float4 vpos : POSITION,
in float2 TexCoord : TEXCOORD0,
in float2 FakeResolution : TEXCOORD1,
in float2 wpos : WPOS,
uniform sampler2D s_p : TEXUNIT0,
uniform float Time
) : COLOR

View File

@ -18,7 +18,6 @@
<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="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.Extensions.Creative" 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.Resources.Extensions" Version="7.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.XAudio2" Version="2.4.2" /> <!-- last version with .NET Standard 2.0 support -->
</ItemGroup>

View File

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

View File

@ -9,7 +9,7 @@ namespace BizHawk.Bizware.BizwareGL
/// <summary>
/// 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
/// 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...
/// </summary>

View File

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

View File

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

View File

@ -27,6 +27,11 @@ namespace BizHawk.Bizware.Graphics.Controls
/// </summary>
private GDIPlusRenderTarget RenderTarget { get; }
public override void AllowTearing(bool state)
{
// not controllable
}
public override void SetVsync(bool state)
{
// 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)
{
MakeContextCurrent();

View File

@ -4,6 +4,12 @@ namespace BizHawk.Bizware.Graphics.Controls
{
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>
/// Sets whether presentation operations on this control will vsync
/// </summary>

View File

@ -14,7 +14,7 @@ namespace BizHawk.Bizware.Graphics.Controls
GraphicsControl ret = gl switch
{
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),
_ => throw new InvalidOperationException()
};

View File

@ -9,8 +9,9 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Silk.NET.OpenGL.Legacy" />
<PackageReference Include="SharpDX.Direct3D9" />
<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" />
</ItemGroup>
</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;
if (owner.API == "D3D9")
switch (owner.API)
{
vsProgram = DefaultShader_d3d9;
psProgram = DefaultShader_d3d9;
}
else
{
vsProgram = DefaultVertexShader_gl;
psProgram = DefaultPixelShader_gl;
case "D3D11":
vsProgram = DefaultShader_d3d9;
psProgram = DefaultShader_d3d9;
break;
case "OPENGL":
vsProgram = DefaultVertexShader_gl;
psProgram = DefaultPixelShader_gl;
break;
default:
throw new InvalidOperationException();
}
var vs = Owner.CreateVertexShader(vsProgram, "vsmain", true);
@ -177,7 +180,6 @@ namespace BizHawk.Bizware.Graphics
SetModulateColorWhite();
}
public void Flush()
{
// 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
#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 = @"
//vertex shader uniforms
float4x4 um44Modelview, um44Projection;
@ -407,6 +459,7 @@ struct VS_OUTPUT
struct PS_INPUT
{
float4 vPosition : POSITION;
float2 vTexcoord0 : TEXCOORD0;
float4 vCornerColor : COLOR0;
};

View File

@ -88,7 +88,7 @@ namespace BizHawk.Client.Common
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"));
if (fiHq2x.Exists)
@ -102,7 +102,7 @@ namespace BizHawk.Client.Common
using var stream = fiScanlines.OpenRead();
_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));
if (fiBicubic.Exists)
{

View File

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

View File

@ -6,10 +6,10 @@ namespace BizHawk.Client.Common
{
public static class HostCapabilityDetector
{
private static readonly Lazy<bool> _hasD3D9 = new(() =>
private static readonly Lazy<bool> _hasD3D11 = new(() =>
{
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;
OSTailoredCode.LinkedLibManager.FreeByPtr(p);
return true;
@ -37,7 +37,7 @@ namespace BizHawk.Client.Common
return false;
});
public static bool HasD3D9 => _hasD3D9.Value;
public static bool HasD3D11 => _hasD3D11.Value;
public static bool HasXAudio2 => _hasXAudio2.Value;
}
}

View File

@ -186,9 +186,9 @@ namespace BizHawk.Client.Common
public bool VSync { get; set; }
/// <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>
public bool DispAlternateVsync { get; set; }
public bool DispAllowTearing { get; set; }
// Display options
public bool DisplayFps { get; set; }
@ -220,7 +220,7 @@ namespace BizHawk.Client.Common
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 bool DispChromeStatusBarWindowed { get; set; } = true;

View File

@ -263,7 +263,7 @@
<Compile Update="CustomControls/ViewportPanel.cs" SubType="Component" />
<Compile Update="GraphicsImplementations/GLControlWrapper_SlimDX9.cs" SubType="Component" />
<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.Designer.cs" 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)
{
bool alternateVsync = false;
if (!job.Offscreen)
{
//apply the vsync setting (should probably try to avoid repeating this)
@ -73,12 +71,9 @@ namespace BizHawk.Client.EmuHawk
vsync = false;
//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)
{
alternateVsync = true;
//unset normal vsync if we've chosen the alternate vsync
vsync = false;
}
// no cost currently to just always call this...
_graphicsControl.AllowTearing(GlobalConfig.DispAllowTearing);
//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)
@ -99,7 +94,6 @@ namespace BizHawk.Client.EmuHawk
// begin rendering on this context
// 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)
//GraphicsControl.Begin(); // CRITICAL POINT for yabause+GL
//TODO - auto-create and age these (and dispose when old)
int rtCounter = 0;
@ -119,17 +113,11 @@ namespace BizHawk.Client.EmuHawk
Debug.Assert(inFinalTarget);
// wait for vsync to begin
if (alternateVsync) ((dynamic) _gl).AlternateVsyncPass(0);
// present and conclude drawing
_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
// presentationPanel.GraphicsControl.End();
// _graphicsControl.End();
}
}
}

View File

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

View File

@ -207,9 +207,9 @@ namespace BizHawk.Client.EmuHawk
// try to fallback on the faster option on Windows
// if we're on a Unix platform, there's only 1 fallback here...
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.D3D9, "Direct3D9"),
: (EDispMethod.D3D11, "Direct3D11"),
_ => (EDispMethod.GdiPlus, "GDI+")
};
@ -229,7 +229,7 @@ namespace BizHawk.Client.EmuHawk
switch (dispMethod)
{
case EDispMethod.D3D9:
case EDispMethod.D3D11:
if (OSTailoredCode.IsUnixHost || OSTailoredCode.IsWine)
{
// 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
{
return CheckRenderer(new IGL_D3D9());
return CheckRenderer(new IGL_D3D11());
}
catch (Exception ex)
{
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);
}
case EDispMethod.OpenGL:

View File

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

View File

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

View File

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