Replace D3D9 IGL impl with a D3D11 IGL impl
This commit is contained in:
parent
0122dec099
commit
e293e02369
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -4,6 +4,6 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
{
|
||||
OpenGL = 0,
|
||||
GdiPlus = 1,
|
||||
D3D9 = 2
|
||||
D3D11 = 2,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
|
@ -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...
|
||||
|
|
|
@ -68,6 +68,11 @@ namespace BizHawk.Bizware.Graphics.Controls
|
|||
}
|
||||
}
|
||||
|
||||
public override void AllowTearing(bool state)
|
||||
{
|
||||
// not controllable
|
||||
}
|
||||
|
||||
public override void SetVsync(bool state)
|
||||
{
|
||||
MakeContextCurrent();
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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()
|
||||
};
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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(),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 >= Vista, with
|
||||
|
|
Loading…
Reference in New Issue