diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/all.txt b/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/all.txt deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur.ps.glsl b/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur.ps.glsl deleted file mode 100644 index 3ad5cb5856..0000000000 --- a/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur.ps.glsl +++ /dev/null @@ -1,45 +0,0 @@ -void process_fragment(in DolphinFragmentInput frag_input, out DolphinFragmentOutput frag_output) -{ - int layer = int(frag_input.tex0.z); - int r = int(efb_scale) * int(SPREAD_MULTIPLIER); - int coord; - int length; - int2 initial_coords = int2(frag_input.tex0.xy * source_resolution.xy); - vec4 brightness = float4(1.0, 1.0, 1.0, 1.0); - if (HORIZONTAL) - { - length = int(source_resolution.x); - coord = initial_coords.x; - brightness = BRIGHTNESS_MULTIPLIER * brightness; - } - else - { - length = int(source_resolution.y); - coord = initial_coords.y; - } - - int offset; - vec4 count = vec4(0.0,0.0,0.0,0.0); - vec4 col = vec4(0.0,0.0,0.0,0.0); - for (offset = -r; offset <= r; offset++) - { - int pos = coord + offset; - if (pos <= length && pos >= 0) - { - int3 sample_coords; - if (HORIZONTAL) - { - sample_coords = int3(int2(pos, initial_coords.y), layer); - } - else - { - sample_coords = int3(int2(initial_coords.x, pos), layer); - } - - col += texelFetch(samp0, sample_coords, 0); - count += vec4(1.0,1.0,1.0,1.0); - } - } - frag_output.main = col / count * brightness; - -} diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur.rastershader b/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur.rastershader deleted file mode 100644 index 6c66f0b81e..0000000000 --- a/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur.rastershader +++ /dev/null @@ -1,23 +0,0 @@ -{ - "properties":[ - { - "code_name": "HORIZONTAL", - "default": true, - "description": "Whether to apply the blur horizontally or vertically", - "type": "bool" - }, - { - "code_name": "SPREAD_MULTIPLIER", - "default": 1.0, - "description": "How much to spread the blur", - "type": "float" - }, - { - "code_name": "BRIGHTNESS_MULTIPLIER", - "default": 1.0, - "description": "How bright the blur is", - "type": "float" - } - ], - "samplers":[] -} diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur.vs.glsl b/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur.vs.glsl deleted file mode 100644 index 68d5c36778..0000000000 --- a/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur.vs.glsl +++ /dev/null @@ -1,4 +0,0 @@ -void process_vertex(in DolphinVertexInput vertex_input, out DolphinVertexOutput vertex_output) -{ - dolphin_process_emulated_vertex(vertex_input, vertex_output); -} diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur_horizontal.rastermaterial b/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur_horizontal.rastermaterial deleted file mode 100644 index a2b869a214..0000000000 --- a/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur_horizontal.rastermaterial +++ /dev/null @@ -1,19 +0,0 @@ -{ - "next_material_asset":"dolphin_bloom_blur_vertical", - "properties":[ - { - "type": "bool", - "value": true - }, - { - "type": "float", - "value": 1.0 - }, - { - "type": "float", - "value": 1.0 - } - ], - "textures":[], - "shader_asset": "dolphin_bloom_blur" -} diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur_vertical.rastermaterial b/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur_vertical.rastermaterial deleted file mode 100644 index 044d0a33f8..0000000000 --- a/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur_vertical.rastermaterial +++ /dev/null @@ -1,19 +0,0 @@ -{ - "next_material_asset":"", - "properties":[ - { - "type": "bool", - "value": false - }, - { - "type": "float", - "value": 1.0 - }, - { - "type": "float", - "value": 1.0 - } - ], - "textures":[], - "shader_asset": "dolphin_bloom_blur" -} diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/metadata.json b/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/metadata.json deleted file mode 100644 index 8b79c3e05e..0000000000 --- a/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/metadata.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "meta": - { - "title": "Bloom Blurred", - "author": "Dolphin Team", - "description": "Modifies bloom effects to blur them to their native resolution. Results in bloom looking much more natural at higher resolutions but the blur may be too intense in some games." - }, - "features": - [ - { - "group": "Bloom", - "action": "custom_pipeline", - "action_data": - { - "material_asset": "dolphin_bloom_blur_horizontal" - } - } - ], - "assets": [ - { - "data": { - "metadata": "blur.rastershader", - "pixel_shader": "blur.ps.glsl", - "vertex_shader": "blur.vs.glsl" - }, - "name": "dolphin_bloom_blur" - }, - { - "data": { - "metadata": "blur_horizontal.rastermaterial" - }, - "name": "dolphin_bloom_blur_horizontal" - }, - { - "data": { - "metadata": "blur_vertical.rastermaterial" - }, - "name": "dolphin_bloom_blur_vertical" - } - ] -} diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred DOF/all.txt b/Data/Sys/Load/GraphicMods/All Games Blurred DOF/all.txt deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur.ps.glsl b/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur.ps.glsl deleted file mode 100644 index 3ad5cb5856..0000000000 --- a/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur.ps.glsl +++ /dev/null @@ -1,45 +0,0 @@ -void process_fragment(in DolphinFragmentInput frag_input, out DolphinFragmentOutput frag_output) -{ - int layer = int(frag_input.tex0.z); - int r = int(efb_scale) * int(SPREAD_MULTIPLIER); - int coord; - int length; - int2 initial_coords = int2(frag_input.tex0.xy * source_resolution.xy); - vec4 brightness = float4(1.0, 1.0, 1.0, 1.0); - if (HORIZONTAL) - { - length = int(source_resolution.x); - coord = initial_coords.x; - brightness = BRIGHTNESS_MULTIPLIER * brightness; - } - else - { - length = int(source_resolution.y); - coord = initial_coords.y; - } - - int offset; - vec4 count = vec4(0.0,0.0,0.0,0.0); - vec4 col = vec4(0.0,0.0,0.0,0.0); - for (offset = -r; offset <= r; offset++) - { - int pos = coord + offset; - if (pos <= length && pos >= 0) - { - int3 sample_coords; - if (HORIZONTAL) - { - sample_coords = int3(int2(pos, initial_coords.y), layer); - } - else - { - sample_coords = int3(int2(initial_coords.x, pos), layer); - } - - col += texelFetch(samp0, sample_coords, 0); - count += vec4(1.0,1.0,1.0,1.0); - } - } - frag_output.main = col / count * brightness; - -} diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur.rastershader b/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur.rastershader deleted file mode 100644 index 6c66f0b81e..0000000000 --- a/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur.rastershader +++ /dev/null @@ -1,23 +0,0 @@ -{ - "properties":[ - { - "code_name": "HORIZONTAL", - "default": true, - "description": "Whether to apply the blur horizontally or vertically", - "type": "bool" - }, - { - "code_name": "SPREAD_MULTIPLIER", - "default": 1.0, - "description": "How much to spread the blur", - "type": "float" - }, - { - "code_name": "BRIGHTNESS_MULTIPLIER", - "default": 1.0, - "description": "How bright the blur is", - "type": "float" - } - ], - "samplers":[] -} diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur.vs.glsl b/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur.vs.glsl deleted file mode 100644 index 68d5c36778..0000000000 --- a/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur.vs.glsl +++ /dev/null @@ -1,4 +0,0 @@ -void process_vertex(in DolphinVertexInput vertex_input, out DolphinVertexOutput vertex_output) -{ - dolphin_process_emulated_vertex(vertex_input, vertex_output); -} diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur_horizontal.rastermaterial b/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur_horizontal.rastermaterial deleted file mode 100644 index ca9887f082..0000000000 --- a/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur_horizontal.rastermaterial +++ /dev/null @@ -1,19 +0,0 @@ -{ - "next_material_asset":"dolphin_dof_blur_vertical", - "properties":[ - { - "type": "bool", - "value": true - }, - { - "type": "float", - "value": 1.0 - }, - { - "type": "float", - "value": 1.0 - } - ], - "textures":[], - "shader_asset": "dolphin_dof_blur" -} diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur_vertical.rastermaterial b/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur_vertical.rastermaterial deleted file mode 100644 index 3934d7994f..0000000000 --- a/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur_vertical.rastermaterial +++ /dev/null @@ -1,19 +0,0 @@ -{ - "next_material_asset":"", - "properties":[ - { - "type": "bool", - "value": false - }, - { - "type": "float", - "value": 1.0 - }, - { - "type": "float", - "value": 1.0 - } - ], - "textures":[], - "shader_asset": "dolphin_dof_blur" -} diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred DOF/metadata.json b/Data/Sys/Load/GraphicMods/All Games Blurred DOF/metadata.json deleted file mode 100644 index 0eb0f4b8b0..0000000000 --- a/Data/Sys/Load/GraphicMods/All Games Blurred DOF/metadata.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "meta": - { - "title": "DOF Blurred", - "author": "Dolphin Team", - "description": "Modifies depth of field effects to blur them to their native resolution. Results in depth of field looking much more natural at higher resolutions but the blur may be too intense in some games." - }, - "features": - [ - { - "group": "DOF", - "action": "custom_pipeline", - "action_data": - { - "material_asset": "dolphin_dof_blur_horizontal" - } - } - ], - "assets": [ - { - "data": { - "metadata": "blur.rastershader", - "pixel_shader": "blur.ps.glsl", - "vertex_shader": "blur.vs.glsl" - }, - "name": "dolphin_dof_blur" - }, - { - "data": { - "metadata": "blur_horizontal.rastermaterial" - }, - "name": "dolphin_dof_blur_horizontal" - }, - { - "data": { - "metadata": "blur_vertical.rastermaterial" - }, - "name": "dolphin_dof_blur_vertical" - } - ] -} diff --git a/Data/Sys/Shaders/16bit.glsl b/Data/Sys/Shaders/16bit.glsl deleted file mode 100644 index fd13d3469e..0000000000 --- a/Data/Sys/Shaders/16bit.glsl +++ /dev/null @@ -1,54 +0,0 @@ -void main() -{ - //Change this number to increase the pixel size. - float pixelSize = 3.0; - - float red = 0.0; - float green = 0.0; - float blue = 0.0; - - float2 pos = floor(GetCoordinates() * GetResolution() / pixelSize) * pixelSize * GetInvResolution(); - - float4 c0 = SampleLocation(pos); - - if (c0.r < 0.1) - red = 0.1; - else if (c0.r < 0.20) - red = 0.20; - else if (c0.r < 0.40) - red = 0.40; - else if (c0.r < 0.60) - red = 0.60; - else if (c0.r < 0.80) - red = 0.80; - else - red = 1.0; - - if (c0.b < 0.1) - blue = 0.1; - else if (c0.b < 0.20) - blue = 0.20; - else if (c0.b < 0.40) - blue = 0.40; - else if (c0.b < 0.60) - blue = 0.60; - else if (c0.b < 0.80) - blue = 0.80; - else - blue = 1.0; - - if (c0.g < 0.1) - green = 0.1; - else if (c0.g < 0.20) - green = 0.20; - else if (c0.g < 0.40) - green = 0.40; - else if (c0.g < 0.60) - green = 0.60; - else if (c0.g < 0.80) - green = 0.80; - else - green = 1.0; - - SetOutput(float4(red, green, blue, c0.a)); -} diff --git a/Data/Sys/Shaders/32bit.glsl b/Data/Sys/Shaders/32bit.glsl deleted file mode 100644 index d0e43db2ce..0000000000 --- a/Data/Sys/Shaders/32bit.glsl +++ /dev/null @@ -1,79 +0,0 @@ -void main() -{ - //Change this number to increase the pixel size. - float pixelSize = 2.0; - - float red = 0.0; - float green = 0.0; - float blue = 0.0; - - float2 pos = floor(GetCoordinates() * GetResolution() / pixelSize) * pixelSize * GetInvResolution(); - - float4 c0 = SampleLocation(pos); - - if (c0.r < 0.06) - red = 0.06; - else if (c0.r < 0.13) - red = 0.13; - else if (c0.r < 0.26) - red = 0.26; - else if (c0.r < 0.33) - red = 0.33; - else if (c0.r < 0.46) - red = 0.46; - else if (c0.r < 0.60) - red = 0.60; - else if (c0.r < 0.73) - red = 0.73; - else if (c0.r < 0.80) - red = 0.80; - else if (c0.r < 0.93) - red = 0.93; - else - red = 1.0; - - if (c0.b < 0.06) - blue = 0.06; - else if (c0.b < 0.13) - blue = 0.13; - else if (c0.b < 0.26) - blue = 0.26; - else if (c0.b < 0.33) - blue = 0.33; - else if (c0.b < 0.46) - blue = 0.46; - else if (c0.b < 0.60) - blue = 0.60; - else if (c0.b < 0.73) - blue = 0.73; - else if (c0.b < 0.80) - blue = 0.80; - else if( c0.b < 0.93) - blue = 0.93; - else - blue = 1.0; - - - if (c0.g < 0.06) - green = 0.06; - else if (c0.g < 0.13) - green = 0.13; - else if (c0.g < 0.26) - green = 0.26; - else if (c0.g < 0.33) - green = 0.33; - else if (c0.g < 0.46) - green = 0.46; - else if (c0.g < 0.60) - green = 0.60; - else if (c0.g < 0.73) - green = 0.73; - else if (c0.g < 0.80) - green = 0.80; - else if( c0.g < 0.93) - green = 0.93; - else - green = 1.0; - - SetOutput(float4(red, green, blue, c0.a)); -} diff --git a/Data/Sys/Shaders/Anaglyph/dubois-LCD-Amber-Blue.glsl b/Data/Sys/Shaders/Anaglyph/dubois-LCD-Amber-Blue.glsl deleted file mode 100644 index c6410c5c19..0000000000 --- a/Data/Sys/Shaders/Anaglyph/dubois-LCD-Amber-Blue.glsl +++ /dev/null @@ -1,20 +0,0 @@ -// Anaglyph Amber-Blue shader based on Dubois algorithm -// Constants taken from the screenshot: -// "https://www.flickr.com/photos/e_dubois/5230654930/" -// Eric Dubois - -void main() -{ - float4 c0 = SampleLayer(0); - float4 c1 = SampleLayer(1); - - float3 lr = float3( 1.062,-0.205, 0.299); - float3 lg = float3(-0.026, 0.908, 0.068); - float3 lb = float3(-0.038,-0.173, 0.022); - - float3 rr = float3(-0.016,-0.123,-0.017); - float3 rg = float3( 0.006, 0.062, 0.017); - float3 rb = float3(-0.094,-0.185, 0.991); - - SetOutput(float4(dot(lr, c0.rgb) + dot(rr, c1.rgb), dot(lg, c0.rgb) + dot(rg, c1.rgb), dot(lb, c0.rgb) + dot(rb, c1.rgb), c0.a)); -} diff --git a/Data/Sys/Shaders/Anaglyph/dubois-LCD-Green-Magenta.glsl b/Data/Sys/Shaders/Anaglyph/dubois-LCD-Green-Magenta.glsl deleted file mode 100644 index bb97bf107b..0000000000 --- a/Data/Sys/Shaders/Anaglyph/dubois-LCD-Green-Magenta.glsl +++ /dev/null @@ -1,20 +0,0 @@ -// Anaglyph Green-Magenta shader based on Dubois algorithm -// Constants taken from the screenshot: -// "https://www.flickr.com/photos/e_dubois/5132528166/" -// Eric Dubois - -void main() -{ - float4 c0 = SampleLayer(0); - float4 c1 = SampleLayer(1); - - float3 lr = float3(-0.062,-0.158,-0.039); - float3 lg = float3( 0.284, 0.668, 0.143); - float3 lb = float3(-0.015,-0.027, 0.021); - - float3 rr = float3( 0.529, 0.705, 0.024); - float3 rg = float3(-0.016,-0.015, 0.065); - float3 rb = float3( 0.009, 0.075, 0.937); - - SetOutput(float4(dot(lr, c0.rgb) + dot(rr, c1.rgb), dot(lg, c0.rgb) + dot(rg, c1.rgb), dot(lb, c0.rgb) + dot(rb, c1.rgb), c0.a)); -} diff --git a/Data/Sys/Shaders/Anaglyph/dubois.glsl b/Data/Sys/Shaders/Anaglyph/dubois.glsl deleted file mode 100644 index 18c714ddbe..0000000000 --- a/Data/Sys/Shaders/Anaglyph/dubois.glsl +++ /dev/null @@ -1,21 +0,0 @@ -// Anaglyph Red-Cyan shader based on Dubois algorithm -// Constants taken from the paper: -// "Conversion of a Stereo Pair to Anaglyph with -// the Least-Squares Projection Method" -// Eric Dubois, March 2009 - -void main() -{ - float4 c0 = SampleLayer(0); - float4 c1 = SampleLayer(1); - - float3 lr = float3( 0.437, 0.449, 0.164); - float3 lg = float3(-0.062,-0.062,-0.024); - float3 lb = float3(-0.048,-0.050,-0.017); - - float3 rr = float3(-0.011,-0.032,-0.007); - float3 rg = float3( 0.377, 0.761, 0.009); - float3 rb = float3(-0.026,-0.093, 1.234); - - SetOutput(float4(dot(lr, c0.rgb) + dot(rr, c1.rgb), dot(lg, c0.rgb) + dot(rg, c1.rgb), dot(lb, c0.rgb) + dot(rb, c1.rgb), c0.a)); -} diff --git a/Data/Sys/Shaders/Anaglyph/fullcolor.glsl b/Data/Sys/Shaders/Anaglyph/fullcolor.glsl deleted file mode 100644 index 8f033aedf1..0000000000 --- a/Data/Sys/Shaders/Anaglyph/fullcolor.glsl +++ /dev/null @@ -1,8 +0,0 @@ -// Anaglyph Red-Cyan shader without compensation - -void main() -{ - float4 c0 = SampleLayer(0); - float4 c1 = SampleLayer(1); - SetOutput(float4(c0.r, c1.gb, c0.a)); -} diff --git a/Data/Sys/Shaders/Anaglyph/grayscale.glsl b/Data/Sys/Shaders/Anaglyph/grayscale.glsl deleted file mode 100644 index a1be73da28..0000000000 --- a/Data/Sys/Shaders/Anaglyph/grayscale.glsl +++ /dev/null @@ -1,10 +0,0 @@ -// Anaglyph Red-Cyan grayscale shader - -void main() -{ - float4 c0 = SampleLayer(0); - float avg0 = (c0.r + c0.g + c0.b) / 3.0; - float4 c1 = SampleLayer(1); - float avg1 = (c1.r + c1.g + c1.b) / 3.0; - SetOutput(float4(avg0, avg1, avg1, c0.a)); -} diff --git a/Data/Sys/Shaders/Anaglyph/grayscale2.glsl b/Data/Sys/Shaders/Anaglyph/grayscale2.glsl deleted file mode 100644 index 14c5068704..0000000000 --- a/Data/Sys/Shaders/Anaglyph/grayscale2.glsl +++ /dev/null @@ -1,12 +0,0 @@ -// Anaglyph Red-Cyan luma grayscale shader -// Info: https://web.archive.org/web/20040101053504/http://www.oreillynet.com:80/cs/user/view/cs_msg/8691 - -void main() -{ - float3 luma = float3(0.222, 0.707, 0.071); - float4 c0 = SampleLayer(0); - float avg0 = dot(c0.rgb, luma); - float4 c1 = SampleLayer(1); - float avg1 = dot(c1.rgb, luma); - SetOutput(float4(avg0, avg1, avg1, c0.a)); -} diff --git a/Data/Sys/Shaders/AutoHDR.glsl b/Data/Sys/Shaders/AutoHDR.glsl deleted file mode 100644 index b806d65838..0000000000 --- a/Data/Sys/Shaders/AutoHDR.glsl +++ /dev/null @@ -1,69 +0,0 @@ -// Based on https://github.com/Filoppi/PumboAutoHDR - -/* -[configuration] - -[OptionRangeFloat] -GUIName = HDR Display Max Nits -OptionName = HDR_DISPLAY_MAX_NITS -MinValue = 80 -MaxValue = 2000 -StepAmount = 1 -DefaultValue = 400 - -[OptionRangeFloat] -GUIName = Shoulder Start Alpha -OptionName = AUTO_HDR_SHOULDER_START_ALPHA -MinValue = 0 -MaxValue = 1 -StepAmount = 0.01 -DefaultValue = 0 - -[OptionRangeFloat] -GUIName = Shoulder Pow -OptionName = AUTO_HDR_SHOULDER_POW -MinValue = 1 -MaxValue = 10 -StepAmount = 0.05 -DefaultValue = 2.5 - -[/configuration] -*/ - -float luminance(float3 color) -{ - return dot(color, float3(0.2126f, 0.7152f, 0.0722f)); -} - -void main() -{ - float4 color = Sample(); - - // Nothing to do here, we are in SDR - if (!OptionEnabled(hdr_output) || !OptionEnabled(linear_space_output)) - { - SetOutput(color); - return; - } - - const float hdr_paper_white = hdr_paper_white_nits / hdr_sdr_white_nits; - - // Restore the original SDR (0-1) brightness (we might or might not restore it later) - color.rgb /= hdr_paper_white; - - // Find the color luminance (it works better than average) - float sdr_ratio = luminance(color.rgb); - - const float auto_hdr_max_white = max(HDR_DISPLAY_MAX_NITS / (hdr_paper_white_nits / hdr_sdr_white_nits), hdr_sdr_white_nits) / hdr_sdr_white_nits; - if (sdr_ratio > AUTO_HDR_SHOULDER_START_ALPHA && AUTO_HDR_SHOULDER_START_ALPHA < 1.0) - { - const float auto_hdr_shoulder_ratio = 1.0 - (max(1.0 - sdr_ratio, 0.0) / (1.0 - AUTO_HDR_SHOULDER_START_ALPHA)); - const float auto_hdr_extra_ratio = pow(auto_hdr_shoulder_ratio, AUTO_HDR_SHOULDER_POW) * (auto_hdr_max_white - 1.0); - const float auto_hdr_total_ratio = sdr_ratio + auto_hdr_extra_ratio; - color.rgb *= auto_hdr_total_ratio / sdr_ratio; - } - - color.rgb *= hdr_paper_white; - - SetOutput(color); -} diff --git a/Data/Sys/Shaders/FXAA.glsl b/Data/Sys/Shaders/FXAA.glsl deleted file mode 100644 index 897bd30e62..0000000000 --- a/Data/Sys/Shaders/FXAA.glsl +++ /dev/null @@ -1,67 +0,0 @@ -// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -// Version 2, December 2004 - -// Copyright (C) 2013 mudlord - -// Everyone is permitted to copy and distribute verbatim or modified -// copies of this license document, and changing it is allowed as long -// as the name is changed. - -// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - -// 0. You just DO WHAT THE FUCK YOU WANT TO. - -#define FXAA_REDUCE_MIN (1.0/ 128.0) -#define FXAA_REDUCE_MUL (1.0 / 8.0) -#define FXAA_SPAN_MAX 8.0 - -float4 applyFXAA(float2 fragCoord) -{ - float4 color; - float2 inverseVP = GetInvResolution(); - float3 rgbNW = SampleLocation((fragCoord + float2(-1.0, -1.0)) * inverseVP).xyz; - float3 rgbNE = SampleLocation((fragCoord + float2(1.0, -1.0)) * inverseVP).xyz; - float3 rgbSW = SampleLocation((fragCoord + float2(-1.0, 1.0)) * inverseVP).xyz; - float3 rgbSE = SampleLocation((fragCoord + float2(1.0, 1.0)) * inverseVP).xyz; - float3 rgbM = SampleLocation(fragCoord * inverseVP).xyz; - float3 luma = float3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - float2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(float2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(float2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * inverseVP; - - float3 rgbA = 0.5 * ( - SampleLocation(fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - SampleLocation(fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - float3 rgbB = rgbA * 0.5 + 0.25 * ( - SampleLocation(fragCoord * inverseVP + dir * -0.5).xyz + - SampleLocation(fragCoord * inverseVP + dir * 0.5).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = float4(rgbA, 1.0); - else - color = float4(rgbB, 1.0); - return color; -} - -void main() -{ - SetOutput(applyFXAA(GetCoordinates() * GetResolution())); -} diff --git a/Data/Sys/Shaders/Passive/horizontal.glsl b/Data/Sys/Shaders/Passive/horizontal.glsl deleted file mode 100644 index 7b2535bbf0..0000000000 --- a/Data/Sys/Shaders/Passive/horizontal.glsl +++ /dev/null @@ -1,7 +0,0 @@ -// Passive (horizontal rows) shader - -void main() -{ - float screen_row = GetWindowResolution().y * GetCoordinates().y; - SetOutput(SampleLayer(int(screen_row) % 2)); -} diff --git a/Data/Sys/Shaders/PerceptualHDR.glsl b/Data/Sys/Shaders/PerceptualHDR.glsl deleted file mode 100644 index 8d020dc659..0000000000 --- a/Data/Sys/Shaders/PerceptualHDR.glsl +++ /dev/null @@ -1,129 +0,0 @@ -/* -[configuration] - -[OptionRangeFloat] -GUIName = Amplificiation -OptionName = AMPLIFICATION -MinValue = 1.0 -MaxValue = 6.0 -StepAmount = 0.25 -DefaultValue = 2.5 - -[/configuration] -*/ - -// ICtCP Colorspace as defined by Dolby here: -// https://professional.dolby.com/siteassets/pdfs/ictcp_dolbywhitepaper_v071.pdf - -/***** Transfer Function *****/ - -const float a = 0.17883277; -const float b = 1.0 - 4.0 * a; -const float c = 0.5 - a * log(4.0 * a); - -float HLG_f(float x) -{ - if (x < 0.0) { - return 0.0; - } - - else if (x < 1.0 / 12.0) { - return sqrt(3.0 * x); - } - - return a * log(12.0 * x - b) + c; -} - -float HLG_inv_f(float x) -{ - if (x < 0.0) { - return 0.0; - } - - else if (x < 1.0 / 2.0) { - return x * x / 3.0; - } - - return (exp((x - c) / a) + b) / 12.0; -} - -float4 HLG(float4 lms) -{ - return float4(HLG_f(lms.x), HLG_f(lms.y), HLG_f(lms.z), lms.w); -} - -float4 HLG_inv(float4 lms) -{ - return float4(HLG_inv_f(lms.x), HLG_inv_f(lms.y), HLG_inv_f(lms.z), lms.w); -} - -/***** Linear <--> ICtCp *****/ - -const mat4 RGBtoLMS = mat4( - 1688.0, 683.0, 99.0, 0.0, - 2146.0, 2951.0, 309.0, 0.0, - 262.0, 462.0, 3688.0, 0.0, - 0.0, 0.0, 0.0, 4096.0) - / 4096.0; - -const mat4 LMStoICtCp = mat4( - +2048.0, +3625.0, +9500.0, 0.0, - +2048.0, -7465.0, -9212.0, 0.0, - +0.0, +3840.0, -288.0, 0.0, - +0.0, +0.0, +0.0, 4096.0) - / 4096.0; - -float4 LinearRGBToICtCP(float4 c) -{ - return LMStoICtCp * HLG(RGBtoLMS * c); -} - -/***** ICtCp <--> Linear *****/ - -mat4 ICtCptoLMS = inverse(LMStoICtCp); -mat4 LMStoRGB = inverse(RGBtoLMS); - -float4 ICtCpToLinearRGB(float4 c) -{ - return LMStoRGB * HLG_inv(ICtCptoLMS * c); -} - -void main() -{ - float4 color = Sample(); - - // Nothing to do here, we are in SDR - if (!OptionEnabled(hdr_output) || !OptionEnabled(linear_space_output)) { - SetOutput(color); - return; - } - - // Renormalize Color to be in [0.0 - 1.0] SDR Space. We will revert this later. - const float hdr_paper_white = hdr_paper_white_nits / hdr_sdr_white_nits; - color.rgb /= hdr_paper_white; - - // Convert Color to Perceptual Color Space. This will allow us to do perceptual - // scaling while also being able to use the luminance channel. - float4 ictcp_color = LinearRGBToICtCP(color); - - // Scale the color in perceptual space depending on the perceived luminance. - // - // At low luminances, ~0.0, pow(AMPLIFICATION, ~0.0) ~= 1.0, so the - // color will appear to be unchanged. This is important as we don't want to - // over expose dark colors which would not have otherwise been seen. - // - // At high luminances, ~1.0, pow(AMPLIFICATION, ~1.0) ~= AMPLIFICATION, - // which is equivalent to scaling the color by AMPLIFICATION. This is - // important as we want to get the most out of the display, and we want to - // get bright colors to hit their target brightness. - // - // For more information, see this desmos demonstrating this scaling process: - // https://www.desmos.com/calculator/syjyrjsj5c - float exposure = length(ictcp_color.xyz); - ictcp_color *= pow(HLG_f(AMPLIFICATION), exposure); - - // Convert back to Linear RGB and output the color to the display. - // We use hdr_paper_white to renormalize the color to the comfortable - // SDR viewing range. - SetOutput(hdr_paper_white * ICtCpToLinearRGB(ictcp_color)); -} diff --git a/Data/Sys/Shaders/acidmetal.glsl b/Data/Sys/Shaders/acidmetal.glsl deleted file mode 100644 index 6ea8891f6a..0000000000 --- a/Data/Sys/Shaders/acidmetal.glsl +++ /dev/null @@ -1,16 +0,0 @@ -void main() -{ - float4 c0 = Sample(); - float red = 0.0; - float blue = 0.0; - - if (c0.r > 0.15 && c0.b > 0.15) - { - blue = 0.5; - red = 0.5; - } - - float green = max(c0.r + c0.b, c0.g); - - SetOutput(float4(red, green, blue, 1.0)); -} diff --git a/Data/Sys/Shaders/acidtrip.glsl b/Data/Sys/Shaders/acidtrip.glsl deleted file mode 100644 index 8722e621f1..0000000000 --- a/Data/Sys/Shaders/acidtrip.glsl +++ /dev/null @@ -1,4 +0,0 @@ -void main() -{ - SetOutput((SampleOffset(int2(1, 1)) - SampleOffset(int2(-1, -1))) * 8.0); -} diff --git a/Data/Sys/Shaders/acidtrip2.glsl b/Data/Sys/Shaders/acidtrip2.glsl deleted file mode 100644 index 054fe17173..0000000000 --- a/Data/Sys/Shaders/acidtrip2.glsl +++ /dev/null @@ -1,6 +0,0 @@ -void main() -{ - float4 a = SampleOffset(int2( 1, 1)); - float4 b = SampleOffset(int2(-1, -1)); - SetOutput(( a*a*1.3 - b ) * 8.0); -} diff --git a/Data/Sys/Shaders/asciiart.glsl b/Data/Sys/Shaders/asciiart.glsl deleted file mode 100644 index 445f204bd7..0000000000 --- a/Data/Sys/Shaders/asciiart.glsl +++ /dev/null @@ -1,485 +0,0 @@ -/* -[configuration] - -[OptionBool] -GUIName = Use target window resolution -OptionName = USE_WINDOW_RES -DefaultValue = true - -[OptionBool] -GUIName = Debug: Calculate only one character per subgroup -OptionName = DEBUG_ONLY_ONE_CHAR -DefaultValue = false - -[/configuration] -*/ - -const uint MAX_CHARS = 96u; // max 96, must be a multiple of 32 -const bool HAVE_FULL_FEATURE_FALLBACK = false; // terrible slow, can easily softlock the GPU -const uint UNROLL_FALLBACK = 4; -const uint UNROLL_SIMD = 3; // max MAX_CHARS / 32 - -// #undef SUPPORTS_SUBGROUP_REDUCTION - -#ifdef API_VULKAN -// By default, subgroupBroadcast only supports compile time constants as index. -// However we need an uniform instead. This is always supported in OpenGL, -// but in Vulkan only in SPIR-V >= 1.5. -// So fall back to subgroupShuffle on Vulkan instead. -#define subgroupBroadcast subgroupShuffle -#endif - -/* -The header-only font -We have 96 (ASCII) characters, each of them is 12 pixels high and 8 pixels wide. -To store the boolean value per pixel, 96 bits per character is needed. -So three 32 bit integers are used per character. -This takes in total roughly 1 kB of constant buffer. -The first character must be all-one for the optimized implementation below. -*/ -const uint char_width = 8; -const uint char_height = 12; -const uint char_count = 96; -const uint char_pixels = char_width * char_height; -const float2 char_dim = float2(char_width, char_height); - -const uint rasters[char_count][(char_pixels + 31) / 32] = { - {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, {0x18181818, 0x00181818, 0x00181800}, - {0x6c6c6c6c, 0x00000000, 0x00000000}, {0x66660000, 0xff6666ff, 0x00006666}, - {0x1bff7e18, 0xd8f87e1f, 0x00187eff}, {0x6edb1b0e, 0x760c1830, 0x0070d8db}, - {0x3333361c, 0x1b0e0e1b, 0x00fe63f3}, {0x18383070, 0x00000000, 0x00000000}, - {0x0c0c1830, 0x0c0c0c0c, 0x0030180c}, {0x3030180c, 0x30303030, 0x000c1830}, - {0x5a990000, 0x5a3cff3c, 0x00000099}, {0x18180000, 0x18ffff18, 0x00001818}, - {0x00000000, 0x38000000, 0x000c1838}, {0x00000000, 0x00ffff00, 0x00000000}, - {0x00000000, 0x00000000, 0x00001c1c}, {0x6060c0c0, 0x18183030, 0x06060c0c}, - {0xe3c3663c, 0xc7cfdbf3, 0x003c66c3}, {0x181e1c18, 0x18181818, 0x007e1818}, - {0x60c0e77e, 0x060c1830, 0x00ff0303}, {0xc0c0e77e, 0xc0e07ee0, 0x007ee7c0}, - {0x363c3830, 0x3030ff33, 0x00303030}, {0x030303ff, 0xc0e07f03, 0x007ee7c0}, - {0x0303e77e, 0xc3e37f03, 0x007ee7c3}, {0xc0c0c0ff, 0x0c183060, 0x000c0c0c}, - {0xc3c3e77e, 0xc3e77ee7, 0x007ee7c3}, {0xc3c3e77e, 0xc0c0fee7, 0x007ee7c0}, - {0x00000000, 0x00001c1c, 0x00001c1c}, {0x38000000, 0x38000038, 0x000c1838}, - {0x0c183060, 0x0c060306, 0x00603018}, {0x00000000, 0xff00ffff, 0x000000ff}, - {0x30180c06, 0x3060c060, 0x00060c18}, {0xc0c3c37e, 0x18183060, 0x00180000}, - {0x7e000000, 0xdbcbbbc3, 0x00fc06f3}, {0xc3663c18, 0xc3ffc3c3, 0x00c3c3c3}, - {0xc3c3e37f, 0xc3e37fe3, 0x007fe3c3}, {0x0303e77e, 0x03030303, 0x007ee703}, - {0xc3e3733f, 0xc3c3c3c3, 0x003f73e3}, {0x030303ff, 0x03033f03, 0x00ff0303}, - {0x030303ff, 0x0303033f, 0x00030303}, {0x0303e77e, 0xc3f30303, 0x007ee7c3}, - {0xc3c3c3c3, 0xc3c3ffc3, 0x00c3c3c3}, {0x1818187e, 0x18181818, 0x007e1818}, - {0x60606060, 0x60606060, 0x003e7763}, {0x1b3363c3, 0x1b0f070f, 0x00c36333}, - {0x03030303, 0x03030303, 0x00ff0303}, {0xffffe7c3, 0xc3c3c3db, 0x00c3c3c3}, - {0xcfcfc7c7, 0xf3fbdbdf, 0x00e3e3f3}, {0xc3c3e77e, 0xc3c3c3c3, 0x007ee7c3}, - {0xc3c3e37f, 0x03037fe3, 0x00030303}, {0xc3c3663c, 0xdbc3c3c3, 0x00fc76fb}, - {0xc3c3e37f, 0x1b0f7fe3, 0x00c36333}, {0x0303e77e, 0xc0e07e07, 0x007ee7c0}, - {0x181818ff, 0x18181818, 0x00181818}, {0xc3c3c3c3, 0xc3c3c3c3, 0x007ee7c3}, - {0xc3c3c3c3, 0x6666c3c3, 0x00183c3c}, {0xc3c3c3c3, 0xffdbdbc3, 0x00c3e7ff}, - {0x3c6666c3, 0x3c3c183c, 0x00c36666}, {0x3c6666c3, 0x1818183c, 0x00181818}, - {0x60c0c0ff, 0x060c7e30, 0x00ff0303}, {0x0c0c0c3c, 0x0c0c0c0c, 0x003c0c0c}, - {0x0c0c0606, 0x30301818, 0xc0c06060}, {0x3030303c, 0x30303030, 0x003c3030}, - {0xc3663c18, 0x00000000, 0x00000000}, {0x00000000, 0x00000000, 0xff000000}, - {0x181c0c0e, 0x00000000, 0x00000000}, {0x00000000, 0xfec0c37e, 0x00fec3c3}, - {0x03030303, 0xc3c37f03, 0x007fc3c3}, {0x00000000, 0x0303c37e, 0x007ec303}, - {0xc0c0c0c0, 0xc3c3fec0, 0x00fec3c3}, {0x00000000, 0x7fc3c37e, 0x00fe0303}, - {0x0c0ccc78, 0x0c0c3f0c, 0x000c0c0c}, {0x00000000, 0xc3c3c37e, 0xc3c0c0fe}, - {0x03030303, 0xc3c3c37f, 0x00c3c3c3}, {0x00001800, 0x18181818, 0x00181818}, - {0x00003000, 0x30303030, 0x36303030}, {0x03030303, 0x0f1b3363, 0x0063331f}, - {0x1818181e, 0x18181818, 0x007e1818}, {0x00000000, 0xdbdbdb7f, 0x00dbdbdb}, - {0x00000000, 0x6363633f, 0x00636363}, {0x00000000, 0x6363633e, 0x003e6363}, - {0x00000000, 0xc3c3c37f, 0x03037fc3}, {0x00000000, 0xc3c3c3fe, 0xc0c0fec3}, - {0x00000000, 0x0303077f, 0x00030303}, {0x00000000, 0x7e0303fe, 0x007fc0c0}, - {0x0c0c0c00, 0x0c0c0c3f, 0x00386c0c}, {0x00000000, 0x63636363, 0x007e6363}, - {0x00000000, 0x6666c3c3, 0x00183c3c}, {0x00000000, 0xdbc3c3c3, 0x00c3e7ff}, - {0x00000000, 0x183c66c3, 0x00c3663c}, {0x00000000, 0x3c6666c3, 0x06060c18}, - {0x00000000, 0x183060ff, 0x00ff060c}, {0x181818f0, 0x181c0f1c, 0x00f01818}, - {0x18181818, 0x18181818, 0x18181818}, {0x1818180f, 0x1838f038, 0x000f1818}, - {0x06000000, 0x0060f18f, 0x00000000}, {0x00000000, 0x00000000, 0x00000000}}; - -// Precalculated sum of all pixels per character -const uint raster_active_pixels[char_count] = { - 96, 18, 16, 40, 56, 42, 46, 10, 22, 22, 32, 28, 10, 16, 6, 24, 52, 29, 36, 44, 35, 42, 50, 28, - 58, 51, 12, 16, 22, 32, 22, 26, 41, 46, 57, 38, 52, 38, 32, 46, 48, 30, 31, 43, 28, 56, 64, 52, - 42, 52, 52, 44, 28, 48, 42, 58, 42, 32, 38, 26, 24, 26, 14, 8, 10, 34, 40, 26, 40, 32, 30, 33, - 39, 16, 20, 37, 28, 43, 30, 30, 34, 34, 20, 28, 27, 30, 26, 36, 26, 24, 26, 30, 24, 30, 14, 0}; - -// Get one sample of the font: (pixel index, character index) -float SampleFont(uint2 pos) -{ - return (rasters[pos.y][pos.x / 32] >> (pos.x % 32)) & uint(1); -} - -// Get one sample of the framebuffer: (character position in screen space, pixel index) -float3 SampleTex(uint2 char_pos, uint pixel) -{ - float2 inv_resoltion = - OptionEnabled(USE_WINDOW_RES) ? GetInvWindowResolution() : GetInvResolution(); - float2 tex_pos = char_pos * char_dim + float2(pixel % char_width, pixel / char_width) + 0.5; - return SampleLocation(tex_pos * inv_resoltion).xyz; -} - -struct CharResults -{ - float3 fg; // font color - float3 bg; // background color - float err; // MSE of this configuration - uint c; // character index -}; - -// Calculate the font and background color and the MSE for a given character -CharResults CalcCharRes(uint c, float3 t, float3 ft) -{ - CharResults o; - o.c = c; - - // Inputs: - // tt: sum of all texture samples squared - // t: sum of all texture samples - // ff: sum of all font samples squared - // f: sum of all font samples - // ft: sum of all font samples * texture samples - - // The font is either 1.0 or 0.0, so ff == f - // As the font is constant, this is pre-calculated - float f = raster_active_pixels[c]; - float ff = f; - - // The calculation isn't stable if the font is all-one. Return max err - // instead. - if (f == char_pixels) - { - o.err = char_pixels * char_pixels; - return o; - } - - // tt is only used as constant offset for the error, define it as zero - float3 tt = float3(0.0, 0.0, 0.0); - - // The next lines are a bit harder, hf :-) - - // The idea is to find the perfect char with the perfect background color - // and the perfect font color. As this is an equation with three unknowns, - // we can't just try all chars and color combinations. - - // As criterion how "perfect" the selection is, we compare the "mean - // squared error" of the resulted colors of all chars. So, now the big - // issue: how to calculate the MSE without knowing the two colors ... - - // In the next steps, "a" is the font color, "b" is the background color, - // "f" is the font value at this pixel, "t" is the texture value - - // So the square error of one pixel is: - // e = ( t - a⋅f - b⋅(1-f) ) ^ 2 - - // In longer: - // e = a^2⋅f^2 - 2⋅a⋅b⋅f^2 + 2⋅a⋅b⋅f - 2⋅a⋅f⋅t + b^2⋅f^2 - 2⋅b^2⋅f + b^2 + - // 2⋅b⋅f⋅t - 2⋅b⋅t + t^2 - - // The sum of all errors is: (as shortcut, ff,f,ft,t,tt are now the sums - // like declared above, sum(1) is the count of pixels) sum(e) = a^2⋅ff - - // 2⋅a^2⋅ff + 2⋅a⋅b⋅f - 2⋅a⋅ft + b^2⋅ff - 2⋅b^2⋅f + b^2⋅sum(1) + 2⋅b⋅ft - - // 2⋅b⋅t + tt - - // tt is only used as a constant offset, so its value has no effect on a,b or - // on the relative error. So it can be completely dropped. - - // To find the minimum, we have to derive this by "a" and "b": - // d/da sum(e) = 2⋅a⋅ff + 2⋅b⋅f - 2⋅b⋅ff - 2⋅ft - // d/db sum(e) = 2⋅a⋅f - 2⋅a⋅ff - 4⋅b⋅f + 2⋅b⋅ff + 2⋅b⋅sum(1) + 2⋅ft - 2⋅t - - // So, both equations must be zero at minimum and there is only one - // solution. - - float3 a = (ft * (f - float(char_pixels)) + t * (f - ff)) / (f * f - ff * float(char_pixels)); - float3 b = (ft * f - t * ff) / (f * f - ff * float(char_pixels)); - - float3 e = a * a * ff + 2.0 * a * b * (f - ff) - 2.0 * a * ft + - b * b * (-2.0 * f + ff + float(char_pixels)) + 2.0 * b * ft - 2.0 * b * t + tt; - o.err = dot(e, float3(1.0, 1.0, 1.0)); - - o.fg = a; - o.bg = b; - o.c = c; - - return o; -} - -// Get the color of the pixel of this invocation based on the character details -float3 GetFinalPixel(CharResults char_out) -{ - float2 resolution = OptionEnabled(USE_WINDOW_RES) ? GetWindowResolution() : GetResolution(); - uint2 char_pos = uint2(floor(GetCoordinates() * resolution / char_dim)); - uint2 pixel_offset = uint2(floor(GetCoordinates() * resolution) - char_pos * char_dim); - float font = SampleFont(int2(pixel_offset.x + char_width * pixel_offset.y, char_out.c)); - return char_out.fg * font + char_out.bg * (1.0 - font); -} - -/* - This shader performs some kind of brute force evaluation, which character fits best. - - for c in characters: - for p in pixels: - ft += font(c,p) * texture(p) - res = CalcCharRes(ft) - min(res.err) - - Terrible in performance, only for reference. - */ -CharResults CalcCharTrivial(uint2 char_pos) -{ - float3 t; - CharResults char_out; - char_out.err = char_pixels * char_pixels; - for (uint c = 0; c < MAX_CHARS; c += 1) - { - float3 ft = float3(0.0, 0.0, 0.0); - for (uint pixel = 0; pixel < char_pixels; pixel += 1) - { - float3 tex = SampleTex(char_pos, pixel); - float font = SampleFont(uint2(pixel, c)); - ft += font * tex; - } - if (c == 0) - t = ft; - CharResults res = CalcCharRes(c, t, ft); - if (res.err < char_out.err) - char_out = res; - } - return char_out; -} - -/* - However for better performance, some characters are tested at once. This saves some expensive - texture() calls. Also split the loop over the pixels in groups of 32 for only fetching the uint32 - of the font once. -*/ -CharResults CalcCharFallback(uint2 char_pos) -{ - float3 t; - CharResults char_out; - char_out.err = char_pixels * char_pixels; - for (uint c = 0; c < MAX_CHARS; c += UNROLL_FALLBACK) - { - // Declare ft - float3 ft[UNROLL_FALLBACK]; - for (uint i = 0; i < UNROLL_FALLBACK; i++) - ft[i] = float3(0.0, 0.0, 0.0); - - // Split `for p : pixels` in groups of 32. This makes accessing the texture (bit in uint32) - // easier. - for (uint pixel = 0; pixel < char_pixels; pixel += 32) - { - uint font_i[UNROLL_FALLBACK]; - for (uint i = 0; i < UNROLL_FALLBACK; i++) - font_i[i] = rasters[c + i][pixel / 32]; - - for (uint pixel_offset = 0; pixel_offset < 32; pixel_offset += 1) - { - float3 tex = SampleTex(char_pos, pixel + pixel_offset); - - // Inner kernel of `ft += font * tex`. Most time is spend in here. - for (uint i = 0; i < UNROLL_FALLBACK; i++) - { - float font = (font_i[i] >> pixel_offset) & uint(1); - - ft[i] += font * tex; - } - } - } - if (c == 0) - { - // First char has font := 1, so t = ft. Cache this value for the next iterations. - t = ft[0]; - } - - // Check if this character fits better than the last one. - for (uint i = 0; i < UNROLL_FALLBACK; i++) - { - CharResults res = CalcCharRes(c + i, t, ft[i]); - if (res.err < char_out.err) - char_out = res; - } - } - - return char_out; -} - -/* - SIMD optimized version with subgroup intrinsics - - distribute all characters over the lanes and check for them in parallel - - distribute the uniform texture access and broadcast each back to each lane -*/ -CharResults CalcCharSIMD(uint2 char_pos, uint simd_width) -{ - // Font color, bg color, character, error -- of character with minimum error - CharResults char_out; - char_out.err = char_pixels * char_pixels; - float3 t; -#ifdef SUPPORTS_SUBGROUP_REDUCTION - - // Hack: Work in hard-codeded fixed SIMD mode - if (gl_SubgroupInvocationID < simd_width) - { - // Loop over all characters - for (uint c = 0; c < MAX_CHARS; c += UNROLL_SIMD * simd_width) - { - // registers for "sum of font * texture" - float3 ft[UNROLL_SIMD]; - for (uint i = 0; i < UNROLL_SIMD; i++) - ft[i] = float3(0.0, 0.0, 0.0); - - for (uint pixel = 0; pixel < char_pixels; pixel += 32) - { - // Preload the font uint32 for the next 32 pixels - uint font_i[UNROLL_SIMD]; - for (uint i = 0; i < UNROLL_SIMD; i++) - font_i[i] = rasters[c + UNROLL_SIMD * gl_SubgroupInvocationID + i][pixel / 32]; - - for (uint pixel_offset = 0; pixel_offset < 32; pixel_offset += simd_width) - { - // Copy one full WRAP of textures into registers and shuffle them around for later usage. - // This avoids one memory transaction per tested pixel & character. - float3 tex_simd = SampleTex(char_pos, pixel + pixel_offset + gl_SubgroupInvocationID); - - for (uint k = 0; k < simd_width; k += 1) - { - float3 tex = subgroupBroadcast(tex_simd, k); - - // Note: As pixel iterates based on power-of-two gl_SubgroupSize, - // the const memory access to rasters is CSE'd and the inner loop - // after unrolling only contains: testing one bit + shuffle + - // conditional add - for (uint i = 0; i < UNROLL_SIMD; i++) - { - float font = (font_i[i] >> (k + pixel_offset % 32)) & uint(1); - ft[i] += font * tex; - } - } - } - } - if (c == 0) - { - // font[0] is a hardcoded 1 font, so t = ft - t = subgroupBroadcast(ft[0], 0); - } - - for (uint i = 0; i < UNROLL_SIMD; i++) - { - CharResults res = CalcCharRes(c + UNROLL_SIMD * gl_SubgroupInvocationID + i, t, ft[i]); - if (res.err < char_out.err) - char_out = res; - } - } - } - - // Broadcast to get the best character of all threads - float err_min = subgroupMin(char_out.err); - uint smallest = subgroupBallotFindLSB(subgroupBallot(err_min == char_out.err)); - char_out.fg = subgroupBroadcast(char_out.fg, smallest); - char_out.bg = subgroupBroadcast(char_out.bg, smallest); - char_out.c = subgroupBroadcast(char_out.c, smallest); - char_out.err = err_min; - -#endif - return char_out; -} - -bool supportsSIMD(uint simd_width) -{ -#ifdef SUPPORTS_SUBGROUP_REDUCTION - const uint mask = simd_width == 32u ? 0xFFFFFFFFu : (1u << simd_width) - 1; - return (subgroupBallot(true)[0] & mask) == mask; -#else - return false; -#endif -} - -// "Error: The AsciiArt shader requires the missing GPU extension KHR_shader_subgroup." -const uint missing_subgroup_warning_len = 82; -const uint missing_subgroup_warning[missing_subgroup_warning_len] = { - 37, 82, 82, 79, 82, 26, 95, 52, 72, 69, 95, 33, 83, 67, 73, 73, 33, 82, 84, 95, 83, - 72, 65, 68, 69, 82, 95, 82, 69, 81, 85, 73, 82, 69, 83, 95, 84, 72, 69, 95, 77, 73, - 83, 83, 73, 78, 71, 95, 39, 48, 53, 95, 69, 88, 84, 69, 78, 84, 73, 79, 78, 95, 43, - 40, 50, 63, 83, 72, 65, 68, 69, 82, 63, 83, 85, 66, 71, 82, 79, 85, 80, 14}; - -float3 ShowWarning(uint2 char_pos) -{ - CharResults char_out; - char_out.fg = float3(1.0, 1.0, 1.0); - char_out.bg = float3(0.0, 0.0, 0.0); - char_out.c = 95u; // just background - - if (char_pos.y == 0u && char_pos.x < missing_subgroup_warning_len) - { - char_out.c = missing_subgroup_warning[char_pos.x]; - } - - return GetFinalPixel(char_out); -} - -void main() -{ - // Calculate the character position of this pixel - float2 resolution = OptionEnabled(USE_WINDOW_RES) ? GetWindowResolution() : GetResolution(); - uint2 char_pos_self = uint2(floor(GetCoordinates() * resolution / char_dim)); - - float3 color_out; - -#ifdef SUPPORTS_SUBGROUP_REDUCTION - if (supportsSIMD(8)) - { - // Loop over all character positions covered by this wave - bool pixel_active = !gl_HelperInvocation; - CharResults char_out; - while (true) - { - // Fetch the next active character position - uint4 active_lanes = subgroupBallot(pixel_active); - if (active_lanes == uint4(0, 0, 0, 0)) - { - break; - } - uint2 char_pos = subgroupBroadcast(char_pos_self, subgroupBallotFindLSB(active_lanes)); - - // And calculate everything for this character position - if (supportsSIMD(32)) - { - char_out = CalcCharSIMD(char_pos, 32); - } - else if (supportsSIMD(16)) - { - char_out = CalcCharSIMD(char_pos, 16); - } - else if (supportsSIMD(8)) - { - char_out = CalcCharSIMD(char_pos, 8); - } - - // Draw the character on screen - if (char_pos == char_pos_self) - { - color_out = GetFinalPixel(char_out); - pixel_active = false; - } - if (OptionEnabled(DEBUG_ONLY_ONE_CHAR)) - { - break; - } - } - } - else -#else - if (char_pos_self.y <= 1u) - { - color_out = ShowWarning(char_pos_self); - } - else -#endif - if (HAVE_FULL_FEATURE_FALLBACK) - { - color_out = GetFinalPixel(CalcCharFallback(char_pos_self)); - } - else - { - color_out = Sample().xyz; - } - - SetOutput(float4(color_out, 1.0)); -} diff --git a/Data/Sys/Shaders/auto_toon.glsl b/Data/Sys/Shaders/auto_toon.glsl deleted file mode 100644 index d4fd1a0bcf..0000000000 --- a/Data/Sys/Shaders/auto_toon.glsl +++ /dev/null @@ -1,15 +0,0 @@ -void main() -{ - float4 to_gray = float4(0.3,0.59,0.11,0); - - float x1 = dot(to_gray, SampleOffset(int2( 1, 1))); - float x0 = dot(to_gray, SampleOffset(int2(-1,-1))); - float x3 = dot(to_gray, SampleOffset(int2( 1,-1))); - float x2 = dot(to_gray, SampleOffset(int2(-1, 1))); - - float edge = (x1 - x0) * (x1 - x0) + (x3 - x2) * (x3 - x2); - - float4 color = Sample(); - - SetOutput(color - float4(edge, edge, edge, edge) * 12.0); -} diff --git a/Data/Sys/Shaders/auto_toon2.glsl b/Data/Sys/Shaders/auto_toon2.glsl deleted file mode 100644 index 5f12ec1559..0000000000 --- a/Data/Sys/Shaders/auto_toon2.glsl +++ /dev/null @@ -1,88 +0,0 @@ -void main() -{ - //Changethis to increase the number of colors. - int numColors =8; - - float4 to_gray = float4(0.3,0.59,0.11,0); - float x1 = dot(to_gray, SampleOffset(int2( 1, 1))); - float x0 = dot(to_gray, SampleOffset(int2(-1,-1))); - float x3 = dot(to_gray, SampleOffset(int2( 1,-1))); - float x2 = dot(to_gray, SampleOffset(int2(-1, 1))); - float edge = (x1 - x0) * (x1 - x0) + (x3 - x2) * (x3 - x2); - float4 color = Sample(); - - float4 c0 = color - float4(edge, edge, edge, edge) * 12.0; - - float red = 0.0; - float green = 0.0; - float blue = 0.0; - bool rr = false; - bool bb = false; - bool gg = false; - int count = 1; - - float colorN = 0.0; - float colorB = 0.0; - - for (count = 1; count <= numColors; count++) - { - colorN = float(count / numColors); - - if ( c0.r <= colorN && c0.r >= colorB && rr == false ) - { - if (count == 1) - { - if (colorN >= 0.1) - red = 0.01; - else - red = colorN; - } - else if (count == numColors) - red = 0.95; - else - red = colorN; - - rr = true; - } - - if (c0.b <= colorN && c0.b >= colorB && bb == false) - { - if (count == 1) - { - if (colorN >= 0.1) - blue = 0.01; - else - blue = colorN; - } - else if (count == numColors) - blue = 0.95; - else - blue = colorN ; - - bb = true; - } - - if (c0.g <= colorN && c0.g >= colorB && gg == false) - { - if (count == 1) - { - if (colorN >= 0.1) - green = 0.01; - else - green = colorN; - } - else if (count == numColors) - green = 0.95; - else - green = colorN; - gg = true; - } - - colorB = float(count / numColors); - - if (rr == true && bb == true && gg == true) - break; - } - - SetOutput(float4(red, green, blue, c0.a)); -} diff --git a/Data/Sys/Shaders/bad_bloom.glsl b/Data/Sys/Shaders/bad_bloom.glsl deleted file mode 100644 index f39e6fcdfe..0000000000 --- a/Data/Sys/Shaders/bad_bloom.glsl +++ /dev/null @@ -1,36 +0,0 @@ -void main() -{ - float4 c_center = Sample(); - - float4 bloom_sum = float4(0.0, 0.0, 0.0, 0.0); - float2 pos = GetCoordinates() + float2(0.3, 0.3) * GetInvResolution(); - float2 radius1 = 1.3 * GetInvResolution(); - bloom_sum += SampleLocation(pos + float2(-1.5, -1.5) * radius1); - bloom_sum += SampleLocation(pos + float2(-2.5, 0.0) * radius1); - bloom_sum += SampleLocation(pos + float2(-1.5, 1.5) * radius1); - bloom_sum += SampleLocation(pos + float2(0.0, 2.5) * radius1); - bloom_sum += SampleLocation(pos + float2(1.5, 1.5) * radius1); - bloom_sum += SampleLocation(pos + float2(2.5, 0.0) * radius1); - bloom_sum += SampleLocation(pos + float2(1.5, -1.5) * radius1); - bloom_sum += SampleLocation(pos + float2(0.0, -2.5) * radius1); - - float2 radius2 = 4.6 * GetInvResolution(); - bloom_sum += SampleLocation(pos + float2(-1.5, -1.5) * radius2); - bloom_sum += SampleLocation(pos + float2(-2.5, 0.0) * radius2); - bloom_sum += SampleLocation(pos + float2(-1.5, 1.5) * radius2); - bloom_sum += SampleLocation(pos + float2(0.0, 2.5) * radius2); - bloom_sum += SampleLocation(pos + float2(1.5, 1.5) * radius2); - bloom_sum += SampleLocation(pos + float2(2.5, 0.0) * radius2); - bloom_sum += SampleLocation(pos + float2(1.5, -1.5) * radius2); - bloom_sum += SampleLocation(pos + float2(0.0, -2.5) * radius2); - - bloom_sum *= 0.07; - bloom_sum -= float4(0.3, 0.3, 0.3, 0.3); - bloom_sum = max(bloom_sum, float4(0.0, 0.0, 0.0, 0.0)); - - float2 vpos = (GetCoordinates() - float2(0.5, 0.5)) * 2.0; - float dist = (dot(vpos, vpos)); - dist = 1.0 - 0.4*dist; - - SetOutput((c_center * 0.7 + bloom_sum) * dist); -} diff --git a/Data/Sys/Shaders/brighten.glsl b/Data/Sys/Shaders/brighten.glsl deleted file mode 100644 index b1cdf24806..0000000000 --- a/Data/Sys/Shaders/brighten.glsl +++ /dev/null @@ -1,4 +0,0 @@ -void main() -{ - SetOutput(Sample()* 3.0); -} diff --git a/Data/Sys/Shaders/chrismas.glsl b/Data/Sys/Shaders/chrismas.glsl deleted file mode 100644 index 7862d26e0e..0000000000 --- a/Data/Sys/Shaders/chrismas.glsl +++ /dev/null @@ -1,13 +0,0 @@ -void main() -{ - float4 c0 = Sample(); - float red = 0.0; - float green = 0.0; - - if (c0.r < 0.35 || c0.b > 0.35) - green = c0.g + (c0.b / 2.0); - else - red = c0.r + 0.4; - - SetOutput(float4(red, green, 0.0, 1.0)); -} diff --git a/Data/Sys/Shaders/cool1.glsl b/Data/Sys/Shaders/cool1.glsl deleted file mode 100644 index b10779c4c9..0000000000 --- a/Data/Sys/Shaders/cool1.glsl +++ /dev/null @@ -1,20 +0,0 @@ -void main() -{ - float4 c0 = Sample(); - float red = 0.0; - float green = 0.0; - float blue = 0.0; - - if (c0.r < 0.50 || c0.b > 0.5) - { - blue = c0.r; - red = c0.g; - } - else - { - blue = c0.r; - green = c0.r; - } - - SetOutput(float4(red, green, blue, 1.0)); -} diff --git a/Data/Sys/Shaders/darkerbrighter.glsl b/Data/Sys/Shaders/darkerbrighter.glsl deleted file mode 100644 index 99b1f4073c..0000000000 --- a/Data/Sys/Shaders/darkerbrighter.glsl +++ /dev/null @@ -1,33 +0,0 @@ -void main() -{ - float4 c0 = Sample(); - float4 c1 = SampleOffset(int2(-1, 0)); - float4 c2 = SampleOffset(int2( 0, -1)); - float4 c3 = SampleOffset(int2( 1, 0)); - float4 c4 = SampleOffset(int2( 0, 1)); - - float red = c0.r; - float blue = c0.b; - float green = c0.g; - - float red2 = (c1.r + c2.r + c3.r + c4.r) / 4.0; - float blue2 = (c1.b + c2.b + c3.b + c4.b) / 4.0; - float green2 = (c1.g + c2.g + c3.g + c4.g) / 4.0; - - if (red2 > 0.3) - red = c0.r + c0.r / 2.0; - else - red = c0.r - c0.r / 2.0; - - if (green2 > 0.3) - green = c0.g+ c0.g / 2.0; - else - green = c0.g - c0.g / 2.0; - - if (blue2 > 0.3) - blue = c0.b+ c0.b / 2.0; - else - blue = c0.b - c0.b / 2.0; - - SetOutput(float4(red, green, blue, c0.a)); -} diff --git a/Data/Sys/Shaders/default_pre_post_process.glsl b/Data/Sys/Shaders/default_pre_post_process.glsl deleted file mode 100644 index b4d5266e65..0000000000 --- a/Data/Sys/Shaders/default_pre_post_process.glsl +++ /dev/null @@ -1,476 +0,0 @@ -/***** COLOR CORRECTION *****/ - -// Color Space references: -// https://www.unravel.com.au/understanding-color-spaces - -// SMPTE 170M - BT.601 (NTSC-M) -> BT.709 -mat3 from_NTSCM = transpose(mat3( - 0.939497225737661, 0.0502268452914346, 0.0102759289709032, - 0.0177558637510127, 0.965824605885027, 0.0164195303639603, - -0.00162163209967010, -0.00437400622653655, 1.00599563832621)); - -// ARIB TR-B9 (9300K+27MPCD with chromatic adaptation) (NTSC-J) -> BT.709 -mat3 from_NTSCJ = transpose(mat3( - 0.768497526, -0.210804164, 0.000297427177, - 0.0397904068, 1.04825413, 0.00555809540, - 0.00147510506, 0.0328789241, 1.36515128)); - -// EBU - BT.470BG/BT.601 (PAL) -> BT.709 -mat3 from_PAL = transpose(mat3( - 1.04408168421813, -0.0440816842181253, 0.000000000000000, - 0.000000000000000, 1.00000000000000, 0.000000000000000, - 0.000000000000000, 0.0118044782106489, 0.988195521789351)); - -float3 LinearTosRGBGamma(float3 color) -{ - const float a = 0.055; - - for (int i = 0; i < 3; ++i) - { - float x = color[i]; - if (x <= 0.0031308) - x = x * 12.92; - else - x = (1.0 + a) * pow(x, 1.0 / 2.4) - a; - color[i] = x; - } - - return color; -} - -float3 Rec709_Luminance = float3(0.2126, 0.7152, 0.0722); - -float Luminance(float3 color, bool native_color_space) -{ - if (native_color_space && OptionEnabled(correct_color_space)) - { - if (game_color_space == 0) - color *= from_NTSCM; - else if (game_color_space == 1) - color *= from_NTSCJ; - else if (game_color_space == 2) - color *= from_PAL; - } - return dot(color, Rec709_Luminance); -} - -/***** COLOR SAMPLING *****/ - -// Non filtered gamma corrected sample (nearest neighbor) -float4 QuickSample(float3 uvw, float gamma) -{ -#if 0 // Test sampling range - const float threshold = 0.00000001; - float2 xy = uvw.xy * GetResolution(); - // Sampling outside the valid range, draw in yellow - if (xy.x < (0.0 - threshold) || xy.x > (GetResolution().x + threshold) || xy.y < (0.0 - threshold) || xy.y > (GetResolution().y + threshold)) - return float4(1.0, 1.0, 0.0, 1); - // Sampling at the edges, draw in purple - if (xy.x < 1.0 || xy.x > (GetResolution().x - 1.0) || xy.y < 1.0 || xy.y > (GetResolution().y - 1.0)) - return float4(0.5, 0, 0.5, 1); -#endif - - float4 color = texture(samp1, uvw); - color.rgb = pow(color.rgb, float3(gamma)); - return color; -} -float4 QuickSample(float2 uv, float w, float gamma) -{ - return QuickSample(float3(uv, w), gamma); -} -float4 QuickSampleByPixel(float2 xy, float w, float gamma) -{ - float3 uvw = float3(xy * GetInvResolution(), w); - return QuickSample(uvw, gamma); -} - -/***** Bilinear Interpolation *****/ - -float4 BilinearSample(float3 uvw, float gamma) -{ - // This emulates the (bi)linear filtering done directly from GPUs HW. - // Note that GPUs might natively filter red green and blue differently, but we don't do it. - // They might also use different filtering between upscaling and downscaling. - float2 source_size = GetResolution(); - float2 pixel = (uvw.xy * source_size) - 0.5; // Try to find the matching pixel top left corner - - // Find the integer and floating point parts - float2 int_pixel = floor(pixel); - float2 frac_pixel = fract(pixel); - - // Take 4 samples around the original uvw - float4 c11 = QuickSampleByPixel(int_pixel + float2(0.5, 0.5), uvw.z, gamma); - float4 c21 = QuickSampleByPixel(int_pixel + float2(1.5, 0.5), uvw.z, gamma); - float4 c12 = QuickSampleByPixel(int_pixel + float2(0.5, 1.5), uvw.z, gamma); - float4 c22 = QuickSampleByPixel(int_pixel + float2(1.5, 1.5), uvw.z, gamma); - - // Blend the 4 samples by their weight - float4 avg_c = lerp(lerp(c11, c21, frac_pixel.x), lerp(c12, c22, frac_pixel.x), frac_pixel.y); - - // Calculate the average of the gamma space luminance, as that can be used to - // properly determine the perceptual brightness the color should have. - float l11 = pow(Luminance(c11.rgb, true), 1.0 / gamma); - float l21 = pow(Luminance(c21.rgb, true), 1.0 / gamma); - float l12 = pow(Luminance(c12.rgb, true), 1.0 / gamma); - float l22 = pow(Luminance(c22.rgb, true), 1.0 / gamma); - float target_avg_c_lum = lerp(lerp(l11, l21, frac_pixel.x), lerp(l12, l22, frac_pixel.x), frac_pixel.y); - - float avg_c_lum = Luminance(avg_c.rgb, true); - if (avg_c_lum != 0.0) - { - avg_c.rgb *= pow(target_avg_c_lum, gamma) / avg_c_lum; - } - - return avg_c; -} - -/***** Bicubic Interpolation *****/ - -// Formula derived from: -// https://en.wikipedia.org/wiki/Mitchell%E2%80%93Netravali_filters#Definition -// Values from: -// https://guideencodemoe-mkdocs.readthedocs.io/encoding/resampling/#mitchell-netravali-bicubic -// Other references: -// https://www.codeproject.com/Articles/236394/Bi-Cubic-and-Bi-Linear-Interpolation-with-GLSL -// https://github.com/ValveSoftware/gamescope/pull/740 -// https://stackoverflow.com/questions/13501081/efficient-bicubic-filtering-code-in-glsl -#define CUBIC_COEFF_GEN(B, C) \ - (mat4(/* t^0 */ ((B) / 6.0), (-(B) / 3.0 + 1.0), ((B) / 6.0), (0.0), \ - /* t^1 */ (-(B) / 2.0 - (C)), (0.0), ((B) / 2.0 + (C)), (0.0), \ - /* t^2 */ ((B) / 2.0 + 2.0 * (C)), (2.0 * (B) + (C)-3.0), \ - (-5.0 * (B) / 2.0 - 2.0 * (C) + 3.0), (-(C)), \ - /* t^3 */ (-(B) / 6.0 - (C)), (-3.0 * (B) / 2.0 - (C) + 2.0), \ - (3.0 * (B) / 2.0 + (C)-2.0), ((B) / 6.0 + (C)))) - -float4 CubicCoeffs(float t, mat4 coeffs) -{ - return coeffs * float4(1.0, t, t * t, t * t * t); -} - -float4 CubicMix(float4 c0, float4 c1, float4 c2, float4 c3, float4 coeffs) -{ - return c0 * coeffs[0] + c1 * coeffs[1] + c2 * coeffs[2] + c3 * coeffs[3]; -} - -// By Sam Belliveau. Public Domain license. -// Simple 16 tap, gamma correct, implementation of bicubic filtering. -float4 BicubicSample(float3 uvw, float gamma, mat4 coeffs) -{ - float2 pixel = (uvw.xy * GetResolution()) - 0.5; - float2 int_pixel = floor(pixel); - float2 frac_pixel = fract(pixel); - - float4 c00 = QuickSampleByPixel(int_pixel + float2(-0.5, -0.5), uvw.z, gamma); - float4 c10 = QuickSampleByPixel(int_pixel + float2(+0.5, -0.5), uvw.z, gamma); - float4 c20 = QuickSampleByPixel(int_pixel + float2(+1.5, -0.5), uvw.z, gamma); - float4 c30 = QuickSampleByPixel(int_pixel + float2(+2.5, -0.5), uvw.z, gamma); - - float4 c01 = QuickSampleByPixel(int_pixel + float2(-0.5, +0.5), uvw.z, gamma); - float4 c11 = QuickSampleByPixel(int_pixel + float2(+0.5, +0.5), uvw.z, gamma); - float4 c21 = QuickSampleByPixel(int_pixel + float2(+1.5, +0.5), uvw.z, gamma); - float4 c31 = QuickSampleByPixel(int_pixel + float2(+2.5, +0.5), uvw.z, gamma); - - float4 c02 = QuickSampleByPixel(int_pixel + float2(-0.5, +1.5), uvw.z, gamma); - float4 c12 = QuickSampleByPixel(int_pixel + float2(+0.5, +1.5), uvw.z, gamma); - float4 c22 = QuickSampleByPixel(int_pixel + float2(+1.5, +1.5), uvw.z, gamma); - float4 c32 = QuickSampleByPixel(int_pixel + float2(+2.5, +1.5), uvw.z, gamma); - - float4 c03 = QuickSampleByPixel(int_pixel + float2(-0.5, +2.5), uvw.z, gamma); - float4 c13 = QuickSampleByPixel(int_pixel + float2(+0.5, +2.5), uvw.z, gamma); - float4 c23 = QuickSampleByPixel(int_pixel + float2(+1.5, +2.5), uvw.z, gamma); - float4 c33 = QuickSampleByPixel(int_pixel + float2(+2.5, +2.5), uvw.z, gamma); - - float4 cx = CubicCoeffs(frac_pixel.x, coeffs); - float4 cy = CubicCoeffs(frac_pixel.y, coeffs); - - float4 x0 = CubicMix(c00, c10, c20, c30, cx); - float4 x1 = CubicMix(c01, c11, c21, c31, cx); - float4 x2 = CubicMix(c02, c12, c22, c32, cx); - float4 x3 = CubicMix(c03, c13, c23, c33, cx); - - return CubicMix(x0, x1, x2, x3, cy); -} - -/***** Sharp Bilinear Filtering *****/ - -// Based on https://github.com/libretro/slang-shaders/blob/master/interpolation/shaders/sharp-bilinear.slang -// by Themaister, Public Domain license -// Does a bilinear stretch, with a preapplied Nx nearest-neighbor scale, -// giving a sharper image than plain bilinear. -float4 SharpBilinearSample(float3 uvw, float gamma) -{ - float2 source_size = GetResolution(); - float2 inverted_source_size = GetInvResolution(); - float2 target_size = GetWindowResolution(); - float2 texel = uvw.xy * source_size; - float2 texel_floored = floor(texel); - float2 s = fract(texel); - float scale = max(floor(max(target_size.x * inverted_source_size.x, target_size.y * inverted_source_size.y)), 1.0); - float region_range = 0.5 - (0.5 / scale); - - // Figure out where in the texel to sample to get correct pre-scaled bilinear. - - float2 center_dist = s - 0.5; - float2 f = ((center_dist - clamp(center_dist, -region_range, region_range)) * scale) + 0.5; - - float2 mod_texel = texel_floored + f; - - uvw.xy = mod_texel * inverted_source_size; - return BilinearSample(uvw, gamma); -} - -/***** Area Sampling *****/ - -// By Sam Belliveau and Filippo Tarpini. Public Domain license. -// Effectively a more accurate sharp bilinear filter when upscaling, -// that also works as a mathematically perfect downscale filter. -// https://entropymine.com/imageworsener/pixelmixing/ -// https://github.com/obsproject/obs-studio/pull/1715 -// https://legacy.imagemagick.org/Usage/filter/ -float4 AreaSampling(float3 uvw, float gamma) -{ - // Determine the sizes of the source and target images. - float2 source_size = GetResolution(); - float2 target_size = GetWindowResolution(); - float2 inverted_target_size = GetInvWindowResolution(); - - // Compute the top-left and bottom-right corners of the target pixel box. - float2 t_beg = floor(uvw.xy * target_size); - float2 t_end = t_beg + float2(1.0, 1.0); - - // Convert the target pixel box to source pixel box. - float2 beg = t_beg * inverted_target_size * source_size; - float2 end = t_end * inverted_target_size * source_size; - - // Compute the top-left and bottom-right corners of the pixel box. - float2 f_beg = floor(beg); - float2 f_end = floor(end); - - // Compute how much of the start and end pixels are covered horizontally & vertically. - float area_w = 1.0 - fract(beg.x); - float area_n = 1.0 - fract(beg.y); - float area_e = fract(end.x); - float area_s = fract(end.y); - - // Compute the areas of the corner pixels in the pixel box. - float area_nw = area_n * area_w; - float area_ne = area_n * area_e; - float area_sw = area_s * area_w; - float area_se = area_s * area_e; - - // Initialize the color accumulator. - float4 avg_color = float4(0.0, 0.0, 0.0, 0.0); - float avg_luminance = 0.0; - float4 temp_color; - - float luminance_gamma = gamma; // For now, default to the user selected gamma (alternatively we could fix it to anything between 2.2 and 3.0) - float luminance_inv_gamma = 1.0 / luminance_gamma; - - // Prevents rounding errors due to the coordinates flooring above - const float2 offset = float2(0.5, 0.5); - - // Accumulate corner pixels. - temp_color = QuickSampleByPixel(float2(f_beg.x, f_beg.y) + offset, uvw.z, gamma); - avg_color += area_nw * temp_color; - avg_luminance += area_nw * pow(Luminance(temp_color.rgb, true), luminance_inv_gamma); - temp_color = QuickSampleByPixel(float2(f_end.x, f_beg.y) + offset, uvw.z, gamma); - avg_color += area_ne * temp_color; - avg_luminance += area_ne * pow(Luminance(temp_color.rgb, true), luminance_inv_gamma); - temp_color = QuickSampleByPixel(float2(f_beg.x, f_end.y) + offset, uvw.z, gamma); - avg_color += area_sw * temp_color; - avg_luminance += area_sw * pow(Luminance(temp_color.rgb, true), luminance_inv_gamma); - temp_color = QuickSampleByPixel(float2(f_end.x, f_end.y) + offset, uvw.z, gamma); - avg_color += area_se * temp_color; - avg_luminance += area_se * pow(Luminance(temp_color.rgb, true), luminance_inv_gamma); - - // Determine the size of the pixel box. - int x_range = int(f_end.x - f_beg.x - 0.5); - int y_range = int(f_end.y - f_beg.y - 0.5); - - // Workaround to compile the shader with DX11/12. - // If this isn't done, it will complain that the loop could have too many iterations. - // This number should be enough to guarantee downscaling from very high to very small resolutions. - // Note that this number might be referenced in the UI. - const int max_iterations = 16; - - // Fix up the average calculations in case we reached the upper limit - x_range = min(x_range, max_iterations); - y_range = min(y_range, max_iterations); - - // Accumulate top and bottom edge pixels. - for (int ix = 0; ix < max_iterations; ++ix) - { - if (ix < x_range) - { - float x = f_beg.x + 1.0 + float(ix); - temp_color = QuickSampleByPixel(float2(x, f_beg.y) + offset, uvw.z, gamma); - avg_color += area_n * temp_color; - avg_luminance += area_n * pow(Luminance(temp_color.rgb, true), luminance_inv_gamma); - temp_color = QuickSampleByPixel(float2(x, f_end.y) + offset, uvw.z, gamma); - avg_color += area_s * temp_color; - avg_luminance += area_s * pow(Luminance(temp_color.rgb, true), luminance_inv_gamma); - } - } - - // Accumulate left and right edge pixels and all the pixels in between. - for (int iy = 0; iy < max_iterations; ++iy) - { - if (iy < y_range) - { - float y = f_beg.y + 1.0 + float(iy); - - temp_color = QuickSampleByPixel(float2(f_beg.x, y) + offset, uvw.z, gamma); - avg_color += area_w * temp_color; - avg_luminance += area_w * pow(Luminance(temp_color.rgb, true), luminance_inv_gamma); - temp_color = QuickSampleByPixel(float2(f_end.x, y) + offset, uvw.z, gamma); - avg_color += area_e * temp_color; - avg_luminance += area_e * pow(Luminance(temp_color.rgb, true), luminance_inv_gamma); - - for (int ix = 0; ix < max_iterations; ++ix) - { - if (ix < x_range) - { - float x = f_beg.x + 1.0 + float(ix); - temp_color = QuickSampleByPixel(float2(x, y) + offset, uvw.z, gamma); - avg_color += temp_color; - avg_luminance += pow(Luminance(temp_color.rgb, true), luminance_inv_gamma); - } - } - } - } - - // Compute the area of the pixel box that was sampled. - float area_corners = area_nw + area_ne + area_sw + area_se; - float area_edges = float(x_range) * (area_n + area_s) + float(y_range) * (area_w + area_e); - float area_center = float(x_range) * float(y_range); - - float4 nrm_color = avg_color / (area_corners + area_edges + area_center); - float target_nrm_color_luminance = avg_luminance / (area_corners + area_edges + area_center); - - // Restore the averaged "gamma" space luminance, for better gamma correction. - // This retains the best feature of gamma correct sampling (no hue shifts), - // while also maintaining the perceptual "brightness" level of blending two colors with an alpha - // (in linear space a 0.5 alpha won't produce a color that has a perceptual brightness in the middle point of the two source colors). - float nrm_color_luminance = Luminance(nrm_color.rgb, true); - if (nrm_color_luminance != 0.0) - { - nrm_color.rgb *= pow(target_nrm_color_luminance, luminance_gamma) / nrm_color_luminance; - } - - // Return the normalized average color. - return nrm_color; -} - -/***** Main Functions *****/ - -// Returns an accurate (gamma corrected) sample of a gamma space space texture. -// Outputs in linear space for simplicity. -float4 LinearGammaCorrectedSample(float gamma) -{ - float3 uvw = v_tex0; - float4 color = float4(0, 0, 0, 1); - - if (resampling_method <= 1) // Bilinear - { - color = BilinearSample(uvw, gamma); - } - else if (resampling_method == 2) // Bicubic: B-Spline - { - color = BicubicSample(uvw, gamma, CUBIC_COEFF_GEN(1.0, 0.0)); - } - else if (resampling_method == 3) // Bicubic: Mitchell-Netravali - { - color = BicubicSample(uvw, gamma, CUBIC_COEFF_GEN(1.0 / 3.0, 1.0 / 3.0)); - } - else if (resampling_method == 4) // Bicubic: Catmull-Rom - { - color = BicubicSample(uvw, gamma, CUBIC_COEFF_GEN(0.0, 0.5)); - } - else if (resampling_method == 5) // Sharp Bilinear - { - color = SharpBilinearSample(uvw, gamma); - } - else if (resampling_method == 6) // Area Sampling - { - color = AreaSampling(uvw, gamma); - } - else if (resampling_method == 7) // Nearest Neighbor - { - color = QuickSample(uvw, gamma); - } - else if (resampling_method == 8) // Bicubic: Hermite - { - color = BicubicSample(uvw, gamma, CUBIC_COEFF_GEN(0.0, 0.0)); - } - - return color; -} - -void main() -{ - // This tries to fall back on GPU HW sampling if it can (it won't be gamma corrected). - bool raw_resampling = resampling_method <= 0; - bool needs_rescaling = GetResolution() != GetWindowResolution(); - - bool needs_resampling = needs_rescaling && (OptionEnabled(hdr_output) || OptionEnabled(correct_gamma) || !raw_resampling); - - float4 color; - - if (needs_resampling) - { - // Doing linear sampling in "gamma space" on linear texture formats isn't correct. - // If the source and target resolutions don't match, the GPU will return a color - // that is the average of 4 gamma space colors, but gamma space colors can't be blended together, - // gamma needs to be de-applied first. This makes a big difference if colors change - // drastically between two pixels. - - color = LinearGammaCorrectedSample(game_gamma); - } - else - { - // Default GPU HW sampling. Bilinear is identical to Nearest Neighbor if the input and output resolutions match. - if (needs_rescaling) - color = texture(samp0, v_tex0); - else - color = texture(samp1, v_tex0); - - // Convert to linear before doing any other of follow up operations. - color.rgb = pow(color.rgb, float3(game_gamma)); - } - - if (OptionEnabled(correct_color_space)) - { - if (game_color_space == 0) - color.rgb = color.rgb * from_NTSCM; - else if (game_color_space == 1) - color.rgb = color.rgb * from_NTSCJ; - else if (game_color_space == 2) - color.rgb = color.rgb * from_PAL; - } - - if (OptionEnabled(hdr_output)) - { - float hdr_paper_white = hdr_paper_white_nits / hdr_sdr_white_nits; - color.rgb *= hdr_paper_white; - } - - if (OptionEnabled(linear_space_output)) - { - // Nothing to do here - } - // Correct the SDR gamma for sRGB (PC/Monitor) or ~2.2 (Common TV gamma) - else if (OptionEnabled(correct_gamma)) - { - if (OptionEnabled(sdr_display_gamma_sRGB)) - color.rgb = LinearTosRGBGamma(color.rgb); - else - color.rgb = pow(color.rgb, float3(1.0 / sdr_display_custom_gamma)); - } - // Restore the original gamma without changes - else - { - color.rgb = pow(color.rgb, float3(1.0 / game_gamma)); - } - - SetOutput(color); -} diff --git a/Data/Sys/Shaders/emboss.glsl b/Data/Sys/Shaders/emboss.glsl deleted file mode 100644 index 0cd3200303..0000000000 --- a/Data/Sys/Shaders/emboss.glsl +++ /dev/null @@ -1,17 +0,0 @@ -void main() -{ - float4 c0 = Sample(); - float4 c1 = SampleOffset(int2(5, 5)); - float y = (0.222 * c1.r) + (0.707 * c1.g) + (0.071 * c1.b); - float y2 = ((0.222 * c0.r) + (0.707 * c0.g) + (0.071 * c0.b)) / 3.0; - float red = c0.r; - float green = c0.g; - float blue = c0.b; - float alpha = c0.a; - - red = y2 + (1.0 - y); - green = y2 + (1.0 - y); - blue = y2 + (1.0 - y); - - SetOutput(float4(red, green, blue, alpha)); -} diff --git a/Data/Sys/Shaders/fire.glsl b/Data/Sys/Shaders/fire.glsl deleted file mode 100644 index 7ca4075a49..0000000000 --- a/Data/Sys/Shaders/fire.glsl +++ /dev/null @@ -1,29 +0,0 @@ -void main() -{ - float4 c0 = Sample(); - float red = 0.0; - float green = 0.0; - float blue = 0.0; - - red = c0.r; - - if (c0.r > 0.0 && c0.g > c0.r) - green = (c0.g - (c0.g - c0.r)) / 3.0; - - if (c0.b > 0.0 && c0.r < 0.25) - { - red = c0.b; - green = c0.b / 3.0; - } - - if (c0.g > 0.0 && c0.r < 0.25) - { - red = c0.g; - green = c0.g / 3.0; - } - - if (((c0.r + c0.g + c0.b) / 3.0) > 0.9) - green = c0.r / 3.0; - - SetOutput(float4(red, green, blue, 1.0)); -} diff --git a/Data/Sys/Shaders/fire2.glsl b/Data/Sys/Shaders/fire2.glsl deleted file mode 100644 index 4b116f9871..0000000000 --- a/Data/Sys/Shaders/fire2.glsl +++ /dev/null @@ -1,13 +0,0 @@ -void main() -{ - float4 c0 = Sample(); - float red = 0.0; - float green = 0.0; - float blue = 0.0; - float avg = (c0.r + c0.g + c0.b) / 3.0; - - red = c0.r + (c0.g / 2.0) + (c0.b / 3.0); - green = c0.r / 3.0; - - SetOutput(float4(red, green, blue, 1.0)); -} diff --git a/Data/Sys/Shaders/firewater.glsl b/Data/Sys/Shaders/firewater.glsl deleted file mode 100644 index 32b9be3d5d..0000000000 --- a/Data/Sys/Shaders/firewater.glsl +++ /dev/null @@ -1,15 +0,0 @@ -void main() -{ - float4 c0 = Sample(); - float4 c1 = SampleOffset(int2( 1, 1)); - float4 c2 = SampleOffset(int2(-1, -1)); - float red = c0.r; - float green = c0.g; - float blue = c0.b; - float alpha = c0.a; - - red = c0.r - c1.b; - blue = c0.b - c2.r + (c0.g - c0.r); - - SetOutput(float4(red, 0.0, blue, alpha)); -} diff --git a/Data/Sys/Shaders/grayscale.glsl b/Data/Sys/Shaders/grayscale.glsl deleted file mode 100644 index a7a211ce4a..0000000000 --- a/Data/Sys/Shaders/grayscale.glsl +++ /dev/null @@ -1,6 +0,0 @@ -void main() -{ - float4 c0 = Sample(); - float avg = (c0.r + c0.g + c0.b) / 3.0; - SetOutput(float4(avg, avg, avg, c0.a)); -} diff --git a/Data/Sys/Shaders/grayscale2.glsl b/Data/Sys/Shaders/grayscale2.glsl deleted file mode 100644 index 5e166699ea..0000000000 --- a/Data/Sys/Shaders/grayscale2.glsl +++ /dev/null @@ -1,7 +0,0 @@ -void main() -{ - float4 c0 = Sample(); - // Info: https://web.archive.org/web/20040101053504/http://www.oreillynet.com:80/cs/user/view/cs_msg/8691 - float avg = (0.222 * c0.r) + (0.707 * c0.g) + (0.071 * c0.b); - SetOutput(float4(avg, avg, avg, c0.a)); -} diff --git a/Data/Sys/Shaders/integer_scaling.glsl b/Data/Sys/Shaders/integer_scaling.glsl deleted file mode 100644 index ff620ad359..0000000000 --- a/Data/Sys/Shaders/integer_scaling.glsl +++ /dev/null @@ -1,182 +0,0 @@ -// Set aspect ratio to 'stretch' - -// Integer Scaling shader by One_More_Try / TryTwo -// Uses Sharp Bilinear from -// https://github.com/libretro/slang-shaders/blob/master/interpolation/shaders/sharp-bilinear.slang -// by Themaister, Public Domain license - -/* -[configuration] -[OptionBool] -GUIName = Please set aspect ratio to stretch -OptionName = ASPECT_MSG -DefaultValue = false - -[OptionBool] -GUIName = Use non-integer width -OptionName = WIDTH_UNLOCK -DefaultValue = false - -[OptionBool] -GUIName = Stretch width to window -OptionName = WIDTH_SKIP -DependentOption = WIDTH_UNLOCK -DefaultValue = false - -[OptionBool] -GUIName = Scale width to fit 4:3 -OptionName = WIDTH_43 -DependentOption = WIDTH_UNLOCK -DefaultValue = false - -[OptionBool] -GUIName = Scale width to fit 16:9 -OptionName = WIDTH_169 -DependentOption = WIDTH_UNLOCK -DefaultValue = false - -[OptionBool] -GUIName = Apply sharp bilinear for custom widths -OptionName = SHARP_BILINEAR -DefaultValue = false - -[OptionRangeFloat] -GUIName = Sharp bilinear factor (0 = auto) -OptionName = SHARP_PRESCALE -MinValue = 0.0 -MaxValue = 16.0 -StepAmount = 1.0 -DefaultValue = 0.0 - -[OptionBool] -GUIName = Manual scale - Set IR first -OptionName = MANUALSCALE -DefaultValue = false - -[OptionRangeFloat] -GUIName = Integer scale - No higher than IR -OptionName = INTEGER_SCALE -DependentOption = MANUALSCALE -MaxValue = 5.0 -MinValue = 1.0 -DefaultValue = 1.0 -StepAmount = 1.0 - -[OptionRangeFloat] -GUIName = Scale width -OptionName = WIDTH_SCALE -DependentOption = MANUALSCALE -MaxValue = 5.0 -MinValue = -2.0 -DefaultValue = 0.0 -StepAmount = 1.0 - -[OptionBool] -GUIName = Auto downscaling -OptionName = DOWNSCALE -DefaultValue = false - -[/configuration] -*/ - -void main() -{ - float4 c0 = float4(0.0, 0.0, 0.0, 0.0); - float2 scale = float2(1.0, 1.0); - float2 xfb_res = GetResolution(); - float2 win_res = GetWindowResolution(); - float2 coords = GetCoordinates(); - - // ratio is used to rescale the coords to the xfb size, which allows for integer scaling. - // ratio can then be multiplied by an integer to upscale/downscale, but upscale isn't supported by - // point-sampling. - float2 ratio = win_res / xfb_res; - - if (OptionEnabled(WIDTH_UNLOCK)) - { - if (OptionEnabled(WIDTH_SKIP)) - ratio.x = 1.0; - else if (OptionEnabled(WIDTH_43)) - ratio.x = win_res.x / (xfb_res.y * 4 / 3); - else if (OptionEnabled(WIDTH_169)) - ratio.x = win_res.x / (xfb_res.y * 16 / 9); - } - - if (OptionEnabled(MANUALSCALE)) - { - // There's no IR variable, so this guesses the IR, but may be off for some games. - float calc_ir = ceil(xfb_res.y / 500); - scale.y = calc_ir / GetOption(INTEGER_SCALE); - float manual_width = GetOption(WIDTH_SCALE); - - if (manual_width < 0.0) - scale.x = scale.y * (abs(manual_width) + 1); - else - scale.x = scale.y / (manual_width + 1); - - ratio = ratio * scale; - } - else if (OptionEnabled(DOWNSCALE) && (ratio.x < 1 || ratio.y < 1)) - { - scale.x = ceil(max(1.0 / ratio.y, 1.0 / ratio.x)); - scale.y = scale.x; - ratio = ratio * scale; - } - - // y and x are used to determine black bars vs drawable space. - float y = win_res.y - xfb_res.y / scale.y; - float y_top = (y / 2.0) * GetInvWindowResolution().y; - float y_bottom = (win_res.y - y / 2.0) * GetInvWindowResolution().y; - float yloc = (coords.y - y_top) * ratio.y; - - float x = win_res.x - xfb_res.x / scale.x; - - if (OptionEnabled(WIDTH_UNLOCK)) - { - if (OptionEnabled(WIDTH_SKIP)) - x = 0.0; - else if (OptionEnabled(WIDTH_43)) - x = win_res.x - xfb_res.y / scale.y * 4 / 3; - else if (OptionEnabled(WIDTH_169)) - x = win_res.x - xfb_res.y / scale.y * 16 / 9; - } - - float x_left = (x / 2.0) * GetInvWindowResolution().x; - float x_right = (win_res.x - x / 2.0) * GetInvWindowResolution().x; - float xloc = (coords.x - x_left) * ratio.x; - - if (OptionEnabled(SHARP_BILINEAR) && - (OptionEnabled(WIDTH_SKIP) || OptionEnabled(WIDTH_43) || OptionEnabled(WIDTH_169) || - (OptionEnabled(MANUALSCALE) && GetOption(WIDTH_SCALE) != 0.0))) - { - float texel = xloc * xfb_res.x; - float texel_floored = floor(texel); - float s = frac(texel); - float scale_sharp = GetOption(SHARP_PRESCALE); - - if (scale_sharp == 0) - { - if (OptionEnabled(WIDTH_43)) - scale_sharp = (4 / 3 * xfb_res.y / xfb_res.x); - else if (OptionEnabled(WIDTH_169)) - scale_sharp = (16 / 9 * xfb_res.y / xfb_res.x); - else - scale_sharp = ceil(win_res.x / xfb_res.x); - } - - float region_range = 0.5 - 0.5 / scale_sharp; - float center_dist = s - 0.5; - float f = (center_dist - clamp(center_dist, -region_range, region_range)) * scale_sharp + 0.5; - - float mod_texel = texel_floored + f; - xloc = mod_texel / xfb_res.x; - } - - if (coords.x >= x_left && x_right >= coords.x && coords.y >= y_top && y_bottom >= coords.y) - { - float2 sample_loc = float2(xloc, yloc); - c0 = SampleLocation(sample_loc); - } - - SetOutput(c0); -} diff --git a/Data/Sys/Shaders/invert.glsl b/Data/Sys/Shaders/invert.glsl deleted file mode 100644 index 46cf142c84..0000000000 --- a/Data/Sys/Shaders/invert.glsl +++ /dev/null @@ -1,4 +0,0 @@ -void main() -{ - SetOutput(float4(1.0, 1.0, 1.0, 1.0) - Sample()); -} diff --git a/Data/Sys/Shaders/invert_blue.glsl b/Data/Sys/Shaders/invert_blue.glsl deleted file mode 100644 index 75602ea2a6..0000000000 --- a/Data/Sys/Shaders/invert_blue.glsl +++ /dev/null @@ -1,4 +0,0 @@ -void main() -{ - SetOutput(float4(0.0, 0.0, 0.7, 1.0) - Sample()); -} diff --git a/Data/Sys/Shaders/invertedoutline.glsl b/Data/Sys/Shaders/invertedoutline.glsl deleted file mode 100644 index fa1cb0f9bd..0000000000 --- a/Data/Sys/Shaders/invertedoutline.glsl +++ /dev/null @@ -1,7 +0,0 @@ -void main() -{ - float4 c0 = Sample(); - float4 c1 = SampleOffset(int2(5, 5)); - - SetOutput(c0 - c1); -} diff --git a/Data/Sys/Shaders/lens_distortion.glsl b/Data/Sys/Shaders/lens_distortion.glsl deleted file mode 100644 index b0c872c45e..0000000000 --- a/Data/Sys/Shaders/lens_distortion.glsl +++ /dev/null @@ -1,93 +0,0 @@ -/* -[configuration] - -[OptionRangeFloat] -GUIName = Distortion amount -OptionName = DISTORTION_FACTOR -MinValue = 1.0 -MaxValue = 10.0 -StepAmount = 0.5 -DefaultValue = 4.0 - -[OptionRangeFloat] -GUIName = Eye Distance Offset -OptionName = EYE_OFFSET -MinValue = 0.0 -MaxValue = 10.0 -StepAmount = 0.25 -DefaultValue = 5.0 - -[OptionRangeFloat] -GUIName = Zoom adjustment -OptionName = SIZE_ADJUST -MinValue = 0.0 -MaxValue = 1.0 -StepAmount = 0.025 -DefaultValue = 0.5 - -[OptionRangeFloat] -GUIName = Aspect Ratio adjustment -OptionName = ASPECT_ADJUST -MinValue = 0.0 -MaxValue = 1.0 -StepAmount = 0.025 -DefaultValue = 0.5 - -[/configuration] -*/ - - -void main() -{ - // Base Cardboard distortion parameters - float factor = GetOption(DISTORTION_FACTOR) * 0.01f; - float ka = factor * 3.0f; - float kb = factor * 5.0f; - - // size and aspect adjustment - float sizeAdjust = 1.0f - GetOption(SIZE_ADJUST) + 0.5f; - float aspectAdjustment = 1.25f - GetOption(ASPECT_ADJUST); - - // offset centering per eye - float stereoOffset = GetOption(EYE_OFFSET) * 0.01f; - float offsetAdd; - - // layer0 = left eye, layer1 = right eye - if (src_layer == 1) - { - offsetAdd = stereoOffset; - } - else - { - offsetAdd = 0.0 - stereoOffset; - } - - // convert coordinates to NDC space - float2 fragPos = (GetCoordinates() - 0.5f - float2(offsetAdd, 0.0f)) * 2.0f; - - // Calculate the source location "radius" (distance from the centre of the viewport) - float destR = length(fragPos); - - // find the radius multiplier - float srcR = destR * sizeAdjust + ( ka * pow(destR, 2.0) + kb * pow(destR, 4.0)); - - // Calculate the source vector (radial) - float2 correctedRadial = normalize(fragPos) * srcR; - - // fix aspect ratio - float2 widenedRadial = correctedRadial * float2(aspectAdjustment, 1.0f); - - // Transform the coordinates (from [-1,1]^2 to [0, 1]^2) - float2 uv = (widenedRadial/2.0f) + float2(0.5f, 0.5f) + float2(offsetAdd, 0.0f); - - // Sample the texture at the source location - if (clamp(uv, 0.0, 1.0) != uv) - { - // black if beyond bounds - SetOutput(float4(0.0, 0.0, 0.0, 0.0)); - } - else - { - SetOutput(SampleLocation(uv)); - } -} diff --git a/Data/Sys/Shaders/mad_world.glsl b/Data/Sys/Shaders/mad_world.glsl deleted file mode 100644 index 8d596541a1..0000000000 --- a/Data/Sys/Shaders/mad_world.glsl +++ /dev/null @@ -1,19 +0,0 @@ -void main() -{ - float4 emboss = (SampleLocation(GetCoordinates()+GetInvResolution()) - SampleLocation(GetCoordinates()-GetInvResolution()))*2.0; - emboss -= (SampleLocation(GetCoordinates()+float2(1,-1)*GetInvResolution()).rgba - SampleLocation(GetCoordinates()+float2(-1,1)*GetInvResolution()).rgba); - float4 color = Sample(); - - if (color.r > 0.8 && color.b + color.b < 0.2) - { - SetOutput(float4(1,0,0,0)); - } - else - { - color += emboss; - if (dot(color.rgb, float3(0.3, 0.5, 0.2)) > 0.5) - SetOutput(float4(1,1,1,1)); - else - SetOutput(float4(0,0,0,0)); - } -} diff --git a/Data/Sys/Shaders/nightvision.glsl b/Data/Sys/Shaders/nightvision.glsl deleted file mode 100644 index 9039b4bbdb..0000000000 --- a/Data/Sys/Shaders/nightvision.glsl +++ /dev/null @@ -1,10 +0,0 @@ -void main() -{ - float4 c0 = Sample(); - float green = c0.g; - - if (c0.g < 0.50) - green = c0.r + c0.b; - - SetOutput(float4(0.0, green, 0.0, 1.0)); -} diff --git a/Data/Sys/Shaders/nightvision2.glsl b/Data/Sys/Shaders/nightvision2.glsl deleted file mode 100644 index dfbbda9761..0000000000 --- a/Data/Sys/Shaders/nightvision2.glsl +++ /dev/null @@ -1,62 +0,0 @@ -void main() -{ - //variables - float internalresolution = 1278.0; - float4 c0 = Sample(); - - //blur - float4 blurtotal = float4(0.0, 0.0, 0.0, 0.0); - float blursize = 1.5; - blurtotal += SampleLocation(GetCoordinates() + float2(-blursize, -blursize) * GetInvResolution()); - blurtotal += SampleLocation(GetCoordinates() + float2(-blursize, blursize) * GetInvResolution()); - blurtotal += SampleLocation(GetCoordinates() + float2( blursize, -blursize) * GetInvResolution()); - blurtotal += SampleLocation(GetCoordinates() + float2( blursize, blursize) * GetInvResolution()); - blurtotal += SampleLocation(GetCoordinates() + float2(-blursize, 0.0) * GetInvResolution()); - blurtotal += SampleLocation(GetCoordinates() + float2( blursize, 0.0) * GetInvResolution()); - blurtotal += SampleLocation(GetCoordinates() + float2( 0.0, -blursize) * GetInvResolution()); - blurtotal += SampleLocation(GetCoordinates() + float2( 0.0, blursize) * GetInvResolution()); - blurtotal *= 0.125; - c0 = blurtotal; - - //greyscale - float grey = ((0.3 * c0.r) + (0.4 * c0.g) + (0.3 * c0.b)); - - // brighten - grey = grey * 0.5 + 0.7; - - // darken edges - float x = GetCoordinates().x * GetResolution().x; - float y = GetCoordinates().y * GetResolution().y; - if (x > internalresolution/2.0) - x = internalresolution-x; - if (y > internalresolution/2.0) - y = internalresolution-y; - if (x > internalresolution/2.0*0.95) - x = internalresolution/2.0*0.95; - if (y > internalresolution/2.0*0.95) - y = internalresolution/2.0*0.95; - x = -x+641.0; - y = -y+641.0; - - /*****inline square root routines*****/ - // bit of a performance bottleneck. - // necessary to make the darkened area rounded - // instead of rhombus-shaped. - float sqrt = x / 10.0; - - while ((sqrt*sqrt) < x) - sqrt+=0.1; - x = sqrt; - sqrt = y / 10.0; - while ((sqrt*sqrt) < y) - sqrt+=0.1; - y = sqrt; - - x *= 2.0; - y *= 2.0; - grey -= x / 200.0; - grey -= y / 200.0; - - // output - SetOutput(float4(0.0, grey, 0.0, 1.0)); -} diff --git a/Data/Sys/Shaders/nightvision2scanlines.glsl b/Data/Sys/Shaders/nightvision2scanlines.glsl deleted file mode 100644 index 5ace5e3be6..0000000000 --- a/Data/Sys/Shaders/nightvision2scanlines.glsl +++ /dev/null @@ -1,71 +0,0 @@ -void main() -{ - //variables - float internalresolution = 1278.0; - float4 c0 = Sample(); - - //blur - float4 blurtotal = float4(0.0, 0.0, 0.0, 0.0); - float blursize = 1.5; - blurtotal += SampleLocation(GetCoordinates() + float2(-blursize, -blursize)*GetInvResolution()); - blurtotal += SampleLocation(GetCoordinates() + float2(-blursize, blursize)*GetInvResolution()); - blurtotal += SampleLocation(GetCoordinates() + float2( blursize, -blursize)*GetInvResolution()); - blurtotal += SampleLocation(GetCoordinates() + float2( blursize, blursize)*GetInvResolution()); - blurtotal += SampleLocation(GetCoordinates() + float2(-blursize, 0.0)*GetInvResolution()); - blurtotal += SampleLocation(GetCoordinates() + float2( blursize, 0.0)*GetInvResolution()); - blurtotal += SampleLocation(GetCoordinates() + float2( 0.0, -blursize)*GetInvResolution()); - blurtotal += SampleLocation(GetCoordinates() + float2( 0.0, blursize)*GetInvResolution()); - blurtotal *= 0.125; - c0 = blurtotal; - - //greyscale - float grey = ((0.3 * c0.r) + (0.4 * c0.g) + (0.3 * c0.b)); - - // brighten and apply horizontal scanlines - // This would have been much simpler if I could get the stupid modulo (%) to work - // If anyone who is more well versed in Cg knows how to do this it'd be slightly more efficient - // float lineIntensity = ((GetCoordinates()[1] % 9) - 4) / 40; - float vPos = GetCoordinates().y*GetResolution().y / 9.0; - float lineIntensity = (((vPos - floor(vPos)) * 9.0) - 4.0) / 40.0; - grey = grey * 0.5 + 0.7 + lineIntensity; - - // darken edges - float x = GetCoordinates().x * GetResolution().x; - float y = GetCoordinates().y * GetResolution().y; - - if (x > internalresolution/2.0) - x = internalresolution-x; - - if (y > internalresolution/2.0) - y = internalresolution-y; - - if (x > internalresolution/2.0*0.95) - x = internalresolution/2.0*0.95; - - if (y > internalresolution/2.0*0.95) - y = internalresolution/2.0*0.95; - - x = -x + 641.0; - y = -y + 641.0; - - //****inline square root routines*****/ - // bit of a performance bottleneck. - // necessary to make the darkened area rounded - // instead of rhombus-shaped. - float sqrt = x / 10.0; - while ((sqrt*sqrt) < x) - sqrt+=0.1; - x = sqrt; - sqrt = y / 10.0; - while ((sqrt*sqrt) < y) - sqrt+=0.1; - y = sqrt; - - x *= 2.0; - y *= 2.0; - grey -= x / 200.0; - grey -= y / 200.0; - - // output - SetOutput(float4(0.0, grey, 0.0, 1.0)); -} diff --git a/Data/Sys/Shaders/posterize.glsl b/Data/Sys/Shaders/posterize.glsl deleted file mode 100644 index dba7e59ee3..0000000000 --- a/Data/Sys/Shaders/posterize.glsl +++ /dev/null @@ -1,18 +0,0 @@ -void main() -{ - float4 c0 = Sample(); - float red = 0.0; - float green = 0.0; - float blue = 0.0; - - if (c0.r > 0.25) - red = c0.r; - - if (c0.g > 0.25) - green = c0.g; - - if (c0.b > 0.25) - blue = c0.b; - - SetOutput(float4(red, green, blue, 1.0)); -} diff --git a/Data/Sys/Shaders/posterize2.glsl b/Data/Sys/Shaders/posterize2.glsl deleted file mode 100644 index 2000b0f726..0000000000 --- a/Data/Sys/Shaders/posterize2.glsl +++ /dev/null @@ -1,18 +0,0 @@ -float bound(float color) -{ - if (color < 0.35) - { - if (color < 0.25) - return color; - - return 0.5; - } - - return 1.0; -} - -void main() -{ - float4 c0 = Sample(); - SetOutput(float4(bound(c0.r), bound(c0.g), bound(c0.b), c0.a)); -} diff --git a/Data/Sys/Shaders/primarycolors.glsl b/Data/Sys/Shaders/primarycolors.glsl deleted file mode 100644 index fb82fd4236..0000000000 --- a/Data/Sys/Shaders/primarycolors.glsl +++ /dev/null @@ -1,77 +0,0 @@ -void main() -{ - float4 c0 = Sample(); - float red = c0.r; - float blue = c0.b; - float green = c0.g; - float factor = 2.0; - float max = 0.8; - float min = 0.3; - - if (c0.r > c0.g && c0.b > c0.g) - { - if (c0.r < c0.b + 0.05 && c0.b < c0.r + 0.05) - { - red = 0.7; - blue = 0.7; - green = 0.05; - } - else if (c0.r > c0.b + 0.05) - { - red = 0.7; - blue = 0.05; - green = 0.05; - } - else if (c0.b > c0.r + 0.05) - { - red = 0.05; - blue = 0.7; - green = 0.05; - } - } - - if (c0.r > c0.b && c0.g > c0.b) - { - if (c0.r < c0.g + 0.05 && c0.g < c0.r + 0.05) - { - red = 0.7; - blue = 0.05; - green = 0.7; - } - else if (c0.r > c0.g + 0.05) - { - red = 0.7; - blue = 0.05; - green = 0.05; - } - else if (c0.g > c0.r + 0.05) - { - red = 0.05; - blue = 0.05; - green = 0.7; - } - } - - if (c0.g > c0.r && c0.b > c0.r) - { - if (c0.g < c0.b + 0.05 && c0.b < c0.g + 0.05) - { - red = 0.05; - blue = 0.7; - green = 0.7; - } - else if (c0.g > c0.b + 0.05) - { - red = 0.05; - blue = 0.05; - green = 0.7; - } - else if (c0.b > c0.g + 0.05) - { - red = 0.05; - blue = 0.7; - green = 0.05; - } - } - SetOutput(float4(red, green, blue, c0.a)); -} diff --git a/Data/Sys/Shaders/sepia.glsl b/Data/Sys/Shaders/sepia.glsl deleted file mode 100644 index 55985553f6..0000000000 --- a/Data/Sys/Shaders/sepia.glsl +++ /dev/null @@ -1,13 +0,0 @@ -void main() -{ - float4 c0 = Sample(); - - // Same coefficients as grayscale2 at this point - float avg = (0.222 * c0.r) + (0.707 * c0.g) + (0.071 * c0.b); - float red=avg; - - // Not sure about these coefficients, they just seem to produce the proper yellow - float green=avg*.75; - float blue=avg*.5; - SetOutput(float4(red, green, blue, c0.a)); -} diff --git a/Data/Sys/Shaders/sketchy.glsl b/Data/Sys/Shaders/sketchy.glsl deleted file mode 100644 index fd6f5832bd..0000000000 --- a/Data/Sys/Shaders/sketchy.glsl +++ /dev/null @@ -1,17 +0,0 @@ -void main() -{ - float4 c0 = Sample(); - float4 tmp = float4(0.0, 0.0, 0.0, 0.0); - tmp += c0 - SampleOffset(int2( 2, 2)); - tmp += c0 - SampleOffset(int2(-2, -2)); - tmp += c0 - SampleOffset(int2( 2, -2)); - tmp += c0 - SampleOffset(int2(-2, 2)); - float grey = ((0.222 * tmp.r) + (0.707 * tmp.g) + (0.071 * tmp.b)); - - // get rid of the bottom line, as it is incorrect. - if (GetCoordinates().y*GetResolution().y < 163.0) - tmp = float4(1.0, 1.0, 1.0, 1.0); - - c0 = c0 + 1.0 - grey * 7.0; - SetOutput(float4(c0.r, c0.g, c0.b, 1.0)); -} diff --git a/Data/Sys/Shaders/spookey1.glsl b/Data/Sys/Shaders/spookey1.glsl deleted file mode 100644 index 9801dcf965..0000000000 --- a/Data/Sys/Shaders/spookey1.glsl +++ /dev/null @@ -1,18 +0,0 @@ -void main() -{ - float4 c0 = Sample(); - float red = 0.0; - float blue = 0.0; - - if (c0.r < 0.35 || c0.b > 0.5) - { - red = c0.g + c0.b; - } - else - { - red = c0.g + c0.b; - blue = c0.r + c0.b; - } - - SetOutput(float4(red, 0.0, blue, 1.0)); -} diff --git a/Data/Sys/Shaders/spookey2.glsl b/Data/Sys/Shaders/spookey2.glsl deleted file mode 100644 index 77a68ff168..0000000000 --- a/Data/Sys/Shaders/spookey2.glsl +++ /dev/null @@ -1,20 +0,0 @@ -void main() -{ - float4 c0 = Sample(); - float red = 0.0; - float green = 0.0; - float blue = 0.0; - - if (c0.r < 0.35 || c0.b > 0.5) - { - red = c0.g + c0.b; - } - else - { - red = c0.g + c0.b; - blue = c0.r + c0.b; - green = c0.r + c0.b; - } - - SetOutput(float4(red, green, blue, 1.0)); -} diff --git a/Data/Sys/Shaders/sunset.glsl b/Data/Sys/Shaders/sunset.glsl deleted file mode 100644 index 000d32f7c6..0000000000 --- a/Data/Sys/Shaders/sunset.glsl +++ /dev/null @@ -1,5 +0,0 @@ -void main() -{ - float4 c0 = Sample(); - SetOutput(float4(c0.r * 1.5, c0.g, c0.b * 0.5, c0.a)); -} diff --git a/Data/Sys/Shaders/swap_RGB_BGR.glsl b/Data/Sys/Shaders/swap_RGB_BGR.glsl deleted file mode 100644 index c71292f9e3..0000000000 --- a/Data/Sys/Shaders/swap_RGB_BGR.glsl +++ /dev/null @@ -1,4 +0,0 @@ -void main() -{ - SetOutput(Sample().bgra); -} diff --git a/Data/Sys/Shaders/swap_RGB_BRG.glsl b/Data/Sys/Shaders/swap_RGB_BRG.glsl deleted file mode 100644 index 3b2738423f..0000000000 --- a/Data/Sys/Shaders/swap_RGB_BRG.glsl +++ /dev/null @@ -1,4 +0,0 @@ -void main() -{ - SetOutput(Sample().brga); -} diff --git a/Data/Sys/Shaders/swap_RGB_GBR.glsl b/Data/Sys/Shaders/swap_RGB_GBR.glsl deleted file mode 100644 index 410958d2a5..0000000000 --- a/Data/Sys/Shaders/swap_RGB_GBR.glsl +++ /dev/null @@ -1,4 +0,0 @@ -void main() -{ - SetOutput(Sample().gbra); -} diff --git a/Data/Sys/Shaders/swap_RGB_GRB.glsl b/Data/Sys/Shaders/swap_RGB_GRB.glsl deleted file mode 100644 index 7a51768421..0000000000 --- a/Data/Sys/Shaders/swap_RGB_GRB.glsl +++ /dev/null @@ -1,4 +0,0 @@ -void main() -{ - SetOutput(Sample().grba); -} diff --git a/Data/Sys/Shaders/swap_RGB_RBG.glsl b/Data/Sys/Shaders/swap_RGB_RBG.glsl deleted file mode 100644 index 77cc11e0c6..0000000000 --- a/Data/Sys/Shaders/swap_RGB_RBG.glsl +++ /dev/null @@ -1,4 +0,0 @@ -void main() -{ - SetOutput(Sample().rbga); -} diff --git a/Data/Sys/Shaders/toxic.glsl b/Data/Sys/Shaders/toxic.glsl deleted file mode 100644 index 1aa38c5e07..0000000000 --- a/Data/Sys/Shaders/toxic.glsl +++ /dev/null @@ -1,20 +0,0 @@ -void main() -{ - float4 c0 = Sample(); - float red = 0.0; - float green = 0.0; - float blue = 0.0; - - if (c0.r < 0.3 || c0.b > 0.5) - { - blue = c0.r + c0.b; - red = c0.g + c0.b / 2.0; - } - else - { - red = c0.g + c0.b; - green = c0.r + c0.b; - } - - SetOutput(float4(red, green, blue, 1.0)); -} diff --git a/Makefile.common b/Makefile.common index 4603ec159e..8f5cdf2d71 100644 --- a/Makefile.common +++ b/Makefile.common @@ -1219,12 +1219,8 @@ DOLPHIN_SOURCES_CXX += \ $(CORE_DIR)/Source/Core/VideoCommon/Assets/CustomAssetLoader.cpp \ $(CORE_DIR)/Source/Core/VideoCommon/Assets/CustomTextureData.cpp \ $(CORE_DIR)/Source/Core/VideoCommon/Assets/DirectFilesystemAssetLibrary.cpp \ - $(CORE_DIR)/Source/Core/VideoCommon/Assets/MaterialAsset.cpp \ - $(CORE_DIR)/Source/Core/VideoCommon/Assets/MeshAsset.cpp \ - $(CORE_DIR)/Source/Core/VideoCommon/Assets/ShaderAsset.cpp \ $(CORE_DIR)/Source/Core/VideoCommon/Assets/TextureAsset.cpp \ $(CORE_DIR)/Source/Core/VideoCommon/Assets/TextureAssetUtils.cpp \ - $(CORE_DIR)/Source/Core/VideoCommon/Assets/TextureSamplerValue.cpp \ $(CORE_DIR)/Source/Core/VideoCommon/AsyncRequests.cpp \ $(CORE_DIR)/Source/Core/VideoCommon/AsyncShaderCompiler.cpp \ $(CORE_DIR)/Source/Core/VideoCommon/BoundingBox.cpp \ @@ -1249,13 +1245,10 @@ DOLPHIN_SOURCES_CXX += \ $(CORE_DIR)/Source/Core/VideoCommon/GraphicsModSystem/Config/GraphicsModGroup.cpp \ $(CORE_DIR)/Source/Core/VideoCommon/GraphicsModSystem/Config/GraphicsTarget.cpp \ $(CORE_DIR)/Source/Core/VideoCommon/GraphicsModSystem/Config/GraphicsTargetGroup.cpp \ - $(CORE_DIR)/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.cpp \ $(CORE_DIR)/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/MoveAction.cpp \ $(CORE_DIR)/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/PrintAction.cpp \ $(CORE_DIR)/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/ScaleAction.cpp \ $(CORE_DIR)/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/SkipAction.cpp \ - $(CORE_DIR)/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomPipeline.cpp \ - $(CORE_DIR)/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomShaderCache.cpp \ $(CORE_DIR)/Source/Core/VideoCommon/GraphicsModSystem/Runtime/FBInfo.cpp \ $(CORE_DIR)/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionFactory.cpp \ $(CORE_DIR)/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.cpp \ @@ -1276,13 +1269,8 @@ DOLPHIN_SOURCES_CXX += \ $(CORE_DIR)/Source/Core/VideoCommon/Present.cpp \ $(CORE_DIR)/Source/Core/VideoCommon/RenderState.cpp \ $(CORE_DIR)/Source/Core/VideoCommon/Resources/CustomResourceManager.cpp \ - $(CORE_DIR)/Source/Core/VideoCommon/Resources/InvalidTextures.cpp \ - $(CORE_DIR)/Source/Core/VideoCommon/Resources/MaterialResource.cpp \ $(CORE_DIR)/Source/Core/VideoCommon/Resources/Resource.cpp \ - $(CORE_DIR)/Source/Core/VideoCommon/Resources/ShaderResource.cpp \ - $(CORE_DIR)/Source/Core/VideoCommon/Resources/TextureAndSamplerResource.cpp \ $(CORE_DIR)/Source/Core/VideoCommon/Resources/TextureDataResource.cpp \ - $(CORE_DIR)/Source/Core/VideoCommon/Resources/TexturePool.cpp \ $(CORE_DIR)/Source/Core/VideoCommon/ShaderCache.cpp \ $(CORE_DIR)/Source/Core/VideoCommon/ShaderCompileUtils.cpp \ $(CORE_DIR)/Source/Core/VideoCommon/ShaderGenCommon.cpp \ diff --git a/Source/Core/Common/CommonPaths.h b/Source/Core/Common/CommonPaths.h index bab757ca4f..140dcfff9b 100644 --- a/Source/Core/Common/CommonPaths.h +++ b/Source/Core/Common/CommonPaths.h @@ -72,15 +72,12 @@ #define DUMP_DEBUG_BRANCHWATCH_DIR "BranchWatch" #define DUMP_DEBUG_JITBLOCKS_DIR "JitBlocks" #define LOGS_DIR "Logs" -#define SHADERS_DIR "Shaders" #define WII_SYSCONF_DIR "shared2" DIR_SEP "sys" #define WII_WC24CONF_DIR "shared2" DIR_SEP "wc24" #define RESOURCES_DIR "Resources" #define THEMES_DIR "Themes" #define STYLES_DIR "Styles" #define GBASAVES_DIR "Saves" -#define ANAGLYPH_DIR "Anaglyph" -#define PASSIVE_DIR "Passive" #define PIPES_DIR "Pipes" #define MEMORYWATCHER_DIR "MemoryWatcher" #define WFSROOT_DIR "WFS" diff --git a/Source/Core/Common/FileUtil.cpp b/Source/Core/Common/FileUtil.cpp index 54fb88b441..9a80e436bd 100644 --- a/Source/Core/Common/FileUtil.cpp +++ b/Source/Core/Common/FileUtil.cpp @@ -962,7 +962,6 @@ static void RebuildUserDirectories(unsigned int dir_index) s_user_paths[D_SHADERCACHE_IDX] = s_user_paths[D_CACHE_IDX] + SHADERCACHE_DIR DIR_SEP; s_user_paths[D_RETROACHIEVEMENTSCACHE_IDX] = s_user_paths[D_CACHE_IDX] + RETROACHIEVEMENTSCACHE_DIR DIR_SEP; - s_user_paths[D_SHADERS_IDX] = s_user_paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; s_user_paths[D_STATESAVES_IDX] = s_user_paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; s_user_paths[D_SCREENSHOTS_IDX] = s_user_paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; s_user_paths[D_LOAD_IDX] = s_user_paths[D_USER_IDX] + LOAD_DIR DIR_SEP; diff --git a/Source/Core/Common/FileUtil.h b/Source/Core/Common/FileUtil.h index 6f83fcaa94..b8948b0519 100644 --- a/Source/Core/Common/FileUtil.h +++ b/Source/Core/Common/FileUtil.h @@ -40,7 +40,6 @@ enum D_REDUMPCACHE_IDX, D_SHADERCACHE_IDX, D_RETROACHIEVEMENTSCACHE_IDX, - D_SHADERS_IDX, D_STATESAVES_IDX, D_SCREENSHOTS_IDX, D_HIRESTEXTURES_IDX, diff --git a/Source/Core/Core/Config/GraphicsSettings.cpp b/Source/Core/Core/Config/GraphicsSettings.cpp index 188a6e0a38..d1515fca06 100644 --- a/Source/Core/Core/Config/GraphicsSettings.cpp +++ b/Source/Core/Core/Config/GraphicsSettings.cpp @@ -143,8 +143,6 @@ const Info GFX_ENHANCE_MAX_ANISOTROPY{ {System::GFX, "Enhancements", "MaxAnisotropy"}, AnisotropicFilteringMode::Default}; const Info GFX_ENHANCE_OUTPUT_RESAMPLING{ {System::GFX, "Enhancements", "OutputResampling"}, OutputResamplingMode::Default}; -const Info GFX_ENHANCE_POST_SHADER{ - {System::GFX, "Enhancements", "PostProcessingShader"}, ""}; const Info GFX_ENHANCE_FORCE_TRUE_COLOR{{System::GFX, "Enhancements", "ForceTrueColor"}, true}; const Info GFX_ENHANCE_DISABLE_COPY_FILTER{{System::GFX, "Enhancements", "DisableCopyFilter"}, diff --git a/Source/Core/Core/Config/GraphicsSettings.h b/Source/Core/Core/Config/GraphicsSettings.h index 0832178116..afbc7fbf88 100644 --- a/Source/Core/Core/Config/GraphicsSettings.h +++ b/Source/Core/Core/Config/GraphicsSettings.h @@ -119,7 +119,6 @@ extern const Info GFX_ENHANCE_FORCE_TEXTURE_FILTERING; // NOTE - this is x in (1 << x) extern const Info GFX_ENHANCE_MAX_ANISOTROPY; extern const Info GFX_ENHANCE_OUTPUT_RESAMPLING; -extern const Info GFX_ENHANCE_POST_SHADER; extern const Info GFX_ENHANCE_FORCE_TRUE_COLOR; extern const Info GFX_ENHANCE_DISABLE_COPY_FILTER; extern const Info GFX_ENHANCE_ARBITRARY_MIPMAP_DETECTION; diff --git a/Source/Core/UICommon/UICommon.cpp b/Source/Core/UICommon/UICommon.cpp index 2a6317d235..fdffef562f 100644 --- a/Source/Core/UICommon/UICommon.cpp +++ b/Source/Core/UICommon/UICommon.cpp @@ -283,8 +283,6 @@ void CreateDirectories() File::CreateFullPath(File::GetUserPath(D_LOGS_IDX)); File::CreateFullPath(File::GetUserPath(D_MAPS_IDX)); File::CreateFullPath(File::GetUserPath(D_SCREENSHOTS_IDX)); - File::CreateFullPath(File::GetUserPath(D_SHADERS_IDX)); - File::CreateFullPath(File::GetUserPath(D_SHADERS_IDX) + ANAGLYPH_DIR DIR_SEP); File::CreateFullPath(File::GetUserPath(D_RETROACHIEVEMENTSCACHE_IDX)); File::CreateFullPath(File::GetUserPath(D_STATESAVES_IDX)); File::CreateFullPath(File::GetUserPath(D_ASM_ROOT_IDX)); diff --git a/Source/Core/VideoBackends/D3D/D3DGfx.cpp b/Source/Core/VideoBackends/D3D/D3DGfx.cpp index dc7ee37908..2505f25e00 100644 --- a/Source/Core/VideoBackends/D3D/D3DGfx.cpp +++ b/Source/Core/VideoBackends/D3D/D3DGfx.cpp @@ -29,7 +29,6 @@ #include "VideoCommon/BPFunctions.h" #include "VideoCommon/FramebufferManager.h" -#include "VideoCommon/PostProcessing.h" #include "VideoCommon/Present.h" #include "VideoCommon/RenderState.h" #include "VideoCommon/VideoConfig.h" diff --git a/Source/Core/VideoBackends/D3D/D3DMain.cpp b/Source/Core/VideoBackends/D3D/D3DMain.cpp index fda563fa52..0bef43d287 100644 --- a/Source/Core/VideoBackends/D3D/D3DMain.cpp +++ b/Source/Core/VideoBackends/D3D/D3DMain.cpp @@ -84,7 +84,6 @@ void VideoBackend::FillBackendInfo() g_backend_info.bSupportsGeometryShaders = true; g_backend_info.bSupportsComputeShaders = false; g_backend_info.bSupports3DVision = true; - g_backend_info.bSupportsPostProcessing = true; g_backend_info.bSupportsPaletteConversion = true; g_backend_info.bSupportsClipControl = true; g_backend_info.bSupportsDepthClamp = true; diff --git a/Source/Core/VideoBackends/D3D/D3DState.cpp b/Source/Core/VideoBackends/D3D/D3DState.cpp index 6faf268240..6eb8fc1e94 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.cpp +++ b/Source/Core/VideoBackends/D3D/D3DState.cpp @@ -59,7 +59,6 @@ void StateManager::Apply() const bool dirtyConstants = m_dirtyFlags.test(DirtyFlag_PixelConstants) || m_dirtyFlags.test(DirtyFlag_VertexConstants) || - m_dirtyFlags.test(DirtyFlag_CustomConstants) || m_dirtyFlags.test(DirtyFlag_GeometryConstants); const bool dirtyShaders = m_dirtyFlags.test(DirtyFlag_PixelShader) || m_dirtyFlags.test(DirtyFlag_VertexShader) || @@ -85,13 +84,6 @@ void StateManager::Apply() m_current.vertexConstants = m_pending.vertexConstants; } - if (m_current.customConstants != m_pending.customConstants) - { - D3D::context->PSSetConstantBuffers(2, 1, &m_pending.customConstants); - D3D::context->VSSetConstantBuffers(2, 1, &m_pending.customConstants); - m_current.customConstants = m_pending.customConstants; - } - if (m_current.geometryConstants != m_pending.geometryConstants) { D3D::context->GSSetConstantBuffers(0, 1, &m_pending.geometryConstants); @@ -332,8 +324,6 @@ void StateManager::Restore() D3D::context->PSSetConstantBuffers(0, 2, m_pending.pixelConstants.data()); D3D::context->VSSetConstantBuffers(0, 1, &m_pending.vertexConstants); D3D::context->VSSetConstantBuffers(1, 1, &m_pending.vertexConstants); - D3D::context->PSSetConstantBuffers(2, 1, &m_pending.customConstants); - D3D::context->VSSetConstantBuffers(2, 1, &m_pending.customConstants); D3D::context->GSSetConstantBuffers(0, 1, &m_pending.geometryConstants); D3D::context->IASetVertexBuffers(0, 1, &m_pending.vertexBuffer, &m_pending.vertexBufferStride, &m_pending.vertexBufferOffset); diff --git a/Source/Core/VideoBackends/D3D/D3DState.h b/Source/Core/VideoBackends/D3D/D3DState.h index 34984af8a6..9c7cca55de 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.h +++ b/Source/Core/VideoBackends/D3D/D3DState.h @@ -108,14 +108,6 @@ public: m_pending.vertexConstants = buffer; } - void SetCustomConstants(ID3D11Buffer* buffer) - { - if (m_current.customConstants != buffer) - m_dirtyFlags.set(DirtyFlag_CustomConstants); - - m_pending.customConstants = buffer; - } - void SetGeometryConstants(ID3D11Buffer* buffer) { if (m_current.geometryConstants != buffer) @@ -240,7 +232,6 @@ private: DirtyFlag_Sampler0 = DirtyFlag_Texture0 + VideoCommon::MAX_PIXEL_SHADER_SAMPLERS, DirtyFlag_PixelConstants = DirtyFlag_Sampler0 + VideoCommon::MAX_PIXEL_SHADER_SAMPLERS, DirtyFlag_VertexConstants, - DirtyFlag_CustomConstants, // Custom shader constants used by both vertex/pixel stages DirtyFlag_GeometryConstants, DirtyFlag_VertexBuffer, @@ -266,7 +257,6 @@ private: std::array samplers; std::array pixelConstants; ID3D11Buffer* vertexConstants; - ID3D11Buffer* customConstants; ID3D11Buffer* geometryConstants; ID3D11Buffer* vertexBuffer; ID3D11Buffer* indexBuffer; diff --git a/Source/Core/VideoBackends/D3D/D3DVertexManager.cpp b/Source/Core/VideoBackends/D3D/D3DVertexManager.cpp index 3b3a5ed588..4a2149b338 100644 --- a/Source/Core/VideoBackends/D3D/D3DVertexManager.cpp +++ b/Source/Core/VideoBackends/D3D/D3DVertexManager.cpp @@ -299,25 +299,10 @@ void VertexManager::UploadUniforms() pixel_shader_manager.dirty = false; } - if (pixel_shader_manager.custom_constants_dirty) - { - if (m_last_custom_buffer_size < pixel_shader_manager.custom_constants.size()) - { - m_custom_constant_buffer = - AllocateConstantBuffer(static_cast(pixel_shader_manager.custom_constants.size())); - } - UpdateConstantBuffer(m_custom_constant_buffer.Get(), - pixel_shader_manager.custom_constants.data(), - static_cast(pixel_shader_manager.custom_constants.size())); - m_last_custom_buffer_size = pixel_shader_manager.custom_constants.size(); - pixel_shader_manager.custom_constants_dirty = false; - } - D3D::stateman->SetPixelConstants( m_pixel_constant_buffer.Get(), g_ActiveConfig.bEnablePixelLighting ? m_vertex_constant_buffer.Get() : nullptr); D3D::stateman->SetVertexConstants(m_vertex_constant_buffer.Get()); D3D::stateman->SetGeometryConstants(m_geometry_constant_buffer.Get()); - D3D::stateman->SetCustomConstants(m_custom_constant_buffer.Get()); } } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/D3DVertexManager.h b/Source/Core/VideoBackends/D3D/D3DVertexManager.h index ef7c4a9191..18a9194ece 100644 --- a/Source/Core/VideoBackends/D3D/D3DVertexManager.h +++ b/Source/Core/VideoBackends/D3D/D3DVertexManager.h @@ -68,8 +68,6 @@ private: ComPtr m_geometry_constant_buffer = nullptr; ComPtr m_pixel_constant_buffer = nullptr; - ComPtr m_custom_constant_buffer = nullptr; - std::size_t m_last_custom_buffer_size = 0; ComPtr m_texel_buffer = nullptr; std::array, NUM_TEXEL_BUFFER_FORMATS> m_texel_buffer_views; diff --git a/Source/Core/VideoBackends/D3D12/D3D12VertexManager.cpp b/Source/Core/VideoBackends/D3D12/D3D12VertexManager.cpp index 4565db29bd..9a77c2439d 100644 --- a/Source/Core/VideoBackends/D3D12/D3D12VertexManager.cpp +++ b/Source/Core/VideoBackends/D3D12/D3D12VertexManager.cpp @@ -141,7 +141,6 @@ void VertexManager::UploadUniforms() UpdateVertexShaderConstants(); UpdateGeometryShaderConstants(); UpdatePixelShaderConstants(); - UpdateCustomShaderConstants(); } void VertexManager::UpdateVertexShaderConstants() @@ -195,36 +194,12 @@ void VertexManager::UpdatePixelShaderConstants() } } -void VertexManager::UpdateCustomShaderConstants() -{ - auto& system = Core::System::GetInstance(); - auto& pixel_shader_manager = system.GetPixelShaderManager(); - - if (!ReserveConstantStorage()) - return; - - if (pixel_shader_manager.custom_constants_dirty) - { - Gfx::GetInstance()->SetConstantBuffer(2, m_uniform_stream_buffer.GetCurrentGPUPointer()); - std::memcpy(m_uniform_stream_buffer.GetCurrentHostPointer(), - pixel_shader_manager.custom_constants.data(), - pixel_shader_manager.custom_constants.size()); - m_uniform_stream_buffer.CommitMemory( - static_cast(pixel_shader_manager.custom_constants.size())); - pixel_shader_manager.custom_constants_dirty = false; - } -} - bool VertexManager::ReserveConstantStorage() { - auto& system = Core::System::GetInstance(); - auto& pixel_shader_manager = system.GetPixelShaderManager(); - static constexpr u32 reserve_size = static_cast(std::max({sizeof(PixelShaderConstants), sizeof(VertexShaderConstants), sizeof(GeometryShaderConstants)})); - const u32 custom_constants_size = static_cast(pixel_shader_manager.custom_constants.size()); - if (m_uniform_stream_buffer.ReserveMemory(reserve_size + custom_constants_size, + if (m_uniform_stream_buffer.ReserveMemory(reserve_size, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT)) { return true; @@ -253,11 +228,7 @@ void VertexManager::UploadAllConstants() constexpr u32 geometry_constants_offset = Common::AlignUp(vertex_constants_offset + sizeof(VertexShaderConstants), D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT); - constexpr u32 custom_pixel_constants_offset = - Common::AlignUp(geometry_constants_offset + sizeof(GeometryShaderConstants), - D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT); - const u32 allocation_size = custom_pixel_constants_offset + - static_cast(pixel_shader_manager.custom_constants.size()); + constexpr u32 allocation_size = geometry_constants_offset + sizeof(GeometryShaderConstants); // Allocate everything at once. // We should only be here if the buffer was full and a command buffer was submitted anyway. @@ -273,8 +244,6 @@ void VertexManager::UploadAllConstants() pixel_constants_offset); Gfx::GetInstance()->SetConstantBuffer(1, m_uniform_stream_buffer.GetCurrentGPUPointer() + vertex_constants_offset); - Gfx::GetInstance()->SetConstantBuffer(2, m_uniform_stream_buffer.GetCurrentGPUPointer() + - custom_pixel_constants_offset); Gfx::GetInstance()->SetConstantBuffer(3, m_uniform_stream_buffer.GetCurrentGPUPointer() + geometry_constants_offset); @@ -288,13 +257,6 @@ void VertexManager::UploadAllConstants() &vertex_shader_manager.constants, sizeof(VertexShaderConstants)); std::memcpy(m_uniform_stream_buffer.GetCurrentHostPointer() + geometry_constants_offset, &geometry_shader_manager.constants, sizeof(GeometryShaderConstants)); - if (!pixel_shader_manager.custom_constants.empty()) - { - std::memcpy(m_uniform_stream_buffer.GetCurrentHostPointer() + custom_pixel_constants_offset, - pixel_shader_manager.custom_constants.data(), - pixel_shader_manager.custom_constants.size()); - } - // Finally, flush buffer memory after copying m_uniform_stream_buffer.CommitMemory(allocation_size); ADDSTAT(g_stats.this_frame.bytes_uniform_streamed, allocation_size); diff --git a/Source/Core/VideoBackends/D3D12/D3D12VertexManager.h b/Source/Core/VideoBackends/D3D12/D3D12VertexManager.h index 76c0c6d7cb..df637f1f53 100644 --- a/Source/Core/VideoBackends/D3D12/D3D12VertexManager.h +++ b/Source/Core/VideoBackends/D3D12/D3D12VertexManager.h @@ -35,7 +35,6 @@ protected: void UpdateVertexShaderConstants(); void UpdateGeometryShaderConstants(); void UpdatePixelShaderConstants(); - void UpdateCustomShaderConstants(); // Allocates storage in the uniform buffer of the specified size. If this storage cannot be // allocated immediately, the current command buffer will be submitted and all stage's diff --git a/Source/Core/VideoBackends/D3D12/VideoBackend.cpp b/Source/Core/VideoBackends/D3D12/VideoBackend.cpp index a5659642c9..e4a72cbc1e 100644 --- a/Source/Core/VideoBackends/D3D12/VideoBackend.cpp +++ b/Source/Core/VideoBackends/D3D12/VideoBackend.cpp @@ -59,7 +59,6 @@ void VideoBackend::FillBackendInfo() g_backend_info.bSupportsBBox = true; g_backend_info.bSupportsGSInstancing = true; g_backend_info.bSupportsPaletteConversion = true; - g_backend_info.bSupportsPostProcessing = true; g_backend_info.bSupportsClipControl = true; g_backend_info.bSupportsSSAA = true; g_backend_info.bSupportsFragmentStoresAndAtomics = true; diff --git a/Source/Core/VideoBackends/Null/NullBackend.cpp b/Source/Core/VideoBackends/Null/NullBackend.cpp index 02b75fe407..740f4c430d 100644 --- a/Source/Core/VideoBackends/Null/NullBackend.cpp +++ b/Source/Core/VideoBackends/Null/NullBackend.cpp @@ -35,7 +35,6 @@ void VideoBackend::InitBackendInfo(const WindowSystemInfo& wsi) g_backend_info.bSupportsBindingLayout = true; g_backend_info.bSupportsBBox = true; g_backend_info.bSupportsGSInstancing = true; - g_backend_info.bSupportsPostProcessing = false; g_backend_info.bSupportsPaletteConversion = true; g_backend_info.bSupportsClipControl = true; g_backend_info.bSupportsSSAA = true; diff --git a/Source/Core/VideoBackends/OGL/OGLMain.cpp b/Source/Core/VideoBackends/OGL/OGLMain.cpp index df0c28a21c..7d3aa3b6f8 100644 --- a/Source/Core/VideoBackends/OGL/OGLMain.cpp +++ b/Source/Core/VideoBackends/OGL/OGLMain.cpp @@ -119,7 +119,6 @@ bool VideoBackend::FillBackendInfo(GLContext* context) g_backend_info.bSupportsGeometryShaders = true; g_backend_info.bSupportsComputeShaders = false; g_backend_info.bSupports3DVision = false; - g_backend_info.bSupportsPostProcessing = true; g_backend_info.bSupportsSSAA = true; g_backend_info.bSupportsReversedDepthRange = true; g_backend_info.bSupportsLogicOp = true; diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp index 1dfd026810..c698afce88 100644 --- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp +++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp @@ -227,12 +227,9 @@ void ProgramShaderCache::UploadConstants() auto& pixel_shader_manager = system.GetPixelShaderManager(); auto& vertex_shader_manager = system.GetVertexShaderManager(); auto& geometry_shader_manager = system.GetGeometryShaderManager(); - if (pixel_shader_manager.dirty || vertex_shader_manager.dirty || geometry_shader_manager.dirty || - pixel_shader_manager.custom_constants_dirty) + if (pixel_shader_manager.dirty || vertex_shader_manager.dirty || geometry_shader_manager.dirty) { - const u32 custom_constants_size = static_cast( - Common::AlignUp(pixel_shader_manager.custom_constants.size(), s_ubo_align)); - auto buffer = s_buffer->Map(s_ubo_buffer_size + custom_constants_size, s_ubo_align); + auto buffer = s_buffer->Map(s_ubo_buffer_size, s_ubo_align); memcpy(buffer.first, &pixel_shader_manager.constants, sizeof(PixelShaderConstants)); @@ -241,17 +238,10 @@ void ProgramShaderCache::UploadConstants() memcpy(buffer.first + size, &vertex_shader_manager.constants, sizeof(VertexShaderConstants)); size += Common::AlignUp(sizeof(VertexShaderConstants), s_ubo_align); - if (!pixel_shader_manager.custom_constants.empty()) - { - memcpy(buffer.first + size, pixel_shader_manager.custom_constants.data(), - pixel_shader_manager.custom_constants.size()); - size += custom_constants_size; - } - memcpy(buffer.first + size, &geometry_shader_manager.constants, sizeof(GeometryShaderConstants)); - s_buffer->Unmap(s_ubo_buffer_size + custom_constants_size); + s_buffer->Unmap(s_ubo_buffer_size); glBindBufferRange(GL_UNIFORM_BUFFER, 1, s_buffer->m_buffer, buffer.second, sizeof(PixelShaderConstants)); @@ -259,22 +249,14 @@ void ProgramShaderCache::UploadConstants() glBindBufferRange(GL_UNIFORM_BUFFER, 2, s_buffer->m_buffer, buffer.second + size, sizeof(VertexShaderConstants)); size += Common::AlignUp(sizeof(VertexShaderConstants), s_ubo_align); - - if (!pixel_shader_manager.custom_constants.empty()) - { - glBindBufferRange(GL_UNIFORM_BUFFER, 3, s_buffer->m_buffer, buffer.second + size, - pixel_shader_manager.custom_constants.size()); - size += Common::AlignUp(pixel_shader_manager.custom_constants.size(), s_ubo_align); - } glBindBufferRange(GL_UNIFORM_BUFFER, 4, s_buffer->m_buffer, buffer.second + size, sizeof(GeometryShaderConstants)); pixel_shader_manager.dirty = false; vertex_shader_manager.dirty = false; geometry_shader_manager.dirty = false; - pixel_shader_manager.custom_constants_dirty = false; - ADDSTAT(g_stats.this_frame.bytes_uniform_streamed, s_ubo_buffer_size + custom_constants_size); + ADDSTAT(g_stats.this_frame.bytes_uniform_streamed, s_ubo_buffer_size); } } diff --git a/Source/Core/VideoBackends/Vulkan/VKVertexManager.cpp b/Source/Core/VideoBackends/Vulkan/VKVertexManager.cpp index 18c5ad560c..a15a38ad5b 100644 --- a/Source/Core/VideoBackends/Vulkan/VKVertexManager.cpp +++ b/Source/Core/VideoBackends/Vulkan/VKVertexManager.cpp @@ -254,28 +254,11 @@ void VertexManager::UpdatePixelShaderConstants() pixel_shader_manager.dirty = false; } - if (pixel_shader_manager.custom_constants_dirty) - { - StateTracker::GetInstance()->SetGXUniformBuffer( - UBO_DESCRIPTOR_SET_BINDING_CUST, m_uniform_stream_buffer->GetBuffer(), - m_uniform_stream_buffer->GetCurrentOffset(), - static_cast(pixel_shader_manager.custom_constants.size())); - std::memcpy(m_uniform_stream_buffer->GetCurrentHostPointer(), - pixel_shader_manager.custom_constants.data(), - pixel_shader_manager.custom_constants.size()); - m_uniform_stream_buffer->CommitMemory( - static_cast(pixel_shader_manager.custom_constants.size())); - pixel_shader_manager.custom_constants_dirty = false; - } } bool VertexManager::ReserveConstantStorage() { - auto& system = Core::System::GetInstance(); - auto& pixel_shader_manager = system.GetPixelShaderManager(); - const u32 custom_constants_size = static_cast(pixel_shader_manager.custom_constants.size()); - - if (m_uniform_stream_buffer->ReserveMemory(m_uniform_buffer_reserve_size + custom_constants_size, + if (m_uniform_stream_buffer->ReserveMemory(m_uniform_buffer_reserve_size, g_vulkan_context->GetUniformBufferAlignment())) { return true; @@ -296,8 +279,6 @@ void VertexManager::UploadAllConstants() auto& system = Core::System::GetInstance(); auto& pixel_shader_manager = system.GetPixelShaderManager(); - const u32 custom_constants_size = static_cast(pixel_shader_manager.custom_constants.size()); - // We are free to re-use parts of the buffer now since we're uploading all constants. const u32 ub_alignment = static_cast(g_vulkan_context->GetUniformBufferAlignment()); const u32 pixel_constants_offset = 0; @@ -305,9 +286,8 @@ void VertexManager::UploadAllConstants() Common::AlignUp(pixel_constants_offset + sizeof(PixelShaderConstants), ub_alignment); const u32 geometry_constants_offset = Common::AlignUp(vertex_constants_offset + sizeof(VertexShaderConstants), ub_alignment); - const u32 custom_pixel_constants_offset = - Common::AlignUp(geometry_constants_offset + sizeof(GeometryShaderConstants), ub_alignment); - const u32 allocation_size = custom_pixel_constants_offset + custom_constants_size; + const u32 allocation_size = + static_cast(geometry_constants_offset + sizeof(GeometryShaderConstants)); // Allocate everything at once. // We should only be here if the buffer was full and a command buffer was submitted anyway. @@ -330,13 +310,6 @@ void VertexManager::UploadAllConstants() m_uniform_stream_buffer->GetCurrentOffset() + vertex_constants_offset, sizeof(VertexShaderConstants)); - if (!pixel_shader_manager.custom_constants.empty()) - { - StateTracker::GetInstance()->SetGXUniformBuffer( - UBO_DESCRIPTOR_SET_BINDING_CUST, m_uniform_stream_buffer->GetBuffer(), - m_uniform_stream_buffer->GetCurrentOffset() + custom_pixel_constants_offset, - custom_constants_size); - } StateTracker::GetInstance()->SetGXUniformBuffer( UBO_DESCRIPTOR_SET_BINDING_GS, m_uniform_stream_buffer->GetBuffer(), m_uniform_stream_buffer->GetCurrentOffset() + geometry_constants_offset, @@ -349,12 +322,6 @@ void VertexManager::UploadAllConstants() &vertex_shader_manager.constants, sizeof(VertexShaderConstants)); std::memcpy(m_uniform_stream_buffer->GetCurrentHostPointer() + geometry_constants_offset, &geometry_shader_manager.constants, sizeof(GeometryShaderConstants)); - if (!pixel_shader_manager.custom_constants.empty()) - { - std::memcpy(m_uniform_stream_buffer->GetCurrentHostPointer() + custom_pixel_constants_offset, - pixel_shader_manager.custom_constants.data(), - pixel_shader_manager.custom_constants.size()); - } // Finally, flush buffer memory after copying m_uniform_stream_buffer->CommitMemory(allocation_size); diff --git a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp index 5f76a85d5a..65910f1993 100644 --- a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp +++ b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp @@ -435,7 +435,6 @@ void VulkanContext::PopulateBackendInfo(BackendInfo* backend_info) backend_info->bSupportsShaderBinaries = true; // Assumed support. backend_info->bSupportsPipelineCacheData = false; // Handled via pipeline caches. backend_info->bSupportsDynamicSamplerIndexing = true; // Assumed support. - backend_info->bSupportsPostProcessing = true; // Assumed support. backend_info->bSupportsBackgroundCompiling = true; // Assumed support. backend_info->bSupportsCopyToVram = true; // Assumed support. backend_info->bSupportsReversedDepthRange = true; // Assumed support. diff --git a/Source/Core/VideoCommon/Assets/CustomAssetLibrary.h b/Source/Core/VideoCommon/Assets/CustomAssetLibrary.h index 10498618c6..52b5988591 100644 --- a/Source/Core/VideoCommon/Assets/CustomAssetLibrary.h +++ b/Source/Core/VideoCommon/Assets/CustomAssetLibrary.h @@ -8,10 +8,6 @@ namespace VideoCommon { class CustomTextureData; -struct MaterialData; -struct MeshData; -struct RasterSurfaceShaderData; -struct TextureAndSamplerData; // This class provides functionality to load // specific data (like textures). Where this data @@ -29,20 +25,7 @@ public: virtual ~CustomAssetLibrary() = default; - // Loads a texture with a sampler and type, if there are no levels, bytes loaded will be empty - virtual LoadInfo LoadTexture(const AssetID& asset_id, TextureAndSamplerData* data) = 0; - // Loads a texture, if there are no levels, bytes loaded will be empty virtual LoadInfo LoadTexture(const AssetID& asset_id, CustomTextureData* data) = 0; - - // Loads a raster surface shader - virtual LoadInfo LoadRasterSurfaceShader(const AssetID& asset_id, - RasterSurfaceShaderData* data) = 0; - - // Loads a material - virtual LoadInfo LoadMaterial(const AssetID& asset_id, MaterialData* data) = 0; - - // Loads a mesh - virtual LoadInfo LoadMesh(const AssetID& asset_id, MeshData* data) = 0; }; } // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Assets/DirectFilesystemAssetLibrary.cpp b/Source/Core/VideoCommon/Assets/DirectFilesystemAssetLibrary.cpp index 58b72ef110..a0b480a109 100644 --- a/Source/Core/VideoCommon/Assets/DirectFilesystemAssetLibrary.cpp +++ b/Source/Core/VideoCommon/Assets/DirectFilesystemAssetLibrary.cpp @@ -14,9 +14,6 @@ #include "Common/Logging/Log.h" #include "Common/StringUtil.h" #include "Core/System.h" -#include "VideoCommon/Assets/MaterialAsset.h" -#include "VideoCommon/Assets/MeshAsset.h" -#include "VideoCommon/Assets/ShaderAsset.h" #include "VideoCommon/Assets/TextureAsset.h" #include "VideoCommon/Assets/TextureAssetUtils.h" #include "VideoCommon/RenderState.h" @@ -40,278 +37,6 @@ std::size_t GetAssetSize(const CustomTextureData& data) } } // namespace -CustomAssetLibrary::LoadInfo -DirectFilesystemAssetLibrary::LoadRasterSurfaceShader(const AssetID& asset_id, - RasterSurfaceShaderData* data) -{ - const auto asset_map = GetAssetMapForID(asset_id); - - // Asset map for a pixel shader is the shader and some metadata - if (asset_map.size() != 3) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' expected to have three files mapped!", asset_id); - return {}; - } - - const auto metadata = asset_map.find("metadata"); - if (metadata == asset_map.end()) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' expected to have a metadata entry mapped!", asset_id); - return {}; - } - - const auto vertex_shader = asset_map.find("vertex_shader"); - if (vertex_shader == asset_map.end()) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' expected to have a vertex shader entry mapped!", asset_id); - return {}; - } - - const auto pixel_shader = asset_map.find("pixel_shader"); - if (pixel_shader == asset_map.end()) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' expected to have a pixel shader entry mapped!", asset_id); - return {}; - } - - std::size_t metadata_size; - { - std::error_code ec; - metadata_size = std::filesystem::file_size(metadata->second, ec); - if (ec) - { - ERROR_LOG_FMT(VIDEO, - "Asset '{}' error - failed to get shader metadata file size with error '{}'!", - asset_id, ec); - return {}; - } - } - std::size_t vertex_shader_size; - { - std::error_code ec; - vertex_shader_size = std::filesystem::file_size(vertex_shader->second, ec); - if (ec) - { - ERROR_LOG_FMT( - VIDEO, "Asset '{}' error - failed to get vertex shader source file size with error '{}'!", - asset_id, ec); - return {}; - } - } - std::size_t pixel_shader_size; - { - std::error_code ec; - pixel_shader_size = std::filesystem::file_size(pixel_shader->second, ec); - if (ec) - { - ERROR_LOG_FMT( - VIDEO, "Asset '{}' error - failed to get pixel shader source file size with error '{}'!", - asset_id, ec); - return {}; - } - } - const auto approx_mem_size = metadata_size + vertex_shader_size + pixel_shader_size; - - if (!File::ReadFileToString(PathToString(vertex_shader->second), data->vertex_source)) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' error - failed to load the vertex shader file '{}',", - asset_id, PathToString(vertex_shader->second)); - return {}; - } - - if (!File::ReadFileToString(PathToString(pixel_shader->second), data->pixel_source)) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' error - failed to load the pixel shader file '{}',", asset_id, - PathToString(pixel_shader->second)); - return {}; - } - - picojson::value root; - std::string error; - if (!JsonFromFile(PathToString(metadata->second), &root, &error)) - { - ERROR_LOG_FMT(VIDEO, - "Asset '{}' error - failed to load the json file '{}', due to parse error: {}", - asset_id, PathToString(metadata->second), error); - return {}; - } - - if (!root.is()) - { - ERROR_LOG_FMT( - VIDEO, - "Asset '{}' error - failed to load the json file '{}', due to root not being an object!", - asset_id, PathToString(metadata->second)); - return {}; - } - - const auto& root_obj = root.get(); - - if (!RasterSurfaceShaderData::FromJson(asset_id, root_obj, data)) - return {}; - - const std::string graphics_mod_builtin = - File::GetSysDirectory() + GRAPHICSMOD_DIR + "/Builtin" + "/Shaders"; - - data->shader_includer = std::make_unique( - PathToString(pixel_shader->second.parent_path()), graphics_mod_builtin); - - return LoadInfo{approx_mem_size}; -} - -CustomAssetLibrary::LoadInfo DirectFilesystemAssetLibrary::LoadMaterial(const AssetID& asset_id, - MaterialData* data) -{ - const auto asset_map = GetAssetMapForID(asset_id); - - // Material is expected to have one asset mapped - if (asset_map.empty() || asset_map.size() > 1) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' error - material expected to have one file mapped!", asset_id); - return {}; - } - const auto& asset_path = asset_map.begin()->second; - - std::size_t metadata_size; - { - std::error_code ec; - metadata_size = std::filesystem::file_size(asset_path, ec); - if (ec) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' error - failed to get material file size with error '{}'!", - asset_id, ec); - return {}; - } - } - - picojson::value root; - std::string error; - if (!JsonFromFile(PathToString(asset_path), &root, &error)) - { - ERROR_LOG_FMT( - VIDEO, - "Asset '{}' error - material failed to load the json file '{}', due to parse error: {}", - asset_id, PathToString(asset_path), error); - return {}; - } - if (!root.is()) - { - ERROR_LOG_FMT(VIDEO, - "Asset '{}' error - material failed to load the json file '{}', due to root not " - "being an object!", - asset_id, PathToString(asset_path)); - return {}; - } - - const auto& root_obj = root.get(); - - if (!MaterialData::FromJson(asset_id, root_obj, data)) - { - ERROR_LOG_FMT(VIDEO, - "Asset '{}' error - material failed to load the json file '{}', as material " - "json could not be parsed!", - asset_id, PathToString(asset_path)); - return {}; - } - - return LoadInfo{metadata_size}; -} - -CustomAssetLibrary::LoadInfo DirectFilesystemAssetLibrary::LoadMesh(const AssetID& asset_id, - MeshData* data) -{ - const auto asset_map = GetAssetMapForID(asset_id); - - // Asset map for a mesh is the mesh and some metadata - if (asset_map.size() != 2) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' expected to have two files mapped!", asset_id); - return {}; - } - - const auto metadata = asset_map.find("metadata"); - const auto mesh = asset_map.find("mesh"); - if (metadata == asset_map.end()) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' expected to have a metadata entry mapped!", asset_id); - return {}; - } - - if (mesh == asset_map.end()) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' expected to have a mesh entry mapped!", asset_id); - return {}; - } - - std::size_t metadata_size; - { - std::error_code ec; - metadata_size = std::filesystem::file_size(metadata->second, ec); - if (ec) - { - ERROR_LOG_FMT(VIDEO, - "Asset '{}' error - failed to get mesh metadata file size with error '{}'!", - asset_id, ec); - return {}; - } - } - std::size_t mesh_size; - { - std::error_code ec; - mesh_size = std::filesystem::file_size(mesh->second, ec); - if (ec) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' error - failed to get mesh file size with error '{}'!", - asset_id, ec); - return {}; - } - } - const auto approx_mem_size = metadata_size + mesh_size; - - File::IOFile file(PathToString(mesh->second), "rb"); - if (!file.IsOpen()) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' error - failed to open mesh file '{}'!", asset_id, - PathToString(mesh->second)); - return {}; - } - - std::vector bytes; - bytes.reserve(file.GetSize()); - file.ReadBytes(bytes.data(), file.GetSize()); - if (!MeshData::FromDolphinMesh(bytes, data)) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' error - failed to load the mesh file '{}'!", asset_id, - PathToString(mesh->second)); - return {}; - } - - picojson::value root; - std::string error; - if (!JsonFromFile(PathToString(metadata->second), &root, &error)) - { - ERROR_LOG_FMT(VIDEO, - "Asset '{}' error - failed to load the json file '{}', due to parse error: {}", - asset_id, PathToString(metadata->second), error); - return {}; - } - if (!root.is()) - { - ERROR_LOG_FMT( - VIDEO, - "Asset '{}' error - failed to load the json file '{}', due to root not being an object!", - asset_id, PathToString(metadata->second)); - return {}; - } - - const auto& root_obj = root.get(); - - if (!MeshData::FromJson(asset_id, root_obj, data)) - return {}; - - return LoadInfo{approx_mem_size}; -} - CustomAssetLibrary::LoadInfo DirectFilesystemAssetLibrary::LoadTexture(const AssetID& asset_id, CustomTextureData* data) { @@ -342,79 +67,6 @@ CustomAssetLibrary::LoadInfo DirectFilesystemAssetLibrary::LoadTexture(const Ass return LoadInfo{GetAssetSize(*data)}; } -CustomAssetLibrary::LoadInfo DirectFilesystemAssetLibrary::LoadTexture(const AssetID& asset_id, - TextureAndSamplerData* data) -{ - const auto asset_map = GetAssetMapForID(asset_id); - - // Texture can optionally have a metadata file as well - if (asset_map.empty() || asset_map.size() > 2) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' error - raw texture expected to have one or two files mapped!", - asset_id); - return {}; - } - - const auto metadata = asset_map.find("metadata"); - const auto texture_path = asset_map.find("texture"); - - if (texture_path == asset_map.end()) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' expected to have a texture entry mapped!", asset_id); - return {}; - } - - std::size_t metadata_size = 0; - if (metadata != asset_map.end()) - { - std::error_code ec; - metadata_size = std::filesystem::file_size(metadata->second, ec); - if (ec) - { - ERROR_LOG_FMT(VIDEO, - "Asset '{}' error - failed to get texture metadata file size with error '{}'!", - asset_id, ec); - return {}; - } - - picojson::value root; - std::string error; - if (!JsonFromFile(PathToString(metadata->second), &root, &error)) - { - ERROR_LOG_FMT(VIDEO, - "Asset '{}' error - failed to load the json file '{}', due to parse error: {}", - asset_id, PathToString(metadata->second), error); - return {}; - } - if (!root.is()) - { - ERROR_LOG_FMT( - VIDEO, - "Asset '{}' error - failed to load the json file '{}', due to root not being an object!", - asset_id, PathToString(metadata->second)); - return {}; - } - - const auto& root_obj = root.get(); - if (!TextureAndSamplerData::FromJson(asset_id, root_obj, data)) - { - return {}; - } - } - else - { - data->sampler = RenderState::GetLinearSamplerState(); - data->type = AbstractTextureType::Texture_2D; - } - - if (!LoadTextureDataFromFile(asset_id, texture_path->second, data->type, &data->texture_data)) - return {}; - if (!PurgeInvalidMipsFromTextureData(asset_id, &data->texture_data)) - return {}; - - return LoadInfo{GetAssetSize(data->texture_data) + metadata_size}; -} - void DirectFilesystemAssetLibrary::SetAssetIDMapData(const AssetID& asset_id, VideoCommon::Assets::AssetMap asset_path_map) { diff --git a/Source/Core/VideoCommon/Assets/DirectFilesystemAssetLibrary.h b/Source/Core/VideoCommon/Assets/DirectFilesystemAssetLibrary.h index 3cc2098401..e1a4cbd66c 100644 --- a/Source/Core/VideoCommon/Assets/DirectFilesystemAssetLibrary.h +++ b/Source/Core/VideoCommon/Assets/DirectFilesystemAssetLibrary.h @@ -20,11 +20,7 @@ namespace VideoCommon class DirectFilesystemAssetLibrary final : public WatchableFilesystemAssetLibrary { public: - LoadInfo LoadTexture(const AssetID& asset_id, TextureAndSamplerData* data) override; LoadInfo LoadTexture(const AssetID& asset_id, CustomTextureData* data) override; - LoadInfo LoadRasterSurfaceShader(const AssetID& asset_id, RasterSurfaceShaderData* data) override; - LoadInfo LoadMaterial(const AssetID& asset_id, MaterialData* data) override; - LoadInfo LoadMesh(const AssetID& asset_id, MeshData* data) override; // Assigns the asset id to a map of files, how this map is read is dependent on the data // For instance, a raw texture would expect the map to have a single entry and load that diff --git a/Source/Core/VideoCommon/Assets/MaterialAsset.cpp b/Source/Core/VideoCommon/Assets/MaterialAsset.cpp deleted file mode 100644 index 200bccf333..0000000000 --- a/Source/Core/VideoCommon/Assets/MaterialAsset.cpp +++ /dev/null @@ -1,482 +0,0 @@ -// Copyright 2023 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "VideoCommon/Assets/MaterialAsset.h" - -#include -#include -#include - -#include "Common/JsonUtil.h" -#include "Common/Logging/Log.h" -#include "Common/StringUtil.h" -#include "Common/VariantUtil.h" -#include "VideoCommon/Assets/CustomAssetLibrary.h" - -namespace VideoCommon -{ -namespace -{ -// While not optimal, we pad our data to match std140 shader requirements -// this memory constant indicates the memory stride for a single uniform -// regardless of data type -constexpr std::size_t MemorySize = sizeof(float) * 4; - -template -bool ParseNumeric(const CustomAssetLibrary::AssetID& asset_id, const picojson::value& json_value, - MaterialProperty::Value* value) -{ - static_assert(ElementCount <= 4, "Numeric data expected to be four elements or less"); - if constexpr (ElementCount == 1) - { - if (!json_value.is()) - { - ERROR_LOG_FMT(VIDEO, - "Asset id '{}' material has attribute where " - "a double was expected but not provided.", - asset_id); - return false; - } - - *value = static_cast(json_value.get()); - } - else - { - if (!json_value.is()) - { - ERROR_LOG_FMT(VIDEO, - "Asset id '{}' material has attribute where " - "an array was expected but not provided.", - asset_id); - return false; - } - - const auto json_data = json_value.get(); - - if (json_data.size() != ElementCount) - { - ERROR_LOG_FMT(VIDEO, - "Asset id '{}' material has attribute with incorrect number " - "of elements, expected {}", - asset_id, ElementCount); - return false; - } - - if (!std::ranges::all_of(json_data, &picojson::value::is)) - { - ERROR_LOG_FMT(VIDEO, - "Asset id '{}' material has attribute where " - "all elements are not of type double.", - asset_id); - return false; - } - - std::array data; - for (std::size_t i = 0; i < ElementCount; i++) - { - data[i] = static_cast(json_data[i].get()); - } - *value = std::move(data); - } - - return true; -} -bool ParsePropertyValue(const CustomAssetLibrary::AssetID& asset_id, - const picojson::value& json_value, std::string_view type, - MaterialProperty::Value* value) -{ - if (type == "int") - { - return ParseNumeric(asset_id, json_value, value); - } - else if (type == "int2") - { - return ParseNumeric(asset_id, json_value, value); - } - else if (type == "int3") - { - return ParseNumeric(asset_id, json_value, value); - } - else if (type == "int4") - { - return ParseNumeric(asset_id, json_value, value); - } - else if (type == "float") - { - return ParseNumeric(asset_id, json_value, value); - } - else if (type == "float2") - { - return ParseNumeric(asset_id, json_value, value); - } - else if (type == "float3") - { - return ParseNumeric(asset_id, json_value, value); - } - else if (type == "float4") - { - return ParseNumeric(asset_id, json_value, value); - } - else if (type == "bool") - { - if (json_value.is()) - { - *value = json_value.get(); - return true; - } - } - - ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse the json, value is not valid for type '{}'", - asset_id, type); - return false; -} - -bool ParseMaterialProperties(const CustomAssetLibrary::AssetID& asset_id, - const picojson::array& values_data, - std::vector* material_property) -{ - for (const auto& value_data : values_data) - { - VideoCommon::MaterialProperty property; - if (!value_data.is()) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse the json, value is not the right json type", - asset_id); - return false; - } - const auto& value_data_obj = value_data.get(); - - const auto type_iter = value_data_obj.find("type"); - if (type_iter == value_data_obj.end()) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse the json, value entry 'type' not found", - asset_id); - return false; - } - if (!type_iter->second.is()) - { - ERROR_LOG_FMT(VIDEO, - "Asset '{}' failed to parse the json, value entry 'type' is not " - "the right json type", - asset_id); - return false; - } - std::string type = type_iter->second.to_str(); - Common::ToLower(&type); - - const auto value_iter = value_data_obj.find("value"); - if (value_iter != value_data_obj.end()) - { - if (!ParsePropertyValue(asset_id, value_iter->second, type, &property.m_value)) - { - return false; - } - } - - material_property->push_back(std::move(property)); - } - - return true; -} -} // namespace - -void MaterialProperty::WriteToMemory(u8*& buffer, const MaterialProperty& property) -{ - const auto write_memory = [&](const void* raw_value, std::size_t data_size) { - std::memcpy(buffer, raw_value, data_size); - std::memset(buffer + data_size, 0, MemorySize - data_size); - buffer += MemorySize; - }; - std::visit( - overloaded{ - [&](s32 value) { write_memory(&value, sizeof(s32)); }, - [&](const std::array& value) { write_memory(value.data(), sizeof(s32) * 2); }, - [&](const std::array& value) { write_memory(value.data(), sizeof(s32) * 3); }, - [&](const std::array& value) { write_memory(value.data(), sizeof(s32) * 4); }, - [&](float value) { write_memory(&value, sizeof(float)); }, - [&](const std::array& value) { write_memory(value.data(), sizeof(float) * 2); }, - [&](const std::array& value) { write_memory(value.data(), sizeof(float) * 3); }, - [&](const std::array& value) { write_memory(value.data(), sizeof(float) * 4); }, - - // Bool has the size of an int in the shader - [&](bool value) { - u32 val = static_cast(value); - write_memory(&val, sizeof(u32)); - }}, - property.m_value); -} - -std::size_t MaterialProperty::GetMemorySize(const MaterialProperty& property) -{ - std::size_t result = 0; - std::visit(overloaded{[&](s32 value) { result = MemorySize; }, - [&](const std::array&) { result = MemorySize; }, - [&](const std::array&) { result = MemorySize; }, - [&](const std::array&) { result = MemorySize; }, - [&](float) { result = MemorySize; }, - [&](const std::array&) { result = MemorySize; }, - [&](const std::array&) { result = MemorySize; }, - [&](const std::array&) { result = MemorySize; }, - [&](bool) { result = MemorySize; }}, - property.m_value); - - return result; -} - -bool MaterialData::FromJson(const CustomAssetLibrary::AssetID& asset_id, - const picojson::object& json, MaterialData* data) -{ - const auto parse_properties = [&](const char* name, - std::vector* material_properties) -> bool { - const auto properties_iter = json.find(name); - if (properties_iter == json.end()) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, '{}' not found", asset_id, name); - return false; - } - if (!properties_iter->second.is()) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, '{}' is not the right json type", - asset_id, name); - return false; - } - const auto& properties_array = properties_iter->second.get(); - - if (!ParseMaterialProperties(asset_id, properties_array, material_properties)) - return false; - return true; - }; - - if (!parse_properties("properties", &data->properties)) - return false; - - if (const auto shader_asset = ReadStringFromJson(json, "shader_asset")) - { - data->shader_asset = *shader_asset; - } - else - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, 'shader_asset' not found or wrong type", - asset_id); - return false; - } - - if (const auto next_material_asset = ReadStringFromJson(json, "next_material_asset")) - { - data->next_material_asset = *next_material_asset; - } - else - { - ERROR_LOG_FMT(VIDEO, - "Asset '{}' failed to parse json, 'next_material_asset' not found or wrong type", - asset_id); - return false; - } - - if (const auto cull_mode = ReadNumericFromJson(json, "cull_mode")) - { - data->cull_mode = *cull_mode; - } - - if (const auto depth_state = json.find("depth_state"); - depth_state != json.end() && depth_state->second.is()) - { - auto& json_obj = depth_state->second.get(); - DepthState state; - state.test_enable = ReadNumericFromJson(json_obj, "test_enable").value_or(0); - state.update_enable = ReadNumericFromJson(json_obj, "update_enable").value_or(0); - state.func = ReadNumericFromJson(json_obj, "func").value_or(CompareMode::Never); - data->depth_state = state; - } - - if (const auto blending_state = json.find("blending_state"); - blending_state != json.end() && blending_state->second.is()) - { - auto& json_obj = blending_state->second.get(); - BlendingState state; - state.blend_enable = ReadNumericFromJson(json_obj, "blend_enable").value_or(0); - state.logic_op_enable = ReadNumericFromJson(json_obj, "logic_op_enable").value_or(0); - state.color_update = ReadNumericFromJson(json_obj, "color_update").value_or(0); - state.alpha_update = ReadNumericFromJson(json_obj, "alpha_update").value_or(0); - state.subtract = ReadNumericFromJson(json_obj, "subtract").value_or(0); - state.subtract_alpha = ReadNumericFromJson(json_obj, "subtract_alpha").value_or(0); - state.use_dual_src = ReadNumericFromJson(json_obj, "use_dual_src").value_or(0); - state.dst_factor = - ReadNumericFromJson(json_obj, "dst_factor").value_or(DstBlendFactor::Zero); - state.src_factor = - ReadNumericFromJson(json_obj, "src_factor").value_or(SrcBlendFactor::Zero); - state.dst_factor_alpha = ReadNumericFromJson(json_obj, "dst_factor_alpha") - .value_or(DstBlendFactor::Zero); - state.src_factor_alpha = ReadNumericFromJson(json_obj, "src_factor_alpha") - .value_or(SrcBlendFactor::Zero); - state.logic_mode = - ReadNumericFromJson(json_obj, "logic_mode").value_or(LogicOp::Clear); - data->blending_state = state; - } - - const auto textures_iter = json.find("textures"); - if (textures_iter == json.end()) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, 'textures' not found", asset_id); - return false; - } - if (!textures_iter->second.is()) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, 'textures' is not the right json type", - asset_id); - return false; - } - const auto& textures_array = textures_iter->second.get(); - if (!std::ranges::all_of(textures_array, [](const picojson::value& json_data) { - return json_data.is(); - })) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, 'textures' must contain objects", - asset_id); - return false; - } - - for (const auto& texture_json : textures_array) - { - auto& texture_json_obj = texture_json.get(); - - TextureSamplerValue sampler_value; - if (!TextureSamplerValue::FromJson(texture_json_obj, &sampler_value)) - return false; - data->textures.push_back(std::move(sampler_value)); - } - - return true; -} - -void MaterialData::ToJson(picojson::object* obj, const MaterialData& data) -{ - if (!obj) [[unlikely]] - return; - - auto& json_obj = *obj; - - const auto add_property = [](picojson::array* json_properties, const MaterialProperty& property) { - picojson::object json_property; - - std::visit(overloaded{[&](s32 value) { - json_property["type"] = picojson::value{"int"}; - json_property["value"] = picojson::value{static_cast(value)}; - }, - [&](const std::array& value) { - json_property["type"] = picojson::value{"int2"}; - json_property["value"] = picojson::value{ToJsonArray(value)}; - }, - [&](const std::array& value) { - json_property["type"] = picojson::value{"int3"}; - json_property["value"] = picojson::value{ToJsonArray(value)}; - }, - [&](const std::array& value) { - json_property["type"] = picojson::value{"int4"}; - json_property["value"] = picojson::value{ToJsonArray(value)}; - }, - [&](float value) { - json_property["type"] = picojson::value{"float"}; - json_property["value"] = picojson::value{static_cast(value)}; - }, - [&](const std::array& value) { - json_property["type"] = picojson::value{"float2"}; - json_property["value"] = picojson::value{ToJsonArray(value)}; - }, - [&](const std::array& value) { - json_property["type"] = picojson::value{"float3"}; - json_property["value"] = picojson::value{ToJsonArray(value)}; - }, - [&](const std::array& value) { - json_property["type"] = picojson::value{"float4"}; - json_property["value"] = picojson::value{ToJsonArray(value)}; - }, - [&](bool value) { - json_property["type"] = picojson::value{"bool"}; - json_property["value"] = picojson::value{value}; - }}, - property.m_value); - - json_properties->emplace_back(std::move(json_property)); - }; - - picojson::array json_properties; - for (const auto& property : data.properties) - { - add_property(&json_properties, property); - } - json_obj.emplace("properties", std::move(json_properties)); - - json_obj.emplace("shader_asset", data.shader_asset); - json_obj.emplace("next_material_asset", data.next_material_asset); - - if (data.cull_mode) - { - json_obj.emplace("cull_mode", static_cast(*data.cull_mode)); - } - - if (data.depth_state) - { - picojson::object depth_state_json; - depth_state_json.emplace("test_enable", - static_cast(data.depth_state->test_enable.Value())); - depth_state_json.emplace("update_enable", - static_cast(data.depth_state->update_enable.Value())); - depth_state_json.emplace("func", static_cast(data.depth_state->func.Value())); - json_obj.emplace("depth_state", depth_state_json); - } - - if (data.blending_state) - { - picojson::object blending_state_json; - blending_state_json.emplace("blend_enable", - static_cast(data.blending_state->blend_enable.Value())); - blending_state_json.emplace("logic_op_enable", - static_cast(data.blending_state->logic_op_enable.Value())); - blending_state_json.emplace("color_update", - static_cast(data.blending_state->color_update.Value())); - blending_state_json.emplace("alpha_update", - static_cast(data.blending_state->alpha_update.Value())); - blending_state_json.emplace("subtract", - static_cast(data.blending_state->subtract.Value())); - blending_state_json.emplace("subtract_alpha", - static_cast(data.blending_state->subtract_alpha.Value())); - blending_state_json.emplace("use_dual_src", - static_cast(data.blending_state->use_dual_src.Value())); - blending_state_json.emplace("dst_factor", - static_cast(data.blending_state->dst_factor.Value())); - blending_state_json.emplace("src_factor", - static_cast(data.blending_state->src_factor.Value())); - blending_state_json.emplace("dst_factor_alpha", - static_cast(data.blending_state->dst_factor_alpha.Value())); - blending_state_json.emplace("src_factor_alpha", - static_cast(data.blending_state->src_factor_alpha.Value())); - blending_state_json.emplace("logic_mode", - static_cast(data.blending_state->logic_mode.Value())); - json_obj.emplace("blending_state", blending_state_json); - } - - picojson::array json_textures; - for (const auto& texture : data.textures) - { - picojson::object json_texture; - TextureSamplerValue::ToJson(&json_texture, texture); - json_textures.emplace_back(std::move(json_texture)); - } - json_obj.emplace("textures", json_textures); -} - -CustomAssetLibrary::LoadInfo MaterialAsset::LoadImpl(const CustomAssetLibrary::AssetID& asset_id) -{ - auto potential_data = std::make_shared(); - const auto loaded_info = m_owning_library->LoadMaterial(asset_id, potential_data.get()); - if (loaded_info.bytes_loaded == 0) - return {}; - { - std::lock_guard lk(m_data_lock); - m_loaded = true; - m_data = std::move(potential_data); - } - return loaded_info; -} -} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Assets/MaterialAsset.h b/Source/Core/VideoCommon/Assets/MaterialAsset.h deleted file mode 100644 index 4be99169d0..0000000000 --- a/Source/Core/VideoCommon/Assets/MaterialAsset.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2023 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include -#include -#include - -#include - -#include "Common/CommonTypes.h" -#include "VideoCommon/Assets/CustomAsset.h" -#include "VideoCommon/Assets/TextureSamplerValue.h" -#include "VideoCommon/BPMemory.h" -#include "VideoCommon/RenderState.h" - -class ShaderCode; - -namespace VideoCommon -{ -struct MaterialProperty -{ - static void WriteToMemory(u8*& buffer, const MaterialProperty& property); - static std::size_t GetMemorySize(const MaterialProperty& property); - using Value = - std::variant, std::array, std::array, float, - std::array, std::array, std::array, bool>; - Value m_value; -}; - -struct MaterialData -{ - static bool FromJson(const CustomAssetLibrary::AssetID& asset_id, const picojson::object& json, - MaterialData* data); - static void ToJson(picojson::object* obj, const MaterialData& data); - CustomAssetLibrary::AssetID shader_asset; - CustomAssetLibrary::AssetID next_material_asset; - std::vector properties; - - std::optional cull_mode; - std::optional depth_state; - std::optional blending_state; - - std::vector textures; -}; - -// Much like Unity and Unreal materials, a Dolphin material does very little on its own -// Its sole purpose is to provide data (through properties) that are used in conjunction -// with a shader asset that is provided by name. It is up to user of this asset to -// use the two together to create the relevant runtime data -class MaterialAsset final : public CustomLoadableAsset -{ -public: - using CustomLoadableAsset::CustomLoadableAsset; - -private: - CustomAssetLibrary::LoadInfo LoadImpl(const CustomAssetLibrary::AssetID& asset_id) override; -}; - -} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Assets/MeshAsset.cpp b/Source/Core/VideoCommon/Assets/MeshAsset.cpp deleted file mode 100644 index 133184aa33..0000000000 --- a/Source/Core/VideoCommon/Assets/MeshAsset.cpp +++ /dev/null @@ -1,661 +0,0 @@ -// Copyright 2023 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "VideoCommon/Assets/MeshAsset.h" - -#include -#include - -#include - -#include "Common/IOFile.h" -#include "Common/Logging/Log.h" -#include "VideoCommon/Assets/CustomAssetLibrary.h" - -namespace VideoCommon -{ -namespace -{ -Common::Matrix44 BuildMatrixFromNode(const tinygltf::Node& node) -{ - if (!node.matrix.empty()) - { - Common::Matrix44 matrix; - for (std::size_t i = 0; i < node.matrix.size(); i++) - { - matrix.data[i] = static_cast(node.matrix[i]); - } - return matrix; - } - - Common::Matrix44 matrix = Common::Matrix44::Identity(); - - // Check individual components - - if (!node.scale.empty()) - { - matrix *= Common::Matrix44::FromMatrix33(Common::Matrix33::Scale( - Common::Vec3{static_cast(node.scale[0]), static_cast(node.scale[1]), - static_cast(node.scale[2])})); - } - - if (!node.rotation.empty()) - { - matrix *= Common::Matrix44::FromQuaternion(Common::Quaternion( - static_cast(node.rotation[3]), static_cast(node.rotation[0]), - static_cast(node.rotation[1]), static_cast(node.rotation[2]))); - } - - if (!node.translation.empty()) - { - matrix *= Common::Matrix44::Translate(Common::Vec3{static_cast(node.translation[0]), - static_cast(node.translation[1]), - static_cast(node.translation[2])}); - } - - return matrix; -} - -bool GLTFComponentTypeToAttributeFormat(int component_type, AttributeFormat* format) -{ - switch (component_type) - { - case TINYGLTF_COMPONENT_TYPE_BYTE: - { - format->type = ComponentFormat::Byte; - format->integer = false; - } - break; - case TINYGLTF_COMPONENT_TYPE_DOUBLE: - { - return false; - } - break; - case TINYGLTF_COMPONENT_TYPE_FLOAT: - { - format->type = ComponentFormat::Float; - format->integer = false; - } - break; - case TINYGLTF_COMPONENT_TYPE_INT: - { - format->type = ComponentFormat::Float; - format->integer = true; - } - break; - case TINYGLTF_COMPONENT_TYPE_SHORT: - { - format->type = ComponentFormat::Short; - format->integer = false; - } - break; - case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE: - { - format->type = ComponentFormat::UByte; - format->integer = false; - } - break; - case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT: - { - return false; - } - break; - case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT: - { - format->type = ComponentFormat::UShort; - format->integer = false; - } - break; - }; - - return true; -} - -bool UpdateVertexStrideFromPrimitive(const tinygltf::Model& model, u32 accessor_index, - MeshDataChunk* chunk) -{ - const tinygltf::Accessor& accessor = model.accessors[accessor_index]; - - const int component_count = tinygltf::GetNumComponentsInType(accessor.type); - if (component_count == -1) - { - ERROR_LOG_FMT(VIDEO, "Failed to update vertex stride, component count was invalid"); - return false; - } - - const int component_size = - tinygltf::GetComponentSizeInBytes(static_cast(accessor.componentType)); - if (component_size == -1) - { - ERROR_LOG_FMT(VIDEO, "Failed to update vertex stride, component size was invalid"); - return false; - } - - chunk->vertex_stride += component_size * component_count; - return true; -} - -bool CopyBufferDataFromPrimitive(const tinygltf::Model& model, u32 accessor_index, - std::size_t* outbound_offset, MeshDataChunk* chunk) -{ - const tinygltf::Accessor& accessor = model.accessors[accessor_index]; - - const int component_count = tinygltf::GetNumComponentsInType(accessor.type); - if (component_count == -1) - { - ERROR_LOG_FMT(VIDEO, "Failed to copy buffer data from primitive, component count was invalid"); - return false; - } - - const int component_size = - tinygltf::GetComponentSizeInBytes(static_cast(accessor.componentType)); - if (component_size == -1) - { - ERROR_LOG_FMT(VIDEO, "Failed to copy buffer data from primitive, component size was invalid"); - return false; - } - - const tinygltf::BufferView& buffer_view = model.bufferViews[accessor.bufferView]; - const tinygltf::Buffer& buffer = model.buffers[buffer_view.buffer]; - - if (buffer_view.byteStride == 0) - { - // Data is tightly packed - const auto data = &buffer.data[accessor.byteOffset + buffer_view.byteOffset]; - for (std::size_t i = 0; i < accessor.count; i++) - { - const std::size_t vertex_data_offset = i * chunk->vertex_stride + *outbound_offset; - memcpy(&chunk->vertex_data[vertex_data_offset], &data[i * component_size * component_count], - component_size * component_count); - } - } - else - { - // Data is interleaved - const auto data = &buffer.data[accessor.byteOffset + buffer_view.byteOffset]; - for (std::size_t i = 0; i < accessor.count; i++) - { - const std::size_t vertex_data_offset = i * chunk->vertex_stride + *outbound_offset; - const std::size_t gltf_data_offset = i * buffer_view.byteStride; - - memcpy(&chunk->vertex_data[vertex_data_offset], &data[gltf_data_offset], - component_size * component_count); - } - } - - *outbound_offset += component_size * component_count; - - return true; -} - -bool ReadGLTFMesh(std::string_view mesh_file, const tinygltf::Model& model, - const tinygltf::Mesh& mesh, const Common::Matrix44& mat, MeshData* data) -{ - for (std::size_t primitive_index = 0; primitive_index < mesh.primitives.size(); ++primitive_index) - { - MeshDataChunk chunk; - chunk.transform = mat; - const tinygltf::Primitive& primitive = mesh.primitives[primitive_index]; - if (primitive.indices == -1) - { - ERROR_LOG_FMT(VIDEO, "Mesh '{}' is expected to have indices but doesn't have any", mesh_file); - return false; - } - chunk.material_name = model.materials[primitive.material].name; - const tinygltf::Accessor& index_accessor = model.accessors[primitive.indices]; - const tinygltf::BufferView& index_buffer_view = model.bufferViews[index_accessor.bufferView]; - const tinygltf::Buffer& index_buffer = model.buffers[index_buffer_view.buffer]; - const int index_stride = index_accessor.ByteStride(index_buffer_view); - if (index_stride == -1) - { - ERROR_LOG_FMT(VIDEO, "Mesh '{}' has invalid stride", mesh_file); - return false; - } - // TODO C++23: use make_unique_overwrite - chunk.indices = std::unique_ptr(new u16[index_accessor.count]); - auto index_src = &index_buffer.data[index_accessor.byteOffset + index_buffer_view.byteOffset]; - for (std::size_t i = 0; i < index_accessor.count; i++) - { - if (index_accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) - { - std::memcpy(&chunk.indices[i], &index_src[i * index_stride], sizeof(u16)); - } - else if (index_accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) - { - u8 unsigned_byte; - std::memcpy(&unsigned_byte, &index_src[i * index_stride], sizeof(u8)); - chunk.indices[i] = unsigned_byte; - } - else if (index_accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) - { - // TODO: update Dolphin to support u32 indices - ERROR_LOG_FMT( - VIDEO, - "Mesh '{}' uses an indice format of unsigned int which is not currently supported", - mesh_file); - return false; - } - } - - chunk.num_indices = static_cast(index_accessor.count); - - if (primitive.mode == TINYGLTF_MODE_TRIANGLES) - { - chunk.primitive_type = PrimitiveType::Triangles; - } - else if (primitive.mode == TINYGLTF_MODE_TRIANGLE_STRIP) - { - chunk.primitive_type = PrimitiveType::TriangleStrip; - } - else if (primitive.mode == TINYGLTF_MODE_TRIANGLE_FAN) - { - ERROR_LOG_FMT(VIDEO, "Mesh '{}' requires triangle fan but that is not supported", mesh_file); - return false; - } - else if (primitive.mode == TINYGLTF_MODE_LINE) - { - chunk.primitive_type = PrimitiveType::Lines; - } - else if (primitive.mode == TINYGLTF_MODE_POINTS) - { - chunk.primitive_type = PrimitiveType::Points; - } - - chunk.vertex_stride = 0; - static constexpr std::array all_names = { - "POSITION", "NORMAL", "COLOR_0", "COLOR_1", "TEXCOORD_0", "TEXCOORD_1", - "TEXCOORD_2", "TEXCOORD_3", "TEXCOORD_4", "TEXCOORD_5", "TEXCOORD_6", "TEXCOORD_7", - }; - for (std::size_t i = 0; i < all_names.size(); i++) - { - const auto it = primitive.attributes.find(std::string{all_names[i]}); - if (it != primitive.attributes.end()) - { - if (!UpdateVertexStrideFromPrimitive(model, it->second, &chunk)) - return false; - } - } - chunk.vertex_declaration.stride = chunk.vertex_stride; - - const auto position_it = primitive.attributes.find("POSITION"); - if (position_it == primitive.attributes.end()) - { - ERROR_LOG_FMT(VIDEO, "Mesh '{}' does not provide a POSITION attribute, that is required", - mesh_file); - return false; - } - std::size_t outbound_offset = 0; - const tinygltf::Accessor& pos_accessor = model.accessors[position_it->second]; - chunk.num_vertices = static_cast(pos_accessor.count); - // TODO C++23: use make_unique_overwrite - chunk.vertex_data = std::unique_ptr(new u8[chunk.num_vertices * chunk.vertex_stride]); - if (!CopyBufferDataFromPrimitive(model, position_it->second, &outbound_offset, &chunk)) - return false; - chunk.components_available = 0; - chunk.vertex_declaration.position.enable = true; - chunk.vertex_declaration.position.components = 3; - chunk.vertex_declaration.position.offset = 0; - if (!GLTFComponentTypeToAttributeFormat(pos_accessor.componentType, - &chunk.vertex_declaration.position)) - { - ERROR_LOG_FMT(VIDEO, "Mesh '{}' has invalid attribute format for position", mesh_file); - return false; - } - - // Save off min and max position in case we want to compute bounds - // GLTF spec expects these values to exist but error if they don't - if (pos_accessor.minValues.size() != 3) - { - ERROR_LOG_FMT(VIDEO, "Mesh '{}' is expected to have a minimum value but it is missing", - mesh_file); - return false; - } - chunk.minimum_position.x = static_cast(pos_accessor.minValues[0]); - chunk.minimum_position.y = static_cast(pos_accessor.minValues[1]); - chunk.minimum_position.z = static_cast(pos_accessor.minValues[2]); - - if (pos_accessor.maxValues.size() != 3) - { - ERROR_LOG_FMT(VIDEO, "Mesh '{}' is expected to have a maximum value but it is missing", - mesh_file); - return false; - } - chunk.maximum_position.x = static_cast(pos_accessor.maxValues[0]); - chunk.maximum_position.y = static_cast(pos_accessor.maxValues[1]); - chunk.maximum_position.z = static_cast(pos_accessor.maxValues[2]); - - static constexpr std::array color_names = { - "COLOR_0", - "COLOR_1", - }; - for (std::size_t i = 0; i < color_names.size(); i++) - { - const auto color_it = primitive.attributes.find(std::string{color_names[i]}); - if (color_it != primitive.attributes.end()) - { - chunk.vertex_declaration.colors[i].offset = static_cast(outbound_offset); - if (!CopyBufferDataFromPrimitive(model, color_it->second, &outbound_offset, &chunk)) - return false; - chunk.components_available |= VB_HAS_COL0 << i; - - chunk.vertex_declaration.colors[i].enable = true; - chunk.vertex_declaration.colors[i].components = 3; - const tinygltf::Accessor& accessor = model.accessors[color_it->second]; - if (!GLTFComponentTypeToAttributeFormat(accessor.componentType, - &chunk.vertex_declaration.colors[i])) - { - ERROR_LOG_FMT(VIDEO, "Mesh '{}' has invalid attribute format for {}", mesh_file, - color_names[i]); - return false; - } - } - else - { - chunk.vertex_declaration.colors[i].enable = false; - } - } - - const auto normal_it = primitive.attributes.find("NORMAL"); - if (normal_it != primitive.attributes.end()) - { - chunk.vertex_declaration.normals[0].offset = static_cast(outbound_offset); - if (!CopyBufferDataFromPrimitive(model, normal_it->second, &outbound_offset, &chunk)) - return false; - chunk.components_available |= VB_HAS_NORMAL; - chunk.vertex_declaration.normals[0].enable = true; - chunk.vertex_declaration.normals[0].components = 3; - const tinygltf::Accessor& accessor = model.accessors[normal_it->second]; - if (!GLTFComponentTypeToAttributeFormat(accessor.componentType, - &chunk.vertex_declaration.normals[0])) - { - ERROR_LOG_FMT(VIDEO, "Mesh '{}' has invalid attribute format for NORMAL", mesh_file); - return false; - } - } - else - { - chunk.vertex_declaration.normals[0].enable = false; - } - - static constexpr std::array texcoord_names = { - "TEXCOORD_0", "TEXCOORD_1", "TEXCOORD_2", "TEXCOORD_3", - "TEXCOORD_4", "TEXCOORD_5", "TEXCOORD_6", "TEXCOORD_7", - }; - for (std::size_t i = 0; i < texcoord_names.size(); i++) - { - const auto texture_it = primitive.attributes.find(std::string{texcoord_names[i]}); - if (texture_it != primitive.attributes.end()) - { - chunk.vertex_declaration.texcoords[i].offset = static_cast(outbound_offset); - if (!CopyBufferDataFromPrimitive(model, texture_it->second, &outbound_offset, &chunk)) - return false; - chunk.components_available |= VB_HAS_UV0 << i; - chunk.vertex_declaration.texcoords[i].enable = true; - chunk.vertex_declaration.texcoords[i].components = 2; - const tinygltf::Accessor& accessor = model.accessors[texture_it->second]; - if (!GLTFComponentTypeToAttributeFormat(accessor.componentType, - &chunk.vertex_declaration.texcoords[i])) - { - ERROR_LOG_FMT(VIDEO, "Mesh '{}' has invalid attribute format for {}", mesh_file, - texcoord_names[i]); - return false; - } - } - else - { - chunk.vertex_declaration.texcoords[i].enable = false; - } - } - - // Position matrix can be enabled if the draw that is using - // this mesh needs it - chunk.vertex_declaration.posmtx.enable = false; - - data->m_mesh_chunks.push_back(std::move(chunk)); - } - - return true; -} - -bool ReadGLTFNodes(std::string_view mesh_file, const tinygltf::Model& model, - const tinygltf::Node& node, const Common::Matrix44& mat, MeshData* data) -{ - if (node.mesh != -1) - { - if (!ReadGLTFMesh(mesh_file, model, model.meshes[node.mesh], mat, data)) - return false; - } - - for (std::size_t i = 0; i < node.children.size(); i++) - { - const tinygltf::Node& child = model.nodes[node.children[i]]; - const auto child_mat = mat * BuildMatrixFromNode(child); - if (!ReadGLTFNodes(mesh_file, model, child, child_mat, data)) - return false; - } - - return true; -} - -bool ReadGLTFMaterials(std::string_view mesh_file, const tinygltf::Model& model, MeshData* data) -{ - for (std::size_t i = 0; i < model.materials.size(); i++) - { - const tinygltf::Material& material = model.materials[i]; - - // TODO: support converting material data into Dolphin material assets - data->m_mesh_material_to_material_asset_id.insert_or_assign(material.name, ""); - } - - return true; -} - -bool ReadGLTF(std::string_view mesh_file, const tinygltf::Model& model, MeshData* data) -{ - int scene_index = model.defaultScene; - if (scene_index == -1) - scene_index = 0; - - const auto& scene = model.scenes[scene_index]; - const auto scene_node_indices = scene.nodes; - for (std::size_t i = 0; i < scene_node_indices.size(); i++) - { - const tinygltf::Node& node = model.nodes[scene_node_indices[i]]; - const auto mat = BuildMatrixFromNode(node); - if (!ReadGLTFNodes(mesh_file, model, node, mat, data)) - return false; - } - - return ReadGLTFMaterials(mesh_file, model, data); -} -} // namespace -bool MeshData::FromJson(const VideoCommon::CustomAssetLibrary::AssetID& asset_id, - const picojson::object& json, MeshData* data) -{ - if (const auto iter = json.find("material_mapping"); iter != json.end()) - { - if (!iter->second.is()) - { - ERROR_LOG_FMT( - VIDEO, - "Asset '{}' failed to parse json, expected 'material_mapping' to be of type object", - asset_id); - return false; - } - - for (const auto& [material_name, asset_id_json] : iter->second.get()) - { - if (!asset_id_json.is()) - { - ERROR_LOG_FMT( - VIDEO, - "Asset '{}' failed to parse json, material name '{}' linked to a non-string value", - asset_id, material_name); - return false; - } - - data->m_mesh_material_to_material_asset_id[material_name] = asset_id_json.to_str(); - } - } - return true; -} - -void MeshData::ToJson(picojson::object& obj, const MeshData& data) -{ - picojson::object material_mapping; - for (const auto& [material_name, asset_id] : data.m_mesh_material_to_material_asset_id) - { - material_mapping.emplace(material_name, asset_id); - } - obj.emplace("material_mapping", std::move(material_mapping)); -} - -bool MeshData::FromDolphinMesh(std::span raw_data, MeshData* data) -{ - std::size_t offset = 0; - - std::size_t chunk_size = 0; - std::memcpy(&chunk_size, raw_data.data(), sizeof(std::size_t)); - offset += sizeof(std::size_t); - - data->m_mesh_chunks.reserve(chunk_size); - for (std::size_t i = 0; i < chunk_size; i++) - { - MeshDataChunk chunk; - - std::memcpy(&chunk.num_vertices, raw_data.data() + offset, sizeof(u32)); - offset += sizeof(u32); - - std::memcpy(&chunk.vertex_stride, raw_data.data() + offset, sizeof(u32)); - offset += sizeof(u32); - - // TODO C++23: use make_unique_overwrite - chunk.vertex_data = std::unique_ptr(new u8[chunk.num_vertices * chunk.vertex_stride]); - std::memcpy(chunk.vertex_data.get(), raw_data.data() + offset, - chunk.num_vertices * chunk.vertex_stride); - offset += chunk.num_vertices * chunk.vertex_stride; - - std::memcpy(&chunk.num_indices, raw_data.data() + offset, sizeof(u32)); - offset += sizeof(u32); - - // TODO C++23: use make_unique_overwrite - chunk.indices = std::unique_ptr(new u16[chunk.num_indices]); - std::memcpy(chunk.indices.get(), raw_data.data() + offset, chunk.num_indices * sizeof(u16)); - offset += chunk.num_indices * sizeof(u16); - - std::memcpy(&chunk.vertex_declaration, raw_data.data() + offset, - sizeof(PortableVertexDeclaration)); - offset += sizeof(PortableVertexDeclaration); - - std::memcpy(&chunk.primitive_type, raw_data.data() + offset, sizeof(PrimitiveType)); - offset += sizeof(PrimitiveType); - - std::memcpy(&chunk.components_available, raw_data.data() + offset, sizeof(u32)); - offset += sizeof(u32); - - std::memcpy(&chunk.minimum_position, raw_data.data() + offset, sizeof(Common::Vec3)); - offset += sizeof(Common::Vec3); - - std::memcpy(&chunk.maximum_position, raw_data.data() + offset, sizeof(Common::Vec3)); - offset += sizeof(Common::Vec3); - - std::memcpy(&chunk.transform.data[0], raw_data.data() + offset, - chunk.transform.data.size() * sizeof(float)); - offset += chunk.transform.data.size() * sizeof(float); - - std::size_t material_name_size = 0; - std::memcpy(&material_name_size, raw_data.data() + offset, sizeof(std::size_t)); - offset += sizeof(std::size_t); - - chunk.material_name.assign(raw_data.data() + offset, - raw_data.data() + offset + material_name_size); - offset += material_name_size * sizeof(char); - - data->m_mesh_chunks.push_back(std::move(chunk)); - } - - return true; -} - -bool MeshData::ToDolphinMesh(File::IOFile* file_data, const MeshData& data) -{ - const std::size_t chunk_size = data.m_mesh_chunks.size(); - file_data->WriteBytes(&chunk_size, sizeof(std::size_t)); - for (const auto& chunk : data.m_mesh_chunks) - { - if (!file_data->WriteBytes(&chunk.num_vertices, sizeof(u32))) - return false; - if (!file_data->WriteBytes(&chunk.vertex_stride, sizeof(u32))) - return false; - if (!file_data->WriteBytes(chunk.vertex_data.get(), chunk.num_vertices * chunk.vertex_stride)) - return false; - if (!file_data->WriteBytes(&chunk.num_indices, sizeof(u32))) - return false; - if (!file_data->WriteBytes(chunk.indices.get(), chunk.num_indices * sizeof(u16))) - return false; - if (!file_data->WriteBytes(&chunk.vertex_declaration, sizeof(PortableVertexDeclaration))) - return false; - if (!file_data->WriteBytes(&chunk.primitive_type, sizeof(PrimitiveType))) - return false; - if (!file_data->WriteBytes(&chunk.components_available, sizeof(u32))) - return false; - if (!file_data->WriteBytes(&chunk.minimum_position, sizeof(Common::Vec3))) - return false; - if (!file_data->WriteBytes(&chunk.maximum_position, sizeof(Common::Vec3))) - return false; - if (!file_data->WriteBytes(&chunk.transform.data[0], - chunk.transform.data.size() * sizeof(float))) - { - return false; - } - - const std::size_t material_name_size = chunk.material_name.size(); - if (!file_data->WriteBytes(&material_name_size, sizeof(std::size_t))) - return false; - if (!file_data->WriteBytes(&chunk.material_name[0], chunk.material_name.size() * sizeof(char))) - return false; - } - return true; -} - -bool MeshData::FromGLTF(std::string_view gltf_file, MeshData* data) -{ - if (gltf_file.ends_with(".glb")) - { - ERROR_LOG_FMT(VIDEO, "File '{}' with glb extension is not supported at this time", gltf_file); - return false; - } - - if (gltf_file.ends_with(".gltf")) - { - tinygltf::Model model; - tinygltf::TinyGLTF loader; - std::string model_errors; - std::string model_warnings; - if (!loader.LoadASCIIFromFile(&model, &model_errors, &model_warnings, std::string{gltf_file})) - { - ERROR_LOG_FMT(VIDEO, "File '{}' was invalid GLTF, error: {}, warning: {}", gltf_file, - model_errors, model_warnings); - return false; - } - return ReadGLTF(gltf_file, model, data); - } - - ERROR_LOG_FMT(VIDEO, "GLTF '{}' has invalid extension", gltf_file); - return false; -} - -CustomAssetLibrary::LoadInfo MeshAsset::LoadImpl(const CustomAssetLibrary::AssetID& asset_id) -{ - auto potential_data = std::make_shared(); - const auto loaded_info = m_owning_library->LoadMesh(asset_id, potential_data.get()); - if (loaded_info.bytes_loaded == 0) - return {}; - { - std::lock_guard lk(m_data_lock); - m_loaded = true; - m_data = std::move(potential_data); - } - return loaded_info; -} -} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Assets/MeshAsset.h b/Source/Core/VideoCommon/Assets/MeshAsset.h deleted file mode 100644 index a678b14cee..0000000000 --- a/Source/Core/VideoCommon/Assets/MeshAsset.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2023 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include -#include -#include -#include - -#include - -#include "Common/CommonTypes.h" -#include "Common/Matrix.h" - -#include "VideoCommon/Assets/CustomAsset.h" -#include "VideoCommon/NativeVertexFormat.h" -#include "VideoCommon/RenderState.h" - -namespace File -{ -class IOFile; -} - -namespace VideoCommon -{ -struct MeshDataChunk -{ - std::unique_ptr vertex_data; - u32 vertex_stride; - u32 num_vertices; - std::unique_ptr indices; - u32 num_indices; - PortableVertexDeclaration vertex_declaration; - PrimitiveType primitive_type; - u32 components_available; - Common::Vec3 minimum_position; - Common::Vec3 maximum_position; - Common::Matrix44 transform; - std::string material_name; -}; - -struct MeshData -{ - static bool FromJson(const CustomAssetLibrary::AssetID& asset_id, const picojson::object& json, - MeshData* data); - static void ToJson(picojson::object& obj, const MeshData& data); - - static bool FromDolphinMesh(std::span raw_data, MeshData* data); - - static bool ToDolphinMesh(File::IOFile* file_data, const MeshData& data); - - static bool FromGLTF(std::string_view gltf_file, MeshData* data); - - std::vector m_mesh_chunks; - std::map> - m_mesh_material_to_material_asset_id; -}; - -class MeshAsset final : public CustomLoadableAsset -{ -public: - using CustomLoadableAsset::CustomLoadableAsset; - -private: - CustomAssetLibrary::LoadInfo LoadImpl(const CustomAssetLibrary::AssetID& asset_id) override; -}; -} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Assets/ShaderAsset.cpp b/Source/Core/VideoCommon/Assets/ShaderAsset.cpp deleted file mode 100644 index d6ec53db6d..0000000000 --- a/Source/Core/VideoCommon/Assets/ShaderAsset.cpp +++ /dev/null @@ -1,509 +0,0 @@ -// Copyright 2023 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "VideoCommon/Assets/ShaderAsset.h" - -#include -#include - -#include "Common/JsonUtil.h" -#include "Common/Logging/Log.h" -#include "Common/StringUtil.h" -#include "Common/VariantUtil.h" -#include "VideoCommon/Assets/CustomAssetLibrary.h" -#include "VideoCommon/ShaderGenCommon.h" - -namespace VideoCommon -{ -template -bool ParseNumeric(const CustomAssetLibrary::AssetID& asset_id, const picojson::value& json_value, - std::string_view code_name, PropertyType* value) -{ - static_assert(ElementCount <= 4, "Numeric data expected to be four elements or less"); - if constexpr (ElementCount == 1) - { - if (!json_value.is()) - { - ERROR_LOG_FMT(VIDEO, - "Asset id '{}' shader has attribute '{}' where " - "a double was expected but not provided.", - asset_id, code_name); - return false; - } - - *value = static_cast(json_value.get()); - } - else - { - if (!json_value.is()) - { - ERROR_LOG_FMT(VIDEO, - "Asset id '{}' shader has attribute '{}' where " - "an array was expected but not provided.", - asset_id, code_name); - return false; - } - - const auto json_data = json_value.get(); - - if (json_data.size() != ElementCount) - { - ERROR_LOG_FMT(VIDEO, - "Asset id '{}' shader has attribute '{}' with incorrect number " - "of elements, expected {}", - asset_id, code_name, ElementCount); - return false; - } - - if (!std::ranges::all_of(json_data, &picojson::value::is)) - { - ERROR_LOG_FMT(VIDEO, - "Asset id '{}' shader has attribute '{}' where " - "all elements are not of type double.", - asset_id, code_name); - return false; - } - - std::array data; - for (std::size_t i = 0; i < ElementCount; i++) - { - data[i] = static_cast(json_data[i].get()); - } - *value = std::move(data); - } - - return true; -} - -static bool ParseShaderValue(const CustomAssetLibrary::AssetID& asset_id, - const picojson::value& json_value, std::string_view code_name, - std::string_view type, ShaderProperty::Value* value) -{ - if (type == "int") - { - return ParseNumeric(asset_id, json_value, code_name, value); - } - else if (type == "int2") - { - return ParseNumeric(asset_id, json_value, code_name, value); - } - else if (type == "int3") - { - return ParseNumeric(asset_id, json_value, code_name, value); - } - else if (type == "int4") - { - return ParseNumeric(asset_id, json_value, code_name, value); - } - else if (type == "float") - { - return ParseNumeric(asset_id, json_value, code_name, value); - } - else if (type == "float2") - { - return ParseNumeric(asset_id, json_value, code_name, value); - } - else if (type == "float3") - { - return ParseNumeric(asset_id, json_value, code_name, value); - } - else if (type == "float4") - { - return ParseNumeric(asset_id, json_value, code_name, value); - } - else if (type == "rgb") - { - ShaderProperty::RGB rgb; - if (!ParseNumeric(asset_id, json_value, code_name, &rgb.value)) - return false; - *value = rgb; - return true; - } - else if (type == "rgba") - { - ShaderProperty::RGBA rgba; - if (!ParseNumeric(asset_id, json_value, code_name, &rgba.value)) - return false; - *value = rgba; - return true; - } - else if (type == "bool") - { - if (json_value.is()) - { - *value = json_value.get(); - return true; - } - } - - ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse the json, value is not valid for type '{}'", - asset_id, type); - return false; -} - -static bool ParseShaderProperties(const VideoCommon::CustomAssetLibrary::AssetID& asset_id, - const picojson::array& properties_data, - std::vector* shader_properties) -{ - if (!shader_properties) [[unlikely]] - return false; - - for (const auto& property_data : properties_data) - { - VideoCommon::ShaderProperty property; - if (!property_data.is()) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, property is not the right json type", - asset_id); - return false; - } - const auto& property_data_obj = property_data.get(); - - const auto type_iter = property_data_obj.find("type"); - if (type_iter == property_data_obj.end()) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, property entry 'type' not found", - asset_id); - return false; - } - if (!type_iter->second.is()) - { - ERROR_LOG_FMT(VIDEO, - "Asset '{}' failed to parse json, property entry 'type' is not " - "the right json type", - asset_id); - return false; - } - std::string type = type_iter->second.to_str(); - Common::ToLower(&type); - - const auto description_iter = property_data_obj.find("description"); - if (description_iter == property_data_obj.end()) - { - ERROR_LOG_FMT(VIDEO, - "Asset '{}' failed to parse json, property entry 'description' not found", - asset_id); - return false; - } - if (!description_iter->second.is()) - { - ERROR_LOG_FMT(VIDEO, - "Asset '{}' failed to parse json, property entry 'description' is not " - "the right json type", - asset_id); - return false; - } - property.description = description_iter->second.to_str(); - - const auto code_name_iter = property_data_obj.find("code_name"); - if (code_name_iter == property_data_obj.end()) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, property entry 'code_name' not found", - asset_id); - return false; - } - if (!code_name_iter->second.is()) - { - ERROR_LOG_FMT(VIDEO, - "Asset '{}' failed to parse json, property entry 'code_name' is not " - "the right json type", - asset_id); - return false; - } - property.name = code_name_iter->second.to_str(); - - const auto default_iter = property_data_obj.find("default"); - if (default_iter != property_data_obj.end()) - { - if (!ParseShaderValue(asset_id, default_iter->second, property.name, type, - &property.default_value)) - { - return false; - } - } - else - { - property.default_value = ShaderProperty::GetDefaultValueFromTypeName(type); - } - - shader_properties->push_back(std::move(property)); - } - - return true; -} - -bool RasterSurfaceShaderData::FromJson(const VideoCommon::CustomAssetLibrary::AssetID& asset_id, - const picojson::object& json, RasterSurfaceShaderData* data) -{ - const auto parse_properties = [&](const char* name, std::string_view source, - std::vector* shader_properties) -> bool { - const auto properties_iter = json.find(name); - if (properties_iter == json.end()) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, '{}' not found", asset_id, name); - return false; - } - if (!properties_iter->second.is()) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, '{}' is not the right json type", - asset_id, name); - return false; - } - const auto& properties_array = properties_iter->second.get(); - - return ParseShaderProperties(asset_id, properties_array, shader_properties); - }; - - const auto parse_samplers = - [&](const char* name, - std::vector* samplers_out) -> bool { - const auto samplers_iter = json.find(name); - if (samplers_iter == json.end()) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, '{}' not found", asset_id, name); - return false; - } - if (!samplers_iter->second.is()) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, '{}' is not the right json type", - asset_id, name); - return false; - } - const auto& samplers_array = samplers_iter->second.get(); - if (!std::ranges::all_of(samplers_array, [](const picojson::value& json_data) { - return json_data.is(); - })) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, '{}' must contain objects", asset_id, - name); - return false; - } - - for (const auto& sampler_json : samplers_array) - { - auto& sampler_json_obj = sampler_json.get(); - - SamplerData sampler; - - if (const auto sampler_name = ReadStringFromJson(sampler_json_obj, "name")) - { - sampler.name = *sampler_name; - } - else - { - ERROR_LOG_FMT(VIDEO, - "Asset '{}' failed to parse sampler json, 'name' not found or wrong type", - asset_id); - return false; - } - - if (const auto sampler_type = - ReadNumericFromJson(sampler_json_obj, "type")) - { - sampler.type = *sampler_type; - } - else - { - ERROR_LOG_FMT(VIDEO, - "Asset '{}' failed to parse sampler json, 'type' not found or wrong type", - asset_id); - return false; - } - samplers_out->push_back(std::move(sampler)); - } - - return true; - }; - - if (!parse_properties("properties", data->pixel_source, &data->uniform_properties)) - return false; - - if (!parse_samplers("samplers", &data->samplers)) - return false; - - return true; -} - -void RasterSurfaceShaderData::ToJson(picojson::object& obj, const RasterSurfaceShaderData& data) -{ - const auto add_property = [](picojson::array* json_properties, const ShaderProperty& property) { - picojson::object json_property; - - json_property.emplace("code_name", property.name); - json_property.emplace("description", property.description); - - std::visit(overloaded{[&](s32 default_value) { - json_property.emplace("type", "int"); - json_property.emplace("default", static_cast(default_value)); - }, - [&](const std::array& default_value) { - json_property.emplace("type", "int2"); - json_property.emplace("default", ToJsonArray(default_value)); - }, - [&](const std::array& default_value) { - json_property.emplace("type", "int3"); - json_property.emplace("default", ToJsonArray(default_value)); - }, - [&](const std::array& default_value) { - json_property.emplace("type", "int4"); - json_property.emplace("default", ToJsonArray(default_value)); - }, - [&](float default_value) { - json_property.emplace("type", "float"); - json_property.emplace("default", static_cast(default_value)); - }, - [&](const std::array& default_value) { - json_property.emplace("type", "float2"); - json_property.emplace("default", ToJsonArray(default_value)); - }, - [&](const std::array& default_value) { - json_property.emplace("type", "float3"); - json_property.emplace("default", ToJsonArray(default_value)); - }, - [&](const std::array& default_value) { - json_property.emplace("type", "float4"); - json_property.emplace("default", ToJsonArray(default_value)); - }, - [&](const ShaderProperty::RGB& default_value) { - json_property.emplace("type", "rgb"); - json_property.emplace("default", ToJsonArray(default_value.value)); - }, - [&](const ShaderProperty::RGBA& default_value) { - json_property.emplace("type", "rgba"); - json_property.emplace("default", ToJsonArray(default_value.value)); - }, - [&](bool default_value) { - json_property.emplace("type", "bool"); - json_property.emplace("default", default_value); - }}, - property.default_value); - - json_properties->emplace_back(std::move(json_property)); - }; - - const auto add_sampler = [](picojson::array* json_samplers, const SamplerData& sampler) { - picojson::object json_sampler; - json_sampler.emplace("name", sampler.name); - json_sampler.emplace("type", static_cast(sampler.type)); - json_samplers->emplace_back(std::move(json_sampler)); - }; - - picojson::array json_properties; - for (const auto& property : data.uniform_properties) - { - add_property(&json_properties, property); - } - obj.emplace("properties", std::move(json_properties)); - - picojson::array json_samplers; - for (const auto& sampler : data.samplers) - { - add_sampler(&json_samplers, sampler); - } - obj.emplace("samplers", json_samplers); -} - -std::span ShaderProperty::GetValueTypeNames() -{ - static constexpr std::array values = { - "int", "int2", "int3", "int4", "float", "float2", "float3", "float4", "rgb", "rgba", "bool"}; - return values; -} - -ShaderProperty::Value ShaderProperty::GetDefaultValueFromTypeName(std::string_view name) -{ - if (name == "int") - { - return 0; - } - else if (name == "int2") - { - return std::array{}; - } - else if (name == "int3") - { - return std::array{}; - } - else if (name == "int4") - { - return std::array{}; - } - else if (name == "float") - { - return 0.0f; - } - else if (name == "float2") - { - return std::array{}; - } - else if (name == "float3") - { - return std::array{}; - } - else if (name == "float4") - { - return std::array{}; - } - else if (name == "rgb") - { - return RGB{}; - } - else if (name == "rgba") - { - return RGBA{}; - } - else if (name == "bool") - { - return false; - } - - return Value{}; -} - -void ShaderProperty::WriteAsShaderCode(ShaderCode& shader_source, const ShaderProperty& property) -{ - const auto write_shader = [&](std::string_view type, u32 element_count) { - if (element_count == 1) - { - shader_source.Write("{} {};\n", type, property.name); - } - else - { - shader_source.Write("{}{} {};\n", type, element_count, property.name); - } - - for (std::size_t i = element_count; i < 4; i++) - { - shader_source.Write("{} {}_padding_{};\n", type, property.name, i + 1); - } - }; - std::visit(overloaded{[&](s32) { write_shader("int", 1); }, - [&](const std::array&) { write_shader("int", 2); }, - [&](const std::array&) { write_shader("int", 3); }, - [&](const std::array&) { write_shader("int", 4); }, - [&](float) { write_shader("float", 1); }, - [&](const std::array&) { write_shader("float", 2); }, - [&](const std::array&) { write_shader("float", 3); }, - [&](const std::array&) { write_shader("float", 4); }, - [&](const ShaderProperty::RGB&) { write_shader("float", 3); }, - [&](const ShaderProperty::RGBA&) { write_shader("float", 4); }, - [&](bool) { write_shader("bool", 1); }}, - property.default_value); -} - -CustomAssetLibrary::LoadInfo -RasterSurfaceShaderAsset::LoadImpl(const CustomAssetLibrary::AssetID& asset_id) -{ - auto potential_data = std::make_shared(); - const auto loaded_info = - m_owning_library->LoadRasterSurfaceShader(asset_id, potential_data.get()); - if (loaded_info.bytes_loaded == 0) - return {}; - { - std::lock_guard lk(m_data_lock); - m_loaded = true; - m_data = std::move(potential_data); - } - return loaded_info; -} -} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Assets/ShaderAsset.h b/Source/Core/VideoCommon/Assets/ShaderAsset.h deleted file mode 100644 index 3a785ad310..0000000000 --- a/Source/Core/VideoCommon/Assets/ShaderAsset.h +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2023 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "VideoCommon/Assets/CustomAsset.h" -#include "VideoCommon/ShaderCompileUtils.h" -#include "VideoCommon/TextureConfig.h" - -class ShaderCode; - -namespace VideoCommon -{ -struct ShaderProperty -{ - struct RGB - { - std::array value; - }; - - struct RGBA - { - std::array value; - }; - - using Value = std::variant, std::array, std::array, float, - std::array, std::array, std::array, bool, - RGB, RGBA>; - static std::span GetValueTypeNames(); - static Value GetDefaultValueFromTypeName(std::string_view name); - static void WriteAsShaderCode(ShaderCode& shader_source, const ShaderProperty& property); - - Value default_value; - std::string name; - std::string description; -}; - -struct RasterSurfaceShaderData -{ - RasterSurfaceShaderData() = default; - RasterSurfaceShaderData(const RasterSurfaceShaderData&) = delete; - RasterSurfaceShaderData(RasterSurfaceShaderData&&) = default; - ~RasterSurfaceShaderData() = default; - RasterSurfaceShaderData& operator=(const RasterSurfaceShaderData&) = delete; - RasterSurfaceShaderData& operator=(RasterSurfaceShaderData&&) = default; - - static bool FromJson(const CustomAssetLibrary::AssetID& asset_id, const picojson::object& json, - RasterSurfaceShaderData* data); - static void ToJson(picojson::object& obj, const RasterSurfaceShaderData& data); - - // These shader properties describe the input that the - // shader expects to expose. The key is text - // expected to be in the shader code and the property - // describes various details about the input - std::vector uniform_properties; - std::string vertex_source; - std::string pixel_source; - - struct SamplerData - { - AbstractTextureType type; - std::string name; - - bool operator==(const SamplerData&) const = default; - }; - std::vector samplers; - - std::unique_ptr shader_includer; -}; - -class RasterSurfaceShaderAsset final : public CustomLoadableAsset -{ -public: - using CustomLoadableAsset::CustomLoadableAsset; - -private: - CustomAssetLibrary::LoadInfo LoadImpl(const CustomAssetLibrary::AssetID& asset_id) override; -}; -} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Assets/TextureAsset.cpp b/Source/Core/VideoCommon/Assets/TextureAsset.cpp index 7c76426619..9c2d8bdb13 100644 --- a/Source/Core/VideoCommon/Assets/TextureAsset.cpp +++ b/Source/Core/VideoCommon/Assets/TextureAsset.cpp @@ -3,262 +3,10 @@ #include "VideoCommon/Assets/TextureAsset.h" -#include - -#include "Common/JsonUtil.h" #include "Common/Logging/Log.h" -#include "Common/StringUtil.h" -#include "VideoCommon/BPMemory.h" namespace VideoCommon { -namespace -{ -std::optional ReadWrapModeFromJSON(const picojson::object& json, const std::string& uv) -{ - auto uv_mode = ReadStringFromJson(json, uv).value_or(""); - Common::ToLower(&uv_mode); - - if (uv_mode == "clamp") - { - return WrapMode::Clamp; - } - else if (uv_mode == "repeat") - { - return WrapMode::Repeat; - } - else if (uv_mode == "mirror") - { - return WrapMode::Mirror; - } - - return std::nullopt; -} - -std::optional ReadFilterModeFromJSON(const picojson::object& json, - const std::string& filter) -{ - auto filter_mode = ReadStringFromJson(json, filter).value_or(""); - Common::ToLower(&filter_mode); - - if (filter_mode == "linear") - { - return FilterMode::Linear; - } - else if (filter_mode == "near") - { - return FilterMode::Near; - } - - return std::nullopt; -} - -bool ParseSampler(const VideoCommon::CustomAssetLibrary::AssetID& asset_id, - const picojson::object& json, SamplerState* sampler) -{ - if (!sampler) [[unlikely]] - return false; - - *sampler = RenderState::GetLinearSamplerState(); - - const auto sampler_state_wrap_iter = json.find("wrap_mode"); - if (sampler_state_wrap_iter != json.end()) - { - if (!sampler_state_wrap_iter->second.is()) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, 'wrap_mode' is not the right type", - asset_id); - return false; - } - const auto sampler_state_wrap_obj = sampler_state_wrap_iter->second.get(); - - if (const auto mode = ReadWrapModeFromJSON(sampler_state_wrap_obj, "u")) - { - sampler->tm0.wrap_u = *mode; - } - else - { - ERROR_LOG_FMT(VIDEO, - "Asset '{}' failed to parse json, 'wrap_mode[u]' has an invalid " - "value", - asset_id); - return false; - } - - if (const auto mode = ReadWrapModeFromJSON(sampler_state_wrap_obj, "v")) - { - sampler->tm0.wrap_v = *mode; - } - else - { - ERROR_LOG_FMT(VIDEO, - "Asset '{}' failed to parse json, 'wrap_mode[v]' has an invalid " - "value", - asset_id); - return false; - } - } - - const auto sampler_state_filter_iter = json.find("filter_mode"); - if (sampler_state_filter_iter != json.end()) - { - if (!sampler_state_filter_iter->second.is()) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, 'filter_mode' is not the right type", - asset_id); - return false; - } - const auto sampler_state_filter_obj = sampler_state_filter_iter->second.get(); - - if (const auto mode = ReadFilterModeFromJSON(sampler_state_filter_obj, "min")) - { - sampler->tm0.min_filter = *mode; - } - else - { - ERROR_LOG_FMT(VIDEO, - "Asset '{}' failed to parse json, 'filter_mode[min]' has an invalid " - "value", - asset_id); - return false; - } - - if (const auto mode = ReadFilterModeFromJSON(sampler_state_filter_obj, "mag")) - { - sampler->tm0.mag_filter = *mode; - } - else - { - ERROR_LOG_FMT(VIDEO, - "Asset '{}' failed to parse json, 'filter_mode[mag]' has an invalid " - "value", - asset_id); - return false; - } - - if (const auto mode = ReadFilterModeFromJSON(sampler_state_filter_obj, "mipmap")) - { - sampler->tm0.mipmap_filter = *mode; - } - else - { - ERROR_LOG_FMT(VIDEO, - "Asset '{}' failed to parse json, 'filter_mode[mipmap]' has an invalid " - "value", - asset_id); - return false; - } - } - - return true; -} -} // namespace -bool TextureAndSamplerData::FromJson(const CustomAssetLibrary::AssetID& asset_id, - const picojson::object& json, TextureAndSamplerData* data) -{ - const auto type_iter = json.find("type"); - if (type_iter == json.end()) - { - ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, property entry 'type' not found", - asset_id); - return false; - } - if (!type_iter->second.is()) - { - ERROR_LOG_FMT(VIDEO, - "Asset '{}' failed to parse json, property entry 'type' is not " - "the right json type", - asset_id); - return false; - } - std::string type = type_iter->second.to_str(); - Common::ToLower(&type); - - if (type == "texture2d") - { - data->type = AbstractTextureType::Texture_2D; - - if (!ParseSampler(asset_id, json, &data->sampler)) - { - return false; - } - } - else if (type == "texturecube") - { - data->type = AbstractTextureType::Texture_CubeMap; - } - else if (type == "texture2darray") - { - data->type = AbstractTextureType::Texture_2DArray; - } - else - { - ERROR_LOG_FMT(VIDEO, - "Asset '{}' failed to parse json, texture type '{}' " - "an invalid option", - asset_id, type); - return false; - } - - return true; -} - -void TextureAndSamplerData::ToJson(picojson::object* obj, const TextureAndSamplerData& data) -{ - if (!obj) [[unlikely]] - return; - - auto& json_obj = *obj; - switch (data.type) - { - case AbstractTextureType::Texture_2D: - json_obj.emplace("type", "texture2d"); - break; - case AbstractTextureType::Texture_CubeMap: - json_obj.emplace("type", "texturecube"); - break; - case AbstractTextureType::Texture_2DArray: - json_obj.emplace("type", "texture2darray"); - break; - }; - - auto wrap_mode_to_string = [](WrapMode mode) { - switch (mode) - { - case WrapMode::Clamp: - return "clamp"; - case WrapMode::Mirror: - return "mirror"; - case WrapMode::Repeat: - return "repeat"; - }; - - return ""; - }; - auto filter_mode_to_string = [](FilterMode mode) { - switch (mode) - { - case FilterMode::Linear: - return "linear"; - case FilterMode::Near: - return "near"; - }; - - return ""; - }; - - picojson::object wrap_mode; - wrap_mode.emplace("u", wrap_mode_to_string(data.sampler.tm0.wrap_u)); - wrap_mode.emplace("v", wrap_mode_to_string(data.sampler.tm0.wrap_v)); - json_obj.emplace("wrap_mode", wrap_mode); - - picojson::object filter_mode; - filter_mode.emplace("min", filter_mode_to_string(data.sampler.tm0.min_filter)); - filter_mode.emplace("mag", filter_mode_to_string(data.sampler.tm0.mag_filter)); - filter_mode.emplace("mipmap", filter_mode_to_string(data.sampler.tm0.mipmap_filter)); - json_obj.emplace("filter_mode", filter_mode); -} - CustomAssetLibrary::LoadInfo TextureAsset::LoadImpl(const CustomAssetLibrary::AssetID& asset_id) { auto potential_data = std::make_shared(); @@ -272,19 +20,4 @@ CustomAssetLibrary::LoadInfo TextureAsset::LoadImpl(const CustomAssetLibrary::As } return loaded_info; } - -CustomAssetLibrary::LoadInfo -TextureAndSamplerAsset::LoadImpl(const CustomAssetLibrary::AssetID& asset_id) -{ - auto potential_data = std::make_shared(); - const auto loaded_info = m_owning_library->LoadTexture(asset_id, potential_data.get()); - if (loaded_info.bytes_loaded == 0) - return {}; - { - std::lock_guard lk(m_data_lock); - m_loaded = true; - m_data = std::move(potential_data); - } - return loaded_info; -} } // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Assets/TextureAsset.h b/Source/Core/VideoCommon/Assets/TextureAsset.h index a3c1fa104a..7b6cb2c552 100644 --- a/Source/Core/VideoCommon/Assets/TextureAsset.h +++ b/Source/Core/VideoCommon/Assets/TextureAsset.h @@ -3,40 +3,16 @@ #pragma once -#include -#include - -#include "Common/EnumFormatter.h" #include "VideoCommon/Assets/CustomAsset.h" #include "VideoCommon/Assets/CustomTextureData.h" -#include "VideoCommon/RenderState.h" namespace VideoCommon { -struct TextureAndSamplerData -{ - static bool FromJson(const CustomAssetLibrary::AssetID& asset_id, const picojson::object& json, - TextureAndSamplerData* data); - static void ToJson(picojson::object* obj, const TextureAndSamplerData& data); - AbstractTextureType type; - CustomTextureData texture_data; - SamplerState sampler; -}; - class TextureAsset final : public CustomLoadableAsset { public: using CustomLoadableAsset::CustomLoadableAsset; -private: - CustomAssetLibrary::LoadInfo LoadImpl(const CustomAssetLibrary::AssetID& asset_id) override; -}; - -class TextureAndSamplerAsset final : public CustomLoadableAsset -{ -public: - using CustomLoadableAsset::CustomLoadableAsset; - private: CustomAssetLibrary::LoadInfo LoadImpl(const CustomAssetLibrary::AssetID& asset_id) override; }; diff --git a/Source/Core/VideoCommon/Assets/TextureSamplerValue.cpp b/Source/Core/VideoCommon/Assets/TextureSamplerValue.cpp deleted file mode 100644 index 19fd4181a3..0000000000 --- a/Source/Core/VideoCommon/Assets/TextureSamplerValue.cpp +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2024 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "VideoCommon/Assets/TextureSamplerValue.h" - -#include - -#include "Common/JsonUtil.h" -#include "Common/StringUtil.h" - -namespace VideoCommon -{ -namespace -{ -std::optional -ReadSamplerOriginFromJSON(const picojson::object& json) -{ - auto sampler_origin = ReadStringFromJson(json, "sampler_origin").value_or(""); - Common::ToLower(&sampler_origin); - - if (sampler_origin == "asset") - { - return TextureSamplerValue::SamplerOrigin::Asset; - } - else if (sampler_origin == "texture_hash") - { - return TextureSamplerValue::SamplerOrigin::TextureHash; - } - - return std::nullopt; -} -} // namespace -std::string TextureSamplerValue::ToString(SamplerOrigin sampler_origin) -{ - if (sampler_origin == SamplerOrigin::Asset) - return "asset"; - - return "texture_hash"; -} - -bool TextureSamplerValue::FromJson(const picojson::object& json, TextureSamplerValue* data) -{ - data->asset = ReadStringFromJson(json, "asset").value_or(""); - data->texture_hash = ReadStringFromJson(json, "texture_hash").value_or(""); - data->sampler_origin = - ReadSamplerOriginFromJSON(json).value_or(TextureSamplerValue::SamplerOrigin::Asset); - - return true; -} - -void TextureSamplerValue::ToJson(picojson::object* obj, const TextureSamplerValue& data) -{ - if (!obj) [[unlikely]] - return; - - obj->emplace("asset", data.asset); - obj->emplace("texture_hash", data.texture_hash); - obj->emplace("sampler_origin", ToString(data.sampler_origin)); -} -} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Assets/TextureSamplerValue.h b/Source/Core/VideoCommon/Assets/TextureSamplerValue.h deleted file mode 100644 index 9b21b6bf8d..0000000000 --- a/Source/Core/VideoCommon/Assets/TextureSamplerValue.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2024 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include - -#include - -#include "VideoCommon/Assets/CustomAssetLibrary.h" - -namespace VideoCommon -{ -// A structure that provides metadata about a texture to a material -struct TextureSamplerValue -{ - CustomAssetLibrary::AssetID asset; - - // Where does the sampler originate from - // If 'Asset' is used, the sampler is pulled - // directly from the asset properties - // If 'TextureHash' is chosen, the sampler is pulled - // from the game with the corresponding texture hash - enum class SamplerOrigin - { - Asset, - TextureHash - }; - static std::string ToString(SamplerOrigin sampler_origin); - SamplerOrigin sampler_origin = SamplerOrigin::Asset; - std::string texture_hash; - - static bool FromJson(const picojson::object& json, TextureSamplerValue* data); - static void ToJson(picojson::object* obj, const TextureSamplerValue& data); -}; -} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.cpp b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.cpp deleted file mode 100644 index 35c8ce0a25..0000000000 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.cpp +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2022 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.h" - -#include "Common/JsonUtil.h" -#include "Common/Logging/Log.h" -#include "Core/System.h" - -#include "VideoCommon/Resources/CustomResourceManager.h" - -std::unique_ptr -CustomPipelineAction::Create(std::shared_ptr library) -{ - return std::make_unique(std::move(library)); -} - -std::unique_ptr -CustomPipelineAction::Create(const picojson::value& json_data, - std::shared_ptr library) -{ - auto material_asset = ReadStringFromJson(json_data.get(), "material_asset"); - - if (!material_asset) - { - ERROR_LOG_FMT(VIDEO, - "Failed to load custom pipeline action, 'material_asset' does not have a value"); - return nullptr; - } - - return std::make_unique(std::move(library), std::move(*material_asset)); -} - -CustomPipelineAction::CustomPipelineAction(std::shared_ptr library) - : m_library(std::move(library)) -{ -} - -CustomPipelineAction::CustomPipelineAction(std::shared_ptr library, - std::string material_asset) - : m_library(std::move(library)), m_material_asset(std::move(material_asset)) -{ -} - -void CustomPipelineAction::OnDrawStarted(GraphicsModActionData::DrawStarted*) -{ - // TODO -} - -void CustomPipelineAction::AfterEFB(GraphicsModActionData::PostEFB* post_efb) -{ - if (!post_efb) [[unlikely]] - return; - - if (m_material_asset.empty()) - return; - - auto& resource_manager = Core::System::GetInstance().GetCustomResourceManager(); - post_efb->material = - resource_manager.GetPostProcessingMaterialFromAsset(m_material_asset, m_library); -} diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.h b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.h deleted file mode 100644 index d03ccd4a6e..0000000000 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2022 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include -#include - -#include - -#include "VideoCommon/Assets/CustomAssetLibrary.h" -#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModAction.h" - -class CustomPipelineAction final : public GraphicsModAction -{ -public: - static constexpr std::string_view factory_name = "custom_pipeline"; - static std::unique_ptr - Create(const picojson::value& json_data, - std::shared_ptr library); - static std::unique_ptr - Create(std::shared_ptr library); - explicit CustomPipelineAction(std::shared_ptr library); - CustomPipelineAction(std::shared_ptr library, - std::string material_asset); - void OnDrawStarted(GraphicsModActionData::DrawStarted*) override; - void AfterEFB(GraphicsModActionData::PostEFB*) override; - -private: - std::shared_ptr m_library; - std::string m_material_asset; -}; diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomPipeline.cpp b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomPipeline.cpp deleted file mode 100644 index df8e07469f..0000000000 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomPipeline.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2024 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "VideoCommon/GraphicsModSystem/Runtime/CustomPipeline.h" - -#include -#include - -#include "Common/CommonTypes.h" -#include "VideoCommon/Assets/CustomAssetLibrary.h" - -void CustomPipeline::UpdatePixelData(const VideoCommon::CustomAssetLibrary*, std::span, - const VideoCommon::CustomAssetLibrary::AssetID&) -{ -} diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomPipeline.h b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomPipeline.h deleted file mode 100644 index a05a28ea16..0000000000 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomPipeline.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2024 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include - -#include "Common/CommonTypes.h" -#include "VideoCommon/Assets/CustomAssetLibrary.h" - -struct CustomPipeline -{ - void UpdatePixelData(const VideoCommon::CustomAssetLibrary* library, - std::span texture_units, - const VideoCommon::CustomAssetLibrary::AssetID& material_to_load); -}; diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomShaderCache.cpp b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomShaderCache.cpp deleted file mode 100644 index 91d4082348..0000000000 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomShaderCache.cpp +++ /dev/null @@ -1,387 +0,0 @@ -// Copyright 2022 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "VideoCommon/GraphicsModSystem/Runtime/CustomShaderCache.h" - -#include - -#include "VideoCommon/AbstractGfx.h" -#include "VideoCommon/VideoConfig.h" -#include "VideoCommon/VideoEvents.h" - -CustomShaderCache::CustomShaderCache() -{ - m_api_type = g_backend_info.api_type; - m_host_config.bits = ShaderHostConfig::GetCurrent().bits; - - m_async_shader_compiler = g_gfx->CreateAsyncShaderCompiler(); - m_async_shader_compiler->StartWorkerThreads(1); // TODO - - m_async_uber_shader_compiler = g_gfx->CreateAsyncShaderCompiler(); - m_async_uber_shader_compiler->StartWorkerThreads(1); // TODO - - m_frame_end_handler = GetVideoEvents().after_frame_event.Register( - [this](Core::System&) { RetrieveAsyncShaders(); }); -} - -CustomShaderCache::~CustomShaderCache() -{ - if (m_async_shader_compiler) - { - m_async_shader_compiler->StopWorkerThreads(); - m_async_shader_compiler->ClearAllWork(); - } - - if (m_async_uber_shader_compiler) - { - m_async_uber_shader_compiler->StopWorkerThreads(); - m_async_uber_shader_compiler->ClearAllWork(); - } -} - -void CustomShaderCache::RetrieveAsyncShaders() -{ - m_async_shader_compiler->RetrieveWorkItems(); - m_async_uber_shader_compiler->RetrieveWorkItems(); -} - -void CustomShaderCache::Reload() -{ - while (m_async_shader_compiler->HasPendingWork() || m_async_shader_compiler->HasCompletedWork()) - { - m_async_shader_compiler->RetrieveWorkItems(); - } - - while (m_async_uber_shader_compiler->HasPendingWork() || - m_async_uber_shader_compiler->HasCompletedWork()) - { - m_async_uber_shader_compiler->RetrieveWorkItems(); - } - - m_ps_cache = {}; - m_uber_ps_cache = {}; - m_pipeline_cache = {}; - m_uber_pipeline_cache = {}; -} - -std::optional -CustomShaderCache::GetPipelineAsync(const VideoCommon::GXPipelineUid& uid, - const CustomShaderInstance& custom_shaders, - const AbstractPipelineConfig& pipeline_config) -{ - if (auto holder = m_pipeline_cache.GetHolder(uid, custom_shaders)) - { - if (holder->pending) - return std::nullopt; - return holder->value.get(); - } - AsyncCreatePipeline(uid, custom_shaders, pipeline_config); - return std::nullopt; -} - -std::optional -CustomShaderCache::GetPipelineAsync(const VideoCommon::GXUberPipelineUid& uid, - const CustomShaderInstance& custom_shaders, - const AbstractPipelineConfig& pipeline_config) -{ - if (auto holder = m_uber_pipeline_cache.GetHolder(uid, custom_shaders)) - { - if (holder->pending) - return std::nullopt; - return holder->value.get(); - } - AsyncCreatePipeline(uid, custom_shaders, pipeline_config); - return std::nullopt; -} - -void CustomShaderCache::AsyncCreatePipeline(const VideoCommon::GXPipelineUid& uid, - - const CustomShaderInstance& custom_shaders, - const AbstractPipelineConfig& pipeline_config) -{ - class PipelineWorkItem final : public VideoCommon::AsyncShaderCompiler::WorkItem - { - public: - PipelineWorkItem(CustomShaderCache* shader_cache, VideoCommon::GXPipelineUid uid, - CustomShaderInstance custom_shaders, PipelineIterator iterator, - AbstractPipelineConfig pipeline_config) - : m_shader_cache(shader_cache), m_uid(std::move(uid)), m_iterator(iterator), - m_config(std::move(pipeline_config)), m_custom_shaders(std::move(custom_shaders)) - { - SetStagesReady(); - } - - void SetStagesReady() - { - m_stages_ready = true; - - PixelShaderUid ps_uid = m_uid.ps_uid; - ClearUnusedPixelShaderUidBits(m_shader_cache->m_api_type, m_shader_cache->m_host_config, - &ps_uid); - - if (auto holder = m_shader_cache->m_ps_cache.GetHolder(ps_uid, m_custom_shaders)) - { - // If the pixel shader is no longer pending compilation - // and the shader compilation succeeded, set - // the pipeline to use the new pixel shader. - // Otherwise, use the existing shader. - if (!holder->pending && holder->value.get()) - { - m_config.pixel_shader = holder->value.get(); - } - m_stages_ready &= !holder->pending; - } - else - { - m_stages_ready &= false; - m_shader_cache->QueuePixelShaderCompile(ps_uid, m_custom_shaders); - } - } - - bool Compile() override - { - if (m_stages_ready) - { - m_pipeline = g_gfx->CreatePipeline(m_config); - } - return true; - } - - void Retrieve() override - { - if (m_stages_ready) - { - m_shader_cache->NotifyPipelineFinished(m_iterator, std::move(m_pipeline)); - } - else - { - // Re-queue for next frame. - auto wi = m_shader_cache->m_async_shader_compiler->CreateWorkItem( - m_shader_cache, m_uid, m_custom_shaders, m_iterator, m_config); - m_shader_cache->m_async_shader_compiler->QueueWorkItem(std::move(wi), 0); - } - } - - private: - CustomShaderCache* m_shader_cache; - std::unique_ptr m_pipeline; - VideoCommon::GXPipelineUid m_uid; - PipelineIterator m_iterator; - AbstractPipelineConfig m_config; - CustomShaderInstance m_custom_shaders; - bool m_stages_ready; - }; - - auto list_iter = m_pipeline_cache.InsertElement(uid, custom_shaders); - auto work_item = m_async_shader_compiler->CreateWorkItem( - this, uid, custom_shaders, list_iter, pipeline_config); - m_async_shader_compiler->QueueWorkItem(std::move(work_item), 0); -} - -void CustomShaderCache::AsyncCreatePipeline(const VideoCommon::GXUberPipelineUid& uid, - - const CustomShaderInstance& custom_shaders, - const AbstractPipelineConfig& pipeline_config) -{ - class PipelineWorkItem final : public VideoCommon::AsyncShaderCompiler::WorkItem - { - public: - PipelineWorkItem(CustomShaderCache* shader_cache, VideoCommon::GXUberPipelineUid uid, - CustomShaderInstance custom_shaders, UberPipelineIterator iterator, - AbstractPipelineConfig pipeline_config) - : m_shader_cache(shader_cache), m_uid(std::move(uid)), m_iterator(iterator), - m_config(std::move(pipeline_config)), m_custom_shaders(std::move(custom_shaders)) - { - SetStagesReady(); - } - - void SetStagesReady() - { - m_stages_ready = true; - - UberShader::PixelShaderUid ps_uid = m_uid.ps_uid; - ClearUnusedPixelShaderUidBits(m_shader_cache->m_api_type, m_shader_cache->m_host_config, - &ps_uid); - - if (auto holder = m_shader_cache->m_uber_ps_cache.GetHolder(ps_uid, m_custom_shaders)) - { - if (!holder->pending && holder->value.get()) - { - m_config.pixel_shader = holder->value.get(); - } - m_stages_ready &= !holder->pending; - } - else - { - m_stages_ready &= false; - m_shader_cache->QueuePixelShaderCompile(ps_uid, m_custom_shaders); - } - } - - bool Compile() override - { - if (m_stages_ready) - { - if (m_config.pixel_shader == nullptr || m_config.vertex_shader == nullptr) - return false; - - m_pipeline = g_gfx->CreatePipeline(m_config); - } - return true; - } - - void Retrieve() override - { - if (m_stages_ready) - { - m_shader_cache->NotifyPipelineFinished(m_iterator, std::move(m_pipeline)); - } - else - { - // Re-queue for next frame. - auto wi = m_shader_cache->m_async_uber_shader_compiler->CreateWorkItem( - m_shader_cache, m_uid, m_custom_shaders, m_iterator, m_config); - m_shader_cache->m_async_uber_shader_compiler->QueueWorkItem(std::move(wi), 0); - } - } - - private: - CustomShaderCache* m_shader_cache; - std::unique_ptr m_pipeline; - VideoCommon::GXUberPipelineUid m_uid; - UberPipelineIterator m_iterator; - AbstractPipelineConfig m_config; - CustomShaderInstance m_custom_shaders; - bool m_stages_ready; - }; - - auto list_iter = m_uber_pipeline_cache.InsertElement(uid, custom_shaders); - auto work_item = m_async_uber_shader_compiler->CreateWorkItem( - this, uid, custom_shaders, list_iter, pipeline_config); - m_async_uber_shader_compiler->QueueWorkItem(std::move(work_item), 0); -} - -void CustomShaderCache::NotifyPipelineFinished(PipelineIterator iterator, - std::unique_ptr pipeline) -{ - iterator->second.pending = false; - iterator->second.value = std::move(pipeline); -} - -void CustomShaderCache::NotifyPipelineFinished(UberPipelineIterator iterator, - std::unique_ptr pipeline) -{ - iterator->second.pending = false; - iterator->second.value = std::move(pipeline); -} - -void CustomShaderCache::QueuePixelShaderCompile(const PixelShaderUid& uid, - - const CustomShaderInstance& custom_shaders) -{ - class PixelShaderWorkItem final : public VideoCommon::AsyncShaderCompiler::WorkItem - { - public: - PixelShaderWorkItem(CustomShaderCache* shader_cache, const PixelShaderUid& uid, - CustomShaderInstance custom_shaders, PixelShaderIterator iter) - : m_shader_cache(shader_cache), m_uid(uid), m_custom_shaders(std::move(custom_shaders)), - m_iter(iter) - { - } - - bool Compile() override - { - m_shader = m_shader_cache->CompilePixelShader(m_uid, m_custom_shaders); - return true; - } - - void Retrieve() override - { - m_shader_cache->NotifyPixelShaderFinished(m_iter, std::move(m_shader)); - } - - private: - CustomShaderCache* m_shader_cache; - std::unique_ptr m_shader; - PixelShaderUid m_uid; - CustomShaderInstance m_custom_shaders; - PixelShaderIterator m_iter; - }; - - auto list_iter = m_ps_cache.InsertElement(uid, custom_shaders); - auto work_item = m_async_shader_compiler->CreateWorkItem( - this, uid, custom_shaders, list_iter); - m_async_shader_compiler->QueueWorkItem(std::move(work_item), 0); -} - -void CustomShaderCache::QueuePixelShaderCompile(const UberShader::PixelShaderUid& uid, - - const CustomShaderInstance& custom_shaders) -{ - class PixelShaderWorkItem final : public VideoCommon::AsyncShaderCompiler::WorkItem - { - public: - PixelShaderWorkItem(CustomShaderCache* shader_cache, const UberShader::PixelShaderUid& uid, - CustomShaderInstance custom_shaders, UberPixelShaderIterator iter) - : m_shader_cache(shader_cache), m_uid(uid), m_custom_shaders(std::move(custom_shaders)), - m_iter(iter) - { - } - - bool Compile() override - { - m_shader = m_shader_cache->CompilePixelShader(m_uid, m_custom_shaders); - return true; - } - - void Retrieve() override - { - m_shader_cache->NotifyPixelShaderFinished(m_iter, std::move(m_shader)); - } - - private: - CustomShaderCache* m_shader_cache; - std::unique_ptr m_shader; - UberShader::PixelShaderUid m_uid; - CustomShaderInstance m_custom_shaders; - UberPixelShaderIterator m_iter; - }; - - auto list_iter = m_uber_ps_cache.InsertElement(uid, custom_shaders); - auto work_item = m_async_uber_shader_compiler->CreateWorkItem( - this, uid, custom_shaders, list_iter); - m_async_uber_shader_compiler->QueueWorkItem(std::move(work_item), 0); -} - -std::unique_ptr -CustomShaderCache::CompilePixelShader(const PixelShaderUid& uid, - const CustomShaderInstance& custom_shaders) const -{ - const ShaderCode source_code = - GeneratePixelShaderCode(m_api_type, m_host_config, uid.GetUidData(), {}); - return g_gfx->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer(), nullptr, - "Custom Pixel Shader"); -} - -std::unique_ptr -CustomShaderCache::CompilePixelShader(const UberShader::PixelShaderUid& uid, - const CustomShaderInstance& custom_shaders) const -{ - const ShaderCode source_code = GenPixelShader(m_api_type, m_host_config, uid.GetUidData()); - return g_gfx->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer(), nullptr, - "Custom Uber Pixel Shader"); -} - -void CustomShaderCache::NotifyPixelShaderFinished(PixelShaderIterator iterator, - std::unique_ptr shader) -{ - iterator->second.pending = false; - iterator->second.value = std::move(shader); -} - -void CustomShaderCache::NotifyPixelShaderFinished(UberPixelShaderIterator iterator, - std::unique_ptr shader) -{ - iterator->second.pending = false; - iterator->second.value = std::move(shader); -} diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomShaderCache.h b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomShaderCache.h deleted file mode 100644 index 7890cafeb6..0000000000 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomShaderCache.h +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2022 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include -#include -#include - -#include "Common/HookableEvent.h" - -#include "VideoCommon/AbstractPipeline.h" -#include "VideoCommon/AbstractShader.h" -#include "VideoCommon/AsyncShaderCompiler.h" -#include "VideoCommon/GXPipelineTypes.h" -#include "VideoCommon/PixelShaderGen.h" -#include "VideoCommon/ShaderGenCommon.h" -#include "VideoCommon/UberShaderPixel.h" - -struct CustomShaderInstance -{ - CustomPixelShaderContents pixel_contents; - - bool operator==(const CustomShaderInstance& other) const = default; -}; - -class CustomShaderCache -{ -public: - CustomShaderCache(); - ~CustomShaderCache(); - CustomShaderCache(const CustomShaderCache&) = delete; - CustomShaderCache(CustomShaderCache&&) = delete; - CustomShaderCache& operator=(const CustomShaderCache&) = delete; - CustomShaderCache& operator=(CustomShaderCache&&) = delete; - - // Changes the shader host config. Shaders should be reloaded afterwards. - void SetHostConfig(const ShaderHostConfig& host_config) { m_host_config.bits = host_config.bits; } - - // Retrieves all pending shaders/pipelines from the async compiler. - void RetrieveAsyncShaders(); - - // Reloads/recreates all shaders and pipelines. - void Reload(); - - // The optional will be empty if this pipeline is now background compiling. - std::optional - GetPipelineAsync(const VideoCommon::GXPipelineUid& uid, - const CustomShaderInstance& custom_shaders, - const AbstractPipelineConfig& pipeline_config); - std::optional - GetPipelineAsync(const VideoCommon::GXUberPipelineUid& uid, - const CustomShaderInstance& custom_shaders, - const AbstractPipelineConfig& pipeline_config); - -private: - // Configuration bits. - APIType m_api_type = APIType::Nothing; - ShaderHostConfig m_host_config = {}; - std::unique_ptr m_async_shader_compiler; - std::unique_ptr m_async_uber_shader_compiler; - - void AsyncCreatePipeline(const VideoCommon::GXPipelineUid& uid, - const CustomShaderInstance& custom_shaders, - const AbstractPipelineConfig& pipeline_config); - void AsyncCreatePipeline(const VideoCommon::GXUberPipelineUid& uid, - const CustomShaderInstance& custom_shaders, - const AbstractPipelineConfig& pipeline_config); - - // Shader/Pipeline cache helper - template - struct Cache - { - struct CacheHolder - { - std::unique_ptr value = nullptr; - bool pending = true; - }; - using CacheElement = std::pair; - using CacheList = std::list; - std::map uid_to_cachelist; - - const CacheHolder* GetHolder(const Uid& uid, const CustomShaderInstance& custom_shaders) const - { - if (auto uuid_it = uid_to_cachelist.find(uid); uuid_it != uid_to_cachelist.end()) - { - for (const auto& [custom_shader_val, holder] : uuid_it->second) - { - if (custom_shaders == custom_shader_val) - { - return &holder; - } - } - } - - return nullptr; - } - - typename CacheList::iterator InsertElement(const Uid& uid, - const CustomShaderInstance& custom_shaders) - { - CacheList& cachelist = uid_to_cachelist[uid]; - CacheElement e{custom_shaders, CacheHolder{}}; - return cachelist.emplace(cachelist.begin(), std::move(e)); - } - }; - - Cache m_ps_cache; - Cache m_uber_ps_cache; - Cache m_pipeline_cache; - Cache m_uber_pipeline_cache; - - using PipelineIterator = Cache::CacheList::iterator; - using UberPipelineIterator = - Cache::CacheList::iterator; - using PixelShaderIterator = Cache::CacheList::iterator; - using UberPixelShaderIterator = - Cache::CacheList::iterator; - - void NotifyPipelineFinished(PipelineIterator iterator, - std::unique_ptr pipeline); - void NotifyPipelineFinished(UberPipelineIterator iterator, - std::unique_ptr pipeline); - - std::unique_ptr - CompilePixelShader(const PixelShaderUid& uid, const CustomShaderInstance& custom_shaders) const; - void NotifyPixelShaderFinished(PixelShaderIterator iterator, - std::unique_ptr shader); - std::unique_ptr - CompilePixelShader(const UberShader::PixelShaderUid& uid, - const CustomShaderInstance& custom_shaders) const; - void NotifyPixelShaderFinished(UberPixelShaderIterator iterator, - std::unique_ptr shader); - - void QueuePixelShaderCompile(const PixelShaderUid& uid, - const CustomShaderInstance& custom_shaders); - void QueuePixelShaderCompile(const UberShader::PixelShaderUid& uid, - const CustomShaderInstance& custom_shaders); - - Common::EventHook m_frame_end_handler; -}; diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModAction.h b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModAction.h index 5719d550fe..54424ee42f 100644 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModAction.h +++ b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModAction.h @@ -17,7 +17,6 @@ public: virtual void OnDrawStarted(GraphicsModActionData::DrawStarted*) {} virtual void BeforeEFB(GraphicsModActionData::PreEFB*) {} - virtual void AfterEFB(GraphicsModActionData::PostEFB*) {} virtual void BeforeXFB() {} virtual void OnProjection(GraphicsModActionData::Projection*) {} virtual void OnProjectionAndTexture(GraphicsModActionData::Projection*) {} diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionData.h b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionData.h index e82c87e0e4..f7d3351cf0 100644 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionData.h +++ b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionData.h @@ -12,8 +12,6 @@ #include "Common/Matrix.h" #include "Common/SmallVector.h" #include "VideoCommon/Assets/TextureAsset.h" -#include "VideoCommon/Resources/MaterialResource.h" -#include "VideoCommon/ShaderGenCommon.h" namespace GraphicsModActionData { @@ -21,8 +19,6 @@ struct DrawStarted { const Common::SmallVector& texture_units; bool* skip; - std::optional* custom_pixel_shader; - std::span* material_uniform_buffer; }; struct PreEFB @@ -34,11 +30,6 @@ struct PreEFB u32* scaled_height; }; -struct PostEFB -{ - VideoCommon::MaterialResource* material = nullptr; -}; - struct Projection { Common::Matrix44* matrix; diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionFactory.cpp b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionFactory.cpp index 1059595ef1..d27483ae3c 100644 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionFactory.cpp +++ b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionFactory.cpp @@ -3,7 +3,6 @@ #include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionFactory.h" -#include "VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.h" #include "VideoCommon/GraphicsModSystem/Runtime/Actions/MoveAction.h" #include "VideoCommon/GraphicsModSystem/Runtime/Actions/PrintAction.h" #include "VideoCommon/GraphicsModSystem/Runtime/Actions/ScaleAction.h" @@ -30,10 +29,6 @@ std::unique_ptr Create(std::string_view name, const picojson: { return ScaleAction::Create(json_data); } - else if (name == CustomPipelineAction::factory_name) - { - return CustomPipelineAction::Create(json_data, std::move(library)); - } return nullptr; } diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.cpp b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.cpp index c49b655804..cfb79145ec 100644 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.cpp +++ b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.cpp @@ -44,12 +44,6 @@ public: return; m_action_impl->BeforeEFB(efb); } - void AfterEFB(GraphicsModActionData::PostEFB* efb) override - { - if (!m_mod.m_enabled) - return; - m_action_impl->AfterEFB(efb); - } void OnProjection(GraphicsModActionData::Projection* projection) override { if (!m_mod.m_enabled) diff --git a/Source/Core/VideoCommon/LightingShaderGen.cpp b/Source/Core/VideoCommon/LightingShaderGen.cpp index 6c515b7632..bf3e86f7e1 100644 --- a/Source/Core/VideoCommon/LightingShaderGen.cpp +++ b/Source/Core/VideoCommon/LightingShaderGen.cpp @@ -178,141 +178,3 @@ void GetLightingShaderUid(LightingUidData& uid_data) } } -static void GenerateCustomLightingImpl(ShaderCode* out, const LightingUidData& uid_data, int index, - int litchan_index, u32 channel_index, u32 custom_light_index, - bool alpha) -{ - const auto attnfunc = - static_cast((uid_data.attnfunc >> (2 * litchan_index)) & 0x3); - - const std::string_view light_type = alpha ? "alpha" : "color"; - const std::string name = fmt::format("lights_chan{}_{}", channel_index, light_type); - - out->Write("\t{{\n"); - out->Write("\t\tfrag_input.{}[{}].direction = " LIGHT_DIR ".xyz;\n", name, custom_light_index, - LIGHT_DIR_PARAMS(index)); - out->Write("\t\tfrag_input.{}[{}].position = " LIGHT_POS ".xyz;\n", name, custom_light_index, - LIGHT_POS_PARAMS(index)); - out->Write("\t\tfrag_input.{}[{}].cosatt = " LIGHT_COSATT ";\n", name, custom_light_index, - LIGHT_COSATT_PARAMS(index)); - out->Write("\t\tfrag_input.{}[{}].distatt = " LIGHT_DISTATT ";\n", name, custom_light_index, - LIGHT_DISTATT_PARAMS(index)); - out->Write("\t\tfrag_input.{}[{}].attenuation_type = {};\n", name, custom_light_index, - static_cast(attnfunc)); - if (alpha) - { - out->Write("\t\tfrag_input.{}[{}].color = float3(" LIGHT_COL - ") / float3(255.0, 255.0, 255.0);\n", - name, custom_light_index, LIGHT_COL_PARAMS(index, alpha ? "a" : "rgb")); - } - else - { - out->Write("\t\tfrag_input.{}[{}].color = " LIGHT_COL " / float3(255.0, 255.0, 255.0);\n", name, - custom_light_index, LIGHT_COL_PARAMS(index, alpha ? "a" : "rgb")); - } - out->Write("\t}}\n"); -} - -void GenerateCustomLighting(ShaderCode* out, const LightingUidData& uid_data) -{ - for (u32 i = 0; i < 8; i++) - { - for (u32 channel_index = 0; channel_index < NUM_XF_COLOR_CHANNELS; channel_index++) - { - out->Write("\tfrag_input.lights_chan{}_color[{}].direction = float3(0, 0, 0);\n", - channel_index, i); - out->Write("\tfrag_input.lights_chan{}_color[{}].position = float3(0, 0, 0);\n", - channel_index, i); - out->Write("\tfrag_input.lights_chan{}_color[{}].color = float3(0, 0, 0);\n", channel_index, - i); - out->Write("\tfrag_input.lights_chan{}_color[{}].cosatt = float4(0, 0, 0, 0);\n", - channel_index, i); - out->Write("\tfrag_input.lights_chan{}_color[{}].distatt = float4(0, 0, 0, 0);\n", - channel_index, i); - out->Write("\tfrag_input.lights_chan{}_color[{}].attenuation_type = 0;\n", channel_index, i); - - out->Write("\tfrag_input.lights_chan{}_alpha[{}].direction = float3(0, 0, 0);\n", - channel_index, i); - out->Write("\tfrag_input.lights_chan{}_alpha[{}].position = float3(0, 0, 0);\n", - channel_index, i); - out->Write("\tfrag_input.lights_chan{}_alpha[{}].color = float3(0, 0, 0);\n", channel_index, - i); - out->Write("\tfrag_input.lights_chan{}_alpha[{}].cosatt = float4(0, 0, 0, 0);\n", - channel_index, i); - out->Write("\tfrag_input.lights_chan{}_alpha[{}].distatt = float4(0, 0, 0, 0);\n", - channel_index, i); - out->Write("\tfrag_input.lights_chan{}_alpha[{}].attenuation_type = 0;\n", channel_index, i); - } - } - - for (u32 j = 0; j < NUM_XF_COLOR_CHANNELS; j++) - { - const bool colormatsource = !!(uid_data.matsource & (1 << j)); - if (colormatsource) // from vertex - out->Write("frag_input.base_material[{}] = frag_input.color_{};\n", j, j); - else // from color - out->Write("frag_input.base_material[{}] = {}[{}] / 255.0;\n", j, I_MATERIALS, j + 2); - - if ((uid_data.enablelighting & (1 << j)) != 0) - { - if ((uid_data.ambsource & (1 << j)) != 0) // from vertex - out->Write("frag_input.ambient_lighting[{}] = frag_input.color_{};\n", j, j); - else // from color - out->Write("frag_input.ambient_lighting[{}] = {}[{}] / 255.0;\n", j, I_MATERIALS, j); - } - else - { - out->Write("frag_input.ambient_lighting[{}] = float4(1, 1, 1, 1);\n", j); - } - - // check if alpha is different - const bool alphamatsource = !!(uid_data.matsource & (1 << (j + 2))); - if (alphamatsource != colormatsource) - { - if (alphamatsource) // from vertex - out->Write("frag_input.base_material[{}].w = frag_input.color_{}.w;\n", j, j); - else // from color - out->Write("frag_input.base_material[{}].w = {}[{}].w / 255.0;\n", j, I_MATERIALS, j + 2); - } - - if ((uid_data.enablelighting & (1 << (j + 2))) != 0) - { - if ((uid_data.ambsource & (1 << (j + 2))) != 0) // from vertex - out->Write("frag_input.ambient_lighting[{}].w = frag_input.color_{}.w;\n", j, j); - else // from color - out->Write("frag_input.ambient_lighting[{}].w = {}[{}].w / 255.0;\n", j, I_MATERIALS, j); - } - else - { - out->Write("frag_input.ambient_lighting[{}].w = 1;\n", j); - } - - u32 light_count = 0; - if ((uid_data.enablelighting & (1 << j)) != 0) // Color lights - { - for (int i = 0; i < 8; ++i) - { - if ((uid_data.light_mask & (1 << (i + 8 * j))) != 0) - { - GenerateCustomLightingImpl(out, uid_data, i, j, j, light_count, false); - light_count++; - } - } - } - out->Write("\tfrag_input.light_chan{}_color_count = {};\n", j, light_count); - - light_count = 0; - if ((uid_data.enablelighting & (1 << (j + 2))) != 0) // Alpha lights - { - for (int i = 0; i < 8; ++i) - { - if ((uid_data.light_mask & (1 << (i + 8 * (j + 2)))) != 0) - { - GenerateCustomLightingImpl(out, uid_data, i, j + 2, j, light_count, true); - light_count++; - } - } - } - out->Write("\tfrag_input.light_chan{}_alpha_count = {};\n", j, light_count); - } -} diff --git a/Source/Core/VideoCommon/LightingShaderGen.h b/Source/Core/VideoCommon/LightingShaderGen.h index e7d6f1ed13..c8c1fdb69c 100644 --- a/Source/Core/VideoCommon/LightingShaderGen.h +++ b/Source/Core/VideoCommon/LightingShaderGen.h @@ -46,4 +46,3 @@ constexpr char s_lighting_struct[] = "struct Light {\n" void GenerateLightingShaderHeader(ShaderCode& object, const LightingUidData& uid_data); void GetLightingShaderUid(LightingUidData& uid_data); -void GenerateCustomLighting(ShaderCode* out, const LightingUidData& uid_data); diff --git a/Source/Core/VideoCommon/PixelShaderGen.cpp b/Source/Core/VideoCommon/PixelShaderGen.cpp index 5ce120e9ff..11d48f7ab0 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/PixelShaderGen.cpp @@ -746,8 +746,7 @@ static void WriteFragmentDefinitions(APIType api_type, const ShaderHostConfig& h const pixel_shader_uid_data* uid_data, ShaderCode& out); ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& host_config, - const pixel_shader_uid_data* uid_data, - CustomPixelContents custom_contents) + const pixel_shader_uid_data* uid_data) { ShaderCode out; @@ -896,13 +895,6 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos } } - if (!custom_contents.uniforms.empty()) - { - out.Write("UBO_BINDING(std140, 3) uniform CustomShaderBlock {{\n"); - out.Write("{}", custom_contents.uniforms); - out.Write("}} custom_uniforms;\n"); - } - if (per_pixel_lighting) { GenerateLightingShaderHeader(out, uid_data->lighting); @@ -911,20 +903,11 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos WriteFragmentDefinitions(api_type, host_config, uid_data, out); WriteEmulatedFragmentBodyHeader(api_type, host_config, uid_data, out); - if (custom_contents.shader.empty()) - { - out.Write("void process_fragment(in DolphinFragmentInput frag_input, out DolphinFragmentOutput " - "frag_output)\n"); - out.Write("{{\n"); - - out.Write("\tdolphin_process_emulated_fragment(frag_input, frag_output);\n"); - - out.Write("}}\n"); - } - else - { - out.Write("{}\n", custom_contents.shader); - } + out.Write("void process_fragment(in DolphinFragmentInput frag_input, out DolphinFragmentOutput " + "frag_output)\n"); + out.Write("{{\n"); + out.Write("\tdolphin_process_emulated_fragment(frag_input, frag_output);\n"); + out.Write("}}\n"); out.Write("void main()\n{{\n"); out.Write("\tfloat4 rawpos = gl_FragCoord;\n"); @@ -988,9 +971,6 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos out.Write("\tfrag_input.tex{0} = vec3(0, 0, 0);\n", i); } - if (!custom_contents.shader.empty()) - GenerateCustomLighting(&out, uid_data->lighting); - out.Write("\tDolphinFragmentOutput frag_output;\n"); out.Write("\tprocess_fragment(frag_input, frag_output);\n"); out.Write("\tivec4 prev = frag_output.main & 255;\n"); @@ -2025,16 +2005,6 @@ void WriteFragmentBody(APIType api_type, const ShaderHostConfig& host_config, static void WriteFragmentDefinitions(APIType api_type, const ShaderHostConfig& host_config, const pixel_shader_uid_data* uid_data, ShaderCode& out) { - out.Write("struct DolphinLightData\n"); - out.Write("{{\n"); - out.Write("\tfloat3 position;\n"); - out.Write("\tfloat3 direction;\n"); - out.Write("\tfloat3 color;\n"); - out.Write("\tuint attenuation_type;\n"); - out.Write("\tfloat4 cosatt;\n"); - out.Write("\tfloat4 distatt;\n"); - out.Write("}};\n\n"); - out.Write("struct DolphinFragmentInput\n"); out.Write("{{\n"); out.Write("\tvec4 color_0;\n"); @@ -2046,19 +2016,6 @@ static void WriteFragmentDefinitions(APIType api_type, const ShaderHostConfig& h { out.Write("\tvec3 tex{};\n", i); } - out.Write("\n"); - - out.Write("\tDolphinLightData[8] lights_chan0_color;\n"); - out.Write("\tDolphinLightData[8] lights_chan0_alpha;\n"); - out.Write("\tDolphinLightData[8] lights_chan1_color;\n"); - out.Write("\tDolphinLightData[8] lights_chan1_alpha;\n"); - out.Write("\tfloat4[2] ambient_lighting;\n"); - out.Write("\tfloat4[2] base_material;\n"); - out.Write("\tuint light_chan0_color_count;\n"); - out.Write("\tuint light_chan0_alpha_count;\n"); - out.Write("\tuint light_chan1_color_count;\n"); - out.Write("\tuint light_chan1_alpha_count;\n"); - out.Write("}};\n\n"); out.Write("struct DolphinFragmentOutput\n"); @@ -2066,16 +2023,6 @@ static void WriteFragmentDefinitions(APIType api_type, const ShaderHostConfig& h out.Write("\tivec4 main;\n"); out.Write("\tivec4 last_texture;\n"); out.Write("}};\n\n"); - - // CUSTOM_SHADER_LIGHTING_ATTENUATION_TYPE "enum" values - out.Write("const uint CUSTOM_SHADER_LIGHTING_ATTENUATION_TYPE_NONE = {}u;\n", - static_cast(AttenuationFunc::None)); - out.Write("const uint CUSTOM_SHADER_LIGHTING_ATTENUATION_TYPE_POINT = {}u;\n", - static_cast(AttenuationFunc::Spec)); - out.Write("const uint CUSTOM_SHADER_LIGHTING_ATTENUATION_TYPE_DIR = {}u;\n", - static_cast(AttenuationFunc::Dir)); - out.Write("const uint CUSTOM_SHADER_LIGHTING_ATTENUATION_TYPE_SPOT = {}u;\n", - static_cast(AttenuationFunc::Spot)); } static void WriteEmulatedFragmentBodyHeader(APIType api_type, const ShaderHostConfig& host_config, diff --git a/Source/Core/VideoCommon/PixelShaderGen.h b/Source/Core/VideoCommon/PixelShaderGen.h index f8c0fa96c5..52f048a0ee 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.h +++ b/Source/Core/VideoCommon/PixelShaderGen.h @@ -158,15 +158,8 @@ struct pixel_shader_uid_data using PixelShaderUid = ShaderUid; -struct CustomPixelContents -{ - std::string_view shader = ""; - std::string_view uniforms = ""; -}; - ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& host_config, - const pixel_shader_uid_data* uid_data, - CustomPixelContents custom_contents); + const pixel_shader_uid_data* uid_data); void WritePixelShaderCommonHeader(ShaderCode& out, APIType api_type, const ShaderHostConfig& host_config, bool bounding_box); void WriteFragmentBody(APIType api_type, const ShaderHostConfig& host_config, diff --git a/Source/Core/VideoCommon/PixelShaderManager.h b/Source/Core/VideoCommon/PixelShaderManager.h index 5d3fe7257e..0597bf1f0f 100644 --- a/Source/Core/VideoCommon/PixelShaderManager.h +++ b/Source/Core/VideoCommon/PixelShaderManager.h @@ -54,10 +54,6 @@ public: PixelShaderConstants constants{}; bool dirty = false; - // Constants for custom shaders - std::span custom_constants; - bool custom_constants_dirty = false; - private: bool m_fog_range_adjusted_changed = false; bool m_viewport_changed = false; diff --git a/Source/Core/VideoCommon/PostProcessing.cpp b/Source/Core/VideoCommon/PostProcessing.cpp index 92f7c1f99c..7b6f441ca5 100644 --- a/Source/Core/VideoCommon/PostProcessing.cpp +++ b/Source/Core/VideoCommon/PostProcessing.cpp @@ -3,21 +3,12 @@ #include "VideoCommon/PostProcessing.h" -#include +#include +#include #include -#include -#include - -#include "Common/Assert.h" -#include "Common/CommonPaths.h" #include "Common/CommonTypes.h" -#include "Common/FileSearch.h" -#include "Common/FileUtil.h" -#include "Common/IniFile.h" -#include "Common/Logging/Log.h" #include "Common/MsgHandler.h" -#include "Common/StringUtil.h" #include "VideoCommon/AbstractFramebuffer.h" #include "VideoCommon/AbstractGfx.h" @@ -25,817 +16,503 @@ #include "VideoCommon/AbstractShader.h" #include "VideoCommon/AbstractTexture.h" #include "VideoCommon/Present.h" -#include "VideoCommon/ShaderCache.h" -#include "VideoCommon/ShaderCompileUtils.h" +#include "VideoCommon/RenderState.h" #include "VideoCommon/VertexManagerBase.h" #include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoConfig.h" namespace VideoCommon { -static const char s_empty_pixel_shader[] = "void main() { SetOutput(Sample()); }\n"; -static const char s_default_pixel_shader_name[] = "default_pre_post_process"; -// Keep the highest quality possible to avoid losing quality on subtle gamma conversions. -// RGBA16F should have enough quality even if we store colors in gamma space on it. -static const AbstractTextureFormat s_intermediary_buffer_format = AbstractTextureFormat::RGBA16F; - -static bool LoadShaderFromFile(const std::string& shader, const std::string& sub_dir, - std::string& out_code) +namespace { - std::string path = File::GetUserPath(D_SHADERS_IDX) + sub_dir + shader + ".glsl"; +constexpr char s_copy_pixel_shader[] = "void main() { SetOutput(Sample()); }\n"; - if (!File::Exists(path)) - { - // Fallback to shared user dir - path = File::GetSysDirectory() + SHADERS_DIR DIR_SEP + sub_dir + shader + ".glsl"; - } +// Resampling, gamut and gamma correction and HDR scaling for the final pass. +constexpr char s_correction_pixel_shader[] = +R"(/***** COLOR CORRECTION *****/ - if (!File::ReadFileToString(path, out_code)) - { - out_code = ""; - ERROR_LOG_FMT(VIDEO, "Post-processing shader not found: {}", path); - return false; - } +// Color Space references: +// https://www.unravel.com.au/understanding-color-spaces - return true; +// SMPTE 170M - BT.601 (NTSC-M) -> BT.709 +mat3 from_NTSCM = transpose(mat3( + 0.939497225737661, 0.0502268452914346, 0.0102759289709032, + 0.0177558637510127, 0.965824605885027, 0.0164195303639603, + -0.00162163209967010, -0.00437400622653655, 1.00599563832621)); + +// ARIB TR-B9 (9300K+27MPCD with chromatic adaptation) (NTSC-J) -> BT.709 +mat3 from_NTSCJ = transpose(mat3( + 0.768497526, -0.210804164, 0.000297427177, + 0.0397904068, 1.04825413, 0.00555809540, + 0.00147510506, 0.0328789241, 1.36515128)); + +// EBU - BT.470BG/BT.601 (PAL) -> BT.709 +mat3 from_PAL = transpose(mat3( + 1.04408168421813, -0.0440816842181253, 0.000000000000000, + 0.000000000000000, 1.00000000000000, 0.000000000000000, + 0.000000000000000, 0.0118044782106489, 0.988195521789351)); + +float3 LinearTosRGBGamma(float3 color) +{ + const float a = 0.055; + + for (int i = 0; i < 3; ++i) + { + float x = color[i]; + if (x <= 0.0031308) + x = x * 12.92; + else + x = (1.0 + a) * pow(x, 1.0 / 2.4) - a; + color[i] = x; + } + + return color; } -PostProcessingConfiguration::PostProcessingConfiguration() = default; +float3 Rec709_Luminance = float3(0.2126, 0.7152, 0.0722); -PostProcessingConfiguration::~PostProcessingConfiguration() = default; - -void PostProcessingConfiguration::LoadShader(const std::string& shader) +float Luminance(float3 color, bool native_color_space) { - // Load the shader from the configuration if there isn't one sent to us. - m_current_shader = shader; - if (shader.empty()) - { - LoadDefaultShader(); - return; - } - - std::string sub_dir = ""; - - if (g_Config.stereo_mode == StereoMode::Anaglyph) - { - sub_dir = ANAGLYPH_DIR DIR_SEP; - } - else if (g_Config.stereo_mode == StereoMode::Passive) - { - sub_dir = PASSIVE_DIR DIR_SEP; - } - - std::string code; - if (!LoadShaderFromFile(shader, sub_dir, code)) - { - LoadDefaultShader(); - return; - } - - LoadOptions(code); - // Note that this will build the shaders with the custom options values users - // might have set in the settings - LoadOptionsConfiguration(); - m_current_shader_code = code; - m_shader_includer = - std::make_unique(File::GetUserPath(D_SHADERS_IDX) + sub_dir, - File::GetSysDirectory() + SHADERS_DIR DIR_SEP + sub_dir); + if (native_color_space && OptionEnabled(correct_color_space)) + { + if (game_color_space == 0) + color *= from_NTSCM; + else if (game_color_space == 1) + color *= from_NTSCJ; + else if (game_color_space == 2) + color *= from_PAL; + } + return dot(color, Rec709_Luminance); } -void PostProcessingConfiguration::LoadDefaultShader() +/***** COLOR SAMPLING *****/ + +// Non filtered gamma corrected sample (nearest neighbor) +float4 QuickSample(float3 uvw, float gamma) { - m_options.clear(); - m_any_options_dirty = false; - m_current_shader = ""; - m_current_shader_code = s_empty_pixel_shader; -} - -void PostProcessingConfiguration::LoadOptions(const std::string& code) -{ - const std::string config_start_delimiter = "[configuration]"; - const std::string config_end_delimiter = "[/configuration]"; - size_t configuration_start = code.find(config_start_delimiter); - size_t configuration_end = code.find(config_end_delimiter); - - m_options.clear(); - m_any_options_dirty = true; - - if (configuration_start == std::string::npos || configuration_end == std::string::npos) - { - // Issue loading configuration or there isn't one. - return; - } - - std::string configuration_string = - code.substr(configuration_start + config_start_delimiter.size(), - configuration_end - configuration_start - config_start_delimiter.size()); - - std::istringstream in(configuration_string); - - struct GLSLStringOption - { - std::string m_type; - std::vector> m_options; - }; - - std::vector option_strings; - GLSLStringOption* current_strings = nullptr; - std::string line_str; - while (std::getline(in, line_str)) - { - std::string_view line = line_str; - -#ifndef _WIN32 - // Check for CRLF eol and convert it to LF - if (!line.empty() && line.at(line.size() - 1) == '\r') - line.remove_suffix(1); +#if 0 // Test sampling range + const float threshold = 0.00000001; + float2 xy = uvw.xy * GetResolution(); + // Sampling outside the valid range, draw in yellow + if (xy.x < (0.0 - threshold) || xy.x > (GetResolution().x + threshold) || xy.y < (0.0 - threshold) || xy.y > (GetResolution().y + threshold)) + return float4(1.0, 1.0, 0.0, 1); + // Sampling at the edges, draw in purple + if (xy.x < 1.0 || xy.x > (GetResolution().x - 1.0) || xy.y < 1.0 || xy.y > (GetResolution().y - 1.0)) + return float4(0.5, 0, 0.5, 1); #endif - if (!line.empty()) - { - if (line[0] == '[') - { - size_t endpos = line.find("]"); - - if (endpos != std::string::npos) - { - // New section! - std::string_view sub = line.substr(1, endpos - 1); - option_strings.push_back({std::string(sub)}); - current_strings = &option_strings.back(); - } - } - else - { - if (current_strings) - { - std::string key, value; - Common::IniFile::ParseLine(line, &key, &value); - - if (!(key.empty() && value.empty())) - current_strings->m_options.emplace_back(key, value); - } - } - } - } - - for (const auto& it : option_strings) - { - ConfigurationOption option; - option.m_dirty = true; - - if (it.m_type == "OptionBool") - option.m_type = ConfigurationOption::OptionType::Bool; - else if (it.m_type == "OptionRangeFloat") - option.m_type = ConfigurationOption::OptionType::Float; - else if (it.m_type == "OptionRangeInteger") - option.m_type = ConfigurationOption::OptionType::Integer; - - for (const auto& string_option : it.m_options) - { - if (string_option.first == "GUIName") - { - option.m_gui_name = string_option.second; - } - else if (string_option.first == "OptionName") - { - option.m_option_name = string_option.second; - } - else if (string_option.first == "DependentOption") - { - option.m_dependent_option = string_option.second; - } - else if (string_option.first == "MinValue" || string_option.first == "MaxValue" || - string_option.first == "DefaultValue" || string_option.first == "StepAmount") - { - std::vector* output_integer = nullptr; - std::vector* output_float = nullptr; - - if (string_option.first == "MinValue") - { - output_integer = &option.m_integer_min_values; - output_float = &option.m_float_min_values; - } - else if (string_option.first == "MaxValue") - { - output_integer = &option.m_integer_max_values; - output_float = &option.m_float_max_values; - } - else if (string_option.first == "DefaultValue") - { - output_integer = &option.m_integer_values; - output_float = &option.m_float_values; - } - else if (string_option.first == "StepAmount") - { - output_integer = &option.m_integer_step_values; - output_float = &option.m_float_step_values; - } - - if (option.m_type == ConfigurationOption::OptionType::Bool) - { - TryParse(string_option.second, &option.m_bool_value); - } - else if (option.m_type == ConfigurationOption::OptionType::Integer) - { - TryParseVector(string_option.second, output_integer); - if (output_integer->size() > 4) - output_integer->erase(output_integer->begin() + 4, output_integer->end()); - } - else if (option.m_type == ConfigurationOption::OptionType::Float) - { - TryParseVector(string_option.second, output_float); - if (output_float->size() > 4) - output_float->erase(output_float->begin() + 4, output_float->end()); - } - } - } - m_options[option.m_option_name] = option; - } + float4 color = texture(samp1, uvw); + color.rgb = pow(color.rgb, float3(gamma)); + return color; +} +float4 QuickSample(float2 uv, float w, float gamma) +{ + return QuickSample(float3(uv, w), gamma); +} +float4 QuickSampleByPixel(float2 xy, float w, float gamma) +{ + float3 uvw = float3(xy * GetInvResolution(), w); + return QuickSample(uvw, gamma); } -void PostProcessingConfiguration::LoadOptionsConfiguration() -{ - Common::IniFile ini; - ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); - std::string section = m_current_shader + "-options"; +/***** Bilinear Interpolation *****/ - // We already expect all the options to be marked as "dirty" when we reach here - for (auto& it : m_options) - { - switch (it.second.m_type) - { - case ConfigurationOption::OptionType::Bool: - ini.GetOrCreateSection(section)->Get(it.second.m_option_name, &it.second.m_bool_value, - it.second.m_bool_value); - break; - case ConfigurationOption::OptionType::Integer: - { - std::string value; - ini.GetOrCreateSection(section)->Get(it.second.m_option_name, &value); - if (!value.empty()) - { - auto integer_values = it.second.m_integer_values; - if (TryParseVector(value, &integer_values)) - { - it.second.m_integer_values = integer_values; - } - } - } - break; - case ConfigurationOption::OptionType::Float: - { - std::string value; - ini.GetOrCreateSection(section)->Get(it.second.m_option_name, &value); - if (!value.empty()) - { - auto float_values = it.second.m_float_values; - if (TryParseVector(value, &float_values)) - { - it.second.m_float_values = float_values; - } - } - } - break; - } - } +float4 BilinearSample(float3 uvw, float gamma) +{ + // This emulates the (bi)linear filtering done directly from GPUs HW. + // Note that GPUs might natively filter red green and blue differently, but we don't do it. + // They might also use different filtering between upscaling and downscaling. + float2 source_size = GetResolution(); + float2 pixel = (uvw.xy * source_size) - 0.5; // Try to find the matching pixel top left corner + + // Find the integer and floating point parts + float2 int_pixel = floor(pixel); + float2 frac_pixel = fract(pixel); + + // Take 4 samples around the original uvw + float4 c11 = QuickSampleByPixel(int_pixel + float2(0.5, 0.5), uvw.z, gamma); + float4 c21 = QuickSampleByPixel(int_pixel + float2(1.5, 0.5), uvw.z, gamma); + float4 c12 = QuickSampleByPixel(int_pixel + float2(0.5, 1.5), uvw.z, gamma); + float4 c22 = QuickSampleByPixel(int_pixel + float2(1.5, 1.5), uvw.z, gamma); + + // Blend the 4 samples by their weight + float4 avg_c = lerp(lerp(c11, c21, frac_pixel.x), lerp(c12, c22, frac_pixel.x), frac_pixel.y); + + // Calculate the average of the gamma space luminance, as that can be used to + // properly determine the perceptual brightness the color should have. + float l11 = pow(Luminance(c11.rgb, true), 1.0 / gamma); + float l21 = pow(Luminance(c21.rgb, true), 1.0 / gamma); + float l12 = pow(Luminance(c12.rgb, true), 1.0 / gamma); + float l22 = pow(Luminance(c22.rgb, true), 1.0 / gamma); + float target_avg_c_lum = lerp(lerp(l11, l21, frac_pixel.x), lerp(l12, l22, frac_pixel.x), frac_pixel.y); + + float avg_c_lum = Luminance(avg_c.rgb, true); + if (avg_c_lum != 0.0) + { + avg_c.rgb *= pow(target_avg_c_lum, gamma) / avg_c_lum; + } + + return avg_c; } -void PostProcessingConfiguration::SaveOptionsConfiguration() +/***** Bicubic Interpolation *****/ + +// Formula derived from: +// https://en.wikipedia.org/wiki/Mitchell%E2%80%93Netravali_filters#Definition +// Values from: +// https://guideencodemoe-mkdocs.readthedocs.io/encoding/resampling/#mitchell-netravali-bicubic +// Other references: +// https://www.codeproject.com/Articles/236394/Bi-Cubic-and-Bi-Linear-Interpolation-with-GLSL +// https://github.com/ValveSoftware/gamescope/pull/740 +// https://stackoverflow.com/questions/13501081/efficient-bicubic-filtering-code-in-glsl +#define CUBIC_COEFF_GEN(B, C) \ + (mat4(/* t^0 */ ((B) / 6.0), (-(B) / 3.0 + 1.0), ((B) / 6.0), (0.0), \ + /* t^1 */ (-(B) / 2.0 - (C)), (0.0), ((B) / 2.0 + (C)), (0.0), \ + /* t^2 */ ((B) / 2.0 + 2.0 * (C)), (2.0 * (B) + (C)-3.0), \ + (-5.0 * (B) / 2.0 - 2.0 * (C) + 3.0), (-(C)), \ + /* t^3 */ (-(B) / 6.0 - (C)), (-3.0 * (B) / 2.0 - (C) + 2.0), \ + (3.0 * (B) / 2.0 + (C)-2.0), ((B) / 6.0 + (C)))) + +float4 CubicCoeffs(float t, mat4 coeffs) { - Common::IniFile ini; - ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); - std::string section = m_current_shader + "-options"; - - for (auto& it : m_options) - { - switch (it.second.m_type) - { - case ConfigurationOption::OptionType::Bool: - { - ini.GetOrCreateSection(section)->Set(it.second.m_option_name, it.second.m_bool_value); - } - break; - case ConfigurationOption::OptionType::Integer: - { - std::string value; - for (size_t i = 0; i < it.second.m_integer_values.size(); ++i) - { - value += fmt::format("{}{}", it.second.m_integer_values[i], - i == (it.second.m_integer_values.size() - 1) ? "" : ", "); - } - ini.GetOrCreateSection(section)->Set(it.second.m_option_name, value); - } - break; - case ConfigurationOption::OptionType::Float: - { - std::ostringstream value; - value.imbue(std::locale("C")); - - for (size_t i = 0; i < it.second.m_float_values.size(); ++i) - { - value << it.second.m_float_values[i]; - if (i != (it.second.m_float_values.size() - 1)) - value << ", "; - } - ini.GetOrCreateSection(section)->Set(it.second.m_option_name, value.str()); - } - break; - } - } - ini.Save(File::GetUserPath(F_DOLPHINCONFIG_IDX)); + return coeffs * float4(1.0, t, t * t, t * t * t); } -void PostProcessingConfiguration::SetOptionf(const std::string& option, int index, float value) +float4 CubicMix(float4 c0, float4 c1, float4 c2, float4 c3, float4 coeffs) { - auto it = m_options.find(option); - - it->second.m_float_values[index] = value; - it->second.m_dirty = true; - m_any_options_dirty = true; + return c0 * coeffs[0] + c1 * coeffs[1] + c2 * coeffs[2] + c3 * coeffs[3]; } -void PostProcessingConfiguration::SetOptioni(const std::string& option, int index, s32 value) +// By Sam Belliveau. Public Domain license. +// Simple 16 tap, gamma correct, implementation of bicubic filtering. +float4 BicubicSample(float3 uvw, float gamma, mat4 coeffs) { - auto it = m_options.find(option); + float2 pixel = (uvw.xy * GetResolution()) - 0.5; + float2 int_pixel = floor(pixel); + float2 frac_pixel = fract(pixel); - it->second.m_integer_values[index] = value; - it->second.m_dirty = true; - m_any_options_dirty = true; + float4 c00 = QuickSampleByPixel(int_pixel + float2(-0.5, -0.5), uvw.z, gamma); + float4 c10 = QuickSampleByPixel(int_pixel + float2(+0.5, -0.5), uvw.z, gamma); + float4 c20 = QuickSampleByPixel(int_pixel + float2(+1.5, -0.5), uvw.z, gamma); + float4 c30 = QuickSampleByPixel(int_pixel + float2(+2.5, -0.5), uvw.z, gamma); + + float4 c01 = QuickSampleByPixel(int_pixel + float2(-0.5, +0.5), uvw.z, gamma); + float4 c11 = QuickSampleByPixel(int_pixel + float2(+0.5, +0.5), uvw.z, gamma); + float4 c21 = QuickSampleByPixel(int_pixel + float2(+1.5, +0.5), uvw.z, gamma); + float4 c31 = QuickSampleByPixel(int_pixel + float2(+2.5, +0.5), uvw.z, gamma); + + float4 c02 = QuickSampleByPixel(int_pixel + float2(-0.5, +1.5), uvw.z, gamma); + float4 c12 = QuickSampleByPixel(int_pixel + float2(+0.5, +1.5), uvw.z, gamma); + float4 c22 = QuickSampleByPixel(int_pixel + float2(+1.5, +1.5), uvw.z, gamma); + float4 c32 = QuickSampleByPixel(int_pixel + float2(+2.5, +1.5), uvw.z, gamma); + + float4 c03 = QuickSampleByPixel(int_pixel + float2(-0.5, +2.5), uvw.z, gamma); + float4 c13 = QuickSampleByPixel(int_pixel + float2(+0.5, +2.5), uvw.z, gamma); + float4 c23 = QuickSampleByPixel(int_pixel + float2(+1.5, +2.5), uvw.z, gamma); + float4 c33 = QuickSampleByPixel(int_pixel + float2(+2.5, +2.5), uvw.z, gamma); + + float4 cx = CubicCoeffs(frac_pixel.x, coeffs); + float4 cy = CubicCoeffs(frac_pixel.y, coeffs); + + float4 x0 = CubicMix(c00, c10, c20, c30, cx); + float4 x1 = CubicMix(c01, c11, c21, c31, cx); + float4 x2 = CubicMix(c02, c12, c22, c32, cx); + float4 x3 = CubicMix(c03, c13, c23, c33, cx); + + return CubicMix(x0, x1, x2, x3, cy); } -void PostProcessingConfiguration::SetOptionb(const std::string& option, bool value) -{ - auto it = m_options.find(option); +/***** Sharp Bilinear Filtering *****/ - it->second.m_bool_value = value; - it->second.m_dirty = true; - m_any_options_dirty = true; +// Based on https://github.com/libretro/slang-shaders/blob/master/interpolation/shaders/sharp-bilinear.slang +// by Themaister, Public Domain license +// Does a bilinear stretch, with a preapplied Nx nearest-neighbor scale, +// giving a sharper image than plain bilinear. +float4 SharpBilinearSample(float3 uvw, float gamma) +{ + float2 source_size = GetResolution(); + float2 inverted_source_size = GetInvResolution(); + float2 target_size = GetWindowResolution(); + float2 texel = uvw.xy * source_size; + float2 texel_floored = floor(texel); + float2 s = fract(texel); + float scale = max(floor(max(target_size.x * inverted_source_size.x, target_size.y * inverted_source_size.y)), 1.0); + float region_range = 0.5 - (0.5 / scale); + + // Figure out where in the texel to sample to get correct pre-scaled bilinear. + + float2 center_dist = s - 0.5; + float2 f = ((center_dist - clamp(center_dist, -region_range, region_range)) * scale) + 0.5; + + float2 mod_texel = texel_floored + f; + + uvw.xy = mod_texel * inverted_source_size; + return BilinearSample(uvw, gamma); } -PostProcessing::PostProcessing() +/***** Area Sampling *****/ + +// By Sam Belliveau and Filippo Tarpini. Public Domain license. +// Effectively a more accurate sharp bilinear filter when upscaling, +// that also works as a mathematically perfect downscale filter. +// https://entropymine.com/imageworsener/pixelmixing/ +// https://github.com/obsproject/obs-studio/pull/1715 +// https://legacy.imagemagick.org/Usage/filter/ +float4 AreaSampling(float3 uvw, float gamma) { - m_timer.Start(); + // Determine the sizes of the source and target images. + float2 source_size = GetResolution(); + float2 target_size = GetWindowResolution(); + float2 inverted_target_size = GetInvWindowResolution(); + + // Compute the top-left and bottom-right corners of the target pixel box. + float2 t_beg = floor(uvw.xy * target_size); + float2 t_end = t_beg + float2(1.0, 1.0); + + // Convert the target pixel box to source pixel box. + float2 beg = t_beg * inverted_target_size * source_size; + float2 end = t_end * inverted_target_size * source_size; + + // Compute the top-left and bottom-right corners of the pixel box. + float2 f_beg = floor(beg); + float2 f_end = floor(end); + + // Compute how much of the start and end pixels are covered horizontally & vertically. + float area_w = 1.0 - fract(beg.x); + float area_n = 1.0 - fract(beg.y); + float area_e = fract(end.x); + float area_s = fract(end.y); + + // Compute the areas of the corner pixels in the pixel box. + float area_nw = area_n * area_w; + float area_ne = area_n * area_e; + float area_sw = area_s * area_w; + float area_se = area_s * area_e; + + // Initialize the color accumulator. + float4 avg_color = float4(0.0, 0.0, 0.0, 0.0); + float avg_luminance = 0.0; + float4 temp_color; + + float luminance_gamma = gamma; // For now, default to the user selected gamma (alternatively we could fix it to anything between 2.2 and 3.0) + float luminance_inv_gamma = 1.0 / luminance_gamma; + + // Prevents rounding errors due to the coordinates flooring above + const float2 offset = float2(0.5, 0.5); + + // Accumulate corner pixels. + temp_color = QuickSampleByPixel(float2(f_beg.x, f_beg.y) + offset, uvw.z, gamma); + avg_color += area_nw * temp_color; + avg_luminance += area_nw * pow(Luminance(temp_color.rgb, true), luminance_inv_gamma); + temp_color = QuickSampleByPixel(float2(f_end.x, f_beg.y) + offset, uvw.z, gamma); + avg_color += area_ne * temp_color; + avg_luminance += area_ne * pow(Luminance(temp_color.rgb, true), luminance_inv_gamma); + temp_color = QuickSampleByPixel(float2(f_beg.x, f_end.y) + offset, uvw.z, gamma); + avg_color += area_sw * temp_color; + avg_luminance += area_sw * pow(Luminance(temp_color.rgb, true), luminance_inv_gamma); + temp_color = QuickSampleByPixel(float2(f_end.x, f_end.y) + offset, uvw.z, gamma); + avg_color += area_se * temp_color; + avg_luminance += area_se * pow(Luminance(temp_color.rgb, true), luminance_inv_gamma); + + // Determine the size of the pixel box. + int x_range = int(f_end.x - f_beg.x - 0.5); + int y_range = int(f_end.y - f_beg.y - 0.5); + + // Workaround to compile the shader with DX11/12. + // If this isn't done, it will complain that the loop could have too many iterations. + // This number should be enough to guarantee downscaling from very high to very small resolutions. + // Note that this number might be referenced in the UI. + const int max_iterations = 16; + + // Fix up the average calculations in case we reached the upper limit + x_range = min(x_range, max_iterations); + y_range = min(y_range, max_iterations); + +)" +R"( // Accumulate top and bottom edge pixels. + for (int ix = 0; ix < max_iterations; ++ix) + { + if (ix < x_range) + { + float x = f_beg.x + 1.0 + float(ix); + temp_color = QuickSampleByPixel(float2(x, f_beg.y) + offset, uvw.z, gamma); + avg_color += area_n * temp_color; + avg_luminance += area_n * pow(Luminance(temp_color.rgb, true), luminance_inv_gamma); + temp_color = QuickSampleByPixel(float2(x, f_end.y) + offset, uvw.z, gamma); + avg_color += area_s * temp_color; + avg_luminance += area_s * pow(Luminance(temp_color.rgb, true), luminance_inv_gamma); + } + } + + // Accumulate left and right edge pixels and all the pixels in between. + for (int iy = 0; iy < max_iterations; ++iy) + { + if (iy < y_range) + { + float y = f_beg.y + 1.0 + float(iy); + + temp_color = QuickSampleByPixel(float2(f_beg.x, y) + offset, uvw.z, gamma); + avg_color += area_w * temp_color; + avg_luminance += area_w * pow(Luminance(temp_color.rgb, true), luminance_inv_gamma); + temp_color = QuickSampleByPixel(float2(f_end.x, y) + offset, uvw.z, gamma); + avg_color += area_e * temp_color; + avg_luminance += area_e * pow(Luminance(temp_color.rgb, true), luminance_inv_gamma); + + for (int ix = 0; ix < max_iterations; ++ix) + { + if (ix < x_range) + { + float x = f_beg.x + 1.0 + float(ix); + temp_color = QuickSampleByPixel(float2(x, y) + offset, uvw.z, gamma); + avg_color += temp_color; + avg_luminance += pow(Luminance(temp_color.rgb, true), luminance_inv_gamma); + } + } + } + } + + // Compute the area of the pixel box that was sampled. + float area_corners = area_nw + area_ne + area_sw + area_se; + float area_edges = float(x_range) * (area_n + area_s) + float(y_range) * (area_w + area_e); + float area_center = float(x_range) * float(y_range); + + float4 nrm_color = avg_color / (area_corners + area_edges + area_center); + float target_nrm_color_luminance = avg_luminance / (area_corners + area_edges + area_center); + + // Restore the averaged "gamma" space luminance, for better gamma correction. + // This retains the best feature of gamma correct sampling (no hue shifts), + // while also maintaining the perceptual "brightness" level of blending two colors with an alpha + // (in linear space a 0.5 alpha won't produce a color that has a perceptual brightness in the middle point of the two source colors). + float nrm_color_luminance = Luminance(nrm_color.rgb, true); + if (nrm_color_luminance != 0.0) + { + nrm_color.rgb *= pow(target_nrm_color_luminance, luminance_gamma) / nrm_color_luminance; + } + + // Return the normalized average color. + return nrm_color; } -PostProcessing::~PostProcessing() +/***** Main Functions *****/ + +// Returns an accurate (gamma corrected) sample of a gamma space space texture. +// Outputs in linear space for simplicity. +float4 LinearGammaCorrectedSample(float gamma) { - m_timer.Stop(); + float3 uvw = v_tex0; + float4 color = float4(0, 0, 0, 1); + + if (resampling_method <= 1) // Bilinear + { + color = BilinearSample(uvw, gamma); + } + else if (resampling_method == 2) // Bicubic: B-Spline + { + color = BicubicSample(uvw, gamma, CUBIC_COEFF_GEN(1.0, 0.0)); + } + else if (resampling_method == 3) // Bicubic: Mitchell-Netravali + { + color = BicubicSample(uvw, gamma, CUBIC_COEFF_GEN(1.0 / 3.0, 1.0 / 3.0)); + } + else if (resampling_method == 4) // Bicubic: Catmull-Rom + { + color = BicubicSample(uvw, gamma, CUBIC_COEFF_GEN(0.0, 0.5)); + } + else if (resampling_method == 5) // Sharp Bilinear + { + color = SharpBilinearSample(uvw, gamma); + } + else if (resampling_method == 6) // Area Sampling + { + color = AreaSampling(uvw, gamma); + } + else if (resampling_method == 7) // Nearest Neighbor + { + color = QuickSample(uvw, gamma); + } + else if (resampling_method == 8) // Bicubic: Hermite + { + color = BicubicSample(uvw, gamma, CUBIC_COEFF_GEN(0.0, 0.0)); + } + + return color; } -static std::vector GetShaders(const std::string& sub_dir = "") +void main() { - std::vector paths = - Common::DoFileSearch({{File::GetUserPath(D_SHADERS_IDX) + sub_dir, - File::GetSysDirectory() + SHADERS_DIR DIR_SEP + sub_dir}}, - ".glsl"); - std::vector result; - for (std::string path : paths) - { - std::string name; - SplitPath(path, nullptr, &name, nullptr); - if (name == s_default_pixel_shader_name) - continue; - result.push_back(name); - } - return result; + // This tries to fall back on GPU HW sampling if it can (it won't be gamma corrected). + bool raw_resampling = resampling_method <= 0; + bool needs_rescaling = GetResolution() != GetWindowResolution(); + + bool needs_resampling = needs_rescaling && (OptionEnabled(hdr_output) || OptionEnabled(correct_gamma) || !raw_resampling); + + float4 color; + + if (needs_resampling) + { + // Doing linear sampling in "gamma space" on linear texture formats isn't correct. + // If the source and target resolutions don't match, the GPU will return a color + // that is the average of 4 gamma space colors, but gamma space colors can't be blended together, + // gamma needs to be de-applied first. This makes a big difference if colors change + // drastically between two pixels. + + color = LinearGammaCorrectedSample(game_gamma); + } + else + { + // Default GPU HW sampling. Bilinear is identical to Nearest Neighbor if the input and output resolutions match. + if (needs_rescaling) + color = texture(samp0, v_tex0); + else + color = texture(samp1, v_tex0); + + // Convert to linear before doing any other of follow up operations. + color.rgb = pow(color.rgb, float3(game_gamma)); + } + + if (OptionEnabled(correct_color_space)) + { + if (game_color_space == 0) + color.rgb = color.rgb * from_NTSCM; + else if (game_color_space == 1) + color.rgb = color.rgb * from_NTSCJ; + else if (game_color_space == 2) + color.rgb = color.rgb * from_PAL; + } + + if (OptionEnabled(hdr_output)) + { + float hdr_paper_white = hdr_paper_white_nits / hdr_sdr_white_nits; + color.rgb *= hdr_paper_white; + } + + if (OptionEnabled(linear_space_output)) + { + // Nothing to do here + } + // Correct the SDR gamma for sRGB (PC/Monitor) or ~2.2 (Common TV gamma) + else if (OptionEnabled(correct_gamma)) + { + if (OptionEnabled(sdr_display_gamma_sRGB)) + color.rgb = LinearTosRGBGamma(color.rgb); + else + color.rgb = pow(color.rgb, float3(1.0 / sdr_display_custom_gamma)); + } + // Restore the original gamma without changes + else + { + color.rgb = pow(color.rgb, float3(1.0 / game_gamma)); + } + + SetOutput(color); } -std::vector PostProcessing::GetShaderList() -{ - return GetShaders(); -} - -std::vector PostProcessing::GetAnaglyphShaderList() -{ - return GetShaders(ANAGLYPH_DIR DIR_SEP); -} - -std::vector PostProcessing::GetPassiveShaderList() -{ - return GetShaders(PASSIVE_DIR DIR_SEP); -} - -bool PostProcessing::Initialize(AbstractTextureFormat format) -{ - m_framebuffer_format = format; - // CompilePixelShader() must be run first if configuration options are used. - // Otherwise the UBO has a different member list between vertex and pixel - // shaders, which is a link error on some backends. - if (!CompilePixelShader() || !CompileVertexShader() || !CompilePipeline()) - return false; - - return true; -} - -void PostProcessing::RecompileShader() -{ - // Note: for simplicity we already recompile all the shaders - // and pipelines even if there might not be need to. - - m_default_pipeline.reset(); - m_pipeline.reset(); - m_default_pixel_shader.reset(); - m_pixel_shader.reset(); - m_default_vertex_shader.reset(); - m_vertex_shader.reset(); - if (!CompilePixelShader()) - return; - if (!CompileVertexShader()) - return; - - CompilePipeline(); -} - -void PostProcessing::RecompilePipeline() -{ - m_default_pipeline.reset(); - m_pipeline.reset(); - CompilePipeline(); -} - -bool PostProcessing::IsColorCorrectionActive() const -{ - // We can skip the color correction pass if none of these settings are on - // (it might have still helped with gamma correct sampling, but it's not worth running it). - return g_ActiveConfig.color_correction.bCorrectColorSpace || - g_ActiveConfig.color_correction.bCorrectGamma || - m_framebuffer_format == AbstractTextureFormat::RGBA16F; -} - -bool PostProcessing::NeedsIntermediaryBuffer() const -{ - // If we have no user selected post process shader, - // there's no point in having an intermediary buffer doing nothing. - return !m_config.GetShader().empty(); -} - -void PostProcessing::BlitFromTexture(const MathUtil::Rectangle& dst, - const MathUtil::Rectangle& src, - const AbstractTexture* src_tex, int src_layer) -{ - if (g_gfx->GetCurrentFramebuffer()->GetColorFormat() != m_framebuffer_format) - { - m_framebuffer_format = g_gfx->GetCurrentFramebuffer()->GetColorFormat(); - RecompilePipeline(); - } - - // By default all source layers will be copied into the respective target layers - const bool copy_all_layers = src_layer < 0; - src_layer = std::max(src_layer, 0); - - MathUtil::Rectangle src_rect = src; - g_gfx->SetSamplerState(0, RenderState::GetLinearSamplerState()); - g_gfx->SetSamplerState(1, RenderState::GetPointSamplerState()); - g_gfx->SetTexture(0, src_tex); - g_gfx->SetTexture(1, src_tex); - - const bool needs_color_correction = IsColorCorrectionActive(); - // Rely on the default (bi)linear sampler with the default mode - // (it might not be gamma corrected). - const bool needs_resampling = - g_ActiveConfig.output_resampling_mode > OutputResamplingMode::Default; - const bool needs_intermediary_buffer = NeedsIntermediaryBuffer(); - const bool needs_default_pipeline = needs_color_correction || needs_resampling; - const AbstractPipeline* final_pipeline = m_pipeline.get(); - std::vector* uniform_staging_buffer = &m_default_uniform_staging_buffer; - bool default_uniform_staging_buffer = true; - const MathUtil::Rectangle present_rect = g_presenter->GetTargetRectangle(); - - // Intermediary pass. - // We draw to a high quality intermediary texture for a couple reasons: - // -Consistently do high quality gamma corrected resampling (upscaling/downscaling) - // -Keep quality for gamma and gamut conversions, and HDR output - // (low bit depths lose too much quality with gamma conversions) - // -Keep the post process phase in linear space, to better operate with colors - if (m_default_pipeline && needs_default_pipeline && needs_intermediary_buffer) - { - AbstractFramebuffer* const previous_framebuffer = g_gfx->GetCurrentFramebuffer(); - - // We keep the min number of layers as the render target, - // as in case of OpenGL, the source FBX will have two layers, - // but we will render onto two separate frame buffers (one by one), - // so it would be a waste to allocate two layers (see "bUsesExplictQuadBuffering"). - const u32 target_layers = copy_all_layers ? src_tex->GetLayers() : 1; - - const u32 target_width = - needs_resampling ? present_rect.GetWidth() : static_cast(src_rect.GetWidth()); - const u32 target_height = - needs_resampling ? present_rect.GetHeight() : static_cast(src_rect.GetHeight()); - - if (!m_intermediary_frame_buffer || !m_intermediary_color_texture || - m_intermediary_color_texture->GetWidth() != target_width || - m_intermediary_color_texture->GetHeight() != target_height || - m_intermediary_color_texture->GetLayers() != target_layers) - { - const TextureConfig intermediary_color_texture_config( - target_width, target_height, 1, target_layers, src_tex->GetSamples(), - s_intermediary_buffer_format, AbstractTextureFlag_RenderTarget, - AbstractTextureType::Texture_2DArray); - m_intermediary_color_texture = g_gfx->CreateTexture(intermediary_color_texture_config, - "Intermediary post process texture"); - - m_intermediary_frame_buffer = - g_gfx->CreateFramebuffer(m_intermediary_color_texture.get(), nullptr); - } - - g_gfx->SetFramebuffer(m_intermediary_frame_buffer.get()); - - FillUniformBuffer(src_rect, src_tex, src_layer, g_gfx->GetCurrentFramebuffer()->GetRect(), - present_rect, uniform_staging_buffer->data(), !default_uniform_staging_buffer, - true); - g_vertex_manager->UploadUtilityUniforms(uniform_staging_buffer->data(), - static_cast(uniform_staging_buffer->size())); - - g_gfx->SetViewportAndScissor(g_gfx->ConvertFramebufferRectangle( - m_intermediary_color_texture->GetRect(), m_intermediary_frame_buffer.get())); - g_gfx->SetPipeline(m_default_pipeline.get()); - g_gfx->Draw(0, 3); - - g_gfx->SetFramebuffer(previous_framebuffer); - src_rect = m_intermediary_color_texture->GetRect(); - src_tex = m_intermediary_color_texture.get(); - g_gfx->SetTexture(0, src_tex); - g_gfx->SetTexture(1, src_tex); - // The "m_intermediary_color_texture" has already copied - // from the specified source layer onto its first one. - // If we query for a layer that the source texture doesn't have, - // it will fall back on the first one anyway. - src_layer = 0; - uniform_staging_buffer = &m_uniform_staging_buffer; - default_uniform_staging_buffer = false; - } - else - { - // If we have no custom user shader selected, and color correction - // is active, directly run the fixed pipeline shader instead of - // doing two passes, with the second one doing nothing useful. - if (m_default_pipeline && needs_default_pipeline) - { - final_pipeline = m_default_pipeline.get(); - } - else - { - uniform_staging_buffer = &m_uniform_staging_buffer; - default_uniform_staging_buffer = false; - } - - m_intermediary_frame_buffer.reset(); - m_intermediary_color_texture.reset(); - } - - // TODO: ideally we'd do the user selected post process pass in the intermediary buffer in linear - // space (instead of gamma space), so the shaders could act more accurately (and sample in linear - // space), though that would break the look of some of current post processes we have, and thus is - // better avoided for now. - - // Final pass, either a user selected shader or the default (fixed) shader. - if (final_pipeline) - { - FillUniformBuffer(src_rect, src_tex, src_layer, g_gfx->GetCurrentFramebuffer()->GetRect(), - present_rect, uniform_staging_buffer->data(), !default_uniform_staging_buffer, - false); - g_vertex_manager->UploadUtilityUniforms(uniform_staging_buffer->data(), - static_cast(uniform_staging_buffer->size())); - - g_gfx->SetViewportAndScissor( - g_gfx->ConvertFramebufferRectangle(dst, g_gfx->GetCurrentFramebuffer())); - g_gfx->SetPipeline(final_pipeline); - g_gfx->Draw(0, 3); - } -} - -std::string PostProcessing::GetUniformBufferHeader(bool user_post_process) const -{ - std::ostringstream ss; - u32 unused_counter = 1; - ss << "UBO_BINDING(std140, 1) uniform PSBlock {\n"; - - // Builtin uniforms: - - ss << " float4 resolution;\n"; // Source resolution - ss << " float4 target_resolution;\n"; - ss << " float4 window_resolution;\n"; - // How many horizontal and vertical stereo views do we have? (set to 1 when we use layers instead) - ss << " int2 stereo_views;\n"; - ss << " float4 src_rect;\n"; - // The first (but not necessarily only) source layer we target - ss << " int src_layer;\n"; - ss << " uint time;\n"; - ss << " int graphics_api;\n"; - // If true, it's an intermediary buffer (including the first), if false, it's the final one - ss << " int intermediary_buffer;\n"; - - ss << " int resampling_method;\n"; - ss << " int correct_color_space;\n"; - ss << " int game_color_space;\n"; - ss << " int correct_gamma;\n"; - ss << " float game_gamma;\n"; - ss << " int sdr_display_gamma_sRGB;\n"; - ss << " float sdr_display_custom_gamma;\n"; - ss << " int linear_space_output;\n"; - ss << " int hdr_output;\n"; - ss << " float hdr_paper_white_nits;\n"; - ss << " float hdr_sdr_white_nits;\n"; - - if (user_post_process) - { - ss << "\n"; - // Custom options/uniforms - for (const auto& it : m_config.GetOptions()) - { - if (it.second.m_type == PostProcessingConfiguration::ConfigurationOption::OptionType::Bool) - { - ss << fmt::format(" int {};\n", it.first); - for (u32 i = 0; i < 3; i++) - ss << " int ubo_align_" << unused_counter++ << "_;\n"; - } - else if (it.second.m_type == - PostProcessingConfiguration::ConfigurationOption::OptionType::Integer) - { - u32 count = static_cast(it.second.m_integer_values.size()); - if (count == 1) - ss << fmt::format(" int {};\n", it.first); - else - ss << fmt::format(" int{} {};\n", count, it.first); - - for (u32 i = count; i < 4; i++) - ss << " int ubo_align_" << unused_counter++ << "_;\n"; - } - else if (it.second.m_type == - PostProcessingConfiguration::ConfigurationOption::OptionType::Float) - { - u32 count = static_cast(it.second.m_float_values.size()); - if (count == 1) - ss << fmt::format(" float {};\n", it.first); - else - ss << fmt::format(" float{} {};\n", count, it.first); - - for (u32 i = count; i < 4; i++) - ss << " float ubo_align_" << unused_counter++ << "_;\n"; - } - } - } - - ss << "};\n\n"; - return ss.str(); -} - -std::string PostProcessing::GetHeader(bool user_post_process) const -{ - std::ostringstream ss; - ss << GetUniformBufferHeader(user_post_process); - ss << "SAMPLER_BINDING(0) uniform sampler2DArray samp0;\n"; - ss << "SAMPLER_BINDING(1) uniform sampler2DArray samp1;\n"; - - if (g_backend_info.bSupportsGeometryShaders) - { - ss << "VARYING_LOCATION(0) in VertexData {\n"; - ss << " float3 v_tex0;\n"; - ss << "};\n"; - } - else - { - ss << "VARYING_LOCATION(0) in float3 v_tex0;\n"; - } - - ss << "FRAGMENT_OUTPUT_LOCATION(0) out float4 ocol0;\n"; - - ss << R"( -float4 Sample() { return texture(samp0, v_tex0); } -float4 SampleLocation(float2 location) { return texture(samp0, float3(location, float(v_tex0.z))); } -float4 SampleLayer(int layer) { return texture(samp0, float3(v_tex0.xy, float(layer))); } -#define SampleOffset(offset) textureOffset(samp0, v_tex0, offset) - -float2 GetTargetResolution() -{ - return target_resolution.xy; -} - -float2 GetInvTargetResolution() -{ - return target_resolution.zw; -} - -float2 GetWindowResolution() -{ - return window_resolution.xy; -} - -float2 GetInvWindowResolution() -{ - return window_resolution.zw; -} - -float2 GetResolution() -{ - return resolution.xy; -} - -float2 GetInvResolution() -{ - return resolution.zw; -} - -float2 GetCoordinates() -{ - return v_tex0.xy; -} - -float GetLayer() -{ - return v_tex0.z; -} - -uint GetTime() -{ - return time; -} - -void SetOutput(float4 color) -{ - ocol0 = color; -} - -#define GetOption(x) (x) -#define OptionEnabled(x) ((x) != 0) -#define OptionDisabled(x) ((x) == 0) )"; - return ss.str(); -} -std::string PostProcessing::GetFooter() const +struct Uniforms { - return {}; -} - -static std::string GetVertexShaderBody() -{ - std::ostringstream ss; - if (g_backend_info.bSupportsGeometryShaders) - { - ss << "VARYING_LOCATION(0) out VertexData {\n"; - ss << " float3 v_tex0;\n"; - ss << "};\n"; - } - else - { - ss << "VARYING_LOCATION(0) out float3 v_tex0;\n"; - } - - ss << "#define id gl_VertexID\n"; - ss << "#define opos gl_Position\n"; - ss << "void main() {\n"; - ss << " v_tex0 = float3(float((id << 1) & 2), float(id & 2), 0.0f);\n"; - ss << " opos = float4(v_tex0.xy * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n"; - ss << " v_tex0 = float3(src_rect.xy + (src_rect.zw * v_tex0.xy), float(src_layer));\n"; - - // Vulkan Y needs to be inverted on every pass - if (g_backend_info.api_type == APIType::Vulkan) - { - ss << " opos.y = -opos.y;\n"; - } - // OpenGL Y needs to be inverted in all passes except the last one - else if (g_backend_info.api_type == APIType::OpenGL) - { - ss << " if (intermediary_buffer != 0)\n"; - ss << " opos.y = -opos.y;\n"; - } - - ss << "}\n"; - return ss.str(); -} - -bool PostProcessing::CompileVertexShader() -{ - std::ostringstream ss_default; - ss_default << GetUniformBufferHeader(false); - ss_default << GetVertexShaderBody(); - m_default_vertex_shader = g_gfx->CreateShaderFromSource( - ShaderStage::Vertex, ss_default.str(), nullptr, "Default post-processing vertex shader"); - - std::ostringstream ss; - ss << GetUniformBufferHeader(true); - ss << GetVertexShaderBody(); - m_vertex_shader = g_gfx->CreateShaderFromSource(ShaderStage::Vertex, ss.str(), nullptr, - "Post-processing vertex shader"); - - if (!m_default_vertex_shader || !m_vertex_shader) - { - PanicAlertFmt("Failed to compile post-processing vertex shader"); - m_default_vertex_shader.reset(); - m_vertex_shader.reset(); - return false; - } - - return true; -} - -struct BuiltinUniforms -{ - // bools need to be represented as "s32" - + // bools are s32 std::array source_resolution; std::array target_resolution; std::array window_resolution; @@ -858,211 +535,223 @@ struct BuiltinUniforms float hdr_sdr_white_nits; }; -size_t PostProcessing::CalculateUniformsSize(bool user_post_process) const +constexpr char s_uniform_block[] = R"(UBO_BINDING(std140, 1) uniform PSBlock { + float4 resolution; + float4 target_resolution; + float4 window_resolution; + int2 stereo_views; + float4 src_rect; + int src_layer; + uint time; + int graphics_api; + int intermediary_buffer; + int resampling_method; + int correct_color_space; + int game_color_space; + int correct_gamma; + float game_gamma; + int sdr_display_gamma_sRGB; + float sdr_display_custom_gamma; + int linear_space_output; + int hdr_output; + float hdr_paper_white_nits; + float hdr_sdr_white_nits; +}; + +)"; + +constexpr char s_pixel_header[] = R"(SAMPLER_BINDING(0) uniform sampler2DArray samp0; +SAMPLER_BINDING(1) uniform sampler2DArray samp1; +FRAGMENT_OUTPUT_LOCATION(0) out float4 ocol0; + +float4 Sample() { return texture(samp0, v_tex0); } +float2 GetWindowResolution() { return window_resolution.xy; } +float2 GetInvWindowResolution() { return window_resolution.zw; } +float2 GetResolution() { return resolution.xy; } +float2 GetInvResolution() { return resolution.zw; } +void SetOutput(float4 color) { ocol0 = color; } + +#define OptionEnabled(x) ((x) != 0) + +)"; + +std::string PixelShaderSource(const char* body) { - // Allocate a vec4 for each uniform to simplify allocation. - return sizeof(BuiltinUniforms) + - (user_post_process ? m_config.GetOptions().size() : 0) * sizeof(float) * 4; + std::string source = s_uniform_block; + if (g_backend_info.bSupportsGeometryShaders) + source += "VARYING_LOCATION(0) in VertexData {\n float3 v_tex0;\n};\n"; + else + source += "VARYING_LOCATION(0) in float3 v_tex0;\n"; + source += s_pixel_header; + source += body; + return source; +} + +std::string VertexShaderSource() +{ + std::string source = s_uniform_block; + if (g_backend_info.bSupportsGeometryShaders) + source += "VARYING_LOCATION(0) out VertexData {\n float3 v_tex0;\n};\n"; + else + source += "VARYING_LOCATION(0) out float3 v_tex0;\n"; + source += R"(void main() { + v_tex0 = float3(float((gl_VertexID << 1) & 2), float(gl_VertexID & 2), 0.0f); + gl_Position = float4(v_tex0.xy * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0.0f, 1.0f); + v_tex0 = float3(src_rect.xy + (src_rect.zw * v_tex0.xy), float(src_layer)); +)"; + // Vulkan's Y axis points down + if (g_backend_info.api_type == APIType::Vulkan) + source += " gl_Position.y = -gl_Position.y;\n"; + source += "}\n"; + return source; +} +} // namespace + +PostProcessing::PostProcessing() = default; +PostProcessing::~PostProcessing() = default; + +bool PostProcessing::Initialize(AbstractTextureFormat format) +{ + m_framebuffer_format = format; + m_uniform_staging_buffer.resize(sizeof(Uniforms)); + return CompileShaders() && CompilePipelines(); +} + +void PostProcessing::RecompilePipeline() +{ + m_copy_pipeline.reset(); + m_correction_pipeline.reset(); + CompilePipelines(); +} + +bool PostProcessing::IsColorCorrectionActive() const +{ + return g_ActiveConfig.color_correction.bCorrectColorSpace || + g_ActiveConfig.color_correction.bCorrectGamma || + m_framebuffer_format == AbstractTextureFormat::RGBA16F; +} + +void PostProcessing::BlitFromTexture(const MathUtil::Rectangle& dst, + const MathUtil::Rectangle& src, + const AbstractTexture* src_tex, int src_layer) +{ + if (g_gfx->GetCurrentFramebuffer()->GetColorFormat() != m_framebuffer_format) + { + m_framebuffer_format = g_gfx->GetCurrentFramebuffer()->GetColorFormat(); + RecompilePipeline(); + } + + // The default bilinear sampler covers Default resampling; anything else, and colour + // correction or HDR, takes the correction shader. + const bool needs_correction = + IsColorCorrectionActive() || + g_ActiveConfig.output_resampling_mode > OutputResamplingMode::Default; + const AbstractPipeline* pipeline = + needs_correction && m_correction_pipeline ? m_correction_pipeline.get() : + m_copy_pipeline.get(); + if (!pipeline) + return; + + g_gfx->SetSamplerState(0, RenderState::GetLinearSamplerState()); + g_gfx->SetSamplerState(1, RenderState::GetPointSamplerState()); + g_gfx->SetTexture(0, src_tex); + g_gfx->SetTexture(1, src_tex); + + FillUniformBuffer(src, src_tex, std::max(src_layer, 0), g_gfx->GetCurrentFramebuffer()->GetRect(), + g_presenter->GetTargetRectangle()); + g_vertex_manager->UploadUtilityUniforms(m_uniform_staging_buffer.data(), + static_cast(m_uniform_staging_buffer.size())); + + g_gfx->SetViewportAndScissor( + g_gfx->ConvertFramebufferRectangle(dst, g_gfx->GetCurrentFramebuffer())); + g_gfx->SetPipeline(pipeline); + g_gfx->Draw(0, 3); +} + +bool PostProcessing::CompileShaders() +{ + m_vertex_shader = g_gfx->CreateShaderFromSource(ShaderStage::Vertex, VertexShaderSource(), + nullptr, "Present vertex shader"); + m_copy_pixel_shader = g_gfx->CreateShaderFromSource( + ShaderStage::Pixel, PixelShaderSource(s_copy_pixel_shader), nullptr, + "Present copy pixel shader"); + // Optional: without it the output is copied uncorrected. + m_correction_pixel_shader = g_gfx->CreateShaderFromSource( + ShaderStage::Pixel, PixelShaderSource(s_correction_pixel_shader), nullptr, + "Present correction pixel shader"); + + if (!m_vertex_shader || !m_copy_pixel_shader) + { + PanicAlertFmt("Failed to compile the presentation shaders"); + return false; + } + return true; +} + +bool PostProcessing::CompilePipelines() +{ + // Some backends refuse pipelines with no targets; nothing is drawn then anyway. + if (m_framebuffer_format == AbstractTextureFormat::Undefined) + return true; + + AbstractPipelineConfig config = {}; + config.vertex_shader = m_vertex_shader.get(); + config.rasterization_state = RenderState::GetNoCullRasterizationState(PrimitiveType::Triangles); + config.depth_state = RenderState::GetNoDepthTestingDepthState(); + config.blending_state = RenderState::GetNoBlendingBlendState(); + config.framebuffer_state = RenderState::GetColorFramebufferState(m_framebuffer_format); + config.usage = AbstractPipelineUsage::Utility; + + if (m_correction_pixel_shader) + { + config.pixel_shader = m_correction_pixel_shader.get(); + m_correction_pipeline = g_gfx->CreatePipeline(config); + } + + config.pixel_shader = m_copy_pixel_shader.get(); + m_copy_pipeline = g_gfx->CreatePipeline(config); + return m_copy_pipeline != nullptr; } void PostProcessing::FillUniformBuffer(const MathUtil::Rectangle& src, const AbstractTexture* src_tex, int src_layer, const MathUtil::Rectangle& dst, - const MathUtil::Rectangle& wnd, u8* buffer, - bool user_post_process, bool intermediary_buffer) + const MathUtil::Rectangle& wnd) { const float rcp_src_width = 1.0f / src_tex->GetWidth(); const float rcp_src_height = 1.0f / src_tex->GetHeight(); + const auto& cc = g_ActiveConfig.color_correction; + const bool hdr = m_framebuffer_format == AbstractTextureFormat::RGBA16F; - BuiltinUniforms builtin_uniforms; - builtin_uniforms.source_resolution = {static_cast(src_tex->GetWidth()), - static_cast(src_tex->GetHeight()), rcp_src_width, - rcp_src_height}; - builtin_uniforms.target_resolution = { - static_cast(dst.GetWidth()), static_cast(dst.GetHeight()), - 1.0f / static_cast(dst.GetWidth()), 1.0f / static_cast(dst.GetHeight())}; - builtin_uniforms.window_resolution = { - static_cast(wnd.GetWidth()), static_cast(wnd.GetHeight()), - 1.0f / static_cast(wnd.GetWidth()), 1.0f / static_cast(wnd.GetHeight())}; - builtin_uniforms.src_rect = {static_cast(src.left) * rcp_src_width, - static_cast(src.top) * rcp_src_height, - static_cast(src.GetWidth()) * rcp_src_width, - static_cast(src.GetHeight()) * rcp_src_height}; - builtin_uniforms.src_layer = static_cast(src_layer); - builtin_uniforms.time = static_cast(m_timer.ElapsedMs()); - builtin_uniforms.graphics_api = static_cast(g_backend_info.api_type); - builtin_uniforms.intermediary_buffer = static_cast(intermediary_buffer); + Uniforms u = {}; + u.source_resolution = {static_cast(src_tex->GetWidth()), + static_cast(src_tex->GetHeight()), rcp_src_width, rcp_src_height}; + u.target_resolution = {static_cast(dst.GetWidth()), static_cast(dst.GetHeight()), + 1.0f / static_cast(dst.GetWidth()), + 1.0f / static_cast(dst.GetHeight())}; + u.window_resolution = {static_cast(wnd.GetWidth()), static_cast(wnd.GetHeight()), + 1.0f / static_cast(wnd.GetWidth()), + 1.0f / static_cast(wnd.GetHeight())}; + u.src_rect = {static_cast(src.left) * rcp_src_width, + static_cast(src.top) * rcp_src_height, + static_cast(src.GetWidth()) * rcp_src_width, + static_cast(src.GetHeight()) * rcp_src_height}; + u.src_layer = src_layer; + u.graphics_api = static_cast(g_backend_info.api_type); + u.resampling_method = static_cast(g_ActiveConfig.output_resampling_mode); + u.correct_color_space = cc.bCorrectColorSpace; + u.game_color_space = static_cast(cc.game_color_space); + u.correct_gamma = cc.bCorrectGamma; + u.game_gamma = cc.fGameGamma; + u.sdr_display_gamma_sRGB = cc.bSDRDisplayGammaSRGB; + u.sdr_display_custom_gamma = cc.fSDRDisplayCustomGamma; + // scRGB (RGBA16F) takes linear values, which may leave the 0-1 range + u.linear_space_output = hdr; + u.hdr_output = hdr; + u.hdr_paper_white_nits = cc.fHDRPaperWhiteNits; + // 1.0 is about 80 nits in HDR + u.hdr_sdr_white_nits = 80.f; - builtin_uniforms.resampling_method = static_cast(g_ActiveConfig.output_resampling_mode); - // Color correction related uniforms. - // These are mainly used by the "m_default_pixel_shader", - // but should also be accessible to all other shaders. - builtin_uniforms.correct_color_space = g_ActiveConfig.color_correction.bCorrectColorSpace; - builtin_uniforms.game_color_space = - static_cast(g_ActiveConfig.color_correction.game_color_space); - builtin_uniforms.correct_gamma = g_ActiveConfig.color_correction.bCorrectGamma; - builtin_uniforms.game_gamma = g_ActiveConfig.color_correction.fGameGamma; - builtin_uniforms.sdr_display_gamma_sRGB = g_ActiveConfig.color_correction.bSDRDisplayGammaSRGB; - builtin_uniforms.sdr_display_custom_gamma = - g_ActiveConfig.color_correction.fSDRDisplayCustomGamma; - // scRGB (RGBA16F) expects linear values as opposed to sRGB gamma - builtin_uniforms.linear_space_output = m_framebuffer_format == AbstractTextureFormat::RGBA16F; - // Implies output values can be beyond the 0-1 range - builtin_uniforms.hdr_output = m_framebuffer_format == AbstractTextureFormat::RGBA16F; - builtin_uniforms.hdr_paper_white_nits = g_ActiveConfig.color_correction.fHDRPaperWhiteNits; - // A value of 1 1 1 usually matches 80 nits in HDR - builtin_uniforms.hdr_sdr_white_nits = 80.f; - - std::memcpy(buffer, &builtin_uniforms, sizeof(builtin_uniforms)); - buffer += sizeof(builtin_uniforms); - - // Don't include the custom pp shader options if they are not necessary, - // having mismatching uniforms between different shaders can cause issues on some backends - if (!user_post_process) - return; - - for (auto& it : m_config.GetOptions()) - { - union - { - u32 as_bool[4]; - s32 as_int[4]; - float as_float[4]; - } value = {}; - - switch (it.second.m_type) - { - case PostProcessingConfiguration::ConfigurationOption::OptionType::Bool: - value.as_bool[0] = it.second.m_bool_value ? 1 : 0; - break; - - case PostProcessingConfiguration::ConfigurationOption::OptionType::Integer: - ASSERT(it.second.m_integer_values.size() <= 4); - std::copy_n(it.second.m_integer_values.begin(), it.second.m_integer_values.size(), - value.as_int); - break; - - case PostProcessingConfiguration::ConfigurationOption::OptionType::Float: - ASSERT(it.second.m_float_values.size() <= 4); - std::copy_n(it.second.m_float_values.begin(), it.second.m_float_values.size(), - value.as_float); - break; - } - - it.second.m_dirty = false; - - std::memcpy(buffer, &value, sizeof(value)); - buffer += sizeof(value); - } - - m_config.SetDirty(false); -} - -bool PostProcessing::CompilePixelShader() -{ - m_default_pixel_shader.reset(); - m_pixel_shader.reset(); - - // Generate GLSL and compile the new shaders: - - std::string default_pixel_shader_code; - if (LoadShaderFromFile(s_default_pixel_shader_name, "", default_pixel_shader_code)) - { - m_default_pixel_shader = g_gfx->CreateShaderFromSource( - ShaderStage::Pixel, GetHeader(false) + default_pixel_shader_code + GetFooter(), nullptr, - "Default post-processing pixel shader"); - // We continue even if all of this failed, it doesn't matter - m_default_uniform_staging_buffer.resize(CalculateUniformsSize(false)); - } - else - { - m_default_uniform_staging_buffer.resize(0); - } - - m_config.LoadShader(g_ActiveConfig.sPostProcessingShader); - m_pixel_shader = g_gfx->CreateShaderFromSource( - ShaderStage::Pixel, GetHeader(true) + m_config.GetShaderCode() + GetFooter(), - m_config.GetShaderIncluder(), - fmt::format("User post-processing pixel shader: {}", m_config.GetShader())); - if (!m_pixel_shader) - { - PanicAlertFmt("Failed to compile user post-processing shader {}", m_config.GetShader()); - - // Use default shader. - m_config.LoadDefaultShader(); - m_pixel_shader = g_gfx->CreateShaderFromSource( - ShaderStage::Pixel, GetHeader(true) + m_config.GetShaderCode() + GetFooter(), nullptr, - "Default user post-processing pixel shader"); - if (!m_pixel_shader) - { - m_uniform_staging_buffer.resize(0); - return false; - } - } - - m_uniform_staging_buffer.resize(CalculateUniformsSize(true)); - return true; -} - -static bool UseGeometryShaderForPostProcess(bool is_intermediary_buffer) -{ - // We only return true on stereo modes that need to copy - // both source texture layers into the target texture layers. - // Any other case is handled manually with multiple copies, thus - // it doesn't need a geom shader. - switch (g_ActiveConfig.stereo_mode) - { - case StereoMode::QuadBuffer: - return !g_backend_info.bUsesExplictQuadBuffering; - case StereoMode::Anaglyph: - case StereoMode::Passive: - return is_intermediary_buffer; - case StereoMode::SideBySide: - case StereoMode::TopAndBottom: - case StereoMode::Off: - default: - return false; - } -} - -bool PostProcessing::CompilePipeline() -{ - // Not needed. Some backends don't like making pipelines with no targets, - // and in any case, we don't need to render anything if that happened. - if (m_framebuffer_format == AbstractTextureFormat::Undefined) - return true; - - // If this is true, the "m_default_pipeline" won't be the only one that runs - const bool needs_intermediary_buffer = NeedsIntermediaryBuffer(); - - AbstractPipelineConfig config = {}; - config.vertex_shader = m_default_vertex_shader.get(); - // This geometry shader will take care of reading both layer 0 and 1 on the source texture, - // and writing to both layer 0 and 1 on the render target. - config.geometry_shader = UseGeometryShaderForPostProcess(needs_intermediary_buffer) ? - g_shader_cache->GetTexcoordGeometryShader() : - nullptr; - config.pixel_shader = m_default_pixel_shader.get(); - config.rasterization_state = RenderState::GetNoCullRasterizationState(PrimitiveType::Triangles); - config.depth_state = RenderState::GetNoDepthTestingDepthState(); - config.blending_state = RenderState::GetNoBlendingBlendState(); - config.framebuffer_state = RenderState::GetColorFramebufferState( - needs_intermediary_buffer ? s_intermediary_buffer_format : m_framebuffer_format); - config.usage = AbstractPipelineUsage::Utility; - // We continue even if it failed, it will be skipped later on - if (config.pixel_shader) - m_default_pipeline = g_gfx->CreatePipeline(config); - - config.vertex_shader = m_vertex_shader.get(); - config.geometry_shader = UseGeometryShaderForPostProcess(false) ? - g_shader_cache->GetTexcoordGeometryShader() : - nullptr; - config.pixel_shader = m_pixel_shader.get(); - config.framebuffer_state = RenderState::GetColorFramebufferState(m_framebuffer_format); - m_pipeline = g_gfx->CreatePipeline(config); - if (!m_pipeline) - return false; - - return true; + std::memcpy(m_uniform_staging_buffer.data(), &u, sizeof(u)); } } // namespace VideoCommon diff --git a/Source/Core/VideoCommon/PostProcessing.h b/Source/Core/VideoCommon/PostProcessing.h index 30a0cac2c2..503fa07542 100644 --- a/Source/Core/VideoCommon/PostProcessing.h +++ b/Source/Core/VideoCommon/PostProcessing.h @@ -3,150 +3,46 @@ #pragma once -#include #include -#include #include #include "Common/CommonTypes.h" #include "Common/MathUtil.h" -#include "Common/Timer.h" #include "VideoCommon/TextureConfig.h" class AbstractPipeline; class AbstractShader; class AbstractTexture; -class AbstractFramebuffer; namespace VideoCommon { -class ShaderIncluder; - -class PostProcessingConfiguration -{ -public: - // User defined post process - struct ConfigurationOption - { - enum class OptionType - { - Bool = 0, - Float, - Integer, - }; - - bool m_bool_value = false; - - std::vector m_float_values; - std::vector m_integer_values; - - std::vector m_float_min_values; - std::vector m_integer_min_values; - - std::vector m_float_max_values; - std::vector m_integer_max_values; - - std::vector m_float_step_values; - std::vector m_integer_step_values; - - OptionType m_type = OptionType::Bool; - - std::string m_gui_name; - std::string m_option_name; - std::string m_dependent_option; - bool m_dirty = false; - }; - - using ConfigMap = std::map; - - PostProcessingConfiguration(); - virtual ~PostProcessingConfiguration(); - - // Loads the configuration with a shader - // If the argument is "" the class will load the shader from the g_activeConfig option. - // Returns the loaded shader source from file - void LoadShader(const std::string& shader); - void LoadDefaultShader(); - void SaveOptionsConfiguration(); - const std::string& GetShader() const { return m_current_shader; } - const std::string& GetShaderCode() const { return m_current_shader_code; } - ShaderIncluder* GetShaderIncluder() { return m_shader_includer.get(); } - bool IsDirty() const { return m_any_options_dirty; } - void SetDirty(bool dirty) { m_any_options_dirty = dirty; } - bool HasOptions() const { return m_options.size() > 0; } - const ConfigMap& GetOptions() const { return m_options; } - ConfigMap& GetOptions() { return m_options; } - const ConfigurationOption& GetOption(const std::string& option) { return m_options[option]; } - // For updating option's values - void SetOptionf(const std::string& option, int index, float value); - void SetOptioni(const std::string& option, int index, s32 value); - void SetOptionb(const std::string& option, bool value); - -private: - bool m_any_options_dirty = false; - std::unique_ptr m_shader_includer; - std::string m_current_shader; - std::string m_current_shader_code; - ConfigMap m_options; - - void LoadOptions(const std::string& code); - void LoadOptionsConfiguration(); -}; - +// The final pass from the XFB to the output: a plain copy, or, when the output is resampled, +// colour corrected or HDR, the built-in correction shader. class PostProcessing { public: PostProcessing(); - virtual ~PostProcessing(); - - static std::vector GetShaderList(); - static std::vector GetPassiveShaderList(); - static std::vector GetAnaglyphShaderList(); - - PostProcessingConfiguration* GetConfig() { return &m_config; } + ~PostProcessing(); bool Initialize(AbstractTextureFormat format); - - void RecompileShader(); void RecompilePipeline(); void BlitFromTexture(const MathUtil::Rectangle& dst, const MathUtil::Rectangle& src, const AbstractTexture* src_tex, int src_layer = -1); +private: bool IsColorCorrectionActive() const; - bool NeedsIntermediaryBuffer() const; - -protected: - std::string GetUniformBufferHeader(bool user_post_process) const; - std::string GetHeader(bool user_post_process) const; - std::string GetFooter() const; - - bool CompileVertexShader(); - bool CompilePixelShader(); - bool CompilePipeline(); - - size_t CalculateUniformsSize(bool user_post_process) const; + bool CompileShaders(); + bool CompilePipelines(); void FillUniformBuffer(const MathUtil::Rectangle& src, const AbstractTexture* src_tex, int src_layer, const MathUtil::Rectangle& dst, - const MathUtil::Rectangle& wnd, u8* buffer, bool user_post_process, - bool intermediary_buffer); + const MathUtil::Rectangle& wnd); - // Timer for determining our time value - Common::Timer m_timer; - - // Dolphin fixed post process: - PostProcessingConfiguration::ConfigMap m_default_options; - std::unique_ptr m_default_vertex_shader; - std::unique_ptr m_default_pixel_shader; - std::unique_ptr m_default_pipeline; - std::unique_ptr m_intermediary_frame_buffer; - std::unique_ptr m_intermediary_color_texture; - std::vector m_default_uniform_staging_buffer; - // User post process: - PostProcessingConfiguration m_config; std::unique_ptr m_vertex_shader; - std::unique_ptr m_pixel_shader; - std::unique_ptr m_pipeline; + std::unique_ptr m_copy_pixel_shader; + std::unique_ptr m_correction_pixel_shader; + std::unique_ptr m_copy_pipeline; + std::unique_ptr m_correction_pipeline; std::vector m_uniform_staging_buffer; AbstractTextureFormat m_framebuffer_format = AbstractTextureFormat::Undefined; diff --git a/Source/Core/VideoCommon/Present.cpp b/Source/Core/VideoCommon/Present.cpp index 9989001539..9ffca16f09 100644 --- a/Source/Core/VideoCommon/Present.cpp +++ b/Source/Core/VideoCommon/Present.cpp @@ -395,16 +395,6 @@ void Presenter::OnBackbufferSet(bool size_changed, bool is_first_set) void Presenter::ConfigChanged(u32 changed_bits) { - // Check for post-processing shader changes. Done up here as it doesn't affect anything outside - // the post-processor. Note that options are applied every frame, so no need to check those. - if (changed_bits & ConfigChangeBits::CONFIG_CHANGE_BIT_POST_PROCESSING_SHADER && m_post_processor) - { - // The existing shader must not be in use when it's destroyed - g_gfx->WaitForGPUIdle(); - - m_post_processor->RecompileShader(); - } - // Stereo mode change requires recompiling our post processing pipeline and imgui pipelines for // rendering the UI. if (changed_bits & ConfigChangeBits::CONFIG_CHANGE_BIT_STEREO_MODE) diff --git a/Source/Core/VideoCommon/Resources/CustomResourceManager.cpp b/Source/Core/VideoCommon/Resources/CustomResourceManager.cpp index acc9bb92cf..82b2f49da0 100644 --- a/Source/Core/VideoCommon/Resources/CustomResourceManager.cpp +++ b/Source/Core/VideoCommon/Resources/CustomResourceManager.cpp @@ -3,77 +3,39 @@ #include "VideoCommon/Resources/CustomResourceManager.h" -#include "VideoCommon/AbstractGfx.h" -#include "VideoCommon/PipelineUtils.h" -#include "VideoCommon/Resources/InvalidTextures.h" #include "VideoCommon/VideoEvents.h" namespace VideoCommon { void CustomResourceManager::Initialize() { -#if defined(__LIBRETRO__) && defined(SKIP_RESOURCE_WORKER_THREAD) +#if defined(SKIP_RESOURCE_WORKER_THREAD) return; #endif m_asset_cache.Initialize(); m_worker_thread.Reset("resource-worker"); - m_host_config.bits = ShaderHostConfig::GetCurrent().bits; - m_async_shader_compiler = g_gfx->CreateAsyncShaderCompiler(); - - m_async_shader_compiler->StartWorkerThreads(1); // TODO expose to config m_xfb_event = GetVideoEvents().after_frame_event.Register([this](Core::System&) { XFBTriggered(); }); - - m_invalid_array_texture = CreateInvalidArrayTexture(); - m_invalid_color_texture = CreateInvalidColorTexture(); - m_invalid_cubemap_texture = CreateInvalidCubemapTexture(); - m_invalid_transparent_texture = CreateInvalidTransparentTexture(); } void CustomResourceManager::Shutdown() { - if (m_async_shader_compiler) - { - m_async_shader_compiler->StopWorkerThreads(); - m_async_shader_compiler->ClearAllWork(); - } - m_asset_cache.Shutdown(); m_worker_thread.Shutdown(); -#ifdef __LIBRETRO__ Reset(true); -#else - Reset(); -#endif } -#ifdef __LIBRETRO__ -void CustomResourceManager::Reset(bool isShutdown) -#else -void CustomResourceManager::Reset() -#endif +void CustomResourceManager::Reset(bool is_shutdown) { - m_draw_material_resources.clear(); - m_postprocessing_material_resources.clear(); - m_shader_resources.clear(); m_texture_data_resources.clear(); - m_texture_sampler_resources.clear(); - - m_invalid_transparent_texture.reset(); - m_invalid_color_texture.reset(); - m_invalid_cubemap_texture.reset(); - m_invalid_array_texture.reset(); m_asset_cache.Reset(); - m_texture_pool.Reset(); -#ifdef __LIBRETRO__ - if (isShutdown) + if (is_shutdown) m_worker_thread.Shutdown(); else -#endif - m_worker_thread.Reset("resource-worker"); + m_worker_thread.Reset("resource-worker"); } void CustomResourceManager::MarkAssetDirty(const CustomAssetLibrary::AssetID& asset_id) @@ -86,26 +48,6 @@ void CustomResourceManager::XFBTriggered() m_asset_cache.Update(); } -void CustomResourceManager::SetHostConfig(const ShaderHostConfig& host_config) -{ - for (auto& [id, shader_resources] : m_shader_resources) - { - for (auto& [key, shader_resource] : shader_resources) - { - shader_resource->SetHostConfig(host_config); - - // Hack to get access to resource internals - Resource* resource = shader_resource.get(); - - // Tell shader and references to trigger a reload - // on next usage - resource->NotifyAssetChanged(false); - } - } - - m_host_config.bits = host_config.bits; -} - TextureDataResource* CustomResourceManager::GetTextureDataFromAsset( const CustomAssetLibrary::AssetID& asset_id, std::shared_ptr library) @@ -120,77 +62,11 @@ TextureDataResource* CustomResourceManager::GetTextureDataFromAsset( return resource.get(); } -MaterialResource* CustomResourceManager::GetDrawMaterialFromAsset( - const CustomAssetLibrary::AssetID& asset_id, const GXPipelineUid& pipeline_uid, - std::shared_ptr library) -{ - auto& resource = m_draw_material_resources[asset_id][PipelineToHash(pipeline_uid)]; - if (resource == nullptr) - { - resource = std::make_unique( - CreateResourceContext(asset_id, std::move(library)), pipeline_uid); - } - resource->Process(); - return resource.get(); -} - -MaterialResource* CustomResourceManager::GetPostProcessingMaterialFromAsset( - const CustomAssetLibrary::AssetID& asset_id, - std::shared_ptr library) -{ - auto& resource = m_postprocessing_material_resources[asset_id]; - if (resource == nullptr) - { - resource = - std::make_unique(CreateResourceContext(asset_id, std::move(library))); - } - resource->Process(); - return resource.get(); -} - -ShaderResource* CustomResourceManager::GetShaderFromAsset( - const CustomAssetLibrary::AssetID& asset_id, std::size_t shader_key, - const std::optional& pipeline_uid, const std::string& preprocessor_settings, - std::shared_ptr library) -{ - auto& resource = m_shader_resources[asset_id][shader_key]; - if (resource == nullptr) - { - resource = std::make_unique(CreateResourceContext(asset_id, std::move(library)), - pipeline_uid, preprocessor_settings, m_host_config); - } - resource->Process(); - return resource.get(); -} - -TextureAndSamplerResource* CustomResourceManager::GetTextureAndSamplerFromAsset( - const CustomAssetLibrary::AssetID& asset_id, - std::shared_ptr library) -{ - auto& resource = m_texture_sampler_resources[asset_id]; - if (resource == nullptr) - { - resource = std::make_unique( - CreateResourceContext(asset_id, std::move(library))); - } - resource->Process(); - return resource.get(); -} - Resource::ResourceContext CustomResourceManager::CreateResourceContext( const CustomAssetLibrary::AssetID& asset_id, std::shared_ptr library) { - return Resource::ResourceContext{asset_id, - std::move(library), - &m_asset_cache, - this, - &m_texture_pool, - &m_worker_thread, - m_async_shader_compiler.get(), - m_invalid_array_texture.get(), - m_invalid_color_texture.get(), - m_invalid_cubemap_texture.get(), - m_invalid_transparent_texture.get()}; + return Resource::ResourceContext{asset_id, std::move(library), &m_asset_cache, this, + &m_worker_thread}; } } // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/CustomResourceManager.h b/Source/Core/VideoCommon/Resources/CustomResourceManager.h index bcd7a0ba91..c974ff2dd4 100644 --- a/Source/Core/VideoCommon/Resources/CustomResourceManager.h +++ b/Source/Core/VideoCommon/Resources/CustomResourceManager.h @@ -9,14 +9,8 @@ #include "Common/HookableEvent.h" #include "Common/WorkQueueThread.h" -#include "VideoCommon/AbstractTexture.h" #include "VideoCommon/Assets/CustomAssetCache.h" -#include "VideoCommon/AsyncShaderCompiler.h" -#include "VideoCommon/Resources/MaterialResource.h" -#include "VideoCommon/Resources/ShaderResource.h" -#include "VideoCommon/Resources/TextureAndSamplerResource.h" #include "VideoCommon/Resources/TextureDataResource.h" -#include "VideoCommon/Resources/TexturePool.h" namespace VideoCommon { @@ -25,71 +19,27 @@ class CustomResourceManager public: void Initialize(); void Shutdown(); - -#ifdef __LIBRETRO__ - void Reset(bool isShutdown = false); -#else - void Reset(); -#endif + void Reset(bool is_shutdown = false); // Request that an asset be reloaded void MarkAssetDirty(const CustomAssetLibrary::AssetID& asset_id); void XFBTriggered(); - void SetHostConfig(const ShaderHostConfig& host_config); TextureDataResource* GetTextureDataFromAsset(const CustomAssetLibrary::AssetID& asset_id, std::shared_ptr library); - MaterialResource* - GetDrawMaterialFromAsset(const CustomAssetLibrary::AssetID& asset_id, - const GXPipelineUid& pipeline_uid, - std::shared_ptr library); - MaterialResource* - GetPostProcessingMaterialFromAsset(const CustomAssetLibrary::AssetID& asset_id, - std::shared_ptr library); - - ShaderResource* GetShaderFromAsset(const CustomAssetLibrary::AssetID& asset_id, - std::size_t shader_key, - const std::optional& pipeline_uid, - const std::string& preprocessor_settings, - std::shared_ptr library); - - TextureAndSamplerResource* - GetTextureAndSamplerFromAsset(const CustomAssetLibrary::AssetID& asset_id, - std::shared_ptr library); private: Resource::ResourceContext CreateResourceContext(const CustomAssetLibrary::AssetID& asset_id, std::shared_ptr library); CustomAssetCache m_asset_cache; - TexturePool m_texture_pool; Common::AsyncWorkThreadSP m_worker_thread; - std::unique_ptr m_async_shader_compiler; - - using PipelineIdToMaterial = std::map>; - std::map m_draw_material_resources; - - using ShaderKeyToShader = std::map>; - std::map m_shader_resources; std::map> m_texture_data_resources; - std::map> - m_texture_sampler_resources; - - std::map> - m_postprocessing_material_resources; - - ShaderHostConfig m_host_config; - Common::EventHook m_xfb_event; - - std::unique_ptr m_invalid_transparent_texture; - std::unique_ptr m_invalid_color_texture; - std::unique_ptr m_invalid_cubemap_texture; - std::unique_ptr m_invalid_array_texture; }; } // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/InvalidTextures.cpp b/Source/Core/VideoCommon/Resources/InvalidTextures.cpp deleted file mode 100644 index b27630660e..0000000000 --- a/Source/Core/VideoCommon/Resources/InvalidTextures.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2025 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "VideoCommon/Resources/InvalidTextures.h" - -#include "VideoCommon/AbstractGfx.h" -#include "VideoCommon/TextureConfig.h" - -namespace VideoCommon -{ -std::unique_ptr CreateInvalidTransparentTexture() -{ - const TextureConfig tex_config{ - 1, 1, 1, 1, 1, AbstractTextureFormat::RGBA8, 0, AbstractTextureType::Texture_2D}; - auto texture = g_gfx->CreateTexture(tex_config, "Invalid Transparent Texture"); - const std::array pixel{0, 0, 0, 0}; - texture->Load(0, 1, 1, 1, pixel.data(), pixel.size()); - return texture; -} - -std::unique_ptr CreateInvalidColorTexture() -{ - const TextureConfig tex_config{ - 1, 1, 1, 1, 1, AbstractTextureFormat::RGBA8, 0, AbstractTextureType::Texture_2D}; - auto texture = g_gfx->CreateTexture(tex_config, "Invalid Color Texture"); - const std::array pixel{255, 0, 255, 255}; - texture->Load(0, 1, 1, 1, pixel.data(), pixel.size()); - return texture; -} - -std::unique_ptr CreateInvalidCubemapTexture() -{ -#ifdef __APPLE__ - // TODO: figure out cube map oddness on Apple (specifically Metal) - return nullptr; -#else - const TextureConfig tex_config{ - 1, 1, 1, 6, 1, AbstractTextureFormat::RGBA8, 0, AbstractTextureType::Texture_CubeMap}; - auto texture = g_gfx->CreateTexture(tex_config, "Invalid Cubemap Texture"); - const std::array pixel{255, 0, 255, 255}; - for (u32 i = 0; i < tex_config.layers; i++) - { - texture->Load(0, tex_config.width, tex_config.height, 1, pixel.data(), pixel.size(), i); - } - return texture; -#endif -} - -std::unique_ptr CreateInvalidArrayTexture() -{ - const TextureConfig tex_config{ - 1, 1, 1, 1, 1, AbstractTextureFormat::RGBA8, 0, AbstractTextureType::Texture_2DArray}; - auto texture = g_gfx->CreateTexture(tex_config, "Invalid Array Texture"); - const std::array pixel{255, 0, 255, 255}; - texture->Load(0, 1, 1, 1, pixel.data(), pixel.size()); - return texture; -} -} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/InvalidTextures.h b/Source/Core/VideoCommon/Resources/InvalidTextures.h deleted file mode 100644 index 532f7e0102..0000000000 --- a/Source/Core/VideoCommon/Resources/InvalidTextures.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2025 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include - -#include "VideoCommon/AbstractTexture.h" - -namespace VideoCommon -{ -std::unique_ptr CreateInvalidTransparentTexture(); -std::unique_ptr CreateInvalidColorTexture(); -std::unique_ptr CreateInvalidCubemapTexture(); -std::unique_ptr CreateInvalidArrayTexture(); -} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/MaterialResource.cpp b/Source/Core/VideoCommon/Resources/MaterialResource.cpp deleted file mode 100644 index ea96cdf5f6..0000000000 --- a/Source/Core/VideoCommon/Resources/MaterialResource.cpp +++ /dev/null @@ -1,438 +0,0 @@ -// Copyright 2025 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "VideoCommon/Resources/MaterialResource.h" - -#include - -#include - -#include "Common/VariantUtil.h" - -#include "VideoCommon/AbstractGfx.h" -#include "VideoCommon/Assets/CustomAssetCache.h" -#include "VideoCommon/AsyncShaderCompiler.h" -#include "VideoCommon/FramebufferManager.h" -#include "VideoCommon/PipelineUtils.h" -#include "VideoCommon/Resources/CustomResourceManager.h" -#include "VideoCommon/VideoConfig.h" - -namespace -{ -// TODO: absorb this with TextureCacheBase -bool IsAnisotropicEnhancementSafe(const SamplerState::TM0& tm0) -{ - return !(tm0.min_filter == FilterMode::Near && tm0.mag_filter == FilterMode::Near); -} - -// TODO: absorb this with TextureCacheBase -SamplerState CalculateSamplerAnisotropy(const SamplerState& initial_sampler) -{ - SamplerState state = initial_sampler; - if (g_ActiveConfig.iMaxAnisotropy != AnisotropicFilteringMode::Default && - IsAnisotropicEnhancementSafe(state.tm0)) - { - state.tm0.anisotropic_filtering = std::to_underlying(g_ActiveConfig.iMaxAnisotropy); - } - - if (state.tm0.anisotropic_filtering != 0) - { - // https://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt - // For predictable results on all hardware/drivers, only use one of: - // GL_LINEAR + GL_LINEAR (No Mipmaps [Bilinear]) - // GL_LINEAR + GL_LINEAR_MIPMAP_LINEAR (w/ Mipmaps [Trilinear]) - // Letting the game set other combinations will have varying arbitrary results; - // possibly being interpreted as equal to bilinear/trilinear, implicitly - // disabling anisotropy, or changing the anisotropic algorithm employed. - state.tm0.min_filter = FilterMode::Linear; - state.tm0.mag_filter = FilterMode::Linear; - state.tm0.mipmap_filter = FilterMode::Linear; - } - return state; -} -} // namespace - -namespace VideoCommon -{ -MaterialResource::MaterialResource(Resource::ResourceContext resource_context) - : Resource(std::move(resource_context)) -{ - m_material_asset = m_resource_context.asset_cache->CreateAsset( - m_resource_context.primary_asset_id, m_resource_context.asset_library, this); -} - -MaterialResource::MaterialResource(Resource::ResourceContext resource_context, - GXPipelineUid pipeline_uid) - : Resource(std::move(resource_context)), m_uid(std::move(pipeline_uid)) -{ - m_material_asset = m_resource_context.asset_cache->CreateAsset( - m_resource_context.primary_asset_id, m_resource_context.asset_library, this); - m_uid_vertex_format_copy = - g_gfx->CreateNativeVertexFormat(m_uid->vertex_format->GetVertexDeclaration()); - m_uid->vertex_format = m_uid_vertex_format_copy.get(); -} - -void MaterialResource::ResetData() -{ - if (m_current_data) - { - m_current_data->m_shader_resource->RemoveReference(this); - for (const auto& texture_like_resource : m_current_data->m_texture_like_resources) - { - if (texture_like_resource) - texture_like_resource->RemoveReference(this); - } - if (m_current_data->m_next_material) - m_current_data->m_next_material->RemoveReference(this); - } - m_load_data = std::make_shared(); - m_processing_load_data = false; -} - -Resource::TaskComplete MaterialResource::CollectPrimaryData() -{ - const auto material_data = m_material_asset->GetData(); - if (!material_data) [[unlikely]] - { - return Resource::TaskComplete::No; - } - m_load_data->m_material_data = material_data; - - // A shader asset is required to function - if (m_load_data->m_material_data->shader_asset == "") - { - return Resource::TaskComplete::Error; - } - - CreateTextureData(m_load_data.get()); - SetShaderKey(m_load_data.get(), m_uid ? &*m_uid : nullptr); - - return Resource::TaskComplete::Yes; -} - -Resource::TaskComplete MaterialResource::CollectDependencyData() -{ - bool loaded = true; - { - auto* const shader_resource = m_resource_context.resource_manager->GetShaderFromAsset( - m_load_data->m_material_data->shader_asset, m_load_data->m_shader_key, m_uid, - m_load_data->m_preprocessor_settings, m_resource_context.asset_library); - shader_resource->AddReference(this); - m_load_data->m_shader_resource = shader_resource; - const auto data_processed = shader_resource->IsDataProcessed(); - if (data_processed == TaskComplete::Error) - return TaskComplete::Error; - - loaded &= data_processed == TaskComplete::Yes; - } - - for (std::size_t i = 0; i < m_load_data->m_material_data->textures.size(); i++) - { - const auto& texture_and_sampler = m_load_data->m_material_data->textures[i]; - if (texture_and_sampler.asset == "") - continue; - - const auto texture = m_resource_context.resource_manager->GetTextureAndSamplerFromAsset( - texture_and_sampler.asset, m_resource_context.asset_library); - m_load_data->m_texture_like_resources[i] = texture; - m_load_data->m_texture_like_data[i] = texture->GetData(); - texture->AddReference(this); - - const auto data_processed = texture->IsDataProcessed(); - if (data_processed == TaskComplete::Error) - return TaskComplete::Error; - - loaded &= data_processed == TaskComplete::Yes; - } - - if (m_load_data->m_material_data->next_material_asset != "") - { - if (m_uid) - { - m_load_data->m_next_material = m_resource_context.resource_manager->GetDrawMaterialFromAsset( - m_load_data->m_material_data->next_material_asset, *m_uid, - m_resource_context.asset_library); - } - else - { - m_load_data->m_next_material = - m_resource_context.resource_manager->GetPostProcessingMaterialFromAsset( - m_load_data->m_material_data->next_material_asset, m_resource_context.asset_library); - } - m_load_data->m_next_material->AddReference(this); - const auto data_processed = m_load_data->m_next_material->IsDataProcessed(); - if (data_processed == TaskComplete::Error) - return TaskComplete::Error; - - loaded &= data_processed == TaskComplete::Yes; - } - - return loaded ? TaskComplete::Yes : TaskComplete::No; -} - -Resource::TaskComplete MaterialResource::ProcessData() -{ - auto shader_data = m_load_data->m_shader_resource->GetData(); - - if (!shader_data) [[unlikely]] - return Resource::TaskComplete::Error; - - for (std::size_t i = 0; i < m_load_data->m_texture_like_data.size(); i++) - { - auto& texture_like_reference = m_load_data->m_texture_like_references[i]; - const auto& texture_and_sampler = m_load_data->m_material_data->textures[i]; - - // If the texture doesn't exist, use one of the placeholders - if (texture_and_sampler.asset == "") - { - const auto texture_type = shader_data->GetTextureType(i); - if (texture_type == AbstractTextureType::Texture_2D) - texture_like_reference.texture = m_resource_context.invalid_color_texture; - else if (texture_type == AbstractTextureType::Texture_2DArray) - texture_like_reference.texture = m_resource_context.invalid_array_texture; - else if (texture_type == AbstractTextureType::Texture_CubeMap) - texture_like_reference.texture = m_resource_context.invalid_cubemap_texture; - - if (texture_like_reference.texture == nullptr) - { - PanicAlertFmt("Invalid texture (texture_type={}) is not found during material " - "resource processing (asset_id={})", - texture_type, m_resource_context.primary_asset_id); - } - - continue; - } - - auto& texture_like_data = m_load_data->m_texture_like_data[i]; - - std::visit(overloaded{[&](const std::shared_ptr& data) { - texture_like_reference.texture = data->GetTexture(); - texture_like_reference.sampler = CalculateSamplerAnisotropy(data->GetSampler()); - ; - }}, - texture_like_data); - } - - class WorkItem final : public VideoCommon::AsyncShaderCompiler::WorkItem - { - public: - WorkItem(std::shared_ptr material_resource_data, - std::shared_ptr shader_resource_data, - VideoCommon::GXPipelineUid* uid, FramebufferState frame_buffer_state) - : m_material_resource_data(std::move(material_resource_data)), - m_shader_resource_data(std::move(shader_resource_data)), m_uid(uid), - m_frame_buffer_state(std::move(frame_buffer_state)) - { - } - - bool Compile() override - { - // Sanity check - if (!m_shader_resource_data->IsCompiled()) - { - m_material_resource_data->m_processing_finished = true; - return false; - } - - AbstractPipelineConfig config; - config.vertex_shader = m_shader_resource_data->GetVertexShader(); - config.pixel_shader = m_shader_resource_data->GetPixelShader(); - config.geometry_shader = m_shader_resource_data->GetGeometryShader(); - - if (m_uid) - { - // Draw based pipeline - const auto actual_uid = ApplyDriverBugs(*m_uid); - - if (m_material_resource_data->m_material_data->blending_state) - config.blending_state = *m_material_resource_data->m_material_data->blending_state; - else - config.blending_state = actual_uid.blending_state; - - if (m_material_resource_data->m_material_data->depth_state) - config.depth_state = *m_material_resource_data->m_material_data->depth_state; - else - config.depth_state = actual_uid.depth_state; - - config.framebuffer_state = std::move(m_frame_buffer_state); - config.framebuffer_state.additional_color_attachment_count = 0; - - config.rasterization_state = actual_uid.rasterization_state; - if (m_material_resource_data->m_material_data->cull_mode) - { - config.rasterization_state.cull_mode = - *m_material_resource_data->m_material_data->cull_mode; - } - - config.vertex_format = actual_uid.vertex_format; - config.usage = AbstractPipelineUsage::GX; - } - else - { - // Post processing based pipeline - - // Many of these properties don't make sense to replace but we expose them for draw - // based materials, might as well allow them to be used if the user wants - - if (m_material_resource_data->m_material_data->blending_state) - config.blending_state = *m_material_resource_data->m_material_data->blending_state; - else - config.blending_state = RenderState::GetNoBlendingBlendState(); - - if (m_material_resource_data->m_material_data->depth_state) - config.depth_state = *m_material_resource_data->m_material_data->depth_state; - else - config.depth_state = RenderState::GetNoDepthTestingDepthState(); - - config.framebuffer_state = RenderState::GetRGBA8FramebufferState(); - - config.rasterization_state = - RenderState::GetNoCullRasterizationState(PrimitiveType::Triangles); - if (m_material_resource_data->m_material_data->cull_mode) - { - config.rasterization_state.cull_mode = - *m_material_resource_data->m_material_data->cull_mode; - } - - config.vertex_format = nullptr; - config.usage = AbstractPipelineUsage::Utility; - } - - m_material_resource_data->m_pipeline = g_gfx->CreatePipeline(config); - if (m_material_resource_data->m_pipeline) - { - WriteUniforms(m_material_resource_data.get()); - } - m_material_resource_data->m_processing_finished = true; - return true; - } - void Retrieve() override {} - - private: - std::shared_ptr m_material_resource_data; - std::shared_ptr m_shader_resource_data; - VideoCommon::GXPipelineUid* m_uid; - FramebufferState m_frame_buffer_state; - }; - - if (!m_processing_load_data) - { - auto wi = m_resource_context.shader_compiler->CreateWorkItem( - m_load_data, std::move(shader_data), m_uid ? &*m_uid : nullptr, - g_framebuffer_manager->GetEFBFramebufferState()); - - // We don't need priority, that is already handled by the resource system - m_resource_context.shader_compiler->QueueWorkItem(std::move(wi), 0); - m_processing_load_data = true; - } - - if (!m_load_data->m_processing_finished) - return TaskComplete::No; - - if (!m_load_data->m_pipeline) - { - return TaskComplete::Error; - } - - std::swap(m_current_data, m_load_data); - return TaskComplete::Yes; -} - -void MaterialResource::MarkAsActive() -{ - if (!m_current_data) [[unlikely]] - return; - - m_resource_context.asset_cache->MarkAssetActive(m_material_asset); - for (const auto& texture_like_resource : m_current_data->m_texture_like_resources) - { - if (texture_like_resource) - texture_like_resource->MarkAsActive(); - } - if (m_current_data->m_shader_resource) - m_current_data->m_shader_resource->MarkAsActive(); - if (m_current_data->m_next_material) - m_current_data->m_next_material->MarkAsActive(); -} - -void MaterialResource::MarkAsPending() -{ - m_resource_context.asset_cache->MarkAssetPending(m_material_asset); -} - -void MaterialResource::CreateTextureData(Data* data) -{ - ShaderCode preprocessor_settings; - - const auto& material_data = *data->m_material_data; - data->m_texture_like_data.clear(); - data->m_texture_like_resources.clear(); - data->m_texture_like_references.clear(); - const u32 custom_sampler_index_offset = 8; - for (u32 i = 0; i < static_cast(material_data.textures.size()); i++) - { - const auto& texture_and_sampler = material_data.textures[i]; - data->m_texture_like_references.push_back(TextureLikeReference{}); - - TextureAndSamplerResource* value = nullptr; - data->m_texture_like_resources.push_back(value); - data->m_texture_like_data.push_back(std::shared_ptr{}); - - auto& texture_like_reference = data->m_texture_like_references[i]; - - if (texture_and_sampler.asset == "") - { - preprocessor_settings.Write("#define HAS_SAMPLER_{} 0\n", i); - - // For an invalid asset, force the sampler to use the default sampler - texture_like_reference.sampler_origin = - VideoCommon::TextureSamplerValue::SamplerOrigin::Asset; - texture_like_reference.texture_hash = ""; - } - else - { - preprocessor_settings.Write("#define HAS_SAMPLER_{} 1\n", i); - - texture_like_reference.sampler_origin = texture_and_sampler.sampler_origin; - texture_like_reference.texture_hash = texture_and_sampler.texture_hash; - } - - texture_like_reference.sampler_index = i + custom_sampler_index_offset; - texture_like_reference.texture = nullptr; - } - - data->m_preprocessor_settings = preprocessor_settings.GetBuffer(); -} - -void MaterialResource::SetShaderKey(Data* data, GXPipelineUid* uid) -{ - XXH3_state_t shader_key_hash; - XXH3_INITSTATE(&shader_key_hash); - XXH3_64bits_reset_withSeed(&shader_key_hash, static_cast(1)); - - if (uid) - UpdateHashWithPipeline(*uid, &shader_key_hash); - XXH3_64bits_update(&shader_key_hash, data->m_preprocessor_settings.c_str(), - data->m_preprocessor_settings.size()); - - data->m_shader_key = XXH3_64bits_digest(&shader_key_hash); -} - -void MaterialResource::WriteUniforms(Data* data) -{ - // Calculate the size in memory of the buffer - std::size_t max_uniformdata_size = 0; - for (const auto& property : data->m_material_data->properties) - { - max_uniformdata_size += VideoCommon::MaterialProperty::GetMemorySize(property); - } - data->m_uniform_data = Common::UniqueBuffer(max_uniformdata_size); - - // Now write the memory - u8* uniform_data = data->m_uniform_data.data(); - for (const auto& property : data->m_material_data->properties) - { - VideoCommon::MaterialProperty::WriteToMemory(uniform_data, property); - } -} -} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/MaterialResource.h b/Source/Core/VideoCommon/Resources/MaterialResource.h deleted file mode 100644 index 9729039d43..0000000000 --- a/Source/Core/VideoCommon/Resources/MaterialResource.h +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2025 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "Common/Buffer.h" -#include "Common/SmallVector.h" - -#include "VideoCommon/AbstractPipeline.h" -#include "VideoCommon/Assets/MaterialAsset.h" -#include "VideoCommon/Assets/TextureSamplerValue.h" -#include "VideoCommon/Constants.h" -#include "VideoCommon/GXPipelineTypes.h" -#include "VideoCommon/RenderState.h" -#include "VideoCommon/Resources/Resource.h" -#include "VideoCommon/Resources/ShaderResource.h" -#include "VideoCommon/Resources/TextureAndSamplerResource.h" - -namespace VideoCommon -{ -class MaterialResource final : public Resource -{ -public: - explicit MaterialResource(Resource::ResourceContext resource_context); - MaterialResource(Resource::ResourceContext resource_context, GXPipelineUid pipeline_uid); - - struct TextureLikeReference - { - SamplerState sampler; - u32 sampler_index; - TextureSamplerValue::SamplerOrigin sampler_origin; - std::string_view texture_hash; - AbstractTexture* texture; - }; - - class Data - { - public: - AbstractPipeline* GetPipeline() const { return m_pipeline.get(); } - std::span GetUniforms() const { return m_uniform_data; } - std::span GetTextures() const { return m_texture_like_references; } - MaterialResource* GetNextMaterial() const { return m_next_material; } - - private: - friend class MaterialResource; - std::unique_ptr m_pipeline = nullptr; - Common::UniqueBuffer m_uniform_data; - std::shared_ptr m_material_data = nullptr; - ShaderResource* m_shader_resource = nullptr; - - using TextureLikeResource = Resource*; - Common::SmallVector - m_texture_like_resources; - - // Variant for future expansion... - using TextureLikeData = std::variant>; - Common::SmallVector - m_texture_like_data; - - Common::SmallVector - m_texture_like_references; - - MaterialResource* m_next_material = nullptr; - std::size_t m_shader_key; - std::string m_preprocessor_settings; - std::atomic_bool m_processing_finished; - }; - - const std::shared_ptr& GetData() const { return m_current_data; } - void MarkAsActive() override; - void MarkAsPending() override; - -private: - void ResetData() override; - Resource::TaskComplete CollectPrimaryData() override; - Resource::TaskComplete CollectDependencyData() override; - Resource::TaskComplete ProcessData() override; - - static void CreateTextureData(Data* data); - static void SetShaderKey(Data* data, GXPipelineUid* uid); - static void WriteUniforms(Data* data); - - std::shared_ptr m_current_data; - - std::shared_ptr m_load_data; - bool m_processing_load_data = false; - - // Note: asset cache owns the asset, we access as a reference - MaterialAsset* m_material_asset = nullptr; - - // If provided, denotes this material will be used as a custom draw material. - // If not provided, denotes this will be used as an efb post processing material. - std::optional m_uid; - std::unique_ptr m_uid_vertex_format_copy; -}; -} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/Resource.h b/Source/Core/VideoCommon/Resources/Resource.h index d53460004f..2c6feeff5b 100644 --- a/Source/Core/VideoCommon/Resources/Resource.h +++ b/Source/Core/VideoCommon/Resources/Resource.h @@ -11,13 +11,10 @@ #include #include -class AbstractTexture; namespace VideoCommon { -class AsyncShaderCompiler; class CustomAssetCache; class CustomResourceManager; -class TexturePool; // A resource is an abstract object that maintains // relationships between assets (ex: a material that references a texture), @@ -32,13 +29,7 @@ public: std::shared_ptr asset_library; CustomAssetCache* asset_cache; CustomResourceManager* resource_manager; - TexturePool* texture_pool; Common::AsyncWorkThreadSP* worker_queue; - AsyncShaderCompiler* shader_compiler; - AbstractTexture* invalid_array_texture; - AbstractTexture* invalid_color_texture; - AbstractTexture* invalid_cubemap_texture; - AbstractTexture* invalid_transparent_texture; }; explicit Resource(ResourceContext resource_context); diff --git a/Source/Core/VideoCommon/Resources/ShaderResource.cpp b/Source/Core/VideoCommon/Resources/ShaderResource.cpp deleted file mode 100644 index 7b77886e2e..0000000000 --- a/Source/Core/VideoCommon/Resources/ShaderResource.cpp +++ /dev/null @@ -1,551 +0,0 @@ -// Copyright 2025 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "VideoCommon/Resources/ShaderResource.h" - -#include -#include - -#include - -#include "VideoCommon/AbstractGfx.h" -#include "VideoCommon/Assets/CustomAssetCache.h" -#include "VideoCommon/AsyncShaderCompiler.h" -#include "VideoCommon/FramebufferShaderGen.h" -#include "VideoCommon/GeometryShaderGen.h" -#include "VideoCommon/PipelineUtils.h" -#include "VideoCommon/PixelShaderGen.h" -#include "VideoCommon/VertexShaderGen.h" -#include "VideoCommon/VideoConfig.h" - -namespace VideoCommon -{ -namespace -{ -// TODO: the uniform buffer is combined due to the utility path only having a single -// set of constants, this isn't ideal (both for the end user, where it's more readable -// to see 'custom_uniforms' before variables and from Dolphin because the -// standard uniforms have to be packed with the custom ones -void GeneratePostProcessUniformOutput(ShaderCode& shader_source, std::string_view block_name, - std::string_view uniforms) -{ - shader_source.Write("UBO_BINDING(std140, 1) uniform {} {{\n", block_name); - shader_source.Write("\tvec4 source_resolution;\n"); - shader_source.Write("\tvec4 target_resolution;\n"); - shader_source.Write("\tvec4 window_resolution;\n"); - shader_source.Write("\tvec4 source_region;\n"); - shader_source.Write("\tint source_layer;\n"); - shader_source.Write("\tint source_layer_pad1;\n"); - shader_source.Write("\tint source_layer_pad2;\n"); - shader_source.Write("\tint source_layer_pad3;\n"); - shader_source.Write("\tuint time;\n"); - shader_source.Write("\tuint time_pad1;\n"); - shader_source.Write("\tuint time_pad2;\n"); - shader_source.Write("\tuint time_pad3;\n"); - shader_source.Write("\tint graphics_api;\n"); - shader_source.Write("\tint graphics_api_pad1;\n"); - shader_source.Write("\tint graphics_api_pad2;\n"); - shader_source.Write("\tint graphics_api_pad3;\n"); - shader_source.Write("\tuint efb_scale;\n"); - shader_source.Write("\tuint efb_scale_pad1;\n"); - shader_source.Write("\tuint efb_scale_pad2;\n"); - shader_source.Write("\tuint efb_scale_pad3;\n"); - if (!uniforms.empty()) - { - shader_source.Write("{}", uniforms); - } - shader_source.Write("}};\n"); -} - -// TODO: move this to a more standard post processing file -// once post processing has been cleaned up -void GeneratePostProcessingVertexShader(ShaderCode& shader_source, - const CustomVertexContents& custom_contents) -{ - // Note: if blocks are the same, they need to match for the OpenGL backend - GeneratePostProcessUniformOutput(shader_source, "PSBlock", custom_contents.uniforms); - - // Define some defines that are shared with custom draw shaders, - // so that a common shader code could possibly be used in both - shader_source.Write("#define HAS_COLOR_0 0\n"); - shader_source.Write("#define HAS_COLOR_1 0\n"); - shader_source.Write("#define HAS_NORMAL 0\n"); - shader_source.Write("#define HAS_BINORMAL 0\n"); - shader_source.Write("#define HAS_TANGENT 0\n"); - shader_source.Write("#define HAS_TEXTURE_COORD_0 1\n"); - for (u32 i = 1; i < 8; i++) - { - shader_source.Write("#define HAS_TEXTURE_COORD_{} 0\n", i); - } - - // Write the common structs, might want to consider - // moving these to another location? - shader_source.Write("struct DolphinVertexInput\n"); - shader_source.Write("{{\n"); - shader_source.Write("\tvec4 position;\n"); - shader_source.Write("\tvec3 texture_coord_0;\n"); - shader_source.Write("}};\n\n"); - - shader_source.Write("struct DolphinVertexOutput\n"); - shader_source.Write("{{\n"); - shader_source.Write("\tvec4 position;\n"); - shader_source.Write("\tvec3 texture_coord_0;\n"); - shader_source.Write("}};\n\n"); - - constexpr std::string_view emulated_vertex_definition = - "void dolphin_process_emulated_vertex(in DolphinVertexInput vertex_input, out " - "DolphinVertexOutput vertex_output)"; - shader_source.Write("{}\n", emulated_vertex_definition); - shader_source.Write("{{\n"); - shader_source.Write("\tvertex_output.position = vertex_input.position;\n"); - shader_source.Write("\tvertex_output.texture_coord_0 = vertex_input.texture_coord_0;\n"); - shader_source.Write("}}\n"); - - if (custom_contents.shader.empty()) - { - shader_source.Write( - "void process_vertex(in DolphinVertexInput vertex_input, out DolphinVertexOutput " - "vertex_output)\n"); - shader_source.Write("{{\n"); - - shader_source.Write("\tdolphin_process_emulated_vertex(vertex_input, vertex_output);\n"); - - shader_source.Write("}}\n"); - } - else - { - shader_source.Write("{}\n", custom_contents.shader); - } - - if (g_backend_info.bSupportsGeometryShaders) - { - shader_source.Write("VARYING_LOCATION(0) out VertexData {{\n"); - shader_source.Write("\tvec3 v_tex0;\n"); - shader_source.Write("}};\n"); - } - else - { - shader_source.Write("VARYING_LOCATION(0) out vec3 v_tex0;\n"); - } - - shader_source.Write("void main()\n"); - shader_source.Write("{{\n"); - shader_source.Write("\tDolphinVertexInput vertex_input;\n"); - shader_source.Write("\tvec3 vert = vec3(float((gl_VertexID << 1) & 2), " - "float(gl_VertexID & 2), 0.0f);\n"); - shader_source.Write("\tvertex_input.position = vec4(vert.xy * " - "float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n"); - shader_source.Write("\tvertex_input.texture_coord_0 = vec3(source_region.xy + " - "(source_region.zw * vert.xy), 0.0f);\n"); - shader_source.Write("\tDolphinVertexOutput vertex_output;\n"); - shader_source.Write("\tprocess_vertex(vertex_input, vertex_output);\n"); - shader_source.Write("\tgl_Position = vertex_output.position;\n"); - shader_source.Write("\tv_tex0 = vertex_output.texture_coord_0;\n"); - - // NDC space is flipped in Vulkan - if (g_backend_info.api_type == APIType::Vulkan) - { - shader_source.Write("\tgl_Position.y = -gl_Position.y;\n"); - } - - shader_source.Write("}}\n"); -} - -void GeneratePostProcessingPixelShader(ShaderCode& shader_source, - const CustomPixelContents& custom_contents) -{ - GeneratePostProcessUniformOutput(shader_source, "PSBlock", custom_contents.uniforms); - - shader_source.Write("SAMPLER_BINDING(0) uniform sampler2DArray samp0;\n"); - - if (g_backend_info.bSupportsGeometryShaders) - { - shader_source.Write("VARYING_LOCATION(0) in VertexData {{\n"); - shader_source.Write("\tvec3 v_tex0;\n"); - shader_source.Write("}};\n"); - } - else - { - shader_source.Write("VARYING_LOCATION(0) in float3 v_tex0;\n"); - } - - shader_source.Write("FRAGMENT_OUTPUT_LOCATION(0) out vec4 ocol0;\n"); - - shader_source.Write("struct DolphinFragmentInput\n"); - shader_source.Write("{{\n"); - for (u32 i = 0; i < 1; i++) - { - shader_source.Write("\tvec3 tex{};\n", i); - } - shader_source.Write("\n"); - - shader_source.Write("}};\n\n"); - - shader_source.Write("struct DolphinFragmentOutput\n"); - shader_source.Write("{{\n"); - shader_source.Write("\tvec4 main;\n"); - shader_source.Write("}};\n\n"); - - constexpr std::string_view emulated_fragment_definition = - "void dolphin_process_emulated_fragment(in DolphinFragmentInput frag_input, out " - "DolphinFragmentOutput frag_output)"; - shader_source.Write("{}\n", emulated_fragment_definition); - shader_source.Write("{{\n"); - shader_source.Write("\tfrag_output.main = texture(samp0, frag_input.tex0);\n"); - shader_source.Write("}}\n"); - - if (custom_contents.shader.empty()) - { - shader_source.Write( - "void process_fragment(in DolphinFragmentInput frag_input, out DolphinFragmentOutput " - "frag_output)\n"); - shader_source.Write("{{\n"); - - shader_source.Write("\tdolphin_process_emulated_fragment(frag_input, frag_output);\n"); - - shader_source.Write("}}\n"); - } - else - { - shader_source.Write("{}\n", custom_contents.shader); - } - - shader_source.Write("void main()\n"); - shader_source.Write("{{\n"); - shader_source.Write("\tDolphinFragmentInput frag_input;\n"); - shader_source.Write("\tfrag_input.tex0 = v_tex0;\n"); - shader_source.Write("\tDolphinFragmentOutput frag_output;\n"); - shader_source.Write("\tprocess_fragment(frag_input, frag_output);\n"); - shader_source.Write("\tocol0 = frag_output.main;\n"); - shader_source.Write("}}\n"); -} - -std::unique_ptr CompileGeometryShader(GeometryShaderUid* uid, APIType api_type, - ShaderHostConfig host_config) -{ - if (!uid) - { - return g_gfx->CreateShaderFromSource( - ShaderStage::Geometry, FramebufferShaderGen::GeneratePassthroughGeometryShader(1, 0), - nullptr, "Custom Post Processing Geometry Shader"); - } - - const ShaderCode source_code = - GenerateGeometryShaderCode(api_type, host_config, uid->GetUidData()); - return g_gfx->CreateShaderFromSource(ShaderStage::Geometry, source_code.GetBuffer(), nullptr, - fmt::format("Geometry shader: {}", *uid->GetUidData())); -} - -std::unique_ptr -CompilePixelShader(PixelShaderUid* uid, std::string_view preprocessor_settings, APIType api_type, - const ShaderHostConfig& host_config, RasterSurfaceShaderData* shader_data) -{ - ShaderCode shader_code; - - // Write any preprocessor values that were passed in - shader_code.Write("{}", preprocessor_settings); - - // TODO: in the future we could dynamically determine the amount of samplers - // available, for now just hardcode to start at 8 (the first non game - // sampler index available) - const std::size_t custom_sampler_index_offset = 8; - for (std::size_t i = 0; i < shader_data->samplers.size(); i++) - { - const auto& sampler = shader_data->samplers[i]; - std::string_view sampler_type; - switch (sampler.type) - { - case AbstractTextureType::Texture_2D: - sampler_type = "sampler2D"; - break; - case AbstractTextureType::Texture_2DArray: - sampler_type = "sampler2DArray"; - break; - case AbstractTextureType::Texture_CubeMap: - sampler_type = "samplerCube"; - break; - }; - shader_code.Write("SAMPLER_BINDING({}) uniform {} samp_{};\n", custom_sampler_index_offset + i, - sampler_type, sampler.name); - - // Sampler usage is passed in from the material - // Write a new preprocessor value with the sampler name - // for easier code in the shader - shader_code.Write("#if HAS_SAMPLER_{} == 1\n", i); - shader_code.Write("#define HAS_{} 1\n", sampler.name); - shader_code.Write("#endif\n"); - - shader_code.Write("\n"); - } - shader_code.Write("\n"); - - // Now write the custom shader - shader_code.Write("{}", ReplaceAll(shader_data->pixel_source, "\r\n", "\n")); - - // Write out the uniform data - ShaderCode uniform_code; - for (const auto& property : shader_data->uniform_properties) - { - VideoCommon::ShaderProperty::WriteAsShaderCode(uniform_code, property); - } - if (!shader_data->uniform_properties.empty()) - uniform_code.Write("\n\n"); - - // Compile the shader - CustomPixelContents contents{.shader = shader_code.GetBuffer(), - .uniforms = uniform_code.GetBuffer()}; - - ShaderCode source_code; - if (uid) - { - source_code = GeneratePixelShaderCode(api_type, host_config, uid->GetUidData(), contents); - } - else - { - GeneratePostProcessingPixelShader(source_code, contents); - } - ShaderIncluder* shader_includer = - shader_data->shader_includer ? &*shader_data->shader_includer : nullptr; - return g_gfx->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer(), shader_includer, - "Custom Pixel Shader"); -} - -std::unique_ptr -CompileVertexShader(VertexShaderUid* uid, std::string_view preprocessor_settings, APIType api_type, - const ShaderHostConfig& host_config, const RasterSurfaceShaderData& shader_data) -{ - ShaderCode shader_code; - - // Write any preprocessor values that were passed in - shader_code.Write("{}", preprocessor_settings); - - // TODO: in the future we could dynamically determine the amount of samplers - // available, for now just hardcode to start at 8 (the first non game - // sampler index available) - const std::size_t custom_sampler_index_offset = 8; - for (std::size_t i = 0; i < shader_data.samplers.size(); i++) - { - const auto& sampler = shader_data.samplers[i]; - std::string_view sampler_type = ""; - switch (sampler.type) - { - case AbstractTextureType::Texture_2D: - sampler_type = "sampler2D"; - break; - case AbstractTextureType::Texture_2DArray: - sampler_type = "sampler2DArray"; - break; - case AbstractTextureType::Texture_CubeMap: - sampler_type = "samplerCube"; - break; - }; - shader_code.Write("SAMPLER_BINDING({}) uniform {} samp_{};\n", custom_sampler_index_offset + i, - sampler_type, sampler.name); - - // Sampler usage is passed in from the material - // Write a new preprocessor value with the sampler name - // for easier code in the shader - shader_code.Write("#if HAS_SAMPLER_{} == 1\n", i); - shader_code.Write("#define HAS_{} 1\n", sampler.name); - shader_code.Write("#endif\n"); - - shader_code.Write("\n"); - } - shader_code.Write("\n"); - - // Now write the custom shader - shader_code.Write("{}", ReplaceAll(shader_data.vertex_source, "\r\n", "\n")); - - // Write out the uniform data - ShaderCode uniform_code; - for (const auto& property : shader_data.uniform_properties) - { - VideoCommon::ShaderProperty::WriteAsShaderCode(uniform_code, property); - } - if (!shader_data.uniform_properties.empty()) - uniform_code.Write("\n\n"); - - // Compile the shader - CustomVertexContents contents{.shader = shader_code.GetBuffer(), - .uniforms = uniform_code.GetBuffer()}; - - ShaderCode source_code; - if (uid) - { - source_code = GenerateVertexShaderCode(api_type, host_config, uid->GetUidData(), contents); - } - else - { - GeneratePostProcessingVertexShader(source_code, contents); - } - return g_gfx->CreateShaderFromSource(ShaderStage::Vertex, source_code.GetBuffer(), nullptr, - "Custom Vertex Shader"); -} -} // namespace -ShaderResource::ShaderResource(Resource::ResourceContext resource_context, - std::optional pipeline_uid, - std::string preprocessor_setting, - const ShaderHostConfig& shader_host_config) - : Resource(std::move(resource_context)), m_shader_host_config{.bits = shader_host_config.bits}, - m_uid(std::move(pipeline_uid)), m_preprocessor_settings(std::move(preprocessor_setting)) -{ - m_shader_asset = m_resource_context.asset_cache->CreateAsset( - m_resource_context.primary_asset_id, m_resource_context.asset_library, this); -} - -void ShaderResource::SetHostConfig(const ShaderHostConfig& host_config) -{ - m_shader_host_config.bits = host_config.bits; -} - -void ShaderResource::MarkAsPending() -{ - m_resource_context.asset_cache->MarkAssetPending(m_shader_asset); -} - -void ShaderResource::MarkAsActive() -{ - m_resource_context.asset_cache->MarkAssetActive(m_shader_asset); -} - -AbstractShader* ShaderResource::Data::GetVertexShader() const -{ - if (!m_vertex_shader) - return nullptr; - return m_vertex_shader.get(); -} - -AbstractShader* ShaderResource::Data::GetPixelShader() const -{ - if (!m_pixel_shader) - return nullptr; - return m_pixel_shader.get(); -} - -AbstractShader* ShaderResource::Data::GetGeometryShader() const -{ - if (!m_geometry_shader) - return nullptr; - return m_geometry_shader.get(); -} - -bool ShaderResource::Data::IsCompiled() const -{ - return m_vertex_shader && m_pixel_shader && (!m_needs_geometry_shader || m_geometry_shader); -} - -AbstractTextureType ShaderResource::Data::GetTextureType(std::size_t index) -{ - // If the data doesn't exist, just pick one... - if (!m_shader_data || index >= m_shader_data->samplers.size()) [[unlikely]] - return AbstractTextureType::Texture_2D; - - return m_shader_data->samplers[index].type; -} - -void ShaderResource::ResetData() -{ - m_load_data = std::make_shared(); - m_processing_load_data = false; -} - -Resource::TaskComplete ShaderResource::CollectPrimaryData() -{ - const auto shader_data = m_shader_asset->GetData(); - if (!shader_data) [[unlikely]] - { - return Resource::TaskComplete::No; - } - m_load_data->m_shader_data = shader_data; - - return Resource::TaskComplete::Yes; -} - -Resource::TaskComplete ShaderResource::ProcessData() -{ - class WorkItem final : public VideoCommon::AsyncShaderCompiler::WorkItem - { - public: - WorkItem(std::shared_ptr resource_data, VideoCommon::GXPipelineUid* uid, - u32 shader_bits, std::string_view preprocessor_settings) - : m_resource_data(std::move(resource_data)), m_uid(uid), m_shader_bits(shader_bits), - m_preprocessor_settings(preprocessor_settings) - { - } - - bool Compile() override - { - const ShaderHostConfig shader_host_config{.bits = m_shader_bits}; - if (m_uid) - { - // Draw based shader - auto actual_uid = ApplyDriverBugs(*m_uid); - - ClearUnusedPixelShaderUidBits(g_backend_info.api_type, shader_host_config, - &actual_uid.ps_uid); - m_resource_data->m_needs_geometry_shader = shader_host_config.backend_geometry_shaders && - !actual_uid.gs_uid.GetUidData()->IsPassthrough(); - - if (m_resource_data->m_needs_geometry_shader) - { - m_resource_data->m_geometry_shader = CompileGeometryShader( - &actual_uid.gs_uid, g_backend_info.api_type, shader_host_config); - } - m_resource_data->m_pixel_shader = - CompilePixelShader(&actual_uid.ps_uid, m_preprocessor_settings, g_backend_info.api_type, - shader_host_config, m_resource_data->m_shader_data.get()); - m_resource_data->m_vertex_shader = CompileVertexShader( - &actual_uid.vs_uid, m_preprocessor_settings, g_backend_info.api_type, - shader_host_config, *m_resource_data->m_shader_data); - } - else - { - // Post processing based shader - - m_resource_data->m_needs_geometry_shader = - shader_host_config.backend_geometry_shaders && shader_host_config.stereo; - if (m_resource_data->m_needs_geometry_shader) - { - m_resource_data->m_geometry_shader = - CompileGeometryShader(nullptr, g_backend_info.api_type, shader_host_config); - } - m_resource_data->m_pixel_shader = - CompilePixelShader(nullptr, m_preprocessor_settings, g_backend_info.api_type, - shader_host_config, m_resource_data->m_shader_data.get()); - m_resource_data->m_vertex_shader = - CompileVertexShader(nullptr, m_preprocessor_settings, g_backend_info.api_type, - shader_host_config, *m_resource_data->m_shader_data); - } - m_resource_data->m_processing_finished = true; - return true; - } - void Retrieve() override {} - - private: - std::shared_ptr m_resource_data; - VideoCommon::GXPipelineUid* m_uid; - u32 m_shader_bits; - std::string_view m_preprocessor_settings; - }; - - if (!m_processing_load_data) - { - std::string_view preprocessor_settings = m_preprocessor_settings; - auto wi = m_resource_context.shader_compiler->CreateWorkItem( - m_load_data, m_uid ? &*m_uid : nullptr, m_shader_host_config.bits, preprocessor_settings); - - // We don't need priority, that is already handled by the resource system - m_resource_context.shader_compiler->QueueWorkItem(std::move(wi), 0); - m_processing_load_data = true; - } - - if (!m_load_data->m_processing_finished) - return Resource::TaskComplete::No; - - if (!m_load_data->IsCompiled()) - return Resource::TaskComplete::Error; - - std::swap(m_current_data, m_load_data); - return Resource::TaskComplete::Yes; -} -} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/ShaderResource.h b/Source/Core/VideoCommon/Resources/ShaderResource.h deleted file mode 100644 index 1e59a1b11d..0000000000 --- a/Source/Core/VideoCommon/Resources/ShaderResource.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2025 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include - -#include "VideoCommon/Resources/Resource.h" - -#include "VideoCommon/Assets/ShaderAsset.h" -#include "VideoCommon/GXPipelineTypes.h" -#include "VideoCommon/ShaderGenCommon.h" - -namespace VideoCommon -{ -class ShaderResource final : public Resource -{ -public: - ShaderResource(Resource::ResourceContext resource_context, - std::optional pipeline_uid, std::string preprocessor_setting, - const ShaderHostConfig& shader_host_config); - - class Data - { - public: - AbstractShader* GetVertexShader() const; - AbstractShader* GetPixelShader() const; - AbstractShader* GetGeometryShader() const; - - bool IsCompiled() const; - AbstractTextureType GetTextureType(std::size_t index); - - private: - friend class ShaderResource; - std::unique_ptr m_vertex_shader; - std::unique_ptr m_pixel_shader; - std::unique_ptr m_geometry_shader; - std::shared_ptr m_shader_data; - bool m_needs_geometry_shader = false; - std::atomic_bool m_processing_finished; - }; - - // Changes the shader host config. Shaders should be reloaded afterwards. - void SetHostConfig(const ShaderHostConfig& host_config); - const std::shared_ptr& GetData() const { return m_current_data; } - - void MarkAsActive() override; - void MarkAsPending() override; - -private: - void ResetData() override; - Resource::TaskComplete CollectPrimaryData() override; - TaskComplete ProcessData() override; - - // Note: asset cache owns the asset, we access as a reference - RasterSurfaceShaderAsset* m_shader_asset = nullptr; - - std::shared_ptr m_current_data; - std::shared_ptr m_load_data; - - bool m_processing_load_data = false; - - ShaderHostConfig m_shader_host_config; - - // If provided, denotes this shader will be used as a custom draw shader. - // If not provided, denotes this will be used as an efb post processing shader. - std::optional m_uid; - std::string m_preprocessor_settings; -}; -} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/TextureAndSamplerResource.cpp b/Source/Core/VideoCommon/Resources/TextureAndSamplerResource.cpp deleted file mode 100644 index 735a64a357..0000000000 --- a/Source/Core/VideoCommon/Resources/TextureAndSamplerResource.cpp +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2025 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "VideoCommon/Resources/TextureAndSamplerResource.h" - -#include "VideoCommon/Assets/CustomAssetCache.h" -#include "VideoCommon/Resources/TexturePool.h" - -namespace VideoCommon -{ -TextureAndSamplerResource::TextureAndSamplerResource(Resource::ResourceContext resource_context) - : Resource(std::move(resource_context)) -{ - m_texture_and_sampler_asset = m_resource_context.asset_cache->CreateAsset( - m_resource_context.primary_asset_id, m_resource_context.asset_library, this); -} - -void TextureAndSamplerResource::MarkAsActive() -{ - m_resource_context.asset_cache->MarkAssetActive(m_texture_and_sampler_asset); -} - -void TextureAndSamplerResource::MarkAsPending() -{ - m_resource_context.asset_cache->MarkAssetPending(m_texture_and_sampler_asset); -} - -const std::shared_ptr& TextureAndSamplerResource::GetData() const -{ - return m_current_data; -} - -void TextureAndSamplerResource::ResetData() -{ - m_load_data = std::make_shared(); -} - -Resource::TaskComplete TextureAndSamplerResource::CollectPrimaryData() -{ - m_load_data->m_texture_and_sampler_data = m_texture_and_sampler_asset->GetData(); - if (!m_load_data->m_texture_and_sampler_data) - return Resource::TaskComplete::No; - - auto& texture_data = m_load_data->m_texture_and_sampler_data->texture_data; - if (texture_data.m_slices.empty()) - return Resource::TaskComplete::Error; - - if (texture_data.m_slices[0].m_levels.empty()) - return Resource::TaskComplete::Error; - - const auto& first_level = texture_data.m_slices[0].m_levels[0]; - - auto& config = m_load_data->m_config; - config.format = first_level.format; - config.flags = 0; - config.layers = 1; - config.levels = 1; - config.type = m_load_data->m_texture_and_sampler_data->type; - config.samples = 1; - - config.width = first_level.width; - config.height = first_level.height; - - return Resource::TaskComplete::Yes; -} - -Resource::TaskComplete TextureAndSamplerResource::ProcessData() -{ - auto texture = m_resource_context.texture_pool->AllocateTexture(m_load_data->m_config); - if (!texture) [[unlikely]] - return Resource::TaskComplete::Error; - - m_load_data->m_texture = std::move(texture); - - auto& texture_data = m_load_data->m_texture_and_sampler_data->texture_data; - for (std::size_t slice_index = 0; slice_index < texture_data.m_slices.size(); slice_index++) - { - auto& slice = texture_data.m_slices[slice_index]; - for (u32 level_index = 0; level_index < static_cast(slice.m_levels.size()); ++level_index) - { - auto& level = slice.m_levels[level_index]; - m_load_data->m_texture->Load(level_index, level.width, level.height, level.row_length, - level.data.data(), level.data.size(), - static_cast(slice_index)); - } - } - std::swap(m_current_data, m_load_data); - - // Release old data back to the pool - if (m_load_data) - m_resource_context.texture_pool->ReleaseTexture(std::move(m_load_data->m_texture)); - - return Resource::TaskComplete::Yes; -} - -void TextureAndSamplerResource::OnUnloadRequested() -{ - if (!m_current_data) - return; - m_resource_context.texture_pool->ReleaseTexture(std::move(m_current_data->m_texture)); - m_current_data = nullptr; -} -} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/TextureAndSamplerResource.h b/Source/Core/VideoCommon/Resources/TextureAndSamplerResource.h deleted file mode 100644 index 3641b8eb91..0000000000 --- a/Source/Core/VideoCommon/Resources/TextureAndSamplerResource.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2025 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "VideoCommon/Resources/Resource.h" - -#include "VideoCommon/AbstractTexture.h" -#include "VideoCommon/Assets/TextureAsset.h" - -namespace VideoCommon -{ -class TextureAndSamplerResource final : public Resource -{ -public: - explicit TextureAndSamplerResource(Resource::ResourceContext resource_context); - void MarkAsActive() override; - void MarkAsPending() override; - - class Data - { - public: - AbstractTexture* GetTexture() const { return m_texture.get(); } - const SamplerState& GetSampler() const { return m_texture_and_sampler_data->sampler; } - - private: - friend class TextureAndSamplerResource; - - std::shared_ptr m_texture_and_sampler_data; - std::unique_ptr m_texture; - TextureConfig m_config; - }; - - const std::shared_ptr& GetData() const; - -private: - void ResetData() override; - TaskComplete CollectPrimaryData() override; - TaskComplete ProcessData() override; - - void OnUnloadRequested() override; - - // Note: asset cache owns the asset, we access as a reference - TextureAndSamplerAsset* m_texture_and_sampler_asset = nullptr; - - std::shared_ptr m_current_data; - std::shared_ptr m_load_data; -}; -} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/TexturePool.cpp b/Source/Core/VideoCommon/Resources/TexturePool.cpp deleted file mode 100644 index ce76dc5b24..0000000000 --- a/Source/Core/VideoCommon/Resources/TexturePool.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2025 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "VideoCommon/Resources/TexturePool.h" - -#include "Common/Logging/Log.h" - -#include "VideoCommon/AbstractGfx.h" -#include "VideoCommon/AbstractTexture.h" - -namespace VideoCommon -{ -void TexturePool::Reset() -{ - m_cache.clear(); -} - -std::unique_ptr TexturePool::AllocateTexture(const TextureConfig& config) -{ - const auto iter = m_cache.find(config); - if (iter != m_cache.end()) - { - auto entry = std::move(iter->second); - m_cache.erase(iter); - return entry; - } - - std::unique_ptr texture = g_gfx->CreateTexture(config); - if (!texture) - { - ERROR_LOG_FMT(VIDEO, "Failed to allocate a {}x{}x{} texture", config.width, config.height, - config.layers); - return {}; - } - return texture; -} - -void TexturePool::ReleaseTexture(std::unique_ptr texture) -{ - auto config = texture->GetConfig(); - (void)m_cache.emplace(config, std::move(texture)); -} -} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/TexturePool.h b/Source/Core/VideoCommon/Resources/TexturePool.h deleted file mode 100644 index 6040a3ae76..0000000000 --- a/Source/Core/VideoCommon/Resources/TexturePool.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2025 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include - -#include "VideoCommon/AbstractTexture.h" -#include "VideoCommon/TextureConfig.h" - -namespace VideoCommon -{ -class TexturePool -{ -public: - void Reset(); - - std::unique_ptr AllocateTexture(const TextureConfig& config); - void ReleaseTexture(std::unique_ptr texture); - -private: - std::unordered_multimap> m_cache; -}; -} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/ShaderCache.cpp b/Source/Core/VideoCommon/ShaderCache.cpp index 30d5c8afe0..30bc77c9f2 100644 --- a/Source/Core/VideoCommon/ShaderCache.cpp +++ b/Source/Core/VideoCommon/ShaderCache.cpp @@ -439,7 +439,7 @@ void ShaderCache::CompileMissingPipelines() std::unique_ptr ShaderCache::CompileVertexShader(const VertexShaderUid& uid) const { const ShaderCode source_code = - GenerateVertexShaderCode(m_api_type, m_host_config, uid.GetUidData(), {}); + GenerateVertexShaderCode(m_api_type, m_host_config, uid.GetUidData()); return g_gfx->CreateShaderFromSource(ShaderStage::Vertex, source_code.GetBuffer()); } @@ -455,7 +455,7 @@ ShaderCache::CompileVertexUberShader(const UberShader::VertexShaderUid& uid) con std::unique_ptr ShaderCache::CompilePixelShader(const PixelShaderUid& uid) const { const ShaderCode source_code = - GeneratePixelShaderCode(m_api_type, m_host_config, uid.GetUidData(), {}); + GeneratePixelShaderCode(m_api_type, m_host_config, uid.GetUidData()); return g_gfx->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer()); } diff --git a/Source/Core/VideoCommon/ShaderGenCommon.h b/Source/Core/VideoCommon/ShaderGenCommon.h index 7d2c80f086..aad007051a 100644 --- a/Source/Core/VideoCommon/ShaderGenCommon.h +++ b/Source/Core/VideoCommon/ShaderGenCommon.h @@ -329,19 +329,3 @@ static const char s_geometry_shader_uniforms[] = "\tfloat4 " I_STEREOPARAMS ";\n "\tint4 " I_TEXOFFSET ";\n" "\tuint vs_expand;\n"; -constexpr std::string_view CUSTOM_PIXELSHADER_COLOR_FUNC = "customShaderColor"; - -struct CustomPixelShader -{ - std::string custom_shader; - std::string material_uniform_block; - - bool operator==(const CustomPixelShader& other) const = default; -}; - -struct CustomPixelShaderContents -{ - std::vector shaders; - - bool operator==(const CustomPixelShaderContents& other) const = default; -}; diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index ed07589b27..568abd4e14 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -2360,26 +2360,6 @@ void TextureCacheBase::CopyRenderTargetToTexture( isIntensity, gamma, clamp_top, clamp_bottom, GetVRAMCopyFilterCoefficients(filter_coefficients)); - if (g_ActiveConfig.bGraphicMods) - { - FBInfo info; - info.m_width = tex_w; - info.m_height = tex_h; - info.m_texture_format = baseFormat; - if (!is_xfb_copy) - { - GraphicsModActionData::PostEFB efb; - for (const auto& action : g_graphics_mod_manager->GetEFBActions(info)) - { - action->AfterEFB(&efb); - if (efb.material) - { - ApplyMaterialToCacheEntry(*efb.material, entry.get()); - } - } - } - } - if (is_xfb_copy && (g_ActiveConfig.bDumpXFBTarget || g_ActiveConfig.bGraphicMods)) { const std::string id = fmt::format("{}x{}", tex_w, tex_h); @@ -3086,110 +3066,6 @@ bool TextureCacheBase::DecodeTextureOnGPU(RcTcacheEntry& entry, u32 dst_level, c return true; } -void TextureCacheBase::ApplyMaterialToCacheEntry(const VideoCommon::MaterialResource& material, - TCacheEntry* entry) -{ - const auto material_data = material.GetData(); - if (!material_data) [[unlikely]] - return; - - // Make a copy, we can't write to our texture and use its framebuffer - // at the same time - auto new_entry = AllocateCacheEntry(entry->texture->GetConfig()); - new_entry->SetGeneralParameters(entry->addr, entry->size_in_bytes, entry->format, - entry->should_force_safe_hashing); - new_entry->SetDimensions(entry->native_width, entry->native_height, 1); - new_entry->SetEfbCopy(entry->memory_stride); - new_entry->may_have_overlapping_textures = false; - new_entry->frameCount = FRAMECOUNT_INVALID; - - g_gfx->BeginUtilityDrawing(); - entry->texture->FinishedRendering(); - - const auto custom_uniforms = material_data->GetUniforms(); - - // Set up uniforms. - // TODO: this struct should be shared with post processing - struct Uniforms - { - std::array source_resolution; - std::array target_resolution; - std::array window_resolution; - std::array source_rectangle; - s32 source_layer; - s32 source_layer_pad[3]; - u32 time; - u32 time_pad[3]; - s32 graphics_api; - s32 graphics_api_pad[3]; - u32 efb_scale; - u32 efb_scale_pad[3]; - } uniforms; - - const float rcp_src_width = 1.0f / entry->texture->GetWidth(); - const float rcp_src_height = 1.0f / entry->texture->GetHeight(); - - uniforms.source_resolution = {static_cast(entry->texture->GetWidth()), - static_cast(entry->texture->GetHeight()), rcp_src_width, - rcp_src_height}; - - // The target resolution is the same here, since we're - // injecting into the texture - uniforms.target_resolution = uniforms.source_resolution; - - const auto present_rect = g_presenter->GetTargetRectangle(); - uniforms.window_resolution = {static_cast(present_rect.GetWidth()), - static_cast(present_rect.GetHeight()), - 1.0f / static_cast(present_rect.GetWidth()), - 1.0f / static_cast(present_rect.GetHeight())}; - - uniforms.source_rectangle = {0, 0, 1, 1}; - uniforms.source_layer = 0; - uniforms.time = 0; - uniforms.graphics_api = static_cast(g_backend_info.api_type); - uniforms.efb_scale = g_framebuffer_manager->GetEFBScale(); - - Common::UniqueBuffer uniform_buffer(custom_uniforms.size() + sizeof(uniforms)); - std::memcpy(uniform_buffer.data(), &uniforms, sizeof(uniforms)); - std::memcpy(uniform_buffer.data() + sizeof(uniforms), custom_uniforms.data(), - custom_uniforms.size()); - g_vertex_manager->UploadUtilityUniforms(uniform_buffer.data(), - static_cast(uniform_buffer.size())); - - // Set framebuffer and viewport based on new entry - g_gfx->SetAndDiscardFramebuffer(new_entry->framebuffer.get()); - g_gfx->SetViewportAndScissor(new_entry->framebuffer->GetRect()); - g_gfx->SetPipeline(material_data->GetPipeline()); - - g_gfx->SetTexture(0, entry->texture.get()); - g_gfx->SetSamplerState(0, RenderState::GetPointSamplerState()); - - for (const auto& texture : material_data->GetTextures()) - { - g_gfx->SetTexture(texture.sampler_index, texture.texture); - g_gfx->SetSamplerState(texture.sampler_index, texture.sampler); - } - - g_gfx->Draw(0, 3); - g_gfx->EndUtilityDrawing(); - - // Finish rendering new entry - new_entry->texture->FinishedRendering(); - - // Swap new entry and existing entry - std::swap(entry->texture, new_entry->texture); - std::swap(entry->framebuffer, new_entry->framebuffer); - - // Return old entry to pool for use in another pass - // or future functionality - ReleaseToPool(new_entry.get()); - - if (auto* const next_material = material_data->GetNextMaterial(); next_material) - { - ApplyMaterialToCacheEntry(*next_material, entry); - } -} - u32 TCacheEntry::BytesPerRow() const { // RGBA takes two cache lines per block; all others take one diff --git a/Source/Core/VideoCommon/TextureCacheBase.h b/Source/Core/VideoCommon/TextureCacheBase.h index 7e9d0613d4..1118221d53 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.h +++ b/Source/Core/VideoCommon/TextureCacheBase.h @@ -41,7 +41,6 @@ namespace VideoCommon { class CustomTextureData; class GameTextureAsset; -class MaterialResource; } // namespace VideoCommon constexpr std::string_view EFB_DUMP_PREFIX = "efb1"; @@ -415,7 +414,6 @@ private: void DoSaveState(PointerWrap& p); void DoLoadState(PointerWrap& p); - void ApplyMaterialToCacheEntry(const VideoCommon::MaterialResource& material, TCacheEntry* entry); // m_textures_by_address is the authoritive version of what's actually "in" the texture cache // but it's possible for invalidated TCache entries to live on elsewhere diff --git a/Source/Core/VideoCommon/VertexManagerBase.cpp b/Source/Core/VideoCommon/VertexManagerBase.cpp index 256d9ce9bd..e03b1e6cfe 100644 --- a/Source/Core/VideoCommon/VertexManagerBase.cpp +++ b/Source/Core/VideoCommon/VertexManagerBase.cpp @@ -24,7 +24,6 @@ #include "VideoCommon/DataReader.h" #include "VideoCommon/FramebufferManager.h" #include "VideoCommon/GeometryShaderManager.h" -#include "VideoCommon/GraphicsModSystem/Runtime/CustomShaderCache.h" #include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionData.h" #include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.h" #include "VideoCommon/IndexGenerator.h" @@ -123,7 +122,6 @@ bool VertexManagerBase::Initialize() m_after_present_event = video_events.after_present_event.Register( [this](const PresentInfo& pi) { m_ticks_elapsed = pi.emulated_timestamp; }); m_index_generator.Init(); - m_custom_shader_cache = std::make_unique(); m_cpu_cull.Init(); return true; } @@ -614,25 +612,12 @@ void VertexManagerBase::Flush() if (!m_cull_all) { - CustomPixelShaderContents custom_pixel_shader_contents; - std::optional custom_pixel_shader; - std::vector custom_pixel_texture_names; - std::span custom_pixel_shader_uniforms; bool skip = false; for (size_t i = 0; i < texture_names.size(); i++) { - GraphicsModActionData::DrawStarted draw_started{texture_units, &skip, &custom_pixel_shader, - &custom_pixel_shader_uniforms}; + GraphicsModActionData::DrawStarted draw_started{texture_units, &skip}; for (const auto& action : g_graphics_mod_manager->GetDrawStartedActions(texture_names[i])) - { action->OnDrawStarted(&draw_started); - if (custom_pixel_shader) - { - custom_pixel_shader_contents.shaders.push_back(*custom_pixel_shader); - custom_pixel_texture_names.push_back(texture_names[i]); - } - custom_pixel_shader = std::nullopt; - } } // Now the vertices can be flushed to the GPU. Everything following the CommitBuffer() call @@ -652,18 +637,8 @@ void VertexManagerBase::Flush() UpdatePipelineObject(); if (m_current_pipeline_object) { - const AbstractPipeline* pipeline_object = m_current_pipeline_object; - if (!custom_pixel_shader_contents.shaders.empty()) - { - if (const auto custom_pipeline = - GetCustomPipeline(custom_pixel_shader_contents, m_current_pipeline_config, - m_current_uber_pipeline_config, m_current_pipeline_object)) - { - pipeline_object = custom_pipeline; - } - } - RenderDrawCall(pixel_shader_manager, geometry_shader_manager, custom_pixel_shader_contents, - custom_pixel_shader_uniforms, m_current_primitive_type, pipeline_object); + RenderDrawCall(pixel_shader_manager, geometry_shader_manager, m_current_primitive_type, + m_current_pipeline_object); } } @@ -1052,27 +1027,13 @@ void VertexManagerBase::OnEndFrame() InvalidatePipelineObject(); } -void VertexManagerBase::NotifyCustomShaderCacheOfHostChange(const ShaderHostConfig& host_config) -{ - m_custom_shader_cache->SetHostConfig(host_config); - m_custom_shader_cache->Reload(); -} - void VertexManagerBase::RenderDrawCall( PixelShaderManager& pixel_shader_manager, GeometryShaderManager& geometry_shader_manager, - const CustomPixelShaderContents& custom_pixel_shader_contents, - std::span custom_pixel_shader_uniforms, PrimitiveType primitive_type, - const AbstractPipeline* current_pipeline) + PrimitiveType primitive_type, const AbstractPipeline* current_pipeline) { // Now we can upload uniforms, as nothing else will override them. geometry_shader_manager.SetConstants(primitive_type); pixel_shader_manager.SetConstants(); - if (!custom_pixel_shader_uniforms.empty() && - pixel_shader_manager.custom_constants.data() != custom_pixel_shader_uniforms.data()) - { - pixel_shader_manager.custom_constants_dirty = true; - } - pixel_shader_manager.custom_constants = custom_pixel_shader_uniforms; UploadUniforms(); g_gfx->SetPipeline(current_pipeline); @@ -1103,69 +1064,3 @@ void VertexManagerBase::RenderDrawCall( g_perf_query->DisableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP); } -const AbstractPipeline* VertexManagerBase::GetCustomPipeline( - const CustomPixelShaderContents& custom_pixel_shader_contents, - const VideoCommon::GXPipelineUid& current_pipeline_config, - const VideoCommon::GXUberPipelineUid& current_uber_pipeline_config, - const AbstractPipeline* current_pipeline) const -{ - if (current_pipeline) - { - if (!custom_pixel_shader_contents.shaders.empty()) - { - CustomShaderInstance custom_shaders; - custom_shaders.pixel_contents = custom_pixel_shader_contents; - switch (g_ActiveConfig.iShaderCompilationMode) - { - case ShaderCompilationMode::Synchronous: - case ShaderCompilationMode::AsynchronousSkipRendering: - { - if (auto pipeline = m_custom_shader_cache->GetPipelineAsync( - current_pipeline_config, custom_shaders, current_pipeline->m_config)) - { - return *pipeline; - } - } - break; - case ShaderCompilationMode::SynchronousUberShaders: - { - // D3D has issues compiling large custom ubershaders - // use specialized shaders instead - if (g_backend_info.api_type == APIType::D3D) - { - if (auto pipeline = m_custom_shader_cache->GetPipelineAsync( - current_pipeline_config, custom_shaders, current_pipeline->m_config)) - { - return *pipeline; - } - } - else - { - if (auto pipeline = m_custom_shader_cache->GetPipelineAsync( - current_uber_pipeline_config, custom_shaders, current_pipeline->m_config)) - { - return *pipeline; - } - } - } - break; - case ShaderCompilationMode::AsynchronousUberShaders: - { - if (auto pipeline = m_custom_shader_cache->GetPipelineAsync( - current_pipeline_config, custom_shaders, current_pipeline->m_config)) - { - return *pipeline; - } - else if (auto uber_pipeline = m_custom_shader_cache->GetPipelineAsync( - current_uber_pipeline_config, custom_shaders, current_pipeline->m_config)) - { - return *uber_pipeline; - } - } - break; - }; - } - } - - return nullptr; -} diff --git a/Source/Core/VideoCommon/VertexManagerBase.h b/Source/Core/VideoCommon/VertexManagerBase.h index 715dbee692..2e0d97a2e7 100644 --- a/Source/Core/VideoCommon/VertexManagerBase.h +++ b/Source/Core/VideoCommon/VertexManagerBase.h @@ -15,8 +15,6 @@ #include "VideoCommon/ShaderCache.h" #include "VideoCommon/VideoEvents.h" -struct CustomPixelShaderContents; -class CustomShaderCache; class DataReader; class GeometryShaderManager; class NativeVertexFormat; @@ -134,7 +132,6 @@ public: m_current_pipeline_object = nullptr; m_pipeline_config_changed = true; } - void NotifyCustomShaderCacheOfHostChange(const ShaderHostConfig& host_config); // Utility pipeline drawing (e.g. EFB copies, post-processing, UI). virtual void UploadUtilityUniforms(const void* uniforms, u32 uniforms_size); @@ -225,18 +222,10 @@ private: void RenderDrawCall(PixelShaderManager& pixel_shader_manager, GeometryShaderManager& geometry_shader_manager, - const CustomPixelShaderContents& custom_pixel_shader_contents, - std::span custom_pixel_shader_uniforms, PrimitiveType primitive_type, - const AbstractPipeline* current_pipeline); + PrimitiveType primitive_type, const AbstractPipeline* current_pipeline); void UpdatePipelineConfig(); void UpdatePipelineObject(); - const AbstractPipeline* - GetCustomPipeline(const CustomPixelShaderContents& custom_pixel_shader_contents, - const VideoCommon::GXPipelineUid& current_pipeline_config, - const VideoCommon::GXUberPipelineUid& current_uber_pipeline_confi, - const AbstractPipeline* current_pipeline) const; - bool m_is_flushed = true; FlushStatistics m_flush_statistics = {}; @@ -248,7 +237,6 @@ private: std::vector m_scheduled_command_buffer_kicks; bool m_allow_background_execution = true; - std::unique_ptr m_custom_shader_cache; u64 m_ticks_elapsed = 0; Common::EventHook m_frame_end_event; diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index ac0950628a..e1524b3e29 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -360,8 +360,7 @@ static void WriteEmulatedVertexBodyHeader(APIType api_type, const ShaderHostConf } ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& host_config, - const vertex_shader_uid_data* uid_data, - CustomVertexContents custom_contents) + const vertex_shader_uid_data* uid_data) { ShaderCode out; @@ -380,13 +379,6 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho out.Write("{}", s_shader_uniforms); out.Write("}};\n"); - if (!custom_contents.uniforms.empty()) - { - out.Write("UBO_BINDING(std140, 3) uniform CustomShaderBlock {{\n"); - out.Write("{}", custom_contents.uniforms); - out.Write("}} custom_uniforms;\n"); - } - if (uid_data->vs_expand != VSExpand::None) { out.Write("UBO_BINDING(std140, 4) uniform GSBlock {{\n"); @@ -558,20 +550,11 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho WriteVertexStructs(api_type, host_config, uid_data, out); WriteEmulatedVertexBodyHeader(api_type, host_config, uid_data, out); - if (custom_contents.shader.empty()) - { - out.Write("void process_vertex(in DolphinVertexInput vertex_input, out DolphinVertexOutput " - "vertex_output)\n"); - out.Write("{{\n"); - - out.Write("\tdolphin_process_emulated_vertex(vertex_input, vertex_output);\n"); - - out.Write("}}\n"); - } - else - { - out.Write("{}\n", custom_contents.shader); - } + out.Write("void process_vertex(in DolphinVertexInput vertex_input, out DolphinVertexOutput " + "vertex_output)\n"); + out.Write("{{\n"); + out.Write("\tdolphin_process_emulated_vertex(vertex_input, vertex_output);\n"); + out.Write("}}\n"); out.Write("void main()\n{{\n"); diff --git a/Source/Core/VideoCommon/VertexShaderGen.h b/Source/Core/VideoCommon/VertexShaderGen.h index a0fd342621..fefc0fc6e8 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.h +++ b/Source/Core/VideoCommon/VertexShaderGen.h @@ -105,15 +105,8 @@ static_assert(sizeof(vertex_shader_uid_data) == 28, "vertex_shader_uid_data shou using VertexShaderUid = ShaderUid; -struct CustomVertexContents -{ - std::string_view shader = ""; - std::string_view uniforms = ""; -}; - VertexShaderUid GetVertexShaderUid(); ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& host_config, - const vertex_shader_uid_data* uid_data, - CustomVertexContents custom_contents); + const vertex_shader_uid_data* uid_data); void WriteVertexBody(APIType api_type, const ShaderHostConfig& host_config, const vertex_shader_uid_data* uid_data, ShaderCode& out); diff --git a/Source/Core/VideoCommon/VideoConfig.cpp b/Source/Core/VideoCommon/VideoConfig.cpp index c56f32c00c..5e55dece35 100644 --- a/Source/Core/VideoCommon/VideoConfig.cpp +++ b/Source/Core/VideoCommon/VideoConfig.cpp @@ -150,7 +150,6 @@ void VideoConfig::Refresh() texture_filtering_mode = Config::Get(Config::GFX_ENHANCE_FORCE_TEXTURE_FILTERING); iMaxAnisotropy = Config::Get(Config::GFX_ENHANCE_MAX_ANISOTROPY); output_resampling_mode = Config::Get(Config::GFX_ENHANCE_OUTPUT_RESAMPLING); - sPostProcessingShader = Config::Get(Config::GFX_ENHANCE_POST_SHADER); bForceTrueColor = Config::Get(Config::GFX_ENHANCE_FORCE_TRUE_COLOR); bDisableCopyFilter = Config::Get(Config::GFX_ENHANCE_DISABLE_COPY_FILTER); bArbitraryMipmapDetection = Config::Get(Config::GFX_ENHANCE_ARBITRARY_MIPMAP_DETECTION); @@ -307,7 +306,6 @@ void CheckForConfigChanges() const AspectMode old_aspect_mode = g_ActiveConfig.aspect_mode; const AspectMode old_suggested_aspect_mode = g_ActiveConfig.suggested_aspect_mode; const bool old_widescreen_hack = g_ActiveConfig.bWidescreenHack; - const auto old_post_processing_shader = g_ActiveConfig.sPostProcessingShader; const auto old_hdr = g_ActiveConfig.bHDR; UpdateActiveConfig(); @@ -359,8 +357,6 @@ void CheckForConfigChanges() changed_bits |= CONFIG_CHANGE_BIT_ASPECT_RATIO; if (old_widescreen_hack != g_ActiveConfig.bWidescreenHack) changed_bits |= CONFIG_CHANGE_BIT_ASPECT_RATIO; - if (old_post_processing_shader != g_ActiveConfig.sPostProcessingShader) - changed_bits |= CONFIG_CHANGE_BIT_POST_PROCESSING_SHADER; if (old_hdr != g_ActiveConfig.bHDR) changed_bits |= CONFIG_CHANGE_BIT_HDR; @@ -390,7 +386,6 @@ void CheckForConfigChanges() OSD::AddMessage("Video config changed, reloading shaders.", OSD::Duration::NORMAL); g_gfx->WaitForGPUIdle(); g_vertex_manager->InvalidatePipelineObject(); - g_vertex_manager->NotifyCustomShaderCacheOfHostChange(new_host_config); g_shader_cache->SetHostConfig(new_host_config); g_shader_cache->Reload(); g_framebuffer_manager->RecompileShaders(); diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h index e16015491b..9666299c7b 100644 --- a/Source/Core/VideoCommon/VideoConfig.h +++ b/Source/Core/VideoCommon/VideoConfig.h @@ -119,7 +119,6 @@ enum ConfigChangeBits : u32 CONFIG_CHANGE_BIT_VSYNC = (1 << 6), CONFIG_CHANGE_BIT_BBOX = (1 << 7), CONFIG_CHANGE_BIT_ASPECT_RATIO = (1 << 8), - CONFIG_CHANGE_BIT_POST_PROCESSING_SHADER = (1 << 9), CONFIG_CHANGE_BIT_HDR = (1 << 10), }; @@ -148,7 +147,6 @@ struct BackendInfo bool bSupportsBindingLayout = false; // Needed by ShaderGen, so must stay in VideoCommon bool bSupportsBBox = false; bool bSupportsGSInstancing = false; // Needed by GeometryShaderGen, so must stay in VideoCommon - bool bSupportsPostProcessing = false; bool bSupportsPaletteConversion = false; bool bSupportsClipControl = false; // Needed by VertexShaderGen, so must stay in VideoCommon bool bSupportsSSAA = false; @@ -221,7 +219,6 @@ struct VideoConfig final TextureFilteringMode texture_filtering_mode = TextureFilteringMode::Default; OutputResamplingMode output_resampling_mode = OutputResamplingMode::Default; AnisotropicFilteringMode iMaxAnisotropy = AnisotropicFilteringMode::Default; - std::string sPostProcessingShader; bool bForceTrueColor = false; bool bDisableCopyFilter = false; bool bArbitraryMipmapDetection = false;