First Commit
This commit is contained in:
75
bin/resources/shaders/dx11/cas.hlsl
Normal file
75
bin/resources/shaders/dx11/cas.hlsl
Normal file
@@ -0,0 +1,75 @@
|
||||
// Based on CAS_Shader.hlsl
|
||||
//
|
||||
// Copyright(c) 2019 Advanced Micro Devices, Inc.All rights reserved.
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files(the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions :
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
cbuffer cb : register(b0)
|
||||
{
|
||||
uint4 const0;
|
||||
uint4 const1;
|
||||
int2 srcOffset;
|
||||
};
|
||||
|
||||
Texture2D InputTexture : register(t0);
|
||||
RWTexture2D<float4> OutputTexture : register(u0);
|
||||
|
||||
#define A_GPU 1
|
||||
#define A_HLSL 1
|
||||
|
||||
#include "ffx_a.h"
|
||||
|
||||
AF3 CasLoad(ASU2 p)
|
||||
{
|
||||
return InputTexture.Load(int3(srcOffset, 0) + int3(p, 0)).rgb;
|
||||
}
|
||||
|
||||
// Lets you transform input from the load into a linear color space between 0 and 1. See ffx_cas.h
|
||||
// In this case, our input is already linear and between 0 and 1
|
||||
void CasInput(inout AF1 r, inout AF1 g, inout AF1 b) {}
|
||||
|
||||
#include "ffx_cas.h"
|
||||
|
||||
[numthreads(64, 1, 1)]
|
||||
void main(uint3 LocalThreadId : SV_GroupThreadID, uint3 WorkGroupId : SV_GroupID)
|
||||
{
|
||||
// Do remapping of local xy in workgroup for a more PS-like swizzle pattern.
|
||||
AU2 gxy = ARmp8x8(LocalThreadId.x) + AU2(WorkGroupId.x << 4u, WorkGroupId.y << 4u);
|
||||
|
||||
#if CAS_SHARPEN_ONLY
|
||||
const bool sharpenOnly = true;
|
||||
#else
|
||||
const bool sharpenOnly = false;
|
||||
#endif
|
||||
|
||||
// Filter.
|
||||
AF3 c = (float3)0.0f;
|
||||
|
||||
CasFilter(c.r, c.g, c.b, gxy, const0, const1, sharpenOnly);
|
||||
OutputTexture[ASU2(gxy)] = AF4(c, 1);
|
||||
gxy.x += 8u;
|
||||
|
||||
CasFilter(c.r, c.g, c.b, gxy, const0, const1, sharpenOnly);
|
||||
OutputTexture[ASU2(gxy)] = AF4(c, 1);
|
||||
gxy.y += 8u;
|
||||
|
||||
CasFilter(c.r, c.g, c.b, gxy, const0, const1, sharpenOnly);
|
||||
OutputTexture[ASU2(gxy)] = AF4(c, 1);
|
||||
gxy.x -= 8u;
|
||||
|
||||
CasFilter(c.r, c.g, c.b, gxy, const0, const1, sharpenOnly);
|
||||
OutputTexture[ASU2(gxy)] = AF4(c, 1);
|
||||
}
|
||||
583
bin/resources/shaders/dx11/convert.fx
Normal file
583
bin/resources/shaders/dx11/convert.fx
Normal file
@@ -0,0 +1,583 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
struct VS_INPUT
|
||||
{
|
||||
float4 p : POSITION;
|
||||
float2 t : TEXCOORD0;
|
||||
float4 c : COLOR;
|
||||
};
|
||||
|
||||
struct VS_OUTPUT
|
||||
{
|
||||
float4 p : SV_Position;
|
||||
float2 t : TEXCOORD0;
|
||||
float4 c : COLOR;
|
||||
};
|
||||
|
||||
cbuffer cb0 : register(b0)
|
||||
{
|
||||
float4 BGColor;
|
||||
int EMODA;
|
||||
int EMODC;
|
||||
int DOFFSET;
|
||||
};
|
||||
|
||||
static const float3x3 rgb2yuv =
|
||||
{
|
||||
{0.587, 0.114, 0.299},
|
||||
{-0.311, 0.500, -0.169},
|
||||
{-0.419, -0.081, 0.500}
|
||||
};
|
||||
|
||||
Texture2D Texture;
|
||||
SamplerState TextureSampler;
|
||||
|
||||
float4 sample_c(float2 uv)
|
||||
{
|
||||
return Texture.Sample(TextureSampler, uv);
|
||||
}
|
||||
|
||||
struct PS_INPUT
|
||||
{
|
||||
float4 p : SV_Position;
|
||||
float2 t : TEXCOORD0;
|
||||
float4 c : COLOR;
|
||||
};
|
||||
|
||||
struct PS_OUTPUT
|
||||
{
|
||||
float4 c : SV_Target0;
|
||||
};
|
||||
|
||||
VS_OUTPUT vs_main(VS_INPUT input)
|
||||
{
|
||||
VS_OUTPUT output;
|
||||
|
||||
output.p = input.p;
|
||||
output.t = input.t;
|
||||
output.c = input.c;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_copy(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
output.c = sample_c(input.t);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
float ps_depth_copy(PS_INPUT input) : SV_Depth
|
||||
{
|
||||
return sample_c(input.t).r;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_downsample_copy(PS_INPUT input)
|
||||
{
|
||||
int DownsampleFactor = DOFFSET;
|
||||
int2 ClampMin = int2(EMODA, EMODC);
|
||||
float Weight = BGColor.x;
|
||||
|
||||
int2 coord = max(int2(input.p.xy) * DownsampleFactor, ClampMin);
|
||||
|
||||
PS_OUTPUT output;
|
||||
output.c = (float4)0;
|
||||
for (int yoff = 0; yoff < DownsampleFactor; yoff++)
|
||||
{
|
||||
for (int xoff = 0; xoff < DownsampleFactor; xoff++)
|
||||
output.c += Texture.Load(int3(coord + int2(xoff, yoff), 0));
|
||||
}
|
||||
output.c /= Weight;
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_filter_transparency(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
float4 c = sample_c(input.t);
|
||||
output.c = float4(c.rgb, 1.0);
|
||||
return output;
|
||||
}
|
||||
|
||||
// Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life
|
||||
uint ps_convert_rgba8_16bits(PS_INPUT input) : SV_Target0
|
||||
{
|
||||
uint4 i = sample_c(input.t) * float4(255.5f, 255.5f, 255.5f, 255.5f);
|
||||
|
||||
return ((i.x & 0x00F8u) >> 3) | ((i.y & 0x00F8u) << 2) | ((i.z & 0x00f8u) << 7) | ((i.w & 0x80u) << 8);
|
||||
}
|
||||
|
||||
void ps_datm1(PS_INPUT input)
|
||||
{
|
||||
clip(sample_c(input.t).a - 127.5f / 255); // >= 0x80 pass
|
||||
}
|
||||
|
||||
void ps_datm0(PS_INPUT input)
|
||||
{
|
||||
clip(127.5f / 255 - sample_c(input.t).a); // < 0x80 pass (== 0x80 should not pass)
|
||||
}
|
||||
|
||||
void ps_datm1_rta_correction(PS_INPUT input)
|
||||
{
|
||||
clip(sample_c(input.t).a - 254.5f / 255); // >= 0x80 pass
|
||||
}
|
||||
|
||||
void ps_datm0_rta_correction(PS_INPUT input)
|
||||
{
|
||||
clip(254.5f / 255 - sample_c(input.t).a); // < 0x80 pass (== 0x80 should not pass)
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_rta_correction(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
float4 value = sample_c(input.t);
|
||||
output.c = float4(value.rgb, value.a / (128.25f / 255.0f));
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_rta_decorrection(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
float4 value = sample_c(input.t);
|
||||
output.c = float4(value.rgb, value.a * (128.25f / 255.0f));
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_colclip_init(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
float4 value = sample_c(input.t);
|
||||
output.c = float4(round(value.rgb * 255) / 65535, value.a);
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_colclip_resolve(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
float4 value = sample_c(input.t);
|
||||
output.c = float4(float3(uint3(value.rgb * 65535.5) & 255) / 255, value.a);
|
||||
return output;
|
||||
}
|
||||
|
||||
uint ps_convert_float32_32bits(PS_INPUT input) : SV_Target0
|
||||
{
|
||||
// Convert a FLOAT32 depth texture into a 32 bits UINT texture
|
||||
return uint(exp2(32.0f) * sample_c(input.t).r);
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_convert_float32_rgba8(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
// Convert a FLOAT32 depth texture into a RGBA color texture
|
||||
uint d = uint(sample_c(input.t).r * exp2(32.0f));
|
||||
output.c = float4(uint4((d & 0xFFu), ((d >> 8) & 0xFFu), ((d >> 16) & 0xFFu), (d >> 24))) / 255.0f;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_convert_float16_rgb5a1(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
// Convert a FLOAT32 (only 16 lsb) depth into a RGB5A1 color texture
|
||||
uint d = uint(sample_c(input.t).r * exp2(32.0f));
|
||||
output.c = float4(uint4(d << 3, d >> 2, d >> 7, d >> 8) & uint4(0xf8, 0xf8, 0xf8, 0x80)) / 255.0f;
|
||||
return output;
|
||||
}
|
||||
|
||||
float rgba8_to_depth32(float4 val)
|
||||
{
|
||||
uint4 c = uint4(val * 255.5f);
|
||||
return float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
float rgba8_to_depth24(float4 val)
|
||||
{
|
||||
uint3 c = uint3(val.rgb * 255.5f);
|
||||
return float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
float rgba8_to_depth16(float4 val)
|
||||
{
|
||||
uint2 c = uint2(val.rg * 255.5f);
|
||||
return float(c.r | (c.g << 8)) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
float rgb5a1_to_depth16(float4 val)
|
||||
{
|
||||
uint4 c = uint4(val * 255.5f);
|
||||
return float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
float ps_convert_float32_float24(PS_INPUT input) : SV_Depth
|
||||
{
|
||||
// Truncates depth value to 24bits
|
||||
uint d = uint(sample_c(input.t).r * exp2(32.0f)) & 0xFFFFFFu;
|
||||
return float(d) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
float ps_convert_rgba8_float32(PS_INPUT input) : SV_Depth
|
||||
{
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
return rgba8_to_depth32(sample_c(input.t));
|
||||
}
|
||||
|
||||
float ps_convert_rgba8_float24(PS_INPUT input) : SV_Depth
|
||||
{
|
||||
// Same as above but without the alpha channel (24 bits Z)
|
||||
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
return rgba8_to_depth24(sample_c(input.t));
|
||||
}
|
||||
|
||||
float ps_convert_rgba8_float16(PS_INPUT input) : SV_Depth
|
||||
{
|
||||
// Same as above but without the A/B channels (16 bits Z)
|
||||
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
return rgba8_to_depth16(sample_c(input.t));
|
||||
}
|
||||
|
||||
float ps_convert_rgb5a1_float16(PS_INPUT input) : SV_Depth
|
||||
{
|
||||
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
|
||||
return rgb5a1_to_depth16(sample_c(input.t));
|
||||
}
|
||||
|
||||
#define SAMPLE_RGBA_DEPTH_BILN(CONVERT_FN) \
|
||||
uint width, height; \
|
||||
Texture.GetDimensions(width, height); \
|
||||
float2 top_left_f = input.t * float2(width, height) - 0.5f; \
|
||||
int2 top_left = int2(floor(top_left_f)); \
|
||||
int4 coords = clamp(int4(top_left, top_left + 1), int4(0, 0, 0, 0), int2(width - 1, height - 1).xyxy); \
|
||||
float2 mix_vals = frac(top_left_f); \
|
||||
float depthTL = CONVERT_FN(Texture.Load(int3(coords.xy, 0))); \
|
||||
float depthTR = CONVERT_FN(Texture.Load(int3(coords.zy, 0))); \
|
||||
float depthBL = CONVERT_FN(Texture.Load(int3(coords.xw, 0))); \
|
||||
float depthBR = CONVERT_FN(Texture.Load(int3(coords.zw, 0))); \
|
||||
return lerp(lerp(depthTL, depthTR, mix_vals.x), lerp(depthBL, depthBR, mix_vals.x), mix_vals.y);
|
||||
|
||||
float ps_convert_rgba8_float32_biln(PS_INPUT input) : SV_Depth
|
||||
{
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth32);
|
||||
}
|
||||
|
||||
float ps_convert_rgba8_float24_biln(PS_INPUT input) : SV_Depth
|
||||
{
|
||||
// Same as above but without the alpha channel (24 bits Z)
|
||||
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth24);
|
||||
}
|
||||
|
||||
float ps_convert_rgba8_float16_biln(PS_INPUT input) : SV_Depth
|
||||
{
|
||||
// Same as above but without the A/B channels (16 bits Z)
|
||||
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth16);
|
||||
}
|
||||
|
||||
float ps_convert_rgb5a1_float16_biln(PS_INPUT input) : SV_Depth
|
||||
{
|
||||
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
|
||||
SAMPLE_RGBA_DEPTH_BILN(rgb5a1_to_depth16);
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_convert_rgb5a1_8i(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
// Convert a RGB5A1 texture into a 8 bits packed texture
|
||||
// Input column: 16x2 RGB5A1 pixels
|
||||
// 0: 16 RGBA
|
||||
// 1: 16 RGBA
|
||||
// Output column: 16x4 Index pixels
|
||||
// 0: 16 R5G2
|
||||
// 1: 16 R5G2
|
||||
// 2: 16 G2B5A1
|
||||
// 3: 16 G2B5A1
|
||||
uint2 pos = uint2(input.p.xy);
|
||||
|
||||
// Collapse separate R G B A areas into their base pixel
|
||||
uint2 column = (pos & ~uint2(0u, 3u)) / uint2(1,2);
|
||||
uint2 subcolumn = (pos & uint2(0u, 1u));
|
||||
column.x -= (column.x / 128) * 64;
|
||||
column.y += (column.y / 32) * 32;
|
||||
|
||||
uint PSM = uint(DOFFSET);
|
||||
|
||||
// Deal with swizzling differences
|
||||
if ((PSM & 0x8) != 0) // PSMCT16S
|
||||
{
|
||||
if ((pos.x & 32) != 0)
|
||||
{
|
||||
column.y += 32; // 4 columns high times 4 to get bottom 4 blocks
|
||||
column.x &= ~32;
|
||||
}
|
||||
|
||||
if ((pos.x & 64) != 0)
|
||||
{
|
||||
column.x -= 32;
|
||||
}
|
||||
|
||||
if (((pos.x & 16) != 0) != ((pos.y & 16) != 0))
|
||||
{
|
||||
column.x ^= 16;
|
||||
column.y ^= 8;
|
||||
}
|
||||
|
||||
if ((PSM & 0x30) != 0) // PSMZ16S - Untested but hopefully ok if anything uses it.
|
||||
{
|
||||
column.x ^= 32;
|
||||
column.y ^= 16;
|
||||
}
|
||||
}
|
||||
else // PSMCT16
|
||||
{
|
||||
if ((pos.y & 32) != 0)
|
||||
{
|
||||
column.y -= 16;
|
||||
column.x += 32;
|
||||
}
|
||||
|
||||
if ((pos.x & 96) != 0)
|
||||
{
|
||||
uint multi = (pos.x & 96) / 32;
|
||||
column.y += 16 * multi; // 4 columns high times 4 to get bottom 4 blocks
|
||||
column.x -= (pos.x & 96);
|
||||
}
|
||||
|
||||
if (((pos.x & 16) != 0) != ((pos.y & 16) != 0))
|
||||
{
|
||||
column.x ^= 16;
|
||||
column.y ^= 8;
|
||||
}
|
||||
|
||||
if ((PSM & 0x30) != 0) // PSMZ16 - Untested but hopefully ok if anything uses it.
|
||||
{
|
||||
column.x ^= 32;
|
||||
column.y ^= 32;
|
||||
}
|
||||
}
|
||||
|
||||
uint2 coord = column | subcolumn;
|
||||
|
||||
// Compensate for potentially differing page pitch.
|
||||
uint SBW = uint(EMODA);
|
||||
uint DBW = uint(EMODC);
|
||||
uint2 block_xy = coord / uint2(64,64);
|
||||
uint block_num = (block_xy.y * (DBW / 128)) + block_xy.x;
|
||||
uint2 block_offset = uint2((block_num % (SBW / 64)) * 64, (block_num / (SBW / 64)) * 64);
|
||||
coord = (coord % uint2(64, 64)) + block_offset;
|
||||
|
||||
// Apply offset to cols 1 and 2
|
||||
uint is_col23 = pos.y & 4u;
|
||||
uint is_col13 = pos.y & 2u;
|
||||
uint is_col12 = is_col23 ^ (is_col13 << 1);
|
||||
coord.x ^= is_col12; // If cols 1 or 2, flip bit 3 of x
|
||||
|
||||
float ScaleFactor = BGColor.x;
|
||||
if (floor(ScaleFactor) != ScaleFactor)
|
||||
coord = uint2(float2(coord) * ScaleFactor);
|
||||
else
|
||||
coord *= uint(ScaleFactor);
|
||||
|
||||
float4 pixel = Texture.Load(int3(int2(coord), 0));
|
||||
uint4 denorm_c = (uint4)(pixel * 255.5f);
|
||||
if ((pos.y & 2u) == 0u)
|
||||
{
|
||||
uint red = (denorm_c.r >> 3) & 0x1Fu;
|
||||
uint green = (denorm_c.g >> 3) & 0x1Fu;
|
||||
float sel0 = (float)(((green << 5) | red) & 0xFF) / 255.0f;
|
||||
|
||||
output.c = (float4)(sel0);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint green = (denorm_c.g >> 3) & 0x1Fu;
|
||||
uint blue = (denorm_c.b >> 3) & 0x1Fu;
|
||||
uint alpha = denorm_c.a & 0x80u;
|
||||
float sel0 = (float)((alpha | (blue << 2) | (green >> 3)) & 0xFF) / 255.0f;
|
||||
|
||||
output.c = (float4)(sel0);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_convert_rgba_8i(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
// Convert a RGBA texture into a 8 bits packed texture
|
||||
// Input column: 8x2 RGBA pixels
|
||||
// 0: 8 RGBA
|
||||
// 1: 8 RGBA
|
||||
// Output column: 16x4 Index pixels
|
||||
// 0: 8 R | 8 B
|
||||
// 1: 8 R | 8 B
|
||||
// 2: 8 G | 8 A
|
||||
// 3: 8 G | 8 A
|
||||
uint2 pos = uint2(input.p.xy);
|
||||
|
||||
// Collapse separate R G B A areas into their base pixel
|
||||
uint2 block = (pos & ~uint2(15u, 3u)) >> 1;
|
||||
uint2 subblock = pos & uint2(7u, 1u);
|
||||
uint2 coord = block | subblock;
|
||||
|
||||
// Compensate for potentially differing page pitch.
|
||||
uint SBW = uint(EMODA);
|
||||
uint DBW = uint(EMODC);
|
||||
uint2 block_xy = coord / uint2(64, 32);
|
||||
uint block_num = (block_xy.y * (DBW / 128)) + block_xy.x;
|
||||
uint2 block_offset = uint2((block_num % (SBW / 64)) * 64, (block_num / (SBW / 64)) * 32);
|
||||
coord = (coord % uint2(64, 32)) + block_offset;
|
||||
|
||||
// Apply offset to cols 1 and 2
|
||||
uint is_col23 = pos.y & 4u;
|
||||
uint is_col13 = pos.y & 2u;
|
||||
uint is_col12 = is_col23 ^ (is_col13 << 1);
|
||||
coord.x ^= is_col12; // If cols 1 or 2, flip bit 3 of x
|
||||
|
||||
float ScaleFactor = BGColor.x;
|
||||
if (floor(ScaleFactor) != ScaleFactor)
|
||||
coord = uint2(float2(coord) * ScaleFactor);
|
||||
else
|
||||
coord *= uint(ScaleFactor);
|
||||
|
||||
float4 pixel = Texture.Load(int3(int2(coord), 0));
|
||||
float2 sel0 = (pos.y & 2u) == 0u ? pixel.rb : pixel.ga;
|
||||
float sel1 = (pos.x & 8u) == 0u ? sel0.x : sel0.y;
|
||||
output.c = (float4)(sel1); // Divide by something here?
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_convert_clut_4(PS_INPUT input)
|
||||
{
|
||||
// Borrowing the YUV constant buffer.
|
||||
float scale = BGColor.x;
|
||||
uint2 offset = uint2(uint(EMODA), uint(EMODC)) + uint(DOFFSET);
|
||||
|
||||
// CLUT4 is easy, just two rows of 8x8.
|
||||
uint index = uint(input.p.x);
|
||||
uint2 pos = uint2(index % 8u, index / 8u);
|
||||
|
||||
int2 final = int2(floor(float2(offset + pos) * scale));
|
||||
PS_OUTPUT output;
|
||||
output.c = Texture.Load(int3(final, 0), 0);
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_convert_clut_8(PS_INPUT input)
|
||||
{
|
||||
float scale = BGColor.x;
|
||||
uint2 offset = uint2(uint(EMODA), uint(EMODC));
|
||||
uint index = min(uint(input.p.x) + uint(DOFFSET), 255u);
|
||||
|
||||
// CLUT is arranged into 8 groups of 16x2, with the top-right and bottom-left quadrants swapped.
|
||||
// This can probably be done better..
|
||||
uint subgroup = (index / 8u) % 4u;
|
||||
uint2 pos;
|
||||
pos.x = (index % 8u) + ((subgroup >= 2u) ? 8u : 0u);
|
||||
pos.y = ((index / 32u) * 2u) + (subgroup % 2u);
|
||||
|
||||
int2 final = int2(floor(float2(offset + pos) * scale));
|
||||
PS_OUTPUT output;
|
||||
output.c = Texture.Load(int3(final, 0), 0);
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_yuv(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
float4 i = sample_c(input.t);
|
||||
float3 yuv = mul(rgb2yuv, i.gbr);
|
||||
|
||||
float Y = float(0xDB) / 255.0f * yuv.x + float(0x10) / 255.0f;
|
||||
float Cr = float(0xE0) / 255.0f * yuv.y + float(0x80) / 255.0f;
|
||||
float Cb = float(0xE0) / 255.0f * yuv.z + float(0x80) / 255.0f;
|
||||
|
||||
switch (EMODA)
|
||||
{
|
||||
case 0:
|
||||
output.c.a = i.a;
|
||||
break;
|
||||
case 1:
|
||||
output.c.a = Y;
|
||||
break;
|
||||
case 2:
|
||||
output.c.a = Y / 2.0f;
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
output.c.a = 0.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (EMODC)
|
||||
{
|
||||
case 0:
|
||||
output.c.rgb = i.rgb;
|
||||
break;
|
||||
case 1:
|
||||
output.c.rgb = float3(Y, Y, Y);
|
||||
break;
|
||||
case 2:
|
||||
output.c.rgb = float3(Y, Cb, Cr);
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
output.c.rgb = float3(i.a, i.a, i.a);
|
||||
break;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
float ps_stencil_image_init_0(PS_INPUT input) : SV_Target
|
||||
{
|
||||
float c;
|
||||
if ((127.5f / 255.0f) < sample_c(input.t).a) // < 0x80 pass (== 0x80 should not pass)
|
||||
c = float(-1);
|
||||
else
|
||||
c = float(0x7FFFFFFF);
|
||||
return c;
|
||||
}
|
||||
|
||||
float ps_stencil_image_init_1(PS_INPUT input) : SV_Target
|
||||
{
|
||||
float c;
|
||||
if (sample_c(input.t).a < (127.5f / 255.0f)) // >= 0x80 pass
|
||||
c = float(-1);
|
||||
else
|
||||
c = float(0x7FFFFFFF);
|
||||
return c;
|
||||
}
|
||||
|
||||
float ps_stencil_image_init_2(PS_INPUT input)
|
||||
: SV_Target
|
||||
{
|
||||
float c;
|
||||
if ((254.5f / 255.0f) < sample_c(input.t).a) // < 0x80 pass (== 0x80 should not pass)
|
||||
c = float(-1);
|
||||
else
|
||||
c = float(0x7FFFFFFF);
|
||||
return c;
|
||||
}
|
||||
|
||||
float ps_stencil_image_init_3(PS_INPUT input)
|
||||
: SV_Target
|
||||
{
|
||||
float c;
|
||||
if (sample_c(input.t).a < (254.5f / 255.0f)) // >= 0x80 pass
|
||||
c = float(-1);
|
||||
else
|
||||
c = float(0x7FFFFFFF);
|
||||
return c;
|
||||
}
|
||||
39
bin/resources/shaders/dx11/imgui.fx
Normal file
39
bin/resources/shaders/dx11/imgui.fx
Normal file
@@ -0,0 +1,39 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
cbuffer vertexBuffer : register(b0)
|
||||
{
|
||||
float4x4 ProjectionMatrix;
|
||||
};
|
||||
|
||||
struct VS_INPUT
|
||||
{
|
||||
float2 pos : POSITION;
|
||||
float4 col : COLOR0;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct PS_INPUT
|
||||
{
|
||||
float4 pos : SV_POSITION;
|
||||
float4 col : COLOR0;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
PS_INPUT vs_main(VS_INPUT input)
|
||||
{
|
||||
PS_INPUT output;
|
||||
output.pos = mul(ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));
|
||||
output.col = input.col;
|
||||
output.uv = input.uv;
|
||||
return output;
|
||||
}
|
||||
|
||||
sampler sampler0 : register(s0);
|
||||
Texture2D texture0 : register(t0);
|
||||
|
||||
float4 ps_main(PS_INPUT input) : SV_Target
|
||||
{
|
||||
float4 out_col = input.col * texture0.Sample(sampler0, input.uv);
|
||||
return out_col;
|
||||
}
|
||||
183
bin/resources/shaders/dx11/interlace.fx
Normal file
183
bin/resources/shaders/dx11/interlace.fx
Normal file
@@ -0,0 +1,183 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
Texture2D Texture;
|
||||
SamplerState Sampler;
|
||||
|
||||
cbuffer cb0
|
||||
{
|
||||
float4 ZrH;
|
||||
};
|
||||
|
||||
struct PS_INPUT
|
||||
{
|
||||
float4 p : SV_Position;
|
||||
float2 t : TEXCOORD0;
|
||||
};
|
||||
|
||||
|
||||
// Weave shader
|
||||
float4 ps_main0(PS_INPUT input) : SV_Target0
|
||||
{
|
||||
const int idx = int(ZrH.x); // buffer index passed from CPU
|
||||
const int field = idx & 1; // current field
|
||||
const int vpos = int(input.p.y); // vertical position of destination texture
|
||||
|
||||
if ((vpos & 1) == field)
|
||||
return Texture.SampleLevel(Sampler, input.t, 0);
|
||||
else
|
||||
discard;
|
||||
|
||||
return float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
|
||||
// Bob shader
|
||||
float4 ps_main1(PS_INPUT input) : SV_Target0
|
||||
{
|
||||
return Texture.SampleLevel(Sampler, input.t, 0);
|
||||
}
|
||||
|
||||
|
||||
// Blend shader
|
||||
float4 ps_main2(PS_INPUT input) : SV_Target0
|
||||
{
|
||||
float2 vstep = float2(0.0f, ZrH.y);
|
||||
float4 c0 = Texture.SampleLevel(Sampler, input.t - vstep, 0);
|
||||
float4 c1 = Texture.SampleLevel(Sampler, input.t, 0);
|
||||
float4 c2 = Texture.SampleLevel(Sampler, input.t + vstep, 0);
|
||||
|
||||
return (c0 + c1 * 2 + c2) / 4;
|
||||
}
|
||||
|
||||
|
||||
// MAD shader - buffering
|
||||
float4 ps_main3(PS_INPUT input) : SV_Target0
|
||||
{
|
||||
// We take half the lines from the current frame and stores them in the MAD frame buffer.
|
||||
// the MAD frame buffer is split in 2 consecutive banks of 2 fields each, the fields in each bank
|
||||
// are interleaved (top field at even lines and bottom field at odd lines).
|
||||
// When the source texture has an odd vres, the first line of bank 1 would be an odd index
|
||||
// causing the wrong lines to be discarded, so a vertical offset (lofs) is added to the vertical
|
||||
// position of the destination texture to force the proper field alignment
|
||||
|
||||
const int idx = int(ZrH.x); // buffer index passed from CPU
|
||||
const int bank = idx >> 1; // current bank
|
||||
const int field = idx & 1; // current field
|
||||
const int vres = int(ZrH.z) >> 1; // vertical resolution of source texture
|
||||
const int lofs = ((((vres + 1) >> 1) << 1) - vres) & bank; // line alignment offset for bank 1
|
||||
const int vpos = int(input.p.y) + lofs; // vertical position of destination texture
|
||||
|
||||
// if the index of current destination line belongs to the current fiels we update it, otherwise
|
||||
// we leave the old line in the destination buffer
|
||||
if ((vpos & 1) == field)
|
||||
return Texture.SampleLevel(Sampler, input.t, 0);
|
||||
else
|
||||
discard;
|
||||
|
||||
return float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
|
||||
// MAD shader - reconstruction
|
||||
float4 ps_main4(PS_INPUT input) : SV_Target0
|
||||
{
|
||||
// we use the contents of the MAD frame buffer to reconstruct the missing lines from the current
|
||||
// field.
|
||||
|
||||
const int idx = int(ZrH.x); // buffer index passed from CPU
|
||||
const int field = idx & 1; // current field
|
||||
const int vpos = int(input.p.y); // vertical position of destination texture
|
||||
const float sensitivity = ZrH.w; // passed from CPU, higher values mean more likely to use weave
|
||||
const float3 motion_thr = float3(1.0, 1.0, 1.0) * sensitivity; //
|
||||
const float2 bofs = float2(0.0f, 0.5f); // position of the bank 1 relative to source texture size
|
||||
const float2 vscale = float2(1.0f, 0.5f); // scaling factor from source to destination texture
|
||||
const float2 lofs = float2(0.0f, ZrH.y) * vscale; // distance between two adjacent lines relative to source texture size
|
||||
const float2 iptr = input.t * vscale; // pointer to the current pixel in the source texture
|
||||
|
||||
float2 p_t0; // pointer to current pixel (missing or not) from most recent frame
|
||||
float2 p_t1; // pointer to current pixel (missing or not) from one frame back
|
||||
float2 p_t2; // pointer to current pixel (missing or not) from two frames back
|
||||
float2 p_t3; // pointer to current pixel (missing or not) from three frames back
|
||||
|
||||
switch (idx)
|
||||
{
|
||||
case 1:
|
||||
p_t0 = iptr;
|
||||
p_t1 = iptr;
|
||||
p_t2 = iptr + bofs;
|
||||
p_t3 = iptr + bofs;
|
||||
break;
|
||||
case 2:
|
||||
p_t0 = iptr + bofs;
|
||||
p_t1 = iptr;
|
||||
p_t2 = iptr;
|
||||
p_t3 = iptr + bofs;
|
||||
break;
|
||||
case 3:
|
||||
p_t0 = iptr + bofs;
|
||||
p_t1 = iptr + bofs;
|
||||
p_t2 = iptr;
|
||||
p_t3 = iptr;
|
||||
break;
|
||||
default:
|
||||
p_t0 = iptr;
|
||||
p_t1 = iptr + bofs;
|
||||
p_t2 = iptr + bofs;
|
||||
p_t3 = iptr;
|
||||
break;
|
||||
}
|
||||
|
||||
// calculating motion, only relevant for missing lines where the "center line" is pointed by p_t1
|
||||
|
||||
float4 hn = Texture.SampleLevel(Sampler, p_t0 - lofs, 0); // new high pixel
|
||||
float4 cn = Texture.SampleLevel(Sampler, p_t1, 0); // new center pixel
|
||||
float4 ln = Texture.SampleLevel(Sampler, p_t0 + lofs, 0); // new low pixel
|
||||
|
||||
float4 ho = Texture.SampleLevel(Sampler, p_t2 - lofs, 0); // old high pixel
|
||||
float4 co = Texture.SampleLevel(Sampler, p_t3, 0); // old center pixel
|
||||
float4 lo = Texture.SampleLevel(Sampler, p_t2 + lofs, 0); // old low pixel
|
||||
|
||||
float3 mh = hn.rgb - ho.rgb; // high pixel motion
|
||||
float3 mc = cn.rgb - co.rgb; // center pixel motion
|
||||
float3 ml = ln.rgb - lo.rgb; // low pixel motion
|
||||
|
||||
mh = max(mh, -mh) - motion_thr;
|
||||
mc = max(mc, -mc) - motion_thr;
|
||||
ml = max(ml, -ml) - motion_thr;
|
||||
|
||||
#if 1 // use this code to evaluate each color motion separately
|
||||
float mh_max = max(max(mh.x, mh.y), mh.z);
|
||||
float mc_max = max(max(mc.x, mc.y), mc.z);
|
||||
float ml_max = max(max(ml.x, ml.y), ml.z);
|
||||
#else // use this code to evaluate average color motion
|
||||
float mh_max = mh.x + mh.y + mh.z;
|
||||
float mc_max = mc.x + mc.y + mc.z;
|
||||
float ml_max = ml.x + ml.y + ml.z;
|
||||
#endif
|
||||
|
||||
// selecting deinterlacing output
|
||||
|
||||
if ((vpos & 1) == field)
|
||||
{
|
||||
// output coordinate present on current field
|
||||
return Texture.SampleLevel(Sampler, p_t0, 0);
|
||||
}
|
||||
else if ((iptr.y > 0.5f - lofs.y) || (iptr.y < 0.0 + lofs.y))
|
||||
{
|
||||
// top and bottom lines are always weaved
|
||||
return cn;
|
||||
}
|
||||
else
|
||||
{
|
||||
// missing line needs to be reconstructed
|
||||
if (((mh_max > 0.0f) || (ml_max > 0.0f)) || (mc_max > 0.0f))
|
||||
// high motion -> interpolate pixels above and below
|
||||
return (hn + ln) / 2.0f;
|
||||
else
|
||||
// low motion -> weave
|
||||
return cn;
|
||||
}
|
||||
|
||||
return float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
33
bin/resources/shaders/dx11/merge.fx
Normal file
33
bin/resources/shaders/dx11/merge.fx
Normal file
@@ -0,0 +1,33 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
Texture2D Texture;
|
||||
SamplerState Sampler;
|
||||
|
||||
cbuffer cb0 : register(b0)
|
||||
{
|
||||
float4 BGColor;
|
||||
int EMODA;
|
||||
int EMODC;
|
||||
int cb0_pad[2];
|
||||
};
|
||||
|
||||
struct PS_INPUT
|
||||
{
|
||||
float4 p : SV_Position;
|
||||
float2 t : TEXCOORD0;
|
||||
};
|
||||
|
||||
float4 ps_main0(PS_INPUT input) : SV_Target0
|
||||
{
|
||||
float4 c = Texture.Sample(Sampler, input.t);
|
||||
c.a *= 2.0f;
|
||||
return c;
|
||||
}
|
||||
|
||||
float4 ps_main1(PS_INPUT input) : SV_Target0
|
||||
{
|
||||
float4 c = Texture.Sample(Sampler, input.t);
|
||||
c.a = BGColor.a;
|
||||
return c;
|
||||
}
|
||||
480
bin/resources/shaders/dx11/present.fx
Normal file
480
bin/resources/shaders/dx11/present.fx
Normal file
@@ -0,0 +1,480 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
struct VS_INPUT
|
||||
{
|
||||
float4 p : POSITION;
|
||||
float2 t : TEXCOORD0;
|
||||
float4 c : COLOR;
|
||||
};
|
||||
|
||||
struct VS_OUTPUT
|
||||
{
|
||||
float4 p : SV_Position;
|
||||
float2 t : TEXCOORD0;
|
||||
float4 c : COLOR;
|
||||
};
|
||||
|
||||
cbuffer cb0 : register(b0)
|
||||
{
|
||||
float4 u_source_rect;
|
||||
float4 u_target_rect;
|
||||
float2 u_source_size;
|
||||
float2 u_target_size;
|
||||
float2 u_target_resolution;
|
||||
float2 u_rcp_target_resolution; // 1 / u_target_resolution
|
||||
float2 u_source_resolution;
|
||||
float2 u_rcp_source_resolution; // 1 / u_source_resolution
|
||||
float u_time;
|
||||
};
|
||||
|
||||
Texture2D Texture;
|
||||
SamplerState TextureSampler;
|
||||
|
||||
float4 sample_c(float2 uv)
|
||||
{
|
||||
return Texture.Sample(TextureSampler, uv);
|
||||
}
|
||||
|
||||
struct PS_INPUT
|
||||
{
|
||||
float4 p : SV_Position;
|
||||
float2 t : TEXCOORD0;
|
||||
float4 c : COLOR;
|
||||
};
|
||||
|
||||
struct PS_OUTPUT
|
||||
{
|
||||
float4 c : SV_Target0;
|
||||
};
|
||||
|
||||
VS_OUTPUT vs_main(VS_INPUT input)
|
||||
{
|
||||
VS_OUTPUT output;
|
||||
|
||||
output.p = input.p;
|
||||
output.t = input.t;
|
||||
output.c = input.c;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_copy(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
output.c = sample_c(input.t);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
float4 ps_crt(PS_INPUT input, int i)
|
||||
{
|
||||
float4 mask[4] =
|
||||
{
|
||||
float4(1, 0, 0, 0),
|
||||
float4(0, 1, 0, 0),
|
||||
float4(0, 0, 1, 0),
|
||||
float4(1, 1, 1, 0)
|
||||
};
|
||||
|
||||
return sample_c(input.t) * saturate(mask[i] + 0.5f);
|
||||
}
|
||||
|
||||
float4 ps_scanlines(PS_INPUT input, int i)
|
||||
{
|
||||
float4 mask[2] =
|
||||
{
|
||||
float4(1, 1, 1, 0),
|
||||
float4(0, 0, 0, 0)
|
||||
};
|
||||
|
||||
return sample_c(input.t) * saturate(mask[i] + 0.5f);
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_filter_scanlines(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
uint4 p = (uint4)input.p;
|
||||
|
||||
output.c = ps_scanlines(input, p.y % 2);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_filter_diagonal(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
uint4 p = (uint4)input.p;
|
||||
|
||||
output.c = ps_crt(input, (p.x + (p.y % 3)) % 3);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_filter_triangular(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
uint4 p = (uint4)input.p;
|
||||
|
||||
// output.c = ps_crt(input, ((p.x + (p.y & 1) * 3) >> 1) % 3);
|
||||
output.c = ps_crt(input, ((p.x + ((p.y >> 1) & 1) * 3) >> 1) % 3);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
static const float PI = 3.14159265359f;
|
||||
PS_OUTPUT ps_filter_complex(PS_INPUT input) // triangular
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
float2 texdim;
|
||||
Texture.GetDimensions(texdim.x, texdim.y);
|
||||
|
||||
output.c = (0.9 - 0.4 * cos(2 * PI * input.t.y * texdim.y)) * sample_c(float2(input.t.x, (floor(input.t.y * texdim.y) + 0.5) / texdim.y));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//Lottes CRT
|
||||
#define MaskingType 4 //[1|2|3|4] The type of CRT shadow masking used. 1: compressed TV style, 2: Aperture-grille, 3: Stretched VGA style, 4: VGA style.
|
||||
#define ScanBrightness -8.00 //[-16.0 to 1.0] The overall brightness of the scanline effect. Lower for darker, higher for brighter.
|
||||
#define FilterCRTAmount -3.00 //[-4.0 to 1.0] The amount of filtering used, to replicate the TV CRT look. Lower for less, higher for more.
|
||||
#define HorizontalWarp 0.00 //[0.0 to 0.1] The distortion warping effect for the horizontal (x) axis of the screen. Use small increments.
|
||||
#define VerticalWarp 0.00 //[0.0 to 0.1] The distortion warping effect for the verticle (y) axis of the screen. Use small increments.
|
||||
#define MaskAmountDark 0.50 //[0.0 to 1.0] The value of the dark masking line effect used. Lower for darker lower end masking, higher for brighter.
|
||||
#define MaskAmountLight 1.50 //[0.0 to 2.0] The value of the light masking line effect used. Lower for darker higher end masking, higher for brighter.
|
||||
#define BloomPixel -1.50 //[-2.0 -0.5] Pixel bloom radius. Higher for increased softness of bloom.
|
||||
#define BloomScanLine -2.0 //[-4.0 -1.0] Scanline bloom radius. Higher for increased softness of bloom.
|
||||
#define BloomAmount 0.15 //[0.0 1.0] Bloom intensity. Higher for brighter.
|
||||
#define Shape 2.0 //[0.0 10.0] Kernal filter shape. Lower values will darken image and introduce moire patterns if used with curvature.
|
||||
#define UseShadowMask 1 //[0 or 1] Enables, or disables the use of the CRT shadow mask. 0 is disabled, 1 is enabled.
|
||||
|
||||
float ToLinear1(float c)
|
||||
{
|
||||
return c <= 0.04045 ? c / 12.92 : pow((abs(c) + 0.055) / 1.055, 2.4);
|
||||
}
|
||||
|
||||
float3 ToLinear(float3 c)
|
||||
{
|
||||
return float3(ToLinear1(c.r), ToLinear1(c.g), ToLinear1(c.b));
|
||||
}
|
||||
|
||||
float ToSrgb1(float c)
|
||||
{
|
||||
return c < 0.0031308 ? c * 12.92 : 1.055 * pow(abs(c), 0.41666) - 0.055;
|
||||
}
|
||||
|
||||
float3 ToSrgb(float3 c)
|
||||
{
|
||||
return float3(ToSrgb1(c.r), ToSrgb1(c.g), ToSrgb1(c.b));
|
||||
}
|
||||
|
||||
float3 Fetch(float2 pos, float2 off)
|
||||
{
|
||||
pos = (floor(pos * u_target_size + off) + float2(0.5, 0.5)) / u_target_size;
|
||||
if (max(abs(pos.x - 0.5), abs(pos.y - 0.5)) > 0.5)
|
||||
{
|
||||
return float3(0.0, 0.0, 0.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ToLinear(Texture.Sample(TextureSampler, pos.xy).rgb);
|
||||
}
|
||||
}
|
||||
|
||||
float2 Dist(float2 pos)
|
||||
{
|
||||
pos = pos * float2(640, 480);
|
||||
|
||||
return -((pos - floor(pos)) - float2(0.5, 0.5));
|
||||
}
|
||||
|
||||
float Gaus(float pos, float scale)
|
||||
{
|
||||
return exp2(scale * pos * pos);
|
||||
}
|
||||
|
||||
float3 Horz3(float2 pos, float off)
|
||||
{
|
||||
float3 b = Fetch(pos, float2(-1.0, off));
|
||||
float3 c = Fetch(pos, float2(0.0, off));
|
||||
float3 d = Fetch(pos, float2(1.0, off));
|
||||
float dst = Dist(pos).x;
|
||||
|
||||
// Convert distance to weight.
|
||||
float scale = FilterCRTAmount;
|
||||
float wb = Gaus(dst - 1.0, scale);
|
||||
float wc = Gaus(dst + 0.0, scale);
|
||||
float wd = Gaus(dst + 1.0, scale);
|
||||
|
||||
return (b * wb + c * wc + d * wd) / (wb + wc + wd);
|
||||
}
|
||||
|
||||
float3 Horz5(float2 pos, float off)
|
||||
{
|
||||
float3 a = Fetch(pos, float2(-2.0, off));
|
||||
float3 b = Fetch(pos, float2(-1.0, off));
|
||||
float3 c = Fetch(pos, float2(0.0, off));
|
||||
float3 d = Fetch(pos, float2(1.0, off));
|
||||
float3 e = Fetch(pos, float2(2.0, off));
|
||||
float dst = Dist(pos).x;
|
||||
|
||||
// Convert distance to weight.
|
||||
float scale = FilterCRTAmount;
|
||||
|
||||
float wa = Gaus(dst - 2.0, scale);
|
||||
float wb = Gaus(dst - 1.0, scale);
|
||||
float wc = Gaus(dst + 0.0, scale);
|
||||
float wd = Gaus(dst + 1.0, scale);
|
||||
float we = Gaus(dst + 2.0, scale);
|
||||
|
||||
return (a * wa + b * wb + c * wc + d * wd + e * we) / (wa + wb + wc + wd + we);
|
||||
}
|
||||
|
||||
float3 Horz7(float2 pos, float off)
|
||||
{
|
||||
float3 a = Fetch(pos, float2(-3.0, off));
|
||||
float3 b = Fetch(pos, float2(-2.0, off));
|
||||
float3 c = Fetch(pos, float2(-1.0, off));
|
||||
float3 d = Fetch(pos, float2( 0.0, off));
|
||||
float3 e = Fetch(pos, float2( 1.0, off));
|
||||
float3 f = Fetch(pos, float2( 2.0, off));
|
||||
float3 g = Fetch(pos, float2( 3.0, off));
|
||||
|
||||
float dst = Dist(pos).x;
|
||||
// Convert distance to weight.
|
||||
float scale = BloomPixel;
|
||||
float wa = Gaus(dst - 3.0, scale);
|
||||
float wb = Gaus(dst - 2.0, scale);
|
||||
float wc = Gaus(dst - 1.0, scale);
|
||||
float wd = Gaus(dst + 0.0, scale);
|
||||
float we = Gaus(dst + 1.0, scale);
|
||||
float wf = Gaus(dst + 2.0, scale);
|
||||
float wg = Gaus(dst + 3.0, scale);
|
||||
|
||||
// Return filtered sample.
|
||||
return (a * wa + b * wb + c * wc + d * wd + e * we + f * wf + g * wg) / (wa + wb + wc + wd + we + wf + wg);
|
||||
}
|
||||
|
||||
// Return scanline weight.
|
||||
float Scan(float2 pos, float off)
|
||||
{
|
||||
float dst = Dist(pos).y;
|
||||
return Gaus(dst + off, ScanBrightness);
|
||||
}
|
||||
|
||||
float BloomScan(float2 pos, float off)
|
||||
{
|
||||
float dst = Dist(pos).y;
|
||||
|
||||
return Gaus(dst + off, BloomScanLine);
|
||||
}
|
||||
|
||||
float3 Tri(float2 pos)
|
||||
{
|
||||
float3 a = Horz3(pos, -1.0);
|
||||
float3 b = Horz5(pos, 0.0);
|
||||
float3 c = Horz3(pos, 1.0);
|
||||
|
||||
float wa = Scan(pos, -1.0);
|
||||
float wb = Scan(pos, 0.0);
|
||||
float wc = Scan(pos, 1.0);
|
||||
|
||||
return (a * wa) + (b * wb) + (c * wc);
|
||||
}
|
||||
|
||||
float3 Bloom(float2 pos)
|
||||
{
|
||||
float3 a = Horz5(pos,-2.0);
|
||||
float3 b = Horz7(pos,-1.0);
|
||||
float3 c = Horz7(pos, 0.0);
|
||||
float3 d = Horz7(pos, 1.0);
|
||||
float3 e = Horz5(pos, 2.0);
|
||||
|
||||
float wa = BloomScan(pos,-2.0);
|
||||
float wb = BloomScan(pos,-1.0);
|
||||
float wc = BloomScan(pos, 0.0);
|
||||
float wd = BloomScan(pos, 1.0);
|
||||
float we = BloomScan(pos, 2.0);
|
||||
|
||||
return a * wa + b * wb + c * wc + d * wd + e * we;
|
||||
}
|
||||
|
||||
float2 Warp(float2 pos)
|
||||
{
|
||||
pos = pos * 2.0 - 1.0;
|
||||
pos *= float2(1.0 + (pos.y * pos.y) * HorizontalWarp, 1.0 + (pos.x * pos.x) * VerticalWarp);
|
||||
return pos * 0.5 + 0.5;
|
||||
}
|
||||
|
||||
float3 Mask(float2 pos)
|
||||
{
|
||||
#if MaskingType == 1
|
||||
// Very compressed TV style shadow mask.
|
||||
float lines = MaskAmountLight;
|
||||
float odd = 0.0;
|
||||
|
||||
if (frac(pos.x / 6.0) < 0.5)
|
||||
{
|
||||
odd = 1.0;
|
||||
}
|
||||
if (frac((pos.y + odd) / 2.0) < 0.5)
|
||||
{
|
||||
lines = MaskAmountDark;
|
||||
}
|
||||
pos.x = frac(pos.x / 3.0);
|
||||
float3 mask = float3(MaskAmountDark, MaskAmountDark, MaskAmountDark);
|
||||
|
||||
if (pos.x < 0.333)
|
||||
{
|
||||
mask.r = MaskAmountLight;
|
||||
}
|
||||
else if (pos.x < 0.666)
|
||||
{
|
||||
mask.g = MaskAmountLight;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask.b = MaskAmountLight;
|
||||
}
|
||||
|
||||
mask *= lines;
|
||||
|
||||
return mask;
|
||||
|
||||
#elif MaskingType == 2
|
||||
// Aperture-grille.
|
||||
pos.x = frac(pos.x / 3.0);
|
||||
float3 mask = float3(MaskAmountDark, MaskAmountDark, MaskAmountDark);
|
||||
|
||||
if (pos.x < 0.333)
|
||||
{
|
||||
mask.r = MaskAmountLight;
|
||||
}
|
||||
else if (pos.x < 0.666)
|
||||
{
|
||||
mask.g = MaskAmountLight;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask.b = MaskAmountLight;
|
||||
}
|
||||
|
||||
return mask;
|
||||
|
||||
#elif MaskingType == 3
|
||||
// Stretched VGA style shadow mask (same as prior shaders).
|
||||
pos.x += pos.y * 3.0;
|
||||
float3 mask = float3(MaskAmountDark, MaskAmountDark, MaskAmountDark);
|
||||
pos.x = frac(pos.x / 6.0);
|
||||
|
||||
if (pos.x < 0.333)
|
||||
{
|
||||
mask.r = MaskAmountLight;
|
||||
}
|
||||
else if (pos.x < 0.666)
|
||||
{
|
||||
mask.g = MaskAmountLight;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask.b = MaskAmountLight;
|
||||
}
|
||||
|
||||
return mask;
|
||||
|
||||
#else
|
||||
// VGA style shadow mask.
|
||||
pos.xy = floor(pos.xy * float2(1.0, 0.5));
|
||||
pos.x += pos.y * 3.0;
|
||||
|
||||
float3 mask = float3(MaskAmountDark, MaskAmountDark, MaskAmountDark);
|
||||
pos.x = frac(pos.x / 6.0);
|
||||
|
||||
if (pos.x < 0.333)
|
||||
{
|
||||
mask.r = MaskAmountLight;
|
||||
}
|
||||
else if (pos.x < 0.666)
|
||||
{
|
||||
mask.g = MaskAmountLight;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask.b = MaskAmountLight;
|
||||
}
|
||||
return mask;
|
||||
#endif
|
||||
}
|
||||
|
||||
float4 LottesCRTPass(float4 fragcoord)
|
||||
{
|
||||
float4 color;
|
||||
fragcoord -= u_target_rect;
|
||||
float2 inSize = u_target_resolution - (2 * u_target_rect.xy);
|
||||
|
||||
float2 pos = Warp(fragcoord.xy / inSize);
|
||||
color.rgb = Tri(pos);
|
||||
color.rgb += Bloom(pos) * BloomAmount;
|
||||
#if UseShadowMask
|
||||
color.rgb *= Mask(fragcoord.xy);
|
||||
#endif
|
||||
color.rgb = ToSrgb(color.rgb);
|
||||
color.a = 1.0;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_filter_lottes(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
output.c = LottesCRTPass(input.p);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_4x_rgss(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
float2 dxy = float2(ddx(input.t.x), ddy(input.t.y));
|
||||
float3 color = 0;
|
||||
|
||||
float s = 1.0/8.0;
|
||||
float l = 3.0/8.0;
|
||||
|
||||
color += sample_c(input.t + float2( s, l) * dxy).rgb;
|
||||
color += sample_c(input.t + float2( l,-s) * dxy).rgb;
|
||||
color += sample_c(input.t + float2(-s,-l) * dxy).rgb;
|
||||
color += sample_c(input.t + float2(-l, s) * dxy).rgb;
|
||||
|
||||
output.c = float4(color * 0.25,1);
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_automagical_supersampling(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
float2 ratio = (u_source_size / u_target_size) * 0.5;
|
||||
float2 steps = floor(ratio);
|
||||
float3 col = sample_c(input.t).rgb;
|
||||
float div = 1;
|
||||
|
||||
for (float y = 0; y < steps.y; y++)
|
||||
{
|
||||
for (float x = 0; x < steps.x; x++)
|
||||
{
|
||||
float2 offset = float2(x,y) - ratio * 0.5;
|
||||
col += sample_c(input.t + offset * u_rcp_source_resolution * 2.0).rgb;
|
||||
div++;
|
||||
}
|
||||
}
|
||||
|
||||
output.c = float4(col / div, 1);
|
||||
return output;
|
||||
}
|
||||
52
bin/resources/shaders/dx11/shadeboost.fx
Normal file
52
bin/resources/shaders/dx11/shadeboost.fx
Normal file
@@ -0,0 +1,52 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
Texture2D Texture;
|
||||
SamplerState Sampler;
|
||||
|
||||
cbuffer cb0
|
||||
{
|
||||
float4 params;
|
||||
};
|
||||
|
||||
/*
|
||||
** Contrast, saturation, brightness
|
||||
** Code of this function is from TGM's shader pack
|
||||
** http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=21057
|
||||
*/
|
||||
|
||||
// For all settings: 1.0 = 100% 0.5=50% 1.5 = 150%
|
||||
float4 ContrastSaturationBrightness(float4 color) // Ported to HLSL
|
||||
{
|
||||
float brt = params.x;
|
||||
float con = params.y;
|
||||
float sat = params.z;
|
||||
|
||||
// Increase or decrease these values to adjust r, g and b color channels separately
|
||||
const float AvgLumR = 0.5;
|
||||
const float AvgLumG = 0.5;
|
||||
const float AvgLumB = 0.5;
|
||||
|
||||
const float3 LumCoeff = float3(0.2125, 0.7154, 0.0721);
|
||||
|
||||
float3 AvgLumin = float3(AvgLumR, AvgLumG, AvgLumB);
|
||||
float3 brtColor = color.rgb * brt;
|
||||
float3 intensity = dot(brtColor, LumCoeff);
|
||||
float3 satColor = lerp(intensity, brtColor, sat);
|
||||
float3 conColor = lerp(AvgLumin, satColor, con);
|
||||
|
||||
color.rgb = conColor;
|
||||
return color;
|
||||
}
|
||||
|
||||
struct PS_INPUT
|
||||
{
|
||||
float4 p : SV_Position;
|
||||
float2 t : TEXCOORD0;
|
||||
};
|
||||
|
||||
float4 ps_main(PS_INPUT input) : SV_Target0
|
||||
{
|
||||
float4 c = Texture.Sample(Sampler, input.t);
|
||||
return ContrastSaturationBrightness(c);
|
||||
}
|
||||
1351
bin/resources/shaders/dx11/tfx.fx
Normal file
1351
bin/resources/shaders/dx11/tfx.fx
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user