From 33dc971a2d199314c086a67a3aa4a220851c5dbd Mon Sep 17 00:00:00 2001 From: VelocityRa Date: Wed, 10 Oct 2018 18:50:54 +0300 Subject: [PATCH 1/4] Win64 build for binary addons --- tools/windows/prepare-binary-addons-dev.bat | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/windows/prepare-binary-addons-dev.bat b/tools/windows/prepare-binary-addons-dev.bat index 423380b17f427..eb591bbc21225 100644 --- a/tools/windows/prepare-binary-addons-dev.bat +++ b/tools/windows/prepare-binary-addons-dev.bat @@ -18,7 +18,7 @@ FOR %%b IN (%*) DO ( SETLOCAL DisableDelayedExpansion rem set Visual C++ build environment -call "%VS140COMNTOOLS%..\..\VC\bin\amd64_x86\vcvarsamd64_x86.bat" || call "%VS140COMNTOOLS%..\..\VC\bin\vcvars32.bat" +call "%VS140COMNTOOLS%..\..\VC\bin\amd64\vcvars64.bat" || call "%VS140COMNTOOLS%..\..\VC\bin\vcvars32.bat" SET WORKDIR=%WORKSPACE% @@ -76,7 +76,7 @@ IF "%addon%" NEQ "" ( ) rem execute cmake to generate Visual Studio 12 project files -cmake "%ADDONS_PATH%" -G "Visual Studio 14" ^ +cmake "%ADDONS_PATH%" -G "Visual Studio 15 Win64" ^ -DCMAKE_BUILD_TYPE=Release ^ -DCMAKE_USER_MAKE_RULES_OVERRIDE="%SCRIPTS_PATH%/CFlagOverrides.cmake" ^ -DCMAKE_USER_MAKE_RULES_OVERRIDE_CXX="%SCRIPTS_PATH%/CXXFlagOverrides.cmake" ^ From dfe96375766a9569644ba1915f9bf0ab7875deae Mon Sep 17 00:00:00 2001 From: Garrett Brown Date: Tue, 24 Oct 2017 13:16:22 -0700 Subject: [PATCH 2/4] Import shader presets from libretro-common This imports several shader presets from libretro common at commit 187c161 (https://github.com/libretro/common-shaders/tree/187c161). --- .../resources/strings.po | 154 ++++++- .../cgp/tvout/tvout+ntsc-256px-composite.cgp | 45 ++ .../cgp/tvout/tvout+ntsc-320px-svideo.cgp | 45 ++ .../shaders/presets/HLSL/compat_includes.inc | 5 + .../presets/HLSL/crt/4xbr-hybrid-crt-b.cgp | 11 + system/shaders/presets/HLSL/crt/crt-geom.cgp | 5 + .../HLSL/crt/shaders/4xbr-hybrid-crt-b.cg | 358 ++++++++++++++++ .../presets/HLSL/crt/shaders/crt-geom.cg | 388 ++++++++++++++++++ .../presets/HLSL/crt/shaders/tvout-tweaks.cg | 192 +++++++++ .../presets/HLSL/eagle/shaders/super-eagle.cg | 195 +++++++++ .../presets/HLSL/eagle/super-eagle.cgp | 11 + .../HLSL/handheld/lcd-grid-v2-gba-color.cgp | 27 ++ .../HLSL/handheld/lcd-grid-v2-nds-color.cgp | 27 ++ .../HLSL/handheld/lcd-grid-v2-psp-color.cgp | 27 ++ .../HLSL/handheld/shaders/color/gba-color.cg | 96 +++++ .../HLSL/handheld/shaders/color/nds-color.cg | 89 ++++ .../HLSL/handheld/shaders/color/psp-color.cg | 89 ++++ .../handheld/shaders/lcd_cgwg/lcd-grid-v2.cg | 163 ++++++++ .../HLSL/include/compat_input_struct.inc | 33 ++ .../presets/HLSL/include/compat_macros.inc | 58 +++ .../HLSL/include/compat_orig_struct.inc | 37 ++ .../HLSL/include/compat_prev_struct.inc | 34 ++ .../HLSL/include/compat_vertex_in_out.inc | 23 ++ .../presets/HLSL/misc/image-adjustment.cg | 169 ++++++++ system/shaders/presets/HLSL/ntsc/ntsc.cgp | 25 ++ .../shaders/ntsc-decode-filter-2phase.inc | 70 ++++ .../shaders/ntsc-decode-filter-3phase.inc | 54 +++ .../HLSL/ntsc/shaders/ntsc-gauss-pass.cg | 76 ++++ .../presets/HLSL/ntsc/shaders/ntsc-param.inc | 28 ++ .../shaders/ntsc-pass1-composite-3phase.cg | 20 + .../shaders/ntsc-pass1-encode-demodulate.inc | 19 + .../ntsc/shaders/ntsc-pass1-svideo-2phase.cg | 20 + .../HLSL/ntsc/shaders/ntsc-pass1-vertex.inc | 25 ++ .../HLSL/ntsc/shaders/ntsc-pass2-2phase.cg | 23 ++ .../HLSL/ntsc/shaders/ntsc-pass2-3phase.cg | 23 ++ .../HLSL/ntsc/shaders/ntsc-pass2-decode.inc | 14 + .../HLSL/ntsc/shaders/ntsc-pass2-vertex.inc | 23 ++ .../presets/HLSL/ntsc/shaders/ntsc-rgbyuv.inc | 22 + .../presets/HLSL/ntsc/shaders/ntsc-stock.cg | 44 ++ system/shaders/presets/HLSL/stock.cg | 74 ++++ .../presets/HLSL/xbr/shaders/xbr-lv2-fast.cg | 235 +++++++++++ .../HLSL/xbr/shaders/xbr-lv3-noblend.cg | 271 ++++++++++++ .../presets/HLSL/xbr/shaders/xbr-lv3.cg | 292 +++++++++++++ .../shaders/presets/HLSL/xbr/xbr-lv2-fast.cgp | 5 + .../presets/HLSL/xbr/xbr-lv3-noblend.cgp | 5 + system/shaders/presets/HLSL/xbr/xbr-lv3.cgp | 5 + system/shaders/presets/shader-manifest.xml | 156 +++++++ 47 files changed, 3809 insertions(+), 1 deletion(-) create mode 100644 system/shaders/presets/HLSL/cgp/tvout/tvout+ntsc-256px-composite.cgp create mode 100644 system/shaders/presets/HLSL/cgp/tvout/tvout+ntsc-320px-svideo.cgp create mode 100644 system/shaders/presets/HLSL/compat_includes.inc create mode 100644 system/shaders/presets/HLSL/crt/4xbr-hybrid-crt-b.cgp create mode 100644 system/shaders/presets/HLSL/crt/crt-geom.cgp create mode 100644 system/shaders/presets/HLSL/crt/shaders/4xbr-hybrid-crt-b.cg create mode 100644 system/shaders/presets/HLSL/crt/shaders/crt-geom.cg create mode 100644 system/shaders/presets/HLSL/crt/shaders/tvout-tweaks.cg create mode 100644 system/shaders/presets/HLSL/eagle/shaders/super-eagle.cg create mode 100644 system/shaders/presets/HLSL/eagle/super-eagle.cgp create mode 100644 system/shaders/presets/HLSL/handheld/lcd-grid-v2-gba-color.cgp create mode 100644 system/shaders/presets/HLSL/handheld/lcd-grid-v2-nds-color.cgp create mode 100644 system/shaders/presets/HLSL/handheld/lcd-grid-v2-psp-color.cgp create mode 100644 system/shaders/presets/HLSL/handheld/shaders/color/gba-color.cg create mode 100644 system/shaders/presets/HLSL/handheld/shaders/color/nds-color.cg create mode 100644 system/shaders/presets/HLSL/handheld/shaders/color/psp-color.cg create mode 100644 system/shaders/presets/HLSL/handheld/shaders/lcd_cgwg/lcd-grid-v2.cg create mode 100644 system/shaders/presets/HLSL/include/compat_input_struct.inc create mode 100644 system/shaders/presets/HLSL/include/compat_macros.inc create mode 100644 system/shaders/presets/HLSL/include/compat_orig_struct.inc create mode 100644 system/shaders/presets/HLSL/include/compat_prev_struct.inc create mode 100644 system/shaders/presets/HLSL/include/compat_vertex_in_out.inc create mode 100644 system/shaders/presets/HLSL/misc/image-adjustment.cg create mode 100644 system/shaders/presets/HLSL/ntsc/ntsc.cgp create mode 100644 system/shaders/presets/HLSL/ntsc/shaders/ntsc-decode-filter-2phase.inc create mode 100644 system/shaders/presets/HLSL/ntsc/shaders/ntsc-decode-filter-3phase.inc create mode 100644 system/shaders/presets/HLSL/ntsc/shaders/ntsc-gauss-pass.cg create mode 100644 system/shaders/presets/HLSL/ntsc/shaders/ntsc-param.inc create mode 100644 system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass1-composite-3phase.cg create mode 100644 system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass1-encode-demodulate.inc create mode 100644 system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass1-svideo-2phase.cg create mode 100644 system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass1-vertex.inc create mode 100644 system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass2-2phase.cg create mode 100644 system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass2-3phase.cg create mode 100644 system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass2-decode.inc create mode 100644 system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass2-vertex.inc create mode 100644 system/shaders/presets/HLSL/ntsc/shaders/ntsc-rgbyuv.inc create mode 100644 system/shaders/presets/HLSL/ntsc/shaders/ntsc-stock.cg create mode 100644 system/shaders/presets/HLSL/stock.cg create mode 100644 system/shaders/presets/HLSL/xbr/shaders/xbr-lv2-fast.cg create mode 100644 system/shaders/presets/HLSL/xbr/shaders/xbr-lv3-noblend.cg create mode 100644 system/shaders/presets/HLSL/xbr/shaders/xbr-lv3.cg create mode 100644 system/shaders/presets/HLSL/xbr/xbr-lv2-fast.cgp create mode 100644 system/shaders/presets/HLSL/xbr/xbr-lv3-noblend.cgp create mode 100644 system/shaders/presets/HLSL/xbr/xbr-lv3.cgp create mode 100644 system/shaders/presets/shader-manifest.xml diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po index 07a66466143e3..991079ca2c7e7 100644 --- a/addons/resource.language.en_gb/resources/strings.po +++ b/addons/resource.language.en_gb/resources/strings.po @@ -17587,7 +17587,159 @@ msgctxt "#35259" msgid "Saved" msgstr "" -#empty strings from id 35260 to 35504 +#empty strings from id 35260 to 35401 + +msgctxt "#35402" +msgid "Replicates the 2.6-inch dot matrix screen of the Game Boy. Features the ghosting problems of the original handheld." +msgstr "" + +msgctxt "#35403" +msgid "4xBR Hybrid" +msgstr "" + +msgctxt "#35404" +msgid "CRT Display" +msgstr "" + +msgctxt "#35405" +msgid "Emulates a CRT display. Features scan-lines, color correction, gamma correction and sharpening." +msgstr "" + +msgctxt "#35406" +msgid "Hylian" +msgstr "" + +msgctxt "#35407" +msgid "Emulates a CRT display. Features scan-lines, color correction, gamma correction, sharpening, CRT phosphor and CRT beam effects." +msgstr "" + +msgctxt "#35408" +msgid "Royale" +msgstr "" + +msgctxt "#35409" +msgid "Emulates a CRT display. Resource intensive. Features scan-lines, color correction, gamma correction, sharpening, CRT phosphor emulation, halation, refractive diffusion, curvature and anti-aliasing." +msgstr "" + +msgctxt "#35410" +msgid "CRT Geom" +msgstr "" + +msgctxt "#35411" +msgid "NTSC RF" +msgstr "" + +msgctxt "#35412" +msgid "Replicates an analog signal through a coaxial RF connector. Features color distortion, blurring, NTSC color artifacts and dot crawl." +msgstr "" + +msgctxt "#35413" +msgid "TV-out" +msgstr "" + +msgctxt "#35414" +msgid "NTSC Composite" +msgstr "" + +msgctxt "#35415" +msgid "Replicates an analog signal through an S-Video connector. Features color distortion, blurring, NTSC color artifacts." +msgstr "" + +msgctxt "#35416" +msgid "Replicates an analog signal through a composite connector. Features color distortion, blurring, NTSC color artifacts." +msgstr "" + +#empty string with id 35417 + +msgctxt "#35418" +msgid "Scaling Shader" +msgstr "" + +msgctxt "#35419" +msgid "xBR-lv2 (fast)" +msgstr "" + +msgctxt "#35420" +msgid "Smooths and rounds edges to reduce pixelation. Written by Hyllian." +msgstr "" + +msgctxt "#35421" +msgid "xBR-mlv4" +msgstr "" + +msgctxt "#35422" +msgid "Smooths and rounds edges to reduce pixelation. Image is smoother than other versions. Written by Hyllian." +msgstr "" + +msgctxt "#35424" +msgid "Super Eagle" +msgstr "" + +msgctxt "#35425" +msgid "Smooths and rounds edges to reduce pixelation. Written by Derek Liauw Kie Fa." +msgstr "" + +msgctxt "#35426" +msgid "Game Boy Advance" +msgstr "" + +msgctxt "#35427" +msgid "Nintendo DS" +msgstr "" + +msgctxt "#35428" +msgid "PlayStation Portable" +msgstr "" + +msgctxt "#35429" +msgid "Replicates the 4.3-inch LCD screen of the PlayStation Portable." +msgstr "" + +msgctxt "#35430" +msgid "Replicates the 3-inch LCD screen of the Nintendo DS." +msgstr "" + +msgctxt "#35431" +msgid "Replicates the 2.9-inch color LCD screen of the Game Boy Advance." +msgstr "" + +msgctxt "#35432" +msgid "LCD Screen" +msgstr "" + +msgctxt "#35433" +msgid "LCD3x" +msgstr "" + +msgctxt "#35434" +msgid "Simulates an LCD screen. Written by Gigaherz." +msgstr "" + +msgctxt "#35435" +msgid "NTSC S-video" +msgstr "" + +msgctxt "#35436" +msgid "Emulates a CRT display. Features scan-lines, color correction, gamma correction, sharpening, curvature, interlacing, phosphor and halation." +msgstr "" + +msgctxt "#35437" +msgid "xBR-lv3" +msgstr "" + +msgctxt "#35438" +msgid "xBR-lv3 (no blend)" +msgstr "" + +msgctxt "#35439" +msgid "Smooths and rounds edges to reduce pixelation. Smoother than the no-blend version. Written by Hyllian." +msgstr "" + +msgctxt "#35440" +msgid "Smooths and rounds edges to reduce pixelation. Pixel colors are not blended together. Written by Hyllian." +msgstr "" + +#empty strings from id 35441 to 35504 #. connection state "host unreachable" #: xbmc/pvr/addons/PVRClients.cpp diff --git a/system/shaders/presets/HLSL/cgp/tvout/tvout+ntsc-256px-composite.cgp b/system/shaders/presets/HLSL/cgp/tvout/tvout+ntsc-256px-composite.cgp new file mode 100644 index 0000000000000..0c9caa7695152 --- /dev/null +++ b/system/shaders/presets/HLSL/cgp/tvout/tvout+ntsc-256px-composite.cgp @@ -0,0 +1,45 @@ +shaders = "4" + +shader0 = "../../ntsc/shaders/ntsc-pass1-composite-3phase.cg" +filter_linear0 = "false" +frame_count_mod0 = "2" +float_framebuffer0 = "true" +scale_type_x0 = "absolute" +scale_x0 = "1024" +scale_type_y0 = "source" +scale_y0 = "1.000000" + +shader1 = "../../ntsc/shaders/ntsc-pass2-3phase.cg" +filter_linear1 = "false" +float_framebuffer1 = "false" +scale_type_x1 = "source" +scale_x1 = "0.500000" +scale_type_y1 = "source" +scale_y1 = "1.000000" + +shader2 = "../../crt/shaders/tvout-tweaks.cg" +filter_linear2 = "false" +float_framebuffer2 = "false" +scale_type_x2 = "viewport" +scale_x2 = "1.000000" +scale_type_y2 = "source" +scale_y2 = "1.000000" + +shader3 = "../../misc/image-adjustment.cg" +float_framebuffer3 = "false" + +parameters = "TVOUT_RESOLUTION;TVOUT_COMPOSITE_CONNECTION;TVOUT_TV_COLOR_LEVELS;target_gamma;monitor_gamma;overscan_percent_x;overscan_percent_y;saturation;contrast;luminance;bright_boost;R;G;B" +TVOUT_RESOLUTION = "512.000000" +TVOUT_COMPOSITE_CONNECTION = "0.000000" +TVOUT_TV_COLOR_LEVELS = "1.000000" +target_gamma = "2.400000" +monitor_gamma = "2.200000" +overscan_percent_x = "0.000000" +overscan_percent_y = "0.000000" +saturation = "1.000000" +contrast = "1.000000" +luminance = "1.000000" +bright_boost = "0.000000" +R = "1.000000" +G = "1.000000" +B = "1.000000" \ No newline at end of file diff --git a/system/shaders/presets/HLSL/cgp/tvout/tvout+ntsc-320px-svideo.cgp b/system/shaders/presets/HLSL/cgp/tvout/tvout+ntsc-320px-svideo.cgp new file mode 100644 index 0000000000000..8d9c583a660a7 --- /dev/null +++ b/system/shaders/presets/HLSL/cgp/tvout/tvout+ntsc-320px-svideo.cgp @@ -0,0 +1,45 @@ +shaders = "4" + +shader0 = "../../ntsc/shaders/ntsc-pass1-svideo-2phase.cg" +filter_linear0 = "false" +frame_count_mod0 = "2" +float_framebuffer0 = "true" +scale_type_x0 = "absolute" +scale_x0 = "1920" +scale_type_y0 = "source" +scale_y0 = "1.000000" + +shader1 = "../../ntsc/shaders/ntsc-pass2-2phase.cg" +filter_linear1 = "false" +float_framebuffer1 = "false" +scale_type_x1 = "source" +scale_x1 = "0.500000" +scale_type_y1 = "source" +scale_y1 = "1.000000" + +shader2 = "../../crt/shaders/tvout-tweaks.cg" +filter_linear2 = "false" +float_framebuffer2 = "false" +scale_type_x2 = "viewport" +scale_x2 = "1.000000" +scale_type_y2 = "source" +scale_y2 = "1.000000" + +shader3 = "../../misc/image-adjustment.cg" +float_framebuffer3 = "false" + +parameters = "TVOUT_RESOLUTION;TVOUT_COMPOSITE_CONNECTION;TVOUT_TV_COLOR_LEVELS;target_gamma;monitor_gamma;overscan_percent_x;overscan_percent_y;saturation;contrast;luminance;bright_boost;R;G;B" +TVOUT_RESOLUTION = "512.000000" +TVOUT_COMPOSITE_CONNECTION = "0.000000" +TVOUT_TV_COLOR_LEVELS = "1.000000" +target_gamma = "2.400000" +monitor_gamma = "2.200000" +overscan_percent_x = "0.000000" +overscan_percent_y = "0.000000" +saturation = "1.000000" +contrast = "1.000000" +luminance = "1.000000" +bright_boost = "0.000000" +R = "1.000000" +G = "1.000000" +B = "1.000000" diff --git a/system/shaders/presets/HLSL/compat_includes.inc b/system/shaders/presets/HLSL/compat_includes.inc new file mode 100644 index 0000000000000..d912666c8700b --- /dev/null +++ b/system/shaders/presets/HLSL/compat_includes.inc @@ -0,0 +1,5 @@ +#include "include/compat_input_struct.inc" +#include "include/compat_macros.inc" +#include "include/compat_orig_struct.inc" +#include "include/compat_prev_struct.inc" +#include "include/compat_vertex_in_out.inc" \ No newline at end of file diff --git a/system/shaders/presets/HLSL/crt/4xbr-hybrid-crt-b.cgp b/system/shaders/presets/HLSL/crt/4xbr-hybrid-crt-b.cgp new file mode 100644 index 0000000000000..f3c23dc2ef0db --- /dev/null +++ b/system/shaders/presets/HLSL/crt/4xbr-hybrid-crt-b.cgp @@ -0,0 +1,11 @@ +shaders = 2 + +shader0 = shaders/4xbr-hybrid-crt-b.cg +filter_linear0 = false +scale_type0 = source +scale_x0 = 4.0 +scale_y0 = 4.0 + +shader1 = ../stock.cg +filter_linear1 = true +scale_type_1 = source diff --git a/system/shaders/presets/HLSL/crt/crt-geom.cgp b/system/shaders/presets/HLSL/crt/crt-geom.cgp new file mode 100644 index 0000000000000..8d44a0ba7246b --- /dev/null +++ b/system/shaders/presets/HLSL/crt/crt-geom.cgp @@ -0,0 +1,5 @@ +shaders = 1 + +shader0 = shaders/crt-geom.cg +filter_linear0 = false +scale_type_0 = source diff --git a/system/shaders/presets/HLSL/crt/shaders/4xbr-hybrid-crt-b.cg b/system/shaders/presets/HLSL/crt/shaders/4xbr-hybrid-crt-b.cg new file mode 100644 index 0000000000000..d0a9d0bfa5594 --- /dev/null +++ b/system/shaders/presets/HLSL/crt/shaders/4xbr-hybrid-crt-b.cg @@ -0,0 +1,358 @@ +/* + Hyllian's 4xBR v3.8b+ReverseAA (semi-rounded) Shader + crt-caligari + + Copyright (C) 2011/2012 Hyllian/Jararaca - sergiogdb@gmail.com + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +/* + * ReverseAA part of the code + * + * Copyright (c) 2012, Christoph Feck + * All Rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "../../compat_includes.inc" +uniform COMPAT_Texture2D(decal) : TEXUNIT0; +uniform float4x4 modelViewProj; + +const static float coef = 2.0; +const static float4 eq_threshold = float4(15.0, 15.0, 15.0, 15.0); +const static half y_weight = 48.0; +const static half u_weight = 7.0; +const static half v_weight = 6.0; +const static half3x3 yuv = half3x3(0.299, 0.587, 0.114, -0.169, -0.331, 0.499, 0.499, -0.418, -0.0813); +const static half3x3 yuv_weighted = half3x3(y_weight*yuv[0], u_weight*yuv[1], v_weight*yuv[2]); +const static float4 delta = float4(0.4, 0.4, 0.4, 0.4); +const static float sharpness = 0.65; + +// Constants used with gamma correction. +#define InputGamma 2.4 +#define OutputGamma 2.2 + +#define GAMMA_IN(color) pow(color, float3(InputGamma, InputGamma, InputGamma)) +#define GAMMA_OUT(color) pow(color, float3(1.0 / OutputGamma, 1.0 / OutputGamma, 1.0 / OutputGamma)) + +#define TEX2D(coords) GAMMA_IN( COMPAT_SamplePoint(decal, coords).xyz ) + +// 0.5 = the spot stays inside the original pixel +// 1.0 = the spot bleeds up to the center of next pixel +#define SPOT_HEIGHT 0.58 + +// Used to counteract the desaturation effect of weighting. +#define COLOR_BOOST 1.45 + +// Macro for weights computing +#define WEIGHT(w) \ + if(w>1.0) w=1.0; \ + w = 1.0 - w * w; \ + w = w * w;\ + +float4 df(float4 A, float4 B) +{ + return float4(abs(A-B)); +} + +half c_df(half3 c1, half3 c2) +{ + half3 df = abs(c1 - c2); + return df.r + df.g + df.b; +} + +bool4 eq(float4 A, float4 B) +{ + return (df(A, B) < eq_threshold); +} + +bool4 eq2(float4 A, float4 B) +{ + return (df(A, B) < float4(2.0, 2.0, 2.0, 2.0)); +} + + +float4 weighted_distance(float4 a, float4 b, float4 c, float4 d, float4 e, float4 f, float4 g, float4 h) +{ + return (df(a,b) + df(a,c) + df(d,e) + df(d,f) + 4.0*df(g,h)); +} + +struct out_vertex +{ + half4 position : COMPAT_POS; + float2 texCoord : TEXCOORD0; + float4 t1 : TEXCOORD1; + float4 t2 : TEXCOORD2; + float4 t3 : TEXCOORD3; + float4 t4 : TEXCOORD4; + float4 t5 : TEXCOORD5; + float4 t6 : TEXCOORD6; + float4 t7 : TEXCOORD7; +#ifndef HLSL_4 + float4 Color : COLOR; +#endif +}; + +/* VERTEX_SHADER */ +out_vertex main_vertex(COMPAT_IN_VERTEX) +{ + out_vertex OUT; +#ifdef HLSL_4 + float4 position = VIN.position; + float2 texCoord = VIN.texCoord; +#else + OUT.Color = color; +#endif + + OUT.position = mul(modelViewProj, position); + + float2 ps = float2(1.0/COMPAT_texture_size.x, 1.0/COMPAT_texture_size.y); + float dx = ps.x; + float dy = ps.y; + + // A1 B1 C1 + // A0 A B C C4 + // D0 D E F F4 + // G0 G H I I4 + // G5 H5 I5 + + // This line fix a bug in ATI cards. + float2 texCoord1 = texCoord + float2(0.0000001, 0.0000001); + + OUT.texCoord = texCoord1; + OUT.t1 = texCoord1.xxxy + half4( -dx, 0, dx,-2.0*dy); // A1 B1 C1 + OUT.t2 = texCoord1.xxxy + half4( -dx, 0, dx, -dy); // A B C + OUT.t3 = texCoord1.xxxy + half4( -dx, 0, dx, 0); // D E F + OUT.t4 = texCoord1.xxxy + half4( -dx, 0, dx, dy); // G H I + OUT.t5 = texCoord1.xxxy + half4( -dx, 0, dx, 2.0*dy); // G5 H5 I5 + OUT.t6 = texCoord1.xyyy + half4(-2.0*dx,-dy, 0, dy); // A0 D0 G0 + OUT.t7 = texCoord1.xyyy + half4( 2.0*dx,-dy, 0, dy); // C4 F4 I4 + + return OUT; +} + + +/* FRAGMENT SHADER */ +float4 xBR_hybrid_CRT_b(float2 texture_size, float2 texCoord, COMPAT_Texture2D(decal), float4 t1, float4 t2, float4 t3, float4 t4, + float4 t5, float4 t6, float4 t7) +{ + bool4 edr, edr_left, edr_up, px; // px = pixel, edr = edge detection rule + bool4 interp_restriction_lv1, interp_restriction_lv2_left, interp_restriction_lv2_up; + bool4 nc, nc30, nc60, nc45; // new_color + float4 fx, fx_left, fx_up, final_fx; // inequations of straight lines. + half3 res1, res2, pix1, pix2; + float blend1, blend2; + + float2 fp = frac(texCoord*texture_size); + + half3 A1 = COMPAT_SamplePoint(decal, t1.xw).rgb; + half3 B1 = COMPAT_SamplePoint(decal, t1.yw).rgb; + half3 C1 = COMPAT_SamplePoint(decal, t1.zw).rgb; + + half3 A = COMPAT_SamplePoint(decal, t2.xw).rgb; + half3 B = COMPAT_SamplePoint(decal, t2.yw).rgb; + half3 C = COMPAT_SamplePoint(decal, t2.zw).rgb; + + half3 D = COMPAT_SamplePoint(decal, t3.xw).rgb; + half3 E = COMPAT_SamplePoint(decal, t3.yw).rgb; + half3 F = COMPAT_SamplePoint(decal, t3.zw).rgb; + + half3 G = COMPAT_SamplePoint(decal, t4.xw).rgb; + half3 H = COMPAT_SamplePoint(decal, t4.yw).rgb; + half3 I = COMPAT_SamplePoint(decal, t4.zw).rgb; + + half3 G5 = COMPAT_SamplePoint(decal, t5.xw).rgb; + half3 H5 = COMPAT_SamplePoint(decal, t5.yw).rgb; + half3 I5 = COMPAT_SamplePoint(decal, t5.zw).rgb; + + half3 A0 = COMPAT_SamplePoint(decal, t6.xy).rgb; + half3 D0 = COMPAT_SamplePoint(decal, t6.xz).rgb; + half3 G0 = COMPAT_SamplePoint(decal, t6.xw).rgb; + + half3 C4 = COMPAT_SamplePoint(decal, t7.xy).rgb; + half3 F4 = COMPAT_SamplePoint(decal, t7.xz).rgb; + half3 I4 = COMPAT_SamplePoint(decal, t7.xw).rgb; + + float4 b = mul( half4x3(B, D, H, F), yuv_weighted[0] ); + float4 c = mul( half4x3(C, A, G, I), yuv_weighted[0] ); + float4 e = mul( half4x3(E, E, E, E), yuv_weighted[0] ); + float4 a = c.yzwx; + float4 d = b.yzwx; + float4 f = b.wxyz; + float4 g = c.zwxy; + float4 h = b.zwxy; + float4 i = c.wxyz; + + float4 i4 = mul( half4x3(I4, C1, A0, G5), yuv_weighted[0] ); + float4 i5 = mul( half4x3(I5, C4, A1, G0), yuv_weighted[0] ); + float4 h5 = mul( half4x3(H5, F4, B1, D0), yuv_weighted[0] ); + float4 f4 = h5.yzwx; + + + float4 Ao = float4( 1.0, -1.0, -1.0, 1.0 ); + float4 Bo = float4( 1.0, 1.0, -1.0,-1.0 ); + float4 Co = float4( 1.5, 0.5, -0.5, 0.5 ); + float4 Ax = float4( 1.0, -1.0, -1.0, 1.0 ); + float4 Bx = float4( 0.5, 2.0, -0.5,-2.0 ); + float4 Cx = float4( 1.0, 1.0, -0.5, 0.0 ); + float4 Ay = float4( 1.0, -1.0, -1.0, 1.0 ); + float4 By = float4( 2.0, 0.5, -2.0,-0.5 ); + float4 Cy = float4( 2.0, 0.0, -1.0, 0.5 ); + + // These inequations define the line below which interpolation occurs. + fx = (Ao*fp.y+Bo*fp.x); + fx_left = (Ax*fp.y+Bx*fp.x); + fx_up = (Ay*fp.y+By*fp.x); + + interp_restriction_lv1 = ((e!=f) && (e!=h) && ((eq2(e,b) || eq2(e,d) || !eq2(e,a)) && (eq2(f,f4) || eq2(f,c) || eq2(h,h5) || eq2(h,g))) && ( !eq(f,b) && !eq(h,d) || eq(e,i) && !eq(f,i4) && !eq(h,i5) || eq(e,g) || eq(e,c) ) ); + interp_restriction_lv2_left = ((e!=g) && (d!=g)); + interp_restriction_lv2_up = ((e!=c) && (b!=c)); + + float4 fx45 = smoothstep(Co - delta, Co + delta, fx); + float4 fx30 = smoothstep(Cx - delta, Cx + delta, fx_left); + float4 fx60 = smoothstep(Cy - delta, Cy + delta, fx_up); + + + edr = ((weighted_distance( e, c, g, i, h5, f4, h, f) + 3.5) < weighted_distance( h, d, i5, f, i4, b, e, i)) && interp_restriction_lv1; + edr_left = ((coef*df(f,g)) <= df(h,c)) && interp_restriction_lv2_left; + edr_up = (df(f,g) >= (coef*df(h,c))) && interp_restriction_lv2_up; + + nc45 = ( edr && bool4(fx45)); + nc30 = ( edr && edr_left && bool4(fx30)); + nc60 = ( edr && edr_up && bool4(fx60)); + + px = (df(e,f) <= df(e,h)); + + half3 res = E; + + + float3 n1, n2, n3, n4, s, aa, bb, cc, dd; + + + n1 = B1; n2 = B; s = E; n3 = H; n4 = H5; + aa = n2-n1; bb = s-n2; cc = n3-s; dd = n4-n3; + + float3 t = (7 * (bb + cc) - 3 * (aa + dd)) / 16; + + float3 m = (s < 0.5) ? 2*s : 2*(1.0-s); + + m = min(m, sharpness*abs(bb)); + m = min(m, sharpness*abs(cc)); + + t = clamp(t, -m, m); + + + float3 s1 = (2*fp.y-1)*t + s; + + n1 = D0; n2 = D; s = s1; n3 = F; n4 = F4; + aa = n2-n1; bb = s-n2; cc = n3-s; dd = n4-n3; + + t = (7 * (bb + cc) - 3 * (aa + dd)) / 16; + + m = (s < 0.5) ? 2*s : 2*(1.0-s); + + m = min(m, sharpness*abs(bb)); + m = min(m, sharpness*abs(cc)); + + t = clamp(t, -m, m); + + float3 s0 = (2*fp.x-1)*t + s; + + + nc = (nc30 || nc60 || nc45); + + blend1 = blend2 = 0.0; + + float4 final45 = dot(nc45, fx45); + float4 final30 = dot(nc30, fx30); + float4 final60 = dot(nc60, fx60); + + float4 maximo = max(max(final30, final60), final45); + + if (nc.x) {pix1 = px.x ? F : H; blend1 = maximo.x;} + else if (nc.y) {pix1 = px.y ? B : F; blend1 = maximo.y;} + else if (nc.z) {pix1 = px.z ? D : B; blend1 = maximo.z;} + else if (nc.w) {pix1 = px.w ? H : D; blend1 = maximo.w;} + + if (nc.w) {pix2 = px.w ? H : D; blend2 = maximo.w;} + else if (nc.z) {pix2 = px.z ? D : B; blend2 = maximo.z;} + else if (nc.y) {pix2 = px.y ? B : F; blend2 = maximo.y;} + else if (nc.x) {pix2 = px.x ? F : H; blend2 = maximo.x;} + + res1 = lerp(s0, pix1, blend1); + res2 = lerp(s0, pix2, blend2); + + res = lerp(res1, res2, step(c_df(E, res1), c_df(E, res2))); + +// CRT-caligari - only vertical blend + + float3 color = GAMMA_IN(res); + + float ddy = fp.y - 0.5; + float v_weight_00 = ddy / SPOT_HEIGHT; + WEIGHT(v_weight_00); + color *= float3( v_weight_00, v_weight_00, v_weight_00 ); + + // get closest vertical neighbour to blend + float3 coords10; + if (ddy>0.0) { + coords10 = H; + ddy = 1.0 - ddy; + } else { + coords10 = B; + ddy = 1.0 + ddy; + } + float3 colorNB = GAMMA_IN(coords10); + + float v_weight_10 = ddy / SPOT_HEIGHT; + WEIGHT( v_weight_10 ); + + color += colorNB * float3( v_weight_10, v_weight_10, v_weight_10 ); + + color *= float3( COLOR_BOOST, COLOR_BOOST, COLOR_BOOST ); + + return float4(clamp( GAMMA_OUT(color), 0.0, 1.0 ), 1.0); + + return float4(res.x, res.y, res.z, 1.0); +} + +float4 main_fragment(COMPAT_IN_FRAGMENT) : COMPAT_Output +{ + return xBR_hybrid_CRT_b(COMPAT_texture_size, VOUT.texCoord, decal, VOUT.t1, VOUT.t2, VOUT.t3, VOUT.t4, VOUT.t5, VOUT.t6, VOUT.t7); +} +COMPAT_END \ No newline at end of file diff --git a/system/shaders/presets/HLSL/crt/shaders/crt-geom.cg b/system/shaders/presets/HLSL/crt/shaders/crt-geom.cg new file mode 100644 index 0000000000000..f4f297d5d5964 --- /dev/null +++ b/system/shaders/presets/HLSL/crt/shaders/crt-geom.cg @@ -0,0 +1,388 @@ +#pragma parameter CRTgamma "CRTGeom Target Gamma" 2.4 0.1 5.0 0.1 +#pragma parameter monitorgamma "CRTGeom Monitor Gamma" 2.2 0.1 5.0 0.1 +#pragma parameter d "CRTGeom Distance" 1.5 0.1 3.0 0.1 +#pragma parameter CURVATURE "CRTGeom Curvature Toggle" 1.0 0.0 1.0 1.0 +#pragma parameter R "CRTGeom Curvature Radius" 2.0 0.1 10.0 0.1 +#pragma parameter cornersize "CRTGeom Corner Size" 0.03 0.001 1.0 0.005 +#pragma parameter cornersmooth "CRTGeom Corner Smoothness" 1000.0 80.0 2000.0 100.0 +#pragma parameter x_tilt "CRTGeom Horizontal Tilt" 0.0 -0.5 0.5 0.05 +#pragma parameter y_tilt "CRTGeom Vertical Tilt" 0.0 -0.5 0.5 0.05 +#pragma parameter overscan_x "CRTGeom Horiz. Overscan %" 100.0 -125.0 125.0 1.0 +#pragma parameter overscan_y "CRTGeom Vert. Overscan %" 100.0 -125.0 125.0 1.0 +#pragma parameter DOTMASK "CRTGeom Dot Mask Toggle" 0.3 0.0 0.3 0.3 +#pragma parameter SHARPER "CRTGeom Sharpness" 1.0 1.0 3.0 1.0 +#pragma parameter scanline_weight "CRTGeom Scanline Weight" 0.3 0.1 0.5 0.01 +#pragma parameter lum "CRTGeom Luminance Boost" 0.0 0.0 1.0 0.01 +#pragma parameter interlace_toggle "CRTGeom Interlacing" 1.0 1.0 5.0 4.0 + +#ifdef PARAMETER_UNIFORM +uniform float CRTgamma; +uniform float monitorgamma; +uniform float d; +uniform float CURVATURE; +uniform float R; +uniform float cornersize; +uniform float cornersmooth; +uniform float x_tilt; +uniform float y_tilt; +uniform float overscan_x; +uniform float overscan_y; +uniform float DOTMASK; +uniform float SHARPER; +uniform float scanline_weight; +uniform float lum; +uniform float interlace_toggle; + +#else +#define CRTgamma 2.4 +#define monitorgamma 2.2 +#define d 1.5 +#define CURVATURE 1.0 +#define R 2.0 +#define cornersize 0.03 +#define cornersmooth 1000.0 +#define x_tilt 0.0 +#define y_tilt 0.0 +#define overscan_x 100.0 +#define overscan_y 100.0 +#define DOTMASK 0.3 +#define SHARPER 1.0 +#define scanline_weight 0.3 +#define lum 0.0 +#define interlace_toggle 1.0 + +#endif +// END PARAMETERS // + +/* COMPATIBILITY + - HLSL compilers + - Cg compilers + - FX11 compilers +*/ + +#define mod(x,y) (x - y * trunc(x/y)) + +/* + CRT-interlaced + + Copyright (C) 2010-2012 cgwg, Themaister and DOLLS + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + (cgwg gave their consent to have the original version of this shader + distributed under the GPL in this message: + + http://board.byuu.org/viewtopic.php?p=26075#p26075 + + "Feel free to distribute my shaders under the GPL. After all, the + barrel distortion code was taken from the Curvature shader, which is + under the GPL." + ) + This shader variant is pre-configured with screen curvature +*/ + +#include "../../compat_includes.inc" +uniform COMPAT_Texture2D(decal) : TEXUNIT0; +uniform float4x4 modelViewProj; + + // Comment the next line to disable interpolation in linear gamma (and + // gain speed). + #define LINEAR_PROCESSING + + // Enable 3x oversampling of the beam profile; improves moire effect caused by scanlines+curvature + #define OVERSAMPLE + + // Use the older, purely gaussian beam profile; uncomment for speed + //#define USEGAUSSIAN + + // Use interlacing detection; may interfere with other shaders if combined + #define INTERLACED + + // Enable Dot-mask emulation: + // Output pixels are alternately tinted green and magenta. +// #define DOTMASK + + // Macros. + #define FIX(c) max(abs(c), 1e-5); + #define PI 3.141592653589 + + #ifdef LINEAR_PROCESSING + # define TEX2D(c) pow(COMPAT_SamplePoint(s0, (c)), float4(CRTgamma,CRTgamma,CRTgamma,CRTgamma)) + #else + # define TEX2D(c) COMPAT_SamplePoint(s0, (c)) + #endif + + // aspect ratio + static float2 aspect = float2(1.0, 0.75); + + + float intersect(float2 xy, float4 sin_cos_angle) + { + float A = dot(xy,xy)+d*d; + float B = 2.0*(R*(dot(xy,sin_cos_angle.xy)-d*sin_cos_angle.zw.x*sin_cos_angle.zw.y)-d*d); + float C = d*d + 2.0*R*d*sin_cos_angle.zw.x*sin_cos_angle.zw.y; + return (-B-sqrt(B*B-4.0*A*C))/(2.0*A); + } + + float2 bkwtrans(float2 xy, float4 sin_cos_angle) + { + float c = intersect(xy, sin_cos_angle); + float2 point_ = float2(c,c)*xy; + point_ -= float2(-R,-R)*sin_cos_angle.xy; + point_ /= float2(R,R); + float2 tang = sin_cos_angle.xy/sin_cos_angle.zw; + float2 poc = point_/sin_cos_angle.zw; + float A = dot(tang,tang)+1.0; + float B = -2.0*dot(poc,tang); + float C = dot(poc,poc)-1.0; + float a = (-B+sqrt(B*B-4.0*A*C))/(2.0*A); + float2 uv = (point_-a*sin_cos_angle.xy)/sin_cos_angle.zw; + float r = FIX(R*acos(a)); + return uv*r/sin(r/R); + } + + float2 fwtrans(float2 uv, float4 sin_cos_angle) + { + float r = FIX(sqrt(dot(uv,uv))); + uv *= sin(r/R)/r; + float x = 1.0-cos(r/R); + float D = d/R + x*sin_cos_angle.z*sin_cos_angle.w+dot(uv,sin_cos_angle.xy); + return d*(uv*sin_cos_angle.zw-x*sin_cos_angle.xy)/D; + } + + float3 maxscale(float4 sin_cos_angle) + { + float2 c = bkwtrans(-R * sin_cos_angle.xy / (1.0 + R/d*sin_cos_angle.z*sin_cos_angle.w), sin_cos_angle); + float2 a = float2(0.5,0.5)*aspect; + float2 lo = float2(fwtrans(float2(-a.x,c.y), sin_cos_angle).x, + fwtrans(float2(c.x,-a.y), sin_cos_angle).y)/aspect; + float2 hi = float2(fwtrans(float2(+a.x,c.y), sin_cos_angle).x, + fwtrans(float2(c.x,+a.y), sin_cos_angle).y)/aspect; + return float3((hi+lo)*aspect*0.5,max(hi.x-lo.x,hi.y-lo.y)); + } + + // Calculate the influence of a scanline on the current pixel. + // + // 'distance' is the distance in texture coordinates from the current + // pixel to the scanline in question. + // 'color' is the colour of the scanline at the horizontal location of + // the current pixel. + float4 scanlineWeights(float distance, float4 color) + { + // "wid" controls the width of the scanline beam, for each RGB + // channel The "weights" lines basically specify the formula + // that gives you the profile of the beam, i.e. the intensity as + // a function of distance from the vertical center of the + // scanline. In this case, it is gaussian if width=2, and + // becomes nongaussian for larger widths. Ideally this should + // be normalized so that the integral across the beam is + // independent of its width. That is, for a narrower beam + // "weights" should have a higher peak at the center of the + // scanline than for a wider beam. + #ifdef USEGAUSSIAN + float4 wid = 0.3 + 0.1 * pow(color, float4(3.0, 3.0, 3.0, 3.0)); + float v = distance / (wid * scanline_weight/0.3); + float4 weights = float4(v,v,v,v); + return (lum + 0.4) * exp(-weights * weights) / wid; + #else + float4 wid = 2.0 + 2.0 * pow(color, float4(4.0, 4.0, 4.0, 4.0)); + float v = distance / scanline_weight; + float4 weights = float4(v,v,v,v); + return (lum + 1.4) * exp(-pow(weights * rsqrt(0.5 * wid), wid)) / (0.6 + 0.2 * wid); + #endif + } + +struct out_vertex { + float4 position : COMPAT_POS; + float2 texCoord : TEXCOORD0; +#ifdef HLSL_4 + float2 one : VAR0; + float mod_factor : VAR1; + float2 ilfac : VAR2; + float3 stretch : VAR3; + float4 sin_cos_angle : VAR4; + float2 TextureSize : VAR5; +#else + float2 one; + float mod_factor; + float2 ilfac; + float3 stretch; + float4 sin_cos_angle; + float2 TextureSize; + float4 Color : COLOR; +#endif +}; + + +/* VERTEX_SHADER */ +out_vertex main_vertex(COMPAT_IN_VERTEX) +{ + out_vertex OUT; +#ifdef HLSL_4 + float4 position = VIN.position; + float2 texCoord = VIN.texCoord; +#else + OUT.Color = color; +#endif + + OUT.position = mul(modelViewProj, position); + + // Precalculate a bunch of useful values we'll need in the fragment + // shader. + float2 sinangle = sin(float2(x_tilt, y_tilt)); + float2 cosangle = cos(float2(x_tilt, y_tilt)); + OUT.sin_cos_angle = float4(sinangle.x, sinangle.y, cosangle.x, cosangle.y); + OUT.stretch = maxscale(OUT.sin_cos_angle); + OUT.texCoord = texCoord; + OUT.TextureSize = float2(SHARPER * COMPAT_texture_size.x, COMPAT_texture_size.y); + + OUT.ilfac = float2(1.0,clamp(floor(COMPAT_video_size.y/(200.0 * interlace_toggle)),1.0,2.0)); + + // The size of one texel, in texture-coordinates. + OUT.one = OUT.ilfac / OUT.TextureSize; + + // Resulting X pixel-coordinate of the pixel we're drawing. + OUT.mod_factor = texCoord.x * COMPAT_texture_size.x * COMPAT_output_size.x / COMPAT_video_size.x; + return OUT; +} + +/* FRAGMENT SHADER */ +float4 crt_geom(float2 texture_size, float2 video_size, float2 output_size, float frame_count, float4 sin_cos_angle, float3 stretch, + float2 ilfac, float2 one, float mod_factor, float2 TextureSize, float2 texCoord, COMPAT_Texture2D(s0)) +{ + // Here's a helpful diagram to keep in mind while trying to + // understand the code: + // + // | | | | | + // ------------------------------- + // | | | | | + // | 01 | 11 | 21 | 31 | <-- current scanline + // | | @ | | | + // ------------------------------- + // | | | | | + // | 02 | 12 | 22 | 32 | <-- next scanline + // | | | | | + // ------------------------------- + // | | | | | + // + // Each character-cell represents a pixel on the output + // surface, "@" represents the current pixel (always somewhere + // in the bottom half of the current scan-line, or the top-half + // of the next scanline). The grid of lines represents the + // edges of the texels of the underlying texture. + + // Texture coordinates of the texel containing the active pixel. + float2 xy = 0.0; + if (CURVATURE > 0.5) + { + float2 cd = texCoord; + cd *= texture_size / video_size; + cd = (cd-float2(0.5, 0.5))*aspect*stretch.z+stretch.xy; + xy = (bkwtrans(cd, sin_cos_angle)/float2(overscan_x / 100.0, overscan_y / 100.0)/aspect+float2(0.5, 0.5)) * video_size / texture_size; + } + else + { + xy = texCoord; + } + + float2 cd2 = xy; + cd2 *= texture_size / video_size; + cd2 = (cd2 - float2(0.5, 0.5)) * float2(overscan_x / 100.0, overscan_y / 100.0) + float2(0.5, 0.5); + cd2 = min(cd2, float2(1.0, 1.0)-cd2) * aspect; + float2 cdist = float2(cornersize, cornersize); + cd2 = (cdist - min(cd2,cdist)); + float dist = sqrt(dot(cd2,cd2)); + float cval = clamp((cdist.x-dist)*cornersmooth,0.0, 1.0); + + float2 xy2 = ((xy*TextureSize/video_size-float2(0.5, 0.5))*float2(1.0,1.0)+float2(0.5, 0.5))*video_size/TextureSize; + // Of all the pixels that are mapped onto the texel we are + // currently rendering, which pixel are we currently rendering? + float2 ilfloat = float2(0.0,ilfac.y > 1.5 ? mod(float(frame_count),2.0) : 0.0); + + float2 ratio_scale = (xy * TextureSize - float2(0.5,0.5) + ilfloat)/ilfac; + + #ifdef OVERSAMPLE + float filter = video_size.y / output_size.y; + #endif + float2 uv_ratio = frac(ratio_scale); + + // Snap to the center of the underlying texel. + + xy = (floor(ratio_scale)*ilfac + float2(0.5, 0.5) - ilfloat) / TextureSize; + + // Calculate Lanczos scaling coefficients describing the effect + // of various neighbour texels in a scanline on the current + // pixel. + float4 coeffs = PI * float4(1.0 + uv_ratio.x, uv_ratio.x, 1.0 - uv_ratio.x, 2.0 - uv_ratio.x); + + // Prevent division by zero. + coeffs = FIX(coeffs); + + // Lanczos2 kernel. + coeffs = 2.0 * sin(coeffs) * sin(coeffs / 2.0) / (coeffs * coeffs); + + // Normalize. + coeffs /= dot(coeffs, float4(1.0, 1.0, 1.0, 1.0)); + + // Calculate the effective colour of the current and next + // scanlines at the horizontal location of the current pixel, + // using the Lanczos coefficients above. + float4 col = clamp(mul(coeffs, float4x4( + TEX2D(xy + float2(-one.x, 0.0)), + TEX2D(xy), + TEX2D(xy + float2(one.x, 0.0)), + TEX2D(xy + float2(2.0 * one.x, 0.0)))), + 0.0, 1.0); + float4 col2 = clamp(mul(coeffs, float4x4( + TEX2D(xy + float2(-one.x, one.y)), + TEX2D(xy + float2(0.0, one.y)), + TEX2D(xy + one), + TEX2D(xy + float2(2.0 * one.x, one.y)))), + 0.0, 1.0); + + #ifndef LINEAR_PROCESSING + col = pow(col , float4(CRTgamma)); + col2 = pow(col2, float4(CRTgamma)); + #endif + + // Calculate the influence of the current and next scanlines on + // the current pixel. + float4 weights = scanlineWeights(uv_ratio.y, col); + float4 weights2 = scanlineWeights(1.0 - uv_ratio.y, col2); + #ifdef OVERSAMPLE + uv_ratio.y =uv_ratio.y+1.0/3.0*filter; + weights = (weights+scanlineWeights(uv_ratio.y, col))/3.0; + weights2=(weights2+scanlineWeights(abs(1.0-uv_ratio.y), col2))/3.0; + uv_ratio.y =uv_ratio.y-2.0/3.0*filter; + weights=weights+scanlineWeights(abs(uv_ratio.y), col)/3.0; + weights2=weights2+scanlineWeights(abs(1.0-uv_ratio.y), col2)/3.0; + #endif + float3 mul_res = (col * weights + col2 * weights2).rgb; + mul_res *= float3(cval, cval, cval); + + // dot-mask emulation: + // Output pixels are alternately tinted green and magenta. + float3 dotMaskWeights = lerp( + float3(1.0, 1.0 - DOTMASK, 1.0), + float3(1.0 - DOTMASK, 1.0, 1.0 - DOTMASK), + floor(mod(mod_factor, 2.0)) + ); + mul_res *= dotMaskWeights; + + + // Convert the image gamma for display on our output device. + mul_res = pow(mul_res, float3(1.0 / monitorgamma, 1.0 / monitorgamma, 1.0 / monitorgamma)); + + // Color the texel. + return float4(mul_res, 1.0); +} + +float4 main_fragment(COMPAT_IN_FRAGMENT) : COMPAT_Output +{ + return crt_geom(COMPAT_texture_size, COMPAT_video_size, COMPAT_output_size, COMPAT_frame_count, VOUT.sin_cos_angle, VOUT.stretch, + VOUT.ilfac, VOUT.one, VOUT.mod_factor, VOUT.TextureSize, VOUT.texCoord, decal); +} +COMPAT_END diff --git a/system/shaders/presets/HLSL/crt/shaders/tvout-tweaks.cg b/system/shaders/presets/HLSL/crt/shaders/tvout-tweaks.cg new file mode 100644 index 0000000000000..8c537f539a50b --- /dev/null +++ b/system/shaders/presets/HLSL/crt/shaders/tvout-tweaks.cg @@ -0,0 +1,192 @@ +/////////////// +// TV-out tweaks +// Author: aliaspider - aliaspider@gmail.com +// License: GPLv3 +//////////////////////////////////////////////////////// + +/* COMPATIBILITY + - HLSL compilers + - Cg compilers + - FX11 compilers +*/ + +// this shader is meant to be used when running +// an emulator on a real CRT-TV @240p or @480i +//////////////////////////////////////////////////////// +// Basic settings: + +// signal resolution +// higher = sharper +#pragma parameter TVOUT_RESOLUTION "TVOut Signal Resolution" 256.0 0.0 1024.0 32.0 // default, minimum, maximum, optional step + +// simulate a composite connection instead of RGB +#pragma parameter TVOUT_COMPOSITE_CONNECTION "TVOut Composite Enable" 0.0 0.0 1.0 1.0 + +// use TV video color range (16-235) +// instead of PC full range (0-255) +#pragma parameter TVOUT_TV_COLOR_LEVELS "TVOut TV Color Levels Enable" 0.0 0.0 1.0 1.0 +//////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////// +// Advanced settings: +// +// these values will be used instead +// if COMPOSITE_CONNECTION is defined +// to simulate different signal resolutions(bandwidth) +// for luma (Y) and chroma ( I and Q ) +// this is just an approximation +// and will only simulate the low bandwidth anspect of +// composite signal, not the crosstalk between luma and chroma +// Y = 4MHz I=1.3MHz Q=0.4MHz +#pragma parameter TVOUT_RESOLUTION_Y "TVOut Luma (Y) Resolution" 256.0 0.0 1024.0 32.0 +#pragma parameter TVOUT_RESOLUTION_I "TVOut Chroma (I) Resolution" 83.2 0.0 256.0 8.0 +#pragma parameter TVOUT_RESOLUTION_Q "TVOut Chroma (Q) Resolution" 25.6 0.0 256.0 8.0 + +// formula is MHz=resolution*15750Hz +// 15750Hz being the horizontal Frequency of NTSC +// (=262.5*60Hz) +//////////////////////////////////////////////////////// + +#ifdef PARAMETER_UNIFORM // If the shader implementation understands #pragma parameters, this is defined. +uniform float TVOUT_RESOLUTION; +uniform float TVOUT_COMPOSITE_CONNECTION; +uniform float TVOUT_TV_COLOR_LEVELS; +uniform float TVOUT_RESOLUTION_Y; +uniform float TVOUT_RESOLUTION_I; +uniform float TVOUT_RESOLUTION_Q; +#else +// Fallbacks if parameters are not supported. +#define TVOUT_RESOLUTION 256.0 // Default +#define TVOUT_COMPOSITE_CONNECTION 0 +#define TVOUT_TV_COLOR_LEVELS 0 +#define TVOUT_RESOLUTION_Y 256.0 +#define TVOUT_RESOLUTION_I 83.2 +#define TVOUT_RESOLUTION_Q 25.6 +#endif + +#include "../../compat_includes.inc" +uniform COMPAT_Texture2D(decal) : TEXUNIT0; +uniform float4x4 modelViewProj; + +struct out_vertex +{ + float4 position : COMPAT_POS; + float2 texCoord : TEXCOORD0; +#ifndef HLSL_4 + float4 Color : COLOR; +#endif +}; + +out_vertex main_vertex(COMPAT_IN_VERTEX) +{ + out_vertex OUT; +#ifdef HLSL_4 + float4 position = VIN.position; + float2 texCoord = VIN.texCoord; +#else + OUT.Color = color; +#endif + OUT.position = mul(modelViewProj, position); + OUT.texCoord = texCoord; + + return OUT; +} + +static const float3x3 RGB_to_YIQ = float3x3( + 0.299,0.587,0.114, + 0.595716,-0.274453,-0.321263, + 0.211456,-0.522591, 0.311135); +static const float3x3 YIQ_to_RGB = float3x3( + 1.0,0.9563,0.6210, + 1.0,-0.2721,-0.6474, + 1.0,-1.1070, 1.7046); + +static const float pi = 3.14159265358; + +float L(float C) +{ + return clamp((C - 16.5 / 256.0) * 256.0 / (236.0 - 16.0), 0.0, 1.0); +} + +float LCHR(float C) +{ + return clamp((C - 16.5 / 256.0) * 256.0 / (240.0 - 16.0), 0.0, 1.0); +} + +float STU(float x, float b) +{ + float d = pi * b * min(abs(x) + 0.5, 1.0 / b); + float e = pi * b * min(max(abs(x) - 0.5, -1.0 / b), 1.0 / b); + return ((d + sin(d) - e - sin(e)) / (2.0 * pi)); +} + +float3 LEVELS(float3 c0) +{ + if (TVOUT_TV_COLOR_LEVELS) + { + if (TVOUT_COMPOSITE_CONNECTION) + return float3(L(c0.x), LCHR(c0.y), LCHR(c0.z)); + else + return float3(L(c0.x), L(c0.y), L(c0.z)); + } + else + return c0; +} + +float4 tv_out_tweaks(float2 texture_size, float2 video_size, float2 texCoord, COMPAT_Texture2D(tex)) +{ + float3 tempColor = float3(0.0, 0.0, 0.0); + float offset = frac((texCoord.x * texture_size.x) - 0.5); + float oneT = 1.0/texture_size.x; + float oneI = 1.0/video_size.x; + + float X; + float3 c; + + if (TVOUT_COMPOSITE_CONNECTION) + { + X = offset-(-1); + c = mul(RGB_to_YIQ,LEVELS(COMPAT_Sample(tex, float2(texCoord.x - X*oneT,texCoord.y)).xyz)); + tempColor += float3((c.x*STU(X,(TVOUT_RESOLUTION_Y*oneI))),(c.y*STU(X,(TVOUT_RESOLUTION_I*oneI))),(c.z*STU(X,(TVOUT_RESOLUTION_Q*oneI)))); + + X = offset-(0); + c = mul(RGB_to_YIQ,LEVELS(COMPAT_Sample(tex, float2(texCoord.x - X*oneT,texCoord.y)).xyz)); + tempColor += float3((c.x*STU(X,(TVOUT_RESOLUTION_Y*oneI))),(c.y*STU(X,(TVOUT_RESOLUTION_I*oneI))),(c.z*STU(X,(TVOUT_RESOLUTION_Q*oneI)))); + + X = offset-(1); + c = mul(RGB_to_YIQ,LEVELS(COMPAT_Sample(tex, float2(texCoord.x - X*oneT,texCoord.y)).xyz)); + tempColor += float3((c.x*STU(X,(TVOUT_RESOLUTION_Y*oneI))),(c.y*STU(X,(TVOUT_RESOLUTION_I*oneI))),(c.z*STU(X,(TVOUT_RESOLUTION_Q*oneI)))); + + X = offset-(2); + c = mul(RGB_to_YIQ,LEVELS(COMPAT_Sample(tex, float2(texCoord.x - X*oneT,texCoord.y)).xyz)); + tempColor += float3((c.x*STU(X,(TVOUT_RESOLUTION_Y*oneI))),(c.y*STU(X,(TVOUT_RESOLUTION_I*oneI))),(c.z*STU(X,(TVOUT_RESOLUTION_Q*oneI)))); + } + else + { + X = offset-(-1); + c = (LEVELS(COMPAT_Sample(tex, float2(texCoord.x - X*oneT,texCoord.y)).xyz)); + tempColor += (c*STU(X,(TVOUT_RESOLUTION*oneI))); + + X = offset-(0); + c = (LEVELS(COMPAT_Sample(tex, float2(texCoord.x - X*oneT,texCoord.y)).xyz)); + tempColor += (c*STU(X,(TVOUT_RESOLUTION*oneI))); + + X = offset-(1); + c = (LEVELS(COMPAT_Sample(tex, float2(texCoord.x - X*oneT,texCoord.y)).xyz)); + tempColor += (c*STU(X,(TVOUT_RESOLUTION*oneI))); + + X = offset-(2); + c = (LEVELS(COMPAT_Sample(tex, float2(texCoord.x - X*oneT,texCoord.y)).xyz)); + tempColor += (c*STU(X,(TVOUT_RESOLUTION*oneI))); + } + + tempColor = (TVOUT_COMPOSITE_CONNECTION) ? mul(YIQ_to_RGB,tempColor) : tempColor; + + return float4(tempColor, 1.0); +} + +float4 main_fragment(COMPAT_IN_FRAGMENT) : COMPAT_Output +{ + return tv_out_tweaks(COMPAT_texture_size, COMPAT_video_size, VOUT.texCoord, decal); +} +COMPAT_END \ No newline at end of file diff --git a/system/shaders/presets/HLSL/eagle/shaders/super-eagle.cg b/system/shaders/presets/HLSL/eagle/shaders/super-eagle.cg new file mode 100644 index 0000000000000..0e285f1b39b5f --- /dev/null +++ b/system/shaders/presets/HLSL/eagle/shaders/super-eagle.cg @@ -0,0 +1,195 @@ +/* COMPATIBILITY + - HLSL compilers + - Cg compilers + - FX11 compilers +*/ + +#include "../../compat_includes.inc" +uniform COMPAT_Texture2D(decal) : TEXUNIT0; +uniform float4x4 modelViewProj; + +const static float3 dtt = float3(65536,255,1); + +float reduce(float3 color) +{ + return dot(color, dtt); +} + +struct out_vertex { + float4 position : COMPAT_POS; + float4 t1 : TEXCOORD0; + float4 t2 : TEXCOORD1; + float4 t3 : TEXCOORD2; + float4 t4 : TEXCOORD3; + float4 t5 : TEXCOORD4; + float4 t6 : TEXCOORD5; + float4 t7 : TEXCOORD6; + float4 t8 : TEXCOORD7; +#ifndef HLSL_4 + float4 Color : COLOR; +#endif +}; + +/* VERTEX_SHADER */ +out_vertex main_vertex(COMPAT_IN_VERTEX) +{ + out_vertex OUT; +#ifdef HLSL_4 + float4 position = VIN.position; + float2 texCoord = VIN.texCoord; +#else + OUT.Color = color; +#endif + + OUT.position = mul(modelViewProj, position); + + float2 ps = float2(1.0/COMPAT_texture_size.x, 1.0/COMPAT_texture_size.y); + float dx = ps.x; + float dy = ps.y; + + OUT.t1.xy = texCoord + float2(-dx,-dy); + OUT.t1.zw = texCoord + float2(-dx, 0); + OUT.t2.xy = texCoord + float2(+dx,-dy); + OUT.t2.zw = texCoord + float2(+dx+dx,-dy); + OUT.t3.xy = texCoord + float2(-dx, 0); + OUT.t3.zw = texCoord + float2(+dx, 0); + OUT.t4.xy = texCoord + float2(+dx+dx, 0); + OUT.t4.zw = texCoord + float2(-dx,+dy); + OUT.t5.xy = texCoord + float2( 0,+dy); + OUT.t5.zw = texCoord + float2(+dx,+dy); + OUT.t6.xy = texCoord + float2(+dx+dx,+dy); + OUT.t6.zw = texCoord + float2(-dx,+dy+dy); + OUT.t7.xy = texCoord + float2( 0,+dy+dy); + OUT.t7.zw = texCoord + float2(+dx,+dy+dy); + OUT.t8.xy = texCoord + float2(+dx+dx,+dy+dy); + OUT.t8.zw = texCoord; + + return OUT; +} + +/* GET_RESULT function */ +/* Copyright (c) 1999-2001 by Derek Liauw Kie Fa */ +/* License: GNU-GPL */ +int GET_RESULT(float A, float B, float C, float D) +{ + int x = 0; int y = 0; int r = 0; + if (A == C) x+=1; else if (B == C) y+=1; + if (A == D) x+=1; else if (B == D) y+=1; + if (x <= 1) r+=1; + if (y <= 1) r-=1; + return r; +} + +float4 super_eagle(float2 texture_size, COMPAT_Texture2D(decal), float4 t1, float4 t2, float4 t3, + float4 t4, float4 t5, float4 t6, float4 t7, float4 t8) +{ + float2 fp = frac(t8.zw * texture_size); + + // Reading the texels + + float3 C0 = COMPAT_SamplePoint(decal,t1.xy).xyz; + float3 C1 = COMPAT_SamplePoint(decal,t1.zw).xyz; + float3 C2 = COMPAT_SamplePoint(decal,t2.xy).xyz; + float3 D3 = COMPAT_SamplePoint(decal,t2.zw).xyz; + float3 C3 = COMPAT_SamplePoint(decal,t3.xy).xyz; + float3 C4 = COMPAT_SamplePoint(decal,t8.zw).xyz; + float3 C5 = COMPAT_SamplePoint(decal,t3.zw).xyz; + float3 D4 = COMPAT_SamplePoint(decal,t4.xy).xyz; + float3 C6 = COMPAT_SamplePoint(decal,t4.zw).xyz; + float3 C7 = COMPAT_SamplePoint(decal,t5.xy).xyz; + float3 C8 = COMPAT_SamplePoint(decal,t5.zw).xyz; + float3 D5 = COMPAT_SamplePoint(decal,t6.xy).xyz; + float3 D0 = COMPAT_SamplePoint(decal,t6.zw).xyz; + float3 D1 = COMPAT_SamplePoint(decal,t7.xy).xyz; + float3 D2 = COMPAT_SamplePoint(decal,t7.zw).xyz; + float3 D6 = COMPAT_SamplePoint(decal,t8.xy).xyz; + + float3 p00,p10,p01,p11; + + // reducing float3 to float + float c0 = reduce(C0);float c1 = reduce(C1); + float c2 = reduce(C2);float c3 = reduce(C3); + float c4 = reduce(C4);float c5 = reduce(C5); + float c6 = reduce(C6);float c7 = reduce(C7); + float c8 = reduce(C8);float d0 = reduce(D0); + float d1 = reduce(D1);float d2 = reduce(D2); + float d3 = reduce(D3);float d4 = reduce(D4); + float d5 = reduce(D5);float d6 = reduce(D6); + + /* SuperEagle code */ + /* Copied from the Dosbox source code */ + /* Copyright (C) 2002-2007 The DOSBox Team */ + /* License: GNU-GPL */ + /* Adapted by guest(r) on 16.4.2007 */ + if (c4 != c8) { + if (c7 == c5) { + p01 = p10 = C7; + if ((c6 == c7) || (c5 == c2)) { + p00 = 0.25*(3.0*C7+C4); + } else { + p00 = 0.5*(C4+C5); + } + + if ((c5 == d4) || (c7 == d1)) { + p11 = 0.25*(3.0*C7+C8); + } else { + p11 = 0.5*(C7+C8); + } + } else { + p11 = 0.125*(6.0*C8+C7+C5); + p00 = 0.125*(6.0*C4+C7+C5); + + p10 = 0.125*(6.0*C7+C4+C8); + p01 = 0.125*(6.0*C5+C4+C8); + } + } else { + if (c7 != c5) { + p11 = p00 = C4; + + if ((c1 == c4) || (c8 == d5)) { + p01 = 0.25*(3.0*C4+C5); + } else { + p01 = 0.5*(C4+C5); + } + + if ((c8 == d2) || (c3 == c4)) { + p10 = 0.25*(3.0*C4+C7); + } else { + p10 = 0.5*(C7+C8); + } + } else { + int r = 0; + r += GET_RESULT(c5,c4,c6,d1); + r += GET_RESULT(c5,c4,c3,c1); + r += GET_RESULT(c5,c4,d2,d5); + r += GET_RESULT(c5,c4,c2,d4); + + if (r > 0) { + p01 = p10 = C7; + p00 = p11 = 0.5*(C4+C5); + } else if (r < 0) { + p11 = p00 = C4; + p01 = p10 = 0.5*(C4+C5); + } else { + p11 = p00 = C4; + p01 = p10 = C7; + } + } + } + + + + // Distributing the four products + + p10 = (fp.x < 0.50) ? (fp.y < 0.50 ? p00 : p10) : (fp.y < 0.50 ? p01: p11); + + // OUTPUT + return float4(p10, 1); +} + +float4 main_fragment(COMPAT_IN_FRAGMENT) : COMPAT_Output +{ + return super_eagle(COMPAT_texture_size, decal, VOUT.t1, VOUT.t2, VOUT.t3, VOUT.t4, + VOUT.t5, VOUT.t6, VOUT.t7, VOUT.t8); +} +COMPAT_END diff --git a/system/shaders/presets/HLSL/eagle/super-eagle.cgp b/system/shaders/presets/HLSL/eagle/super-eagle.cgp new file mode 100644 index 0000000000000..10028007bcf28 --- /dev/null +++ b/system/shaders/presets/HLSL/eagle/super-eagle.cgp @@ -0,0 +1,11 @@ +shaders = 2 + +shader0 = shaders/super-eagle.cg +filter_linear0 = false +scale_type0 = source +scale_x0 = 2.0 +scale_y0 = 2.0 + +shader1 = ../stock.cg +filter_linear1 = true +scale_type_1 = source diff --git a/system/shaders/presets/HLSL/handheld/lcd-grid-v2-gba-color.cgp b/system/shaders/presets/HLSL/handheld/lcd-grid-v2-gba-color.cgp new file mode 100644 index 0000000000000..73e43bab9a1de --- /dev/null +++ b/system/shaders/presets/HLSL/handheld/lcd-grid-v2-gba-color.cgp @@ -0,0 +1,27 @@ +shaders = "2" +shader0 = "shaders/lcd_cgwg/lcd-grid-v2.cg" +shader1 = "shaders/color/gba-color.cg" + +filter_linear0 = "false" +scale_type0 = "viewport" +scale0 = "1.0" + +filter_linear1 = "false" +scale_type1 = "source" +scale1 = "1.0" + +parameters = "RSUBPIX_R;RSUBPIX_G;RSUBPIX_B;GSUBPIX_R;GSUBPIX_G;GSUBPIX_B;BSUBPIX_R;BSUBPIX_G;BSUBPIX_B;gain;gamma;blacklevel;ambient;BGR" +RSUBPIX_R = "0.750000" +RSUBPIX_G = "0.000000" +RSUBPIX_B = "0.000000" +GSUBPIX_R = "0.000000" +GSUBPIX_G = "0.750000" +GSUBPIX_B = "0.000000" +BSUBPIX_R = "0.000000" +BSUBPIX_G = "0.000000" +BSUBPIX_B = "0.750000" +gain = "1.500000" +gamma = "2.200000" +blacklevel = "0.000000" +ambient = "0.000000" +BGR = "0.000000" \ No newline at end of file diff --git a/system/shaders/presets/HLSL/handheld/lcd-grid-v2-nds-color.cgp b/system/shaders/presets/HLSL/handheld/lcd-grid-v2-nds-color.cgp new file mode 100644 index 0000000000000..e86da6d034ea5 --- /dev/null +++ b/system/shaders/presets/HLSL/handheld/lcd-grid-v2-nds-color.cgp @@ -0,0 +1,27 @@ +shaders = "2" +shader0 = "shaders/lcd_cgwg/lcd-grid-v2.cg" +shader1 = "shaders/color/nds-color.cg" + +filter_linear0 = "false" +scale_type0 = "viewport" +scale0 = "1.0" + +filter_linear1 = "false" +scale_type1 = "source" +scale1 = "1.0" + +parameters = "RSUBPIX_R;RSUBPIX_G;RSUBPIX_B;GSUBPIX_R;GSUBPIX_G;GSUBPIX_B;BSUBPIX_R;BSUBPIX_G;BSUBPIX_B;gain;gamma;blacklevel;ambient;BGR" +RSUBPIX_R = "0.750000" +RSUBPIX_G = "0.000000" +RSUBPIX_B = "0.000000" +GSUBPIX_R = "0.000000" +GSUBPIX_G = "0.750000" +GSUBPIX_B = "0.000000" +BSUBPIX_R = "0.000000" +BSUBPIX_G = "0.000000" +BSUBPIX_B = "0.750000" +gain = "1.500000" +gamma = "2.200000" +blacklevel = "0.000000" +ambient = "0.000000" +BGR = "0.000000" \ No newline at end of file diff --git a/system/shaders/presets/HLSL/handheld/lcd-grid-v2-psp-color.cgp b/system/shaders/presets/HLSL/handheld/lcd-grid-v2-psp-color.cgp new file mode 100644 index 0000000000000..0e69eae5eb902 --- /dev/null +++ b/system/shaders/presets/HLSL/handheld/lcd-grid-v2-psp-color.cgp @@ -0,0 +1,27 @@ +shaders = "2" +shader0 = "shaders/lcd_cgwg/lcd-grid-v2.cg" +shader1 = "shaders/color/psp-color.cg" + +filter_linear0 = "false" +scale_type0 = "viewport" +scale0 = "1.0" + +filter_linear1 = "false" +scale_type1 = "source" +scale1 = "1.0" + +parameters = "RSUBPIX_R;RSUBPIX_G;RSUBPIX_B;GSUBPIX_R;GSUBPIX_G;GSUBPIX_B;BSUBPIX_R;BSUBPIX_G;BSUBPIX_B;gain;gamma;blacklevel;ambient;BGR" +RSUBPIX_R = "0.750000" +RSUBPIX_G = "0.000000" +RSUBPIX_B = "0.000000" +GSUBPIX_R = "0.000000" +GSUBPIX_G = "0.750000" +GSUBPIX_B = "0.000000" +BSUBPIX_R = "0.000000" +BSUBPIX_G = "0.000000" +BSUBPIX_B = "0.750000" +gain = "1.500000" +gamma = "2.200000" +blacklevel = "0.000000" +ambient = "0.000000" +BGR = "0.000000" \ No newline at end of file diff --git a/system/shaders/presets/HLSL/handheld/shaders/color/gba-color.cg b/system/shaders/presets/HLSL/handheld/shaders/color/gba-color.cg new file mode 100644 index 0000000000000..f00f476f81af7 --- /dev/null +++ b/system/shaders/presets/HLSL/handheld/shaders/color/gba-color.cg @@ -0,0 +1,96 @@ +/* + Shader Modified: Pokefan531 + Color Mangler + Author: hunterk + License: Public domain +*/ + +#include "../../../compat_includes.inc" +uniform COMPAT_Texture2D(decal) : TEXUNIT0; +uniform float4x4 modelViewProj; + +// Shader that replicates the LCD dynamics from a GameBoy Advance +#pragma parameter darken_screen "Darken Screen" 0.5 0.0 2.0 0.05 +#ifdef PARAMETER_UNIFORM +uniform float darken_screen; +#else +#define darken_screen 0.5 +#endif + +#define target_gamma 2.2 +#define display_gamma 2.2 +#define sat 1.0 +#define lum 1.0 +#define contrast 1.0 +#define blr 0.0 +#define blg 0.0 +#define blb 0.0 +#define r 0.81 +#define g 0.67 +#define b 0.73 +#define rg 0.09 +#define rb 0.15 +#define gr 0.23 +#define gb 0.12 +#define br -0.04 +#define bg 0.24 +#define overscan_percent_x 0.0 +#define overscan_percent_y 0.0 + +struct out_vertex +{ + float4 position : COMPAT_POS; + float2 texCoord : TEXCOORD; +#ifndef HLSL_4 + float4 Color : COLOR; +#endif +}; + +/* + VERTEX_SHADER +*/ +out_vertex main_vertex(COMPAT_IN_VERTEX) +{ + out_vertex OUT; +#ifdef HLSL_4 + float4 position = VIN.position; + float2 texCoord = VIN.texCoord; +#else + OUT.Color = color; +#endif + OUT.position = mul(modelViewProj, position); + + float2 shift = 0.5 * COMPAT_video_size / COMPAT_texture_size; + float2 overscan_coord = (texCoord - shift) * (1.0 - float2(overscan_percent_x / 100.0, overscan_percent_y / 100.0)) + shift; + OUT.texCoord = overscan_coord; + return OUT; +} + +float4 gba_color(float2 texCoord : TEXCOORD) +{ + float4 screen = pow(COMPAT_SamplePoint(decal, texCoord), target_gamma + darken_screen).rgba; //sample image in linear colorspace + float4 avglum = float4(0.5,0.5,0.5,0.5); + screen = lerp(screen, avglum, (1.0 - contrast)); + + // r g b black + float4x4 color = {r, gr, br, blr, //red channel + rg, g, bg, blg, //green channel + rb, gb, b, blb, //blue channel + 0.0, 0.0, 0.0, 1.0}; //alpha channel; these numbers do nothing for our purposes. + + float4x4 adjust = {(1.0 - sat) * 0.3086 + sat, (1.0 - sat) * 0.6094, (1.0 - sat) * 0.0820, 0.0, + (1.0 - sat) * 0.3086, (1.0 - sat) * 0.6094 + sat, (1.0 - sat) * 0.0820, 0.0, + (1.0 - sat) * 0.3086, (1.0 - sat) * 0.6094, (1.0 - sat) * 0.0820 + sat, 0.0, + 1.0, 1.0, 1.0, 1.0}; + + color = mul(color, adjust); + screen = saturate(screen * lum); + screen = mul(color, screen); + return pow(screen, 1.0 / display_gamma); +} + +float4 main_fragment(COMPAT_IN_FRAGMENT) : COMPAT_Output +{ + return gba_color(VOUT.texCoord); +} +COMPAT_END \ No newline at end of file diff --git a/system/shaders/presets/HLSL/handheld/shaders/color/nds-color.cg b/system/shaders/presets/HLSL/handheld/shaders/color/nds-color.cg new file mode 100644 index 0000000000000..213451e400eab --- /dev/null +++ b/system/shaders/presets/HLSL/handheld/shaders/color/nds-color.cg @@ -0,0 +1,89 @@ +/* + Shader Modified: Pokefan531 + Color Mangler + Author: hunterk + License: Public domain +*/ + +#include "../../../compat_includes.inc" +uniform COMPAT_Texture2D(decal) : TEXUNIT0; +uniform float4x4 modelViewProj; + +// Shader that replicates the LCD dynamics from an Original Nintendo DS +#define target_gamma 2.2 +#define display_gamma 2.2 +#define sat 1.0 +#define lum 1.0 +#define contrast 1.0 +#define blr 0.0 +#define blg 0.0 +#define blb 0.0 +#define r 0.82 +#define g 0.66 +#define b 0.81 +#define rg 0.085 +#define rb 0.085 +#define gr 0.25 +#define gb 0.105 +#define br -0.07 +#define bg 0.255 +#define overscan_percent_x 0.0 +#define overscan_percent_y 0.0 + +struct out_vertex +{ + float4 position : COMPAT_POS; + float2 texCoord : TEXCOORD; +#ifndef HLSL_4 + float4 Color : COLOR; +#endif +}; + +/* + VERTEX_SHADER +*/ +out_vertex main_vertex(COMPAT_IN_VERTEX) +{ + out_vertex OUT; +#ifdef HLSL_4 + float4 position = VIN.position; + float2 texCoord = VIN.texCoord; +#else + OUT.Color = color; +#endif + OUT.position = mul(modelViewProj, position); + + float2 shift = 0.5 * COMPAT_video_size / COMPAT_texture_size; + float2 overscan_coord = (texCoord - shift) * (1.0 - float2(overscan_percent_x / 100.0, overscan_percent_y / 100.0)) + shift; + OUT.texCoord = overscan_coord; + return OUT; +} + +float4 gba_color(float2 texCoord : TEXCOORD) +{ + float4 screen = pow(COMPAT_SamplePoint(decal, texCoord), target_gamma).rgba; //sample image in linear colorspace + float4 avglum = float4(0.5,0.5,0.5,0.5); + screen = lerp(screen, avglum, (1.0 - contrast)); + + // r g b black + float4x4 color = {r, gr, br, blr, //red channel + rg, g, bg, blg, //green channel + rb, gb, b, blb, //blue channel + 0.0, 0.0, 0.0, 1.0}; //alpha channel; these numbers do nothing for our purposes. + + float4x4 adjust = {(1.0 - sat) * 0.3086 + sat, (1.0 - sat) * 0.6094, (1.0 - sat) * 0.0820, 0.0, + (1.0 - sat) * 0.3086, (1.0 - sat) * 0.6094 + sat, (1.0 - sat) * 0.0820, 0.0, + (1.0 - sat) * 0.3086, (1.0 - sat) * 0.6094, (1.0 - sat) * 0.0820 + sat, 0.0, + 1.0, 1.0, 1.0, 1.0}; + + color = mul(color, adjust); + screen = saturate(screen * lum); + screen = mul(color, screen); + return pow(screen, 1.0 / display_gamma); +} + +float4 main_fragment(COMPAT_IN_FRAGMENT) : COMPAT_Output +{ + return gba_color(VOUT.texCoord); +} +COMPAT_END \ No newline at end of file diff --git a/system/shaders/presets/HLSL/handheld/shaders/color/psp-color.cg b/system/shaders/presets/HLSL/handheld/shaders/color/psp-color.cg new file mode 100644 index 0000000000000..838f8a8fe676a --- /dev/null +++ b/system/shaders/presets/HLSL/handheld/shaders/color/psp-color.cg @@ -0,0 +1,89 @@ +/* + Shader Modified: Pokefan531 + Color Mangler + Author: hunterk + License: Public domain +*/ + +#include "../../../compat_includes.inc" +uniform COMPAT_Texture2D(decal) : TEXUNIT0; +uniform float4x4 modelViewProj; + +// Shader that replicates the LCD dynamics from PSP 1000 and PSP 2000 +#define target_gamma 2.21 +#define display_gamma 2.2 +#define sat 1.0 +#define lum 1.0 +#define contrast 1.0 +#define blr 0.0 +#define blg 0.0 +#define blb 0.0 +#define r 0.92 +#define g 0.795 +#define b 0.975 +#define rg 0.035 +#define rb 0.01 +#define gr 0.24 +#define gb 0.015 +#define br -0.16 +#define bg 0.17 +#define overscan_percent_x 0.0 +#define overscan_percent_y 0.0 + +struct out_vertex +{ + float4 position : COMPAT_POS; + float2 texCoord : TEXCOORD; +#ifndef HLSL_4 + float4 Color : COLOR; +#endif +}; + +/* + VERTEX_SHADER +*/ +out_vertex main_vertex(COMPAT_IN_VERTEX) +{ + out_vertex OUT; +#ifdef HLSL_4 + float4 position = VIN.position; + float2 texCoord = VIN.texCoord; +#else + OUT.Color = color; +#endif + OUT.position = mul(modelViewProj, position); + + float2 shift = 0.5 * COMPAT_video_size / COMPAT_texture_size; + float2 overscan_coord = (texCoord - shift) * (1.0 - float2(overscan_percent_x / 100.0, overscan_percent_y / 100.0)) + shift; + OUT.texCoord = overscan_coord; + return OUT; +} + +float4 gba_color(float2 texCoord : TEXCOORD) +{ + float4 screen = pow(COMPAT_SamplePoint(decal, texCoord), target_gamma).rgba; //sample image in linear colorspace + float4 avglum = float4(0.5,0.5,0.5,0.5); + screen = lerp(screen, avglum, (1.0 - contrast)); + + // r g b black + float4x4 color = {r, gr, br, blr, //red channel + rg, g, bg, blg, //green channel + rb, gb, b, blb, //blue channel + 0.0, 0.0, 0.0, 1.0}; //alpha channel; these numbers do nothing for our purposes. + + float4x4 adjust = {(1.0 - sat) * 0.3086 + sat, (1.0 - sat) * 0.6094, (1.0 - sat) * 0.0820, 0.0, + (1.0 - sat) * 0.3086, (1.0 - sat) * 0.6094 + sat, (1.0 - sat) * 0.0820, 0.0, + (1.0 - sat) * 0.3086, (1.0 - sat) * 0.6094, (1.0 - sat) * 0.0820 + sat, 0.0, + 1.0, 1.0, 1.0, 1.0}; + + color = mul(color, adjust); + screen = saturate(screen * lum); + screen = mul(color, screen); + return pow(screen, 1.0 / display_gamma); +} + +float4 main_fragment(COMPAT_IN_FRAGMENT) : COMPAT_Output +{ + return gba_color(VOUT.texCoord); +} +COMPAT_END \ No newline at end of file diff --git a/system/shaders/presets/HLSL/handheld/shaders/lcd_cgwg/lcd-grid-v2.cg b/system/shaders/presets/HLSL/handheld/shaders/lcd_cgwg/lcd-grid-v2.cg new file mode 100644 index 0000000000000..7c52775c238e6 --- /dev/null +++ b/system/shaders/presets/HLSL/handheld/shaders/lcd_cgwg/lcd-grid-v2.cg @@ -0,0 +1,163 @@ +/* COMPATIBILITY + - HLSL compilers + - Cg compilers + - FX11 compilers +*/ + +// VERTEX SHADER // + +#include "../../../compat_includes.inc" +uniform COMPAT_Texture2D(decal) : TEXUNIT0; +uniform float4x4 modelViewProj; + +struct out_vertex +{ + float4 position : COMPAT_POS; + float2 texCoord : TEXCOORD0; +#ifndef HLSL_4 + float4 Color : COLOR; +#endif +}; + +out_vertex main_vertex(COMPAT_IN_VERTEX) +{ + out_vertex OUT; +#ifdef HLSL_4 + float4 position = VIN.position; + float2 texCoord = VIN.texCoord; +#else + OUT.Color = color; +#endif + OUT.position = mul(modelViewProj, position); + OUT.texCoord = texCoord; + + return OUT; +} + +#pragma parameter RSUBPIX_R "Colour of R subpixel: R" 1.0 0.0 1.0 0.01 +#pragma parameter RSUBPIX_G "Colour of R subpixel: G" 0.0 0.0 1.0 0.01 +#pragma parameter RSUBPIX_B "Colour of R subpixel: B" 0.0 0.0 1.0 0.01 +#pragma parameter GSUBPIX_R "Colour of G subpixel: R" 0.0 0.0 1.0 0.01 +#pragma parameter GSUBPIX_G "Colour of G subpixel: G" 1.0 0.0 1.0 0.01 +#pragma parameter GSUBPIX_B "Colour of G subpixel: B" 0.0 0.0 1.0 0.01 +#pragma parameter BSUBPIX_R "Colour of B subpixel: R" 0.0 0.0 1.0 0.01 +#pragma parameter BSUBPIX_G "Colour of B subpixel: G" 0.0 0.0 1.0 0.01 +#pragma parameter BSUBPIX_B "Colour of B subpixel: B" 1.0 0.0 1.0 0.01 +#pragma parameter gain "Gain" 1.0 0.5 2.0 0.05 +#pragma parameter gamma "LCD Gamma" 3.0 0.5 5.0 0.1 +#pragma parameter blacklevel "Black level" 0.05 0.0 0.5 0.01 +#pragma parameter ambient "Ambient" 0.0 0.0 0.5 0.01 +#pragma parameter BGR "BGR" 0 0 1 1 +#ifdef PARAMETER_UNIFORM +uniform float RSUBPIX_R; +uniform float RSUBPIX_G; +uniform float RSUBPIX_B; +uniform float GSUBPIX_R; +uniform float GSUBPIX_G; +uniform float GSUBPIX_B; +uniform float BSUBPIX_R; +uniform float BSUBPIX_G; +uniform float BSUBPIX_B; +uniform float gain; +uniform float gamma; +uniform float blacklevel; +uniform float ambient; +uniform float BGR; +#else +#define RSUBPIX_R 1.0 +#define RSUBPIX_G 0.0 +#define RSUBPIX_B 0.0 +#define GSUBPIX_R 0.0 +#define GSUBPIX_G 1.0 +#define GSUBPIX_B 0.0 +#define BSUBPIX_R 0.0 +#define BSUBPIX_G 0.0 +#define BSUBPIX_B 1.0 +#define gain 1.0 +#define gamma 3.0 +#define blacklevel 0.05 +#define ambient 0.0 +#define BGR 0.0 +#endif + +#define outgamma 2.2 + +#define fetch_offset(coord,offset) (pow(float3(gain) * texelFetchOffset(decal, (coord), 0, (offset)).rgb + blacklevel3, float3(gamma)) + ambient3) + +// integral of (1 - x^2 - x^4 + x^6)^2 +const float coeffs_x[] = { 1.0, -2.0/3.0, -1.0/5.0, 4.0/7.0, -1.0/9.0, -2.0/11.0, 1.0/13.0 }; +// integral of (1 - 2x^4 + x^6)^2 +const float coeffs_y[] = { 1.0, 0.0, -4.0/5.0, 2.0/7.0, 4.0/9.0, -4.0/11.0, 1.0/13.0 }; +float intsmear_func(float z, float coeffs[7]) +{ + float z2 = z*z; + float zn = z; + float ret = 0.0; + for (int i = 0; i < 7; i++) { + ret += zn*coeffs[i]; + zn *= z2; + } + return ret; +} + +float intsmear(float x, float dx, float d, float coeffs[7]) +{ + float zl = clamp((x-dx*0.5)/d,-1.0,1.0); + float zh = clamp((x+dx*0.5)/d,-1.0,1.0); + return d * ( intsmear_func(zh,coeffs) - intsmear_func(zl,coeffs) )/dx; +} + +float4 lcd_grid_v2(float2 texture_size, float2 video_size, float2 output_size, float2 texCoord, COMPAT_Texture2D(decal)) +{ + float2 texelSize = 1.0 / texture_size; + float2 range; + range = video_size / (output_size * texture_size); + float3 outgamma3 = float3(outgamma, outgamma, outgamma); + float3 cred = pow(float3(RSUBPIX_R, RSUBPIX_G, RSUBPIX_B), outgamma3); + float3 cgreen = pow(float3(GSUBPIX_R, GSUBPIX_G, GSUBPIX_B), outgamma3); + float3 cblue = pow(float3(BSUBPIX_R, BSUBPIX_G, BSUBPIX_B), outgamma3); + + int2 tli = int2(floor(texCoord/texelSize-float2(0.4999, 0.4999))); + + float3 lcol, rcol; + float subpix = (texCoord.x/texelSize.x - 0.4999 - float(tli.x))*3.0; + float rsubpix = range.x/texelSize.x * 3.0; + lcol = float3(intsmear(subpix+1.0,rsubpix, 1.5, coeffs_x), + intsmear(subpix ,rsubpix, 1.5, coeffs_x), + intsmear(subpix-1.0,rsubpix, 1.5, coeffs_x)); + rcol = float3(intsmear(subpix-2.0,rsubpix, 1.5, coeffs_x), + intsmear(subpix-3.0,rsubpix, 1.5, coeffs_x), + intsmear(subpix-4.0,rsubpix, 1.5, coeffs_x)); + if (BGR > 0.5) { + lcol.rgb = lcol.bgr; + rcol.rgb = rcol.bgr; + } + float tcol, bcol; + subpix = texCoord.y/texelSize.y - 0.4999 - float(tli.y); + rsubpix = range.y/texelSize.y; + tcol = intsmear(subpix ,rsubpix, 0.63, coeffs_y); + bcol = intsmear(subpix-1.0,rsubpix, 0.63, coeffs_y); + const float3 gain3 = float3(gain, gain, gain); + const float3 gamma3 = float3(gamma, gamma, gamma); + const float3 blacklevel3 = float3(blacklevel, blacklevel, blacklevel); + const float3 ambient3 = float3(ambient, ambient, ambient); + const float3 tcol3 = float3(tcol, tcol, tcol); + const float3 bcol3 = float3(bcol, bcol, bcol); + const float3 topLeftColor = ((pow(gain3 * COMPAT_SamplePoint(decal, texCoord - 0.25 * texelSize * int2(0,0)).rgb + blacklevel3, gamma3) + ambient3)) * lcol * tcol3; + const float3 bottomRightColor = ((pow(gain3 * COMPAT_SamplePoint(decal, texCoord - 0.25 * texelSize * int2(1,1)).rgb + blacklevel3, gamma3) + ambient3)) * rcol * bcol3; + const float3 bottomLeftColor = ((pow(gain3 * COMPAT_SamplePoint(decal, texCoord - 0.25 * texelSize * int2(0,1)).rgb + blacklevel3, gamma3) + ambient3)) * lcol * bcol3; + const float3 topRightColor = ((pow(gain3 * COMPAT_SamplePoint(decal, texCoord - 0.25 * texelSize * int2(1,0)).rgb + blacklevel3, gamma3) + ambient3)) * rcol * tcol3; + + float3 averageColor = topLeftColor + bottomRightColor + bottomLeftColor + topRightColor; + + averageColor = mul(averageColor, float3x3(cred, cgreen, cblue)); + const float inv_outgamma = 1.0/outgamma; + const float3 inv_outgamma3 = float3(inv_outgamma, inv_outgamma, inv_outgamma); + return float4(pow(averageColor,inv_outgamma3),0.0); +} + +float4 main_fragment(COMPAT_IN_FRAGMENT) : COMPAT_Output +{ + return lcd_grid_v2(COMPAT_texture_size, COMPAT_video_size, COMPAT_output_size, VOUT.texCoord, decal); +} +COMPAT_END \ No newline at end of file diff --git a/system/shaders/presets/HLSL/include/compat_input_struct.inc b/system/shaders/presets/HLSL/include/compat_input_struct.inc new file mode 100644 index 0000000000000..ee03708c0e9a6 --- /dev/null +++ b/system/shaders/presets/HLSL/include/compat_input_struct.inc @@ -0,0 +1,33 @@ +#ifndef COMPAT_INPUT_STRUCT + #define COMPAT_INPUT_STRUCT + + #if defined(HLSL_4) + struct input + { + bool dummy; + }; + cbuffer input : register(b0) + #else + struct input + #endif + { + float2 video_size; + float2 texture_size; + float2 output_size; + float frame_count; + float frame_direction; + }; + #if defined(HLSL_4) + #define COMPAT_video_size video_size + #define COMPAT_texture_size texture_size + #define COMPAT_output_size output_size + #define COMPAT_frame_count frame_count + #define COMPAT_frame_direction frame_direction + #else + #define COMPAT_video_size IN.video_size + #define COMPAT_texture_size IN.texture_size + #define COMPAT_output_size IN.output_size + #define COMPAT_frame_count IN.frame_count + #define COMPAT_frame_direction IN.frame_direction + #endif +#endif // COMPAT_INPUT_STRUCT \ No newline at end of file diff --git a/system/shaders/presets/HLSL/include/compat_macros.inc b/system/shaders/presets/HLSL/include/compat_macros.inc new file mode 100644 index 0000000000000..7682f67949d26 --- /dev/null +++ b/system/shaders/presets/HLSL/include/compat_macros.inc @@ -0,0 +1,58 @@ +#ifndef COMPAT_MACROS + #define COMPAT_MACROS + + #if defined(HLSL_4) + SamplerState LinearSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; + SamplerState PointSampler { Filter = MIN_MAG_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; + #define mod(x,y) (x - y * trunc(x/y)) + #define fract(x) (frac(x)) + #define COMPAT_Texture2D(tex) Texture2D tex + #define COMPAT_TexturePass2D(tex) tex + #define COMPAT_SampleLevelZero(tex, coord) tex.SampleLevel(LinearSampler, coord, 0) + #define COMPAT_SampleLevelZeroPoint(tex, coord) tex.SampleLevel(PointSampler, coord, 0) + #define COMPAT_SampleLevelZeroOffset(tex, coord, offset) tex.SampleLevel(LinearSampler, coord, 0, offset) + #define COMPAT_Sample(tex, coord) tex.Sample(LinearSampler, coord) + #define COMPAT_SamplePoint(tex, coord) tex.Sample(PointSampler, coord) + #define COMPAT_SampleOffset(tex, coord, offset) tex.Sample(LinearSampler, coord, offset) + #define COMPAT_FLATTEN [flatten] + #define COMPAT_BRANCH [branch] + #define COMPAT_Texture2DMS2(tex) Texture2DMS tex + #define COMPAT_Load(tex, pos, sample) tex.Load(pos, sample) + #define COMPAT_Output SV_Target + #define half float + #define half2 float2 + #define half3 float3 + #define half4 float4 + #define half3x3 float3x3 + #define half2x2 float2x2 + #define half4x4 float4x4 + #define half4x3 float4x3 + #define COMPAT_POS SV_POSITION + #else + #define COMPAT_Texture2D(tex) sampler2D tex + #define COMPAT_TexturePass2D(tex) tex + #define COMPAT_SampleLevelZero(tex, coord) tex2Dlod(tex, float4(coord, 0.0, 0.0)) + #define COMPAT_SampleLevelZeroPoint(tex, coord) tex2Dlod(tex, float4(coord, 0.0, 0.0)) + #define COMPAT_SampleLevelZeroOffset(tex, coord, offset) tex2Dlod(tex, float4(coord + offset, 0.0, 0.0)) + #define COMPAT_Sample(tex, coord) tex2D(tex, coord) + #define COMPAT_SamplePoint(tex, coord) tex2D(tex, coord) + #define COMPAT_SampleOffset(tex, coord, offset) tex2D(tex, coord + offset) + #define COMPAT_FLATTEN [flatten] + #define COMPAT_BRANCH [branch] + #define COMPAT_Output COLOR + #define COMPAT_POS POSITION + #endif + #if defined(HLSL_FX) + #define COMPAT_END \ + technique11 TEQ \ + { \ + pass P0 \ + { \ + SetVertexShader( CompileShader( vs_4_0, main_vertex() ) ); \ + SetPixelShader( CompileShader( ps_4_0, main_fragment() ) ); \ + } \ + }; + #else + #define COMPAT_END + #endif +#endif // COMPAT_MACROS \ No newline at end of file diff --git a/system/shaders/presets/HLSL/include/compat_orig_struct.inc b/system/shaders/presets/HLSL/include/compat_orig_struct.inc new file mode 100644 index 0000000000000..830bf2e2a8f00 --- /dev/null +++ b/system/shaders/presets/HLSL/include/compat_orig_struct.inc @@ -0,0 +1,37 @@ +#ifndef COMPAT_ORIG_STRUCT + #define COMPAT_ORIG_STRUCT + + #if defined(HLSL_4) + struct orig + { + bool dummy; + }; + + cbuffer orig : register(b1) + { + float2 orig_video_size; + float2 orig_texture_size; + float2 orig_output_size; + }; + + #define INITIALIZE_ORIG(c) Texture2D ORIGtex: register(t##c); + #define ORIG_Sample(coord) ORIGtex.Sample(LinearSampler, coord) + #define ORIG_SamplePoint(coord) ORIGtex.Sample(PointSampler, coord) + #define ORIG_texture ORIGtex + #else + struct orig + { + float2 video_size; + float2 texture_size; + float2 output_size; + sampler2D texture; + }; + #define INITIALIZE_ORIG(c) + #define ORIG_Sample(coord) tex2D(ORIG, coord) + #define ORIG_SamplePoint(coord) tex2D(ORIG, coord) + #define ORIG_texture ORIG.texture + #define ORIG_video_size ORIG.video_size + #define ORIG_texture_size ORIG.texture_size + #define ORIG_output_size ORIG.output_size + #endif +#endif // COMPAT_ORIG_STRUCT \ No newline at end of file diff --git a/system/shaders/presets/HLSL/include/compat_prev_struct.inc b/system/shaders/presets/HLSL/include/compat_prev_struct.inc new file mode 100644 index 0000000000000..f94e0f84b51aa --- /dev/null +++ b/system/shaders/presets/HLSL/include/compat_prev_struct.inc @@ -0,0 +1,34 @@ +#ifndef COMPAT_PREV_STRUCT + #define COMPAT_PREV_STRUCT + + #if defined(HLSL_4) + struct prev + { + bool dummy; + }; + + cbuffer prev : register(b1) + { + float2 prev_video_size; + float2 prev_texture_size; + float2 prev_output_size; + }; + + #define INITIALIZE_PASSPREV(c, d) Texture2D PASSPREV##c: register(t##d); + #define PASSPREV_Sample(c, coord) PASSPREV##c.Sample(LinearSampler, coord) + #define PASSPREV_SamplePoint(c, coord) PASSPREV##c.Sample(PointSampler, coord) + #define PASSPREV_texture(c) PASSPREV##c + #else + struct prev + { + float2 video_size; + float2 texture_size; + float2 output_size; + sampler2D texture; + }; + #define INITIALIZE_PASSPREV(c, d) + #define PASSPREV_Sample(c, coord) tex2D(PASSPREV##c, coord) + #define PASSPREV_SamplePoint(c, coord) tex2D(PASSPREV##c, coord) + #define PASSPREV_texture(c) PASSPREV##c.texture + #endif +#endif // COMPAT_PREV_STRUCT \ No newline at end of file diff --git a/system/shaders/presets/HLSL/include/compat_vertex_in_out.inc b/system/shaders/presets/HLSL/include/compat_vertex_in_out.inc new file mode 100644 index 0000000000000..0ab4a2c49bc04 --- /dev/null +++ b/system/shaders/presets/HLSL/include/compat_vertex_in_out.inc @@ -0,0 +1,23 @@ +#ifndef COMPAT_VERTEX_IN_OUT + #define COMPAT_VERTEX_IN_OUT + + #ifdef HLSL_4 + struct in_vertex + { + float4 position : COMPAT_POS; + float2 texCoord : TEXCOORD0; + float2 t1 : TEXCOORD1; + }; + + #define COMPAT_IN_VERTEX in_vertex VIN + #define COMPAT_IN_FRAGMENT out_vertex VOUT + #else + struct in_vertex + { + bool dummy; + }; + + #define COMPAT_IN_VERTEX in_vertex VIN, uniform input IN, float4 color : COLOR, float4 position : COMPAT_POS, float2 texCoord : TEXCOORD0, float2 t1 : TEXCOORD1 + #define COMPAT_IN_FRAGMENT out_vertex VOUT, uniform input IN + #endif +#endif // COMPAT_VERTEX_IN_OUT \ No newline at end of file diff --git a/system/shaders/presets/HLSL/misc/image-adjustment.cg b/system/shaders/presets/HLSL/misc/image-adjustment.cg new file mode 100644 index 0000000000000..9778a158a8e00 --- /dev/null +++ b/system/shaders/presets/HLSL/misc/image-adjustment.cg @@ -0,0 +1,169 @@ +#pragma parameter target_gamma "Target Gamma" 2.2 0.1 5.0 0.1 +#pragma parameter monitor_gamma "Monitor Gamma" 2.2 0.1 5.0 0.1 +#pragma parameter overscan_percent_x "Horizontal Overscan %" 0.0 -25.0 25.0 1.0 +#pragma parameter overscan_percent_y "Vertical Overscan %" 0.0 -25.0 25.0 1.0 +#pragma parameter saturation "Saturation" 1.0 0.0 2.0 0.01 +#pragma parameter contrast "Contrast" 1.0 0.0 10.0 0.05 +#pragma parameter luminance "Luminance" 1.0 0.0 2.0 0.03 +#pragma parameter black_level "Black Level" 0.00 -0.30 0.30 0.01 +#pragma parameter bright_boost "Brightness Boost" 0.0 -1.0 1.0 0.05 +#pragma parameter R "Red Channel" 1.0 0.0 2.0 0.05 +#pragma parameter G "Green Channel" 1.0 0.0 2.0 0.05 +#pragma parameter B "Blue Channel" 1.0 0.0 2.0 0.05 +#pragma parameter ZOOM "Zoom Factor" 1.0 0.0 4.0 0.01 +#pragma parameter XPOS "X Modifier" 0.0 -2.0 2.0 0.005 +#pragma parameter YPOS "Y Modifier" 0.0 -2.0 2.0 0.005 +#pragma parameter TOPMASK "Overscan Mask Top" 0.0 0.0 1.0 0.0025 +#pragma parameter BOTMASK "Overscan Mask Bottom" 0.0 0.0 1.0 0.0025 +#pragma parameter LMASK "Overscan Mask Left" 0.0 0.0 1.0 0.0025 +#pragma parameter RMASK "Overscan Mask Right" 0.0 0.0 1.0 0.0025 +#pragma parameter GRAIN_STR "Film Grain" 0.0 0.0 72.0 6.0 +#ifdef PARAMETER_UNIFORM +uniform float target_gamma; +uniform float monitor_gamma; +uniform float overscan_percent_x; +uniform float overscan_percent_y; +uniform float saturation; +uniform float contrast; +uniform float luminance; +uniform float black_level; +uniform float bright_boost; +uniform float R; +uniform float G; +uniform float B; +uniform float ZOOM; +uniform float XPOS; +uniform float YPOS; +uniform float TOPMASK; +uniform float BOTMASK; +uniform float LMASK; +uniform float RMASK; +uniform float GRAIN_STR; +#else +#define overscan_percent_x 0.0 // crop width of image by X%; default is 0.0 +#define overscan_percent_y 0.0 // crop height of image by X%; default is 0.0 +#define saturation 1.0 // color saturation; default 1.0 +#define monitor_gamma 2.2 // gamma setting of your current display; LCD monitors typically have a gamma of 2.2 +#define target_gamma 2.2 // the gamma you want the image to have; CRT TVs typically have a gamma of 2.4 +#define contrast 1.0 // image contrast; default 1.0 +#define luminance 1.0 // image luminance; default 1.0 +#define black_level 0.0 // black level; default 0.0 +#define bright_boost 0.0 // adds to the total brightness. Negative values decrease it; Use values between 1.0 (totally white) and -1.0 (totally black); default is 0.0 +#define R 1.0 +#define G 1.0 +#define B 1.0 +#define ZOOM 1.0 +#define XPOS 0.0 +#define YPOS 0.0 +#define TOPMASK 0.0 +#define BOTMASK 0.0 +#define LMASK 0.0 +#define RMASK 0.0 +#define GRAIN_STR 0.0 +#endif +// END PARAMETERS // + +/* COMPATIBILITY + - HLSL compilers + - Cg compilers +*/ + +#include "../compat_includes.inc" + +uniform COMPAT_Texture2D(decal) : TEXUNIT0; +uniform float4x4 modelViewProj; + +struct out_vertex +{ + float4 position : COMPAT_POS; + float2 texCoord : TEXCOORD; + float2 tex_border : TEXCOORD1; +#ifndef HLSL_4 + float4 Color : COLOR; +#endif +}; + + +out_vertex main_vertex(COMPAT_IN_VERTEX) +{ + out_vertex OUT; +#ifdef HLSL_4 + float4 position = VIN.position; + float2 texCoord = VIN.texCoord; +#else + OUT.Color = color; +#endif + + OUT.position = mul(modelViewProj, position); + float2 shift = 0.5 * COMPAT_video_size / COMPAT_texture_size; + float2 overscan_coord = ((texCoord - shift) / ZOOM) * (1.0 - float2(overscan_percent_x / 100.0, overscan_percent_y / 100.0)) + shift; + OUT.texCoord = overscan_coord + float2(XPOS, YPOS); + return OUT; +} + +//https://www.shadertoy.com/view/4sXSWs strength= 16.0 +float3 filmGrain(float2 uv, float strength, float frameCount ){ + float x = (uv.x + 4.0 ) * (uv.y + 4.0 ) * ((fmod(frameCount, 800.0) + 10.0) * 10.0); + float v = fmod((mod(x, 13.0) + 1.0) * (fmod(x, 123.0) + 1.0), 0.01)-0.005; + return float3(v, v, v) * strength; +} + +float3 grayscale(float3 col) +{ + // ATSC grayscale standard + float b = dot(col, float3(0.2126, 0.7152, 0.0722)); + return float3(b, b, b); +} + +float3 rgb2hsv(float3 c) +{ + float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + float4 p = c.g < c.b ? float4(c.bg, K.wz) : float4(c.gb, K.xy); + float4 q = c.r < p.x ? float4(p.xyw, c.r) : float4(c.r, p.yzx); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +float3 hsv2rgb(float3 c) +{ + float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * lerp(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} + +float4 main_fragment(COMPAT_IN_FRAGMENT) : COMPAT_Output +{ + float2 texCoord = VOUT.texCoord; + + float3 film_grain = filmGrain(texCoord.xy, GRAIN_STR, COMPAT_frame_count); + float2 fragcoord = texCoord.xy * (COMPAT_texture_size.xy / COMPAT_video_size.xy); + float3 res = COMPAT_SamplePoint(decal, texCoord).rgb; // sample the texture + res += film_grain; + float gamma_ratio = monitor_gamma / target_gamma; + float3 gamma = float3(gamma_ratio, gamma_ratio, gamma_ratio); // setup ratio of display's gamma vs desired gamma + +//saturation and luminance + float3 satColor = clamp(hsv2rgb(rgb2hsv(res) * float3(1.0, saturation, luminance)), 0.0, 1.0); + +//contrast and brightness + float3 conColor = clamp((satColor - 0.5) * contrast + 0.5 + bright_boost, 0.0, 1.0); + + conColor -= float3(black_level, black_level, black_level); // apply black level + float min_black = 1.0-black_level; + conColor *= (1.0 / float3(min_black, min_black, min_black)); + conColor = pow(conColor, 1.0 / float3(gamma)); // Apply gamma correction + conColor *= float3(R, G, B); + if (fragcoord.y > TOPMASK && fragcoord.y < (1.0 - BOTMASK)) + conColor = conColor; + else + conColor = 0.0; + + if (fragcoord.x > LMASK && fragcoord.x < (1.0 - RMASK)) + conColor = conColor; + else + conColor = 0.0; + return float4(conColor, 1.0); +} +COMPAT_END diff --git a/system/shaders/presets/HLSL/ntsc/ntsc.cgp b/system/shaders/presets/HLSL/ntsc/ntsc.cgp new file mode 100644 index 0000000000000..4d1f3afc60260 --- /dev/null +++ b/system/shaders/presets/HLSL/ntsc/ntsc.cgp @@ -0,0 +1,25 @@ +shaders = 4 +shader0 = shaders/ntsc-pass1-composite-3phase.cg +shader1 = shaders/ntsc-pass2-3phase.cg +shader2 = shaders/ntsc-gauss-pass.cg +shader3 = shaders/ntsc-stock.cg + +filter_linear0 = false +filter_linear1 = false +filter_linear2 = false +filter_linear3 = true + +scale_type0 = source +scale_x0 = 4.0 +scale_y0 = 1.0 +frame_count_mod0 = 2 +float_framebuffer0 = true + +scale_type1 = source +scale_x1 = 0.5 +scale_y1 = 1.0 + +scale_type_x2 = source +scale_type_y2 = viewport +scale2 = 1.0 + diff --git a/system/shaders/presets/HLSL/ntsc/shaders/ntsc-decode-filter-2phase.inc b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-decode-filter-2phase.inc new file mode 100644 index 0000000000000..86b8a6d95ba70 --- /dev/null +++ b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-decode-filter-2phase.inc @@ -0,0 +1,70 @@ +#define TAPS 32 +static float luma_filter[TAPS + 1] = { + -0.000174844, + -0.000205844, + -0.000149453, + -0.000051693, + 0.000000000, + -0.000066171, + -0.000245058, + -0.000432928, + -0.000472644, + -0.000252236, + 0.000198929, + 0.000687058, + 0.000944112, + 0.000803467, + 0.000363199, + 0.000013422, + 0.000253402, + 0.001339461, + 0.002932972, + 0.003983485, + 0.003026683, + -0.001102056, + -0.008373026, + -0.016897700, + -0.022914480, + -0.021642347, + -0.008863273, + 0.017271957, + 0.054921920, + 0.098342579, + 0.139044281, + 0.168055832, + 0.178571429}; + +static float chroma_filter[TAPS + 1] = { + 0.001384762, + 0.001678312, + 0.002021715, + 0.002420562, + 0.002880460, + 0.003406879, + 0.004004985, + 0.004679445, + 0.005434218, + 0.006272332, + 0.007195654, + 0.008204665, + 0.009298238, + 0.010473450, + 0.011725413, + 0.013047155, + 0.014429548, + 0.015861306, + 0.017329037, + 0.018817382, + 0.020309220, + 0.021785952, + 0.023227857, + 0.024614500, + 0.025925203, + 0.027139546, + 0.028237893, + 0.029201910, + 0.030015081, + 0.030663170, + 0.031134640, + 0.031420995, + 0.031517031}; diff --git a/system/shaders/presets/HLSL/ntsc/shaders/ntsc-decode-filter-3phase.inc b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-decode-filter-3phase.inc new file mode 100644 index 0000000000000..3225c246389b0 --- /dev/null +++ b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-decode-filter-3phase.inc @@ -0,0 +1,54 @@ +#define TAPS 24 +static float luma_filter[TAPS + 1] = { + -0.000012020, + -0.000022146, + -0.000013155, + -0.000012020, + -0.000049979, + -0.000113940, + -0.000122150, + -0.000005612, + 0.000170516, + 0.000237199, + 0.000169640, + 0.000285688, + 0.000984574, + 0.002018683, + 0.002002275, + -0.000909882, + -0.007049081, + -0.013222860, + -0.012606931, + 0.002460860, + 0.035868225, + 0.084016453, + 0.135563500, + 0.175261268, + 0.190176552}; + +static float chroma_filter[TAPS + 1] = { + -0.000118847, + -0.000271306, + -0.000502642, + -0.000930833, + -0.001451013, + -0.002064744, + -0.002700432, + -0.003241276, + -0.003524948, + -0.003350284, + -0.002491729, + -0.000721149, + 0.002164659, + 0.006313635, + 0.011789103, + 0.018545660, + 0.026414396, + 0.035100710, + 0.044196567, + 0.053207202, + 0.061590275, + 0.068803602, + 0.074356193, + 0.077856564, + 0.079052396}; diff --git a/system/shaders/presets/HLSL/ntsc/shaders/ntsc-gauss-pass.cg b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-gauss-pass.cg new file mode 100644 index 0000000000000..1da6db458afcb --- /dev/null +++ b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-gauss-pass.cg @@ -0,0 +1,76 @@ +#include "../../compat_includes.inc" +uniform COMPAT_Texture2D(decal) : TEXUNIT0; +uniform float4x4 modelViewProj; + +struct out_vertex +{ + float4 position : COMPAT_POS; + float2 texCoord : TEXCOORD0; + float2 pix_no : TEXCOORD1; + float2 one : TEXCOORD2; +#ifndef HLSL_4 + float4 Color : COLOR; +#endif +}; + +out_vertex main_vertex(COMPAT_IN_VERTEX) +{ + out_vertex OUT; +#ifdef HLSL_4 + float4 position = VIN.position; + float2 texCoord = VIN.texCoord; +#else + OUT.Color = color; +#endif + OUT.position = mul(modelViewProj, position); + OUT.texCoord = texCoord; + OUT.pix_no = texCoord * COMPAT_texture_size; + OUT.one = 1.0 / COMPAT_texture_size; + + return OUT; +} + +#pragma parameter NTSC_CRT_GAMMA "NTSC CRT Gamma" 2.5 0.0 10.0 0.1 +#pragma parameter NTSC_DISPLAY_GAMMA "NTSC Display Gamma" 2.1 0.0 10.0 0.1 + +#ifdef PARAMETER_UNIFORM +uniform float NTSC_CRT_GAMMA; +uniform float NTSC_DISPLAY_GAMMA; +#else +#define NTSC_CRT_GAMMA 2.5 +#define NTSC_DISPLAY_GAMMA 2.1 +#endif + +float4 ntsc_gauss_pass(float2 tex, COMPAT_Texture2D(s0), float2 one, float2 pix_no) +{ +#define TEX(off) pow(COMPAT_Sample(s0, tex + float2(0.0, (off) * one.y)).rgb, float3(NTSC_CRT_GAMMA, NTSC_CRT_GAMMA, NTSC_CRT_GAMMA)) + + float3 frame0 = TEX(-2.0); + float3 frame1 = TEX(-1.0); + float3 frame2 = TEX(0.0); + float3 frame3 = TEX(1.0); + float3 frame4 = TEX(2.0); + + float offset_dist = frac(pix_no.y) - 0.5; + float dist0 = 2.0 + offset_dist; + float dist1 = 1.0 + offset_dist; + float dist2 = 0.0 + offset_dist; + float dist3 = -1.0 + offset_dist; + float dist4 = -2.0 + offset_dist; + + float3 scanline = frame0 * exp(-5.0 * dist0 * dist0); + scanline += frame1 * exp(-5.0 * dist1 * dist1); + scanline += frame2 * exp(-5.0 * dist2 * dist2); + scanline += frame3 * exp(-5.0 * dist3 * dist3); + scanline += frame4 * exp(-5.0 * dist4 * dist4); + + float3 gamma_mod = float3(1.0 / NTSC_DISPLAY_GAMMA, 1.0 / NTSC_DISPLAY_GAMMA, 1.0 / NTSC_DISPLAY_GAMMA); + + return float4(pow(float3(1.15, 1.15, 1.15) * scanline, gamma_mod), 1.0); +} + +float4 main_fragment(COMPAT_IN_FRAGMENT) : COMPAT_Output +{ + return ntsc_gauss_pass(VOUT.texCoord, decal, VOUT.one, VOUT.pix_no); +} +COMPAT_END \ No newline at end of file diff --git a/system/shaders/presets/HLSL/ntsc/shaders/ntsc-param.inc b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-param.inc new file mode 100644 index 0000000000000..2e6fd72e25f5f --- /dev/null +++ b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-param.inc @@ -0,0 +1,28 @@ +#define PI 3.14159265 + +#if defined(TWO_PHASE) +#define CHROMA_MOD_FREQ (4.0 * PI / 15.0) +#elif defined(THREE_PHASE) +#define CHROMA_MOD_FREQ (PI / 3.0) +#endif + +#if defined(COMPOSITE) +#define SATURATION 1.0 +#define BRIGHTNESS 1.0 +#define ARTIFACTING 1.0 +#define FRINGING 1.0 +#elif defined(SVIDEO) +#define SATURATION 1.0 +#define BRIGHTNESS 1.0 +#define ARTIFACTING 0.0 +#define FRINGING 0.0 +#endif + +#if defined(COMPOSITE) || defined(SVIDEO) +const float3x3 mix_mat = float3x3( + BRIGHTNESS, ARTIFACTING, ARTIFACTING, + FRINGING, 2.0 * SATURATION, 0.0, + FRINGING, 0.0, 2.0 * SATURATION +); +#endif + diff --git a/system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass1-composite-3phase.cg b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass1-composite-3phase.cg new file mode 100644 index 0000000000000..284703fe938de --- /dev/null +++ b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass1-composite-3phase.cg @@ -0,0 +1,20 @@ +#include "../../compat_includes.inc" +uniform COMPAT_Texture2D(decal) : TEXUNIT0; +uniform float4x4 modelViewProj; + +#include "ntsc-pass1-vertex.inc" +#define THREE_PHASE +#define COMPOSITE +#include "ntsc-param.inc" +#include "ntsc-rgbyuv.inc" + +float4 ntsc_pass1_composite_3phase(float2 texture_size, float frame_count, float2 tex, COMPAT_Texture2D(s0), float2 pix_no) +{ +#include "ntsc-pass1-encode-demodulate.inc" +} + +float4 main_fragment(COMPAT_IN_FRAGMENT) : COMPAT_Output +{ + return ntsc_pass1_composite_3phase(COMPAT_texture_size, COMPAT_frame_count, VOUT.texCoord, decal, VOUT.pix_no); +} +COMPAT_END \ No newline at end of file diff --git a/system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass1-encode-demodulate.inc b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass1-encode-demodulate.inc new file mode 100644 index 0000000000000..f47e66b9e4f08 --- /dev/null +++ b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass1-encode-demodulate.inc @@ -0,0 +1,19 @@ +float3 col = COMPAT_Sample(s0, tex).rgb; +float3 yiq = rgb2yiq(col); + +#if defined(TWO_PHASE) +float chroma_phase = PI * (fmod(pix_no.y, 2.0) + frame_count); +#elif defined(THREE_PHASE) +float chroma_phase = 0.6667 * PI * (fmod(pix_no.y, 3.0) + frame_count); +#endif + +float mod_phase = chroma_phase + pix_no.x * CHROMA_MOD_FREQ; + +float i_mod = cos(mod_phase); +float q_mod = sin(mod_phase); + +yiq.yz *= float2(i_mod, q_mod); // Modulate. +yiq = mul(mix_mat, yiq); // Cross-talk. +yiq.yz *= float2(i_mod, q_mod); // Demodulate. +return float4(yiq, 1.0); + diff --git a/system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass1-svideo-2phase.cg b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass1-svideo-2phase.cg new file mode 100644 index 0000000000000..31e8df30bf324 --- /dev/null +++ b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass1-svideo-2phase.cg @@ -0,0 +1,20 @@ +#include "../../compat_includes.inc" +uniform COMPAT_Texture2D(decal) : TEXUNIT0; +uniform float4x4 modelViewProj; + +#include "ntsc-pass1-vertex.inc" +#define TWO_PHASE +#define SVIDEO +#include "ntsc-param.inc" +#include "ntsc-rgbyuv.inc" + +float4 ntsc_pass1_svideo_2phase(float2 texture_size, float frame_count, float2 tex, COMPAT_Texture2D(s0), float2 pix_no) +{ +#include "ntsc-pass1-encode-demodulate.inc" +} + +float4 main_fragment(COMPAT_IN_FRAGMENT) : COMPAT_Output +{ + return ntsc_pass1_svideo_2phase(COMPAT_texture_size, COMPAT_frame_count, VOUT.texCoord, decal, VOUT.pix_no); +} +COMPAT_END \ No newline at end of file diff --git a/system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass1-vertex.inc b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass1-vertex.inc new file mode 100644 index 0000000000000..7cfc3b2ed7f56 --- /dev/null +++ b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass1-vertex.inc @@ -0,0 +1,25 @@ +struct out_vertex +{ + float4 position : COMPAT_POS; + float2 texCoord : TEXCOORD0; + float2 pix_no : TEXCOORD1; +#ifndef HLSL_4 + float4 Color : COLOR; +#endif +}; + +out_vertex main_vertex(COMPAT_IN_VERTEX) +{ + out_vertex OUT; +#ifdef HLSL_4 + float4 position = VIN.position; + float2 texCoord = VIN.texCoord; +#else + OUT.Color = color; +#endif + OUT.position = mul(modelViewProj, position); + OUT.texCoord = texCoord; + OUT.pix_no = texCoord * COMPAT_texture_size * (COMPAT_output_size / COMPAT_video_size); + + return OUT; +} \ No newline at end of file diff --git a/system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass2-2phase.cg b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass2-2phase.cg new file mode 100644 index 0000000000000..c643ba7d3e168 --- /dev/null +++ b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass2-2phase.cg @@ -0,0 +1,23 @@ +#include "../../compat_includes.inc" +uniform COMPAT_Texture2D(decal) : TEXUNIT0; +uniform float4x4 modelViewProj; + +#include "ntsc-pass2-vertex.inc" +#include "ntsc-decode-filter-2phase.inc" +#include "ntsc-rgbyuv.inc" + +#define fetch_offset(offset, one_x) \ + COMPAT_Sample(s0, tex + float2((offset) * (one_x), 0.0)).xyz + +float4 ntsc_pass2_2phase(float2 texture_size, float2 tex, COMPAT_Texture2D(s0)) +{ +#include "ntsc-pass2-decode.inc" + float3 rgb = yiq2rgb(signal); + return float4(rgb, 1.0); +} + +float4 main_fragment(COMPAT_IN_FRAGMENT) : COMPAT_Output +{ + return ntsc_pass2_2phase(COMPAT_texture_size, VOUT.texCoord, decal); +} +COMPAT_END \ No newline at end of file diff --git a/system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass2-3phase.cg b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass2-3phase.cg new file mode 100644 index 0000000000000..ab0a971e69ac9 --- /dev/null +++ b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass2-3phase.cg @@ -0,0 +1,23 @@ +#include "../../compat_includes.inc" +uniform COMPAT_Texture2D(decal) : TEXUNIT0; +uniform float4x4 modelViewProj; + +#include "ntsc-pass2-vertex.inc" +#include "ntsc-decode-filter-3phase.inc" +#include "ntsc-rgbyuv.inc" + +#define fetch_offset(offset, one_x) \ + COMPAT_Sample(s0, tex + float2((offset) * (one_x), 0.0)).xyz + +float4 ntsc_pass2_3phase(float2 texture_size, float2 tex, COMPAT_Texture2D(s0)) +{ +#include "ntsc-pass2-decode.inc" + float3 rgb = yiq2rgb(signal); + return float4(rgb, 1.0); +} + +float4 main_fragment(COMPAT_IN_FRAGMENT) : COMPAT_Output +{ + return ntsc_pass2_3phase(COMPAT_texture_size, VOUT.texCoord, decal); +} +COMPAT_END diff --git a/system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass2-decode.inc b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass2-decode.inc new file mode 100644 index 0000000000000..20e9a9491eddb --- /dev/null +++ b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass2-decode.inc @@ -0,0 +1,14 @@ +float one_x = 1.0 / texture_size.x; +float3 signal = float3(0.0, 0.0, 0.0); +for (int i = 0; i < TAPS; i++) +{ + float offset = float(i); + + float3 sums = fetch_offset(offset - float(TAPS), one_x) + + fetch_offset(float(TAPS) - offset, one_x); + + signal += sums * float3(luma_filter[i], chroma_filter[i], chroma_filter[i]); +} +signal += COMPAT_SamplePoint(s0, tex).xyz * + float3(luma_filter[TAPS], chroma_filter[TAPS], chroma_filter[TAPS]); + diff --git a/system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass2-vertex.inc b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass2-vertex.inc new file mode 100644 index 0000000000000..63900be4e4309 --- /dev/null +++ b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-pass2-vertex.inc @@ -0,0 +1,23 @@ +struct out_vertex +{ + float4 position : COMPAT_POS; + float2 texCoord : TEXCOORD0; +#ifndef HLSL_4 + float4 Color : COLOR; +#endif +}; + +out_vertex main_vertex(COMPAT_IN_VERTEX) +{ + out_vertex OUT; +#ifdef HLSL_4 + float4 position = VIN.position; + float2 texCoord = VIN.texCoord; +#else + OUT.Color = color; +#endif + OUT.position = mul(modelViewProj, position); + OUT.texCoord = texCoord - float2(0.5 / COMPAT_texture_size.x, 0.0); // Compensate for decimate-by-2. + + return OUT; +} \ No newline at end of file diff --git a/system/shaders/presets/HLSL/ntsc/shaders/ntsc-rgbyuv.inc b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-rgbyuv.inc new file mode 100644 index 0000000000000..a5c553e668934 --- /dev/null +++ b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-rgbyuv.inc @@ -0,0 +1,22 @@ +static const float3x3 yiq2rgb_mat = float3x3( + 1.0, 0.956, 0.6210, + 1.0, -0.2720, -0.6474, + 1.0, -1.1060, 1.7046); + +float3 yiq2rgb(float3 yiq) +{ + return mul(yiq2rgb_mat, yiq); +} + +static const float3x3 yiq_mat = float3x3( + 0.2989, 0.5870, 0.1140, + 0.5959, -0.2744, -0.3216, + 0.2115, -0.5229, 0.3114 +); + +float3 rgb2yiq(float3 col) +{ + return mul(yiq_mat, col); +} + + diff --git a/system/shaders/presets/HLSL/ntsc/shaders/ntsc-stock.cg b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-stock.cg new file mode 100644 index 0000000000000..224d73fb0d417 --- /dev/null +++ b/system/shaders/presets/HLSL/ntsc/shaders/ntsc-stock.cg @@ -0,0 +1,44 @@ +/* COMPATIBILITY + - HLSL compilers + - Cg compilers + - FX11 compilers +*/ + +#include "../../compat_includes.inc" +uniform COMPAT_Texture2D(decal) : TEXUNIT0; +uniform float4x4 modelViewProj; + +struct out_vertex +{ + float4 position : COMPAT_POS; + float2 texCoord : TEXCOORD0; +#ifndef HLSL_4 + float4 Color : COLOR; +#endif +}; + +out_vertex main_vertex(COMPAT_IN_VERTEX) +{ + out_vertex OUT; +#ifdef HLSL_4 + float4 position = VIN.position; + float2 texCoord = VIN.texCoord; +#else + OUT.Color = color; +#endif + OUT.position = mul(modelViewProj, position); + OUT.texCoord = texCoord; + + return OUT; +} + +float4 stock(float2 tex) +{ + return COMPAT_Sample(decal, tex); +} + +float4 main_fragment(COMPAT_IN_FRAGMENT) : COMPAT_Output +{ + return stock(VOUT.texCoord); +} +COMPAT_END \ No newline at end of file diff --git a/system/shaders/presets/HLSL/stock.cg b/system/shaders/presets/HLSL/stock.cg new file mode 100644 index 0000000000000..73dbd1f09010d --- /dev/null +++ b/system/shaders/presets/HLSL/stock.cg @@ -0,0 +1,74 @@ +/* COMPATIBILITY + - HLSL compilers + - Cg compilers + - FX11 +*/ + +#include "compat_includes.inc" + +// ************ +// * UNIFORMS * +// ************ + +// The view projects and the texture are global uniforms, +// not args to shader functions +uniform float4x4 modelViewProj; +uniform COMPAT_Texture2D(decal); + +// *********** +// * STRUCTS * +// *********** + +// Vertex shader output truct +// Pixel shader input struct +struct out_vertex +{ + float4 position : COMPAT_POS; + float2 texCoord : TEXCOORD0; +#ifndef HLSL_4 + float4 Color : COLOR; +#endif +}; + +// ***************** +// * VERTEX SHADER * +// ***************** + +// Vertex shader returns one struct, 'in_vertex'. no "out" shenanigans +// It can not have more args +// Uniforms are declared in global scope +// Other args are passed to out_vertex for the rasterizer and the pixel shader to use +out_vertex main_vertex(COMPAT_IN_VERTEX) +{ + out_vertex OUT; +#ifdef HLSL_4 + float4 position = VIN.position; + float2 texCoord = VIN.texCoord; +#else + OUT.Color = color; +#endif + OUT.position = mul(modelViewProj, position); + OUT.texCoord = texCoord; + + return OUT; +} + +// Instead of the shader above we could have used +// 'COMPAT_DEFAULT_VS_SHADER' + +// **************** +// * PIXEL SHADER * +// **************** + +// Same as the vertex shader: +// Uniforms are not here but declared in global scope +// It can not have more args +// There's no "uniform input IN" either, +// shaders can refer to fields of the input struct (like 'ouput_size') as if they're globals ('output_size') +float4 main_fragment(COMPAT_IN_FRAGMENT) : COMPAT_Output +{ + return COMPAT_Sample(decal, VOUT.texCoord); +} + +// Add this at the end of every shader +COMPAT_END \ No newline at end of file diff --git a/system/shaders/presets/HLSL/xbr/shaders/xbr-lv2-fast.cg b/system/shaders/presets/HLSL/xbr/shaders/xbr-lv2-fast.cg new file mode 100644 index 0000000000000..d783bc620348c --- /dev/null +++ b/system/shaders/presets/HLSL/xbr/shaders/xbr-lv2-fast.cg @@ -0,0 +1,235 @@ +#pragma parameter XBR_SCALE "xBR Scale" 3.0 1.0 5.0 1.0 +#pragma parameter XBR_Y_WEIGHT "Y Weight" 48.0 0.0 100.0 1.0 +#pragma parameter XBR_EQ_THRESHOLD "Eq Threshold" 15.0 0.0 50.0 1.0 +#pragma parameter XBR_LV2_COEFFICIENT "Lv2 Coefficient" 2.0 1.0 3.0 0.1 +#ifdef PARAMETER_UNIFORM +uniform float XBR_SCALE; +uniform float XBR_Y_WEIGHT; +uniform float XBR_EQ_THRESHOLD; +uniform float XBR_LV2_COEFFICIENT; +#else +#define XBR_SCALE 3.0 +#define XBR_Y_WEIGHT 48.0 +#define XBR_EQ_THRESHOLD 15.0 +#define XBR_LV2_COEFFICIENT 2.0 +#endif +// END PARAMETERS // + +/* COMPATIBILITY + - HLSL compilers + - Cg compilers + - FX11 compilers +*/ + + +/* + Hyllian's xBR-lv2-lq Shader + + Copyright (C) 2011/2015 Hyllian/Jararaca - sergiogdb@gmail.com + + Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + + Incorporates some of the ideas from SABR shader. Thanks to Joshua Street. +*/ + + +#include "../../compat_includes.inc" + +uniform COMPAT_Texture2D(decal) : TEXUNIT0; +uniform float4x4 modelViewProj; + +// Uncomment just one of the three params below to choose the corner detection +//#define CORNER_A +#define CORNER_C + +#ifdef CORNER_C + #define SMOOTH_TIPS +#endif + +const static float4 Ao = float4( 1.0, -1.0, -1.0, 1.0 ); +const static float4 Bo = float4( 1.0, 1.0, -1.0,-1.0 ); +const static float4 Co = float4( 1.5, 0.5, -0.5, 0.5 ); +const static float4 Ax = float4( 1.0, -1.0, -1.0, 1.0 ); +const static float4 Bx = float4( 0.5, 2.0, -0.5,-2.0 ); +const static float4 Cx = float4( 1.0, 1.0, -0.5, 0.0 ); +const static float4 Ay = float4( 1.0, -1.0, -1.0, 1.0 ); +const static float4 By = float4( 2.0, 0.5, -2.0,-0.5 ); +const static float4 Cy = float4( 2.0, 0.0, -1.0, 0.5 ); +const static float4 Ci = float4(0.25, 0.25, 0.25, 0.25); + +const static float3 Y = float3(0.2126, 0.7152, 0.0722); + +float4 df(float4 A, float4 B) +{ + return float4(abs(A-B)); +} + +float c_df(float3 c1, float3 c2) +{ + float3 df = abs(c1 - c2); + return df.r + df.g + df.b; +} + +bool4 eq(float4 A, float4 B) +{ + return (df(A, B) < float4(XBR_EQ_THRESHOLD, XBR_EQ_THRESHOLD, XBR_EQ_THRESHOLD, XBR_EQ_THRESHOLD)); +} + +float4 weighted_distance(float4 a, float4 b, float4 c, float4 d, float4 e, float4 f, float4 g, float4 h) +{ + return (df(c,d) + df(e,f) + 3.0*df(g,h)); +// return (1.0*df(a,b) + 2.0*df(c,d) + 2.0*df(e,f) + 4.0*df(g,h)); +} + +struct out_vertex { + float4 position : COMPAT_POS; + float2 texCoord : TEXCOORD0; + float4 t1 : TEXCOORD1; + float4 t2 : TEXCOORD2; + float4 t3 : TEXCOORD3; +#ifndef HLSL_4 + float4 Color : COLOR; +#endif +}; + +/* VERTEX_SHADER */ +out_vertex main_vertex(COMPAT_IN_VERTEX) +{ + out_vertex OUT; +#ifdef HLSL_4 + float4 position = VIN.position; + float2 texCoord = VIN.texCoord; +#else + OUT.Color = color; +#endif + + OUT.position = mul(modelViewProj, position); + + float2 ps = float2(1.0/COMPAT_texture_size.x, 1.0/COMPAT_texture_size.y); + float dx = ps.x; + float dy = ps.y; + + // A1 B1 C1 + // A0 A B C C4 + // D0 D E F F4 + // G0 G H I I4 + // G5 H5 I5 + + OUT.texCoord = texCoord; + OUT.t1 = texCoord.xxxy + float4( -dx, 0, dx, -dy); // A B C + OUT.t2 = texCoord.xxxy + float4( -dx, 0, dx, 0); // D E F + OUT.t3 = texCoord.xxxy + float4( -dx, 0, dx, dy); // G H I + + return OUT; +} + + +/* FRAGMENT SHADER */ +float4 main_fragment(COMPAT_IN_FRAGMENT) : COMPAT_Output +{ + bool4 edri, edr, edr_left, edr_up, px; // px = pixel, edr = edge detection rule + bool4 interp_restriction_lv0, interp_restriction_lv1, interp_restriction_lv2_left, interp_restriction_lv2_up; + float4 fx, fx_left, fx_up; // inequations of straight lines. + + float4 delta = float4(1.0/XBR_SCALE, 1.0/XBR_SCALE, 1.0/XBR_SCALE, 1.0/XBR_SCALE); + float4 deltaL = float4(0.5/XBR_SCALE, 1.0/XBR_SCALE, 0.5/XBR_SCALE, 1.0/XBR_SCALE); + float4 deltaU = deltaL.yxwz; + + float2 fp = frac(VOUT.texCoord*COMPAT_texture_size); + + float3 A = COMPAT_SamplePoint(decal, VOUT.t1.xw).rgb; + float3 B = COMPAT_SamplePoint(decal, VOUT.t1.yw).rgb; + float3 C = COMPAT_SamplePoint(decal, VOUT.t1.zw).rgb; + + float3 D = COMPAT_SamplePoint(decal, VOUT.t2.xw).rgb; + float3 E = COMPAT_SamplePoint(decal, VOUT.t2.yw).rgb; + float3 F = COMPAT_SamplePoint(decal, VOUT.t2.zw).rgb; + + float3 G = COMPAT_SamplePoint(decal, VOUT.t3.xw).rgb; + float3 H = COMPAT_SamplePoint(decal, VOUT.t3.yw).rgb; + float3 I = COMPAT_SamplePoint(decal, VOUT.t3.zw).rgb; + + + float4 b = mul( float4x3(B, D, H, F), XBR_Y_WEIGHT*Y ); + float4 c = mul( float4x3(C, A, G, I), XBR_Y_WEIGHT*Y ); + float4 e = mul( float4x3(E, E, E, E), XBR_Y_WEIGHT*Y ); + float4 a = c.yzwx; + float4 d = b.yzwx; + float4 f = b.wxyz; + float4 g = c.zwxy; + float4 h = b.zwxy; + float4 i = c.wxyz; + + // These inequations define the line below which interpolation occurs. + fx = (Ao*fp.y+Bo*fp.x); + fx_left = (Ax*fp.y+Bx*fp.x); + fx_up = (Ay*fp.y+By*fp.x); + + interp_restriction_lv1 = interp_restriction_lv0 = ((e!=f) && (e!=h)); + +#ifndef CORNER_A + interp_restriction_lv1 = ( interp_restriction_lv0 && ( !eq(f,b) && !eq(f,c) || !eq(h,d) && !eq(h,g) || eq(e,g) || eq(e,c)) ); +#endif + + interp_restriction_lv2_left = ((e!=g) && (d!=g)); + interp_restriction_lv2_up = ((e!=c) && (b!=c)); + + float4 fx45i = saturate((fx + delta -Co - Ci)/(2*delta )); + float4 fx45 = saturate((fx + delta -Co )/(2*delta )); + float4 fx30 = saturate((fx_left + deltaL -Cx )/(2*deltaL)); + float4 fx60 = saturate((fx_up + deltaU -Cy )/(2*deltaU)); + + float4 wd1 = weighted_distance( d, b, g, e, e, c, h, f); + float4 wd2 = weighted_distance( a, e, b, f, d, h, e, i); + + edri = (wd1 <= wd2) && interp_restriction_lv0; + edr = (wd1 < wd2) && interp_restriction_lv1; + edr_left = ((XBR_LV2_COEFFICIENT*df(f,g)) <= df(h,c)) && interp_restriction_lv2_left && edr; + edr_up = (df(f,g) >= (XBR_LV2_COEFFICIENT*df(h,c))) && interp_restriction_lv2_up && edr; + + fx45 = edr*fx45; + fx30 = edr_left*fx30; + fx60 = edr_up*fx60; + fx45i = edri*fx45i; + + px = (df(e,f) <= df(e,h)); + +#ifdef SMOOTH_TIPS + float4 maximos = max(max(fx30, fx60), max(fx45, fx45i)); +#else + float4 maximos = max(max(fx30, fx60), fx45); +#endif + + float3 res1 = E; + res1 = lerp(res1, lerp(H, F, px.x), maximos.x); + res1 = lerp(res1, lerp(B, D, px.z), maximos.z); + + float3 res2 = E; + res2 = lerp(res2, lerp(F, B, px.y), maximos.y); + res2 = lerp(res2, lerp(D, H, px.w), maximos.w); + + float3 res = lerp(res1, res2, step(c_df(E, res1), c_df(E, res2))); + + return float4(res, 1.0); +} + +COMPAT_END \ No newline at end of file diff --git a/system/shaders/presets/HLSL/xbr/shaders/xbr-lv3-noblend.cg b/system/shaders/presets/HLSL/xbr/shaders/xbr-lv3-noblend.cg new file mode 100644 index 0000000000000..42f0e48f043d3 --- /dev/null +++ b/system/shaders/presets/HLSL/xbr/shaders/xbr-lv3-noblend.cg @@ -0,0 +1,271 @@ +#pragma parameter XBR_EQ_THRESHOLD "Eq Threshold" 0.6 0.0 1.0 0.1 +#pragma parameter XBR_EQ_THRESHOLD2 "Eq Threshold2" 0.01 0.0 0.10 0.002 +#pragma parameter XBR_LV2_COEFFICIENT "Lv2 Coefficient" 2.0 1.0 3.0 0.1 +#ifdef PARAMETER_UNIFORM +uniform float XBR_EQ_THRESHOLD; +uniform float XBR_EQ_THRESHOLD2; +uniform float XBR_LV2_COEFFICIENT; +#else +#define XBR_EQ_THRESHOLD 0.6 +#define XBR_EQ_THRESHOLD2 0.01 +#define XBR_LV2_COEFFICIENT 2.0 +#endif +// END PARAMETERS // + +/* COMPATIBILITY + - HLSL compilers + - Cg compilers + - FX11 compilers +*/ + +#include "../../compat_includes.inc" +uniform COMPAT_Texture2D(decal) : TEXUNIT0; +uniform float4x4 modelViewProj; + +/* + Hyllian's xBR-lv3-noblend - Shader + + Copyright (C) 2011/2016 Hyllian - sergiogdb@gmail.com + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +// Uncomment just one of the three params below to choose the corner detection +#define CORNER_A +//#define CORNER_B +//#define CORNER_C +//#define CORNER_D + +const static float3 Y = float3(0.2126, 0.7152, 0.0722); + + +float4 df(float4 A, float4 B) +{ + return float4(abs(A-B)); +} + +float c_df(float3 c1, float3 c2) +{ + float3 df = abs(c1 - c2); + return df.r + df.g + df.b; +} + +bool4 eq(float4 A, float4 B) +{ + return (df(A, B) < float4(XBR_EQ_THRESHOLD, XBR_EQ_THRESHOLD, XBR_EQ_THRESHOLD, XBR_EQ_THRESHOLD)); +} + +bool4 eq2(float4 A, float4 B) +{ + return (df(A, B) < float4(XBR_EQ_THRESHOLD2, XBR_EQ_THRESHOLD2, XBR_EQ_THRESHOLD2, XBR_EQ_THRESHOLD2)); +} + + +float4 weighted_distance(float4 a, float4 b, float4 c, float4 d, float4 e, float4 f, float4 g, float4 h) +{ + return (df(a,b) + df(a,c) + df(d,e) + df(d,f) + 4.0*df(g,h)); +} + +struct out_vertex { + float4 position : COMPAT_POS; + float2 texCoord : TEXCOORD0; + float4 t1 : TEXCOORD1; + float4 t2 : TEXCOORD2; + float4 t3 : TEXCOORD3; + float4 t4 : TEXCOORD4; + float4 t5 : TEXCOORD5; + float4 t6 : TEXCOORD6; + float4 t7 : TEXCOORD7; +#ifndef HLSL_4 + float4 Color : COLOR; +#endif +}; + +/* VERTEX_SHADER */ +out_vertex main_vertex(COMPAT_IN_VERTEX) +{ + out_vertex OUT; +#ifdef HLSL_4 + float4 position = VIN.position; + float2 texCoord = VIN.texCoord; +#else + OUT.Color = color; +#endif + + OUT.position = mul(modelViewProj, position); + + float2 ps = float2(1.0/COMPAT_texture_size.x, 1.0/COMPAT_texture_size.y); + float dx = ps.x; + float dy = ps.y; + + // A1 B1 C1 + // A0 A B C C4 + // D0 D E F F4 + // G0 G H I I4 + // G5 H5 I5 + + // This line fix a bug in ATI cards. + texCoord = texCoord + float2(0.0000001, 0.0000001); + + OUT.texCoord = texCoord; + OUT.t1 = texCoord.xxxy + float4( -dx, 0, dx,-2.0*dy); // A1 B1 C1 + OUT.t2 = texCoord.xxxy + float4( -dx, 0, dx, -dy); // A B C + OUT.t3 = texCoord.xxxy + float4( -dx, 0, dx, 0); // D E F + OUT.t4 = texCoord.xxxy + float4( -dx, 0, dx, dy); // G H I + OUT.t5 = texCoord.xxxy + float4( -dx, 0, dx, 2.0*dy); // G5 H5 I5 + OUT.t6 = texCoord.xyyy + float4(-2.0*dx,-dy, 0, dy); // A0 D0 G0 + OUT.t7 = texCoord.xyyy + float4( 2.0*dx,-dy, 0, dy); // C4 F4 I4 + + return OUT; +} + + +/* FRAGMENT SHADER */ +float4 main_fragment(COMPAT_IN_FRAGMENT) : COMPAT_Output +{ + bool4 edri, edr, edr_left, edr_up, edr3_left, edr3_up, px; // px = pixel, edr = edge detection rule + bool4 interp_restriction_lv1, interp_restriction_lv2_left, interp_restriction_lv2_up; + bool4 interp_restriction_lv3_left, interp_restriction_lv3_up; + bool4 nc; // new_color + bool4 fx, fx_left, fx_up, fx3_left, fx3_up; // inequations of straight lines. + + float2 fp = frac(VOUT.texCoord*COMPAT_texture_size); + + float3 A1 = COMPAT_SamplePoint(decal, VOUT.t1.xw).rgb; + float3 B1 = COMPAT_SamplePoint(decal, VOUT.t1.yw).rgb; + float3 C1 = COMPAT_SamplePoint(decal, VOUT.t1.zw).rgb; + + float3 A = COMPAT_SamplePoint(decal, VOUT.t2.xw).rgb; + float3 B = COMPAT_SamplePoint(decal, VOUT.t2.yw).rgb; + float3 C = COMPAT_SamplePoint(decal, VOUT.t2.zw).rgb; + + float3 D = COMPAT_SamplePoint(decal, VOUT.t3.xw).rgb; + float3 E = COMPAT_SamplePoint(decal, VOUT.t3.yw).rgb; + float3 F = COMPAT_SamplePoint(decal, VOUT.t3.zw).rgb; + + float3 G = COMPAT_SamplePoint(decal, VOUT.t4.xw).rgb; + float3 H = COMPAT_SamplePoint(decal, VOUT.t4.yw).rgb; + float3 I = COMPAT_SamplePoint(decal, VOUT.t4.zw).rgb; + + float3 G5 = COMPAT_SamplePoint(decal, VOUT.t5.xw).rgb; + float3 H5 = COMPAT_SamplePoint(decal, VOUT.t5.yw).rgb; + float3 I5 = COMPAT_SamplePoint(decal, VOUT.t5.zw).rgb; + + float3 A0 = COMPAT_SamplePoint(decal, VOUT.t6.xy).rgb; + float3 D0 = COMPAT_SamplePoint(decal, VOUT.t6.xz).rgb; + float3 G0 = COMPAT_SamplePoint(decal, VOUT.t6.xw).rgb; + + float3 C4 = COMPAT_SamplePoint(decal, VOUT.t7.xy).rgb; + float3 F4 = COMPAT_SamplePoint(decal, VOUT.t7.xz).rgb; + float3 I4 = COMPAT_SamplePoint(decal, VOUT.t7.xw).rgb; + + float4 b = mul( float4x3(B, D, H, F), Y ); + float4 c = mul( float4x3(C, A, G, I), Y ); + float4 e = mul( float4x3(E, E, E, E), Y ); + float4 d = b.yzwx; + float4 f = b.wxyz; + float4 g = c.zwxy; + float4 h = b.zwxy; + float4 i = c.wxyz; + + float4 i4 = mul( float4x3(I4, C1, A0, G5), Y ); + float4 i5 = mul( float4x3(I5, C4, A1, G0), Y ); + float4 h5 = mul( float4x3(H5, F4, B1, D0), Y ); + float4 f4 = h5.yzwx; + + float4 c4 = i5.yzwx; + float4 g5 = i4.wxyz; + + float4 c1 = i4.yzwx; + float4 g0 = i5.wxyz; + float4 b1 = h5.zwxy; + float4 d0 = h5.wxyz; + + + float4 Ao = float4( 1.0, -1.0, -1.0, 1.0 ); + float4 Bo = float4( 1.0, 1.0, -1.0,-1.0 ); + float4 Co = float4( 1.5, 0.5, -0.5, 0.5 ); + float4 Ax = float4( 1.0, -1.0, -1.0, 1.0 ); + float4 Bx = float4( 0.5, 2.0, -0.5,-2.0 ); + float4 Cx = float4( 1.0, 1.0, -0.5, 0.0 ); + float4 Ay = float4( 1.0, -1.0, -1.0, 1.0 ); + float4 By = float4( 2.0, 0.5, -2.0,-0.5 ); + float4 Cy = float4( 2.0, 0.0, -1.0, 0.5 ); + + float4 Az = float4( 6.0, -2.0, -6.0, 2.0 ); + float4 Bz = float4( 2.0, 6.0, -2.0, -6.0 ); + float4 Cz = float4( 5.0, 3.0, -3.0, -1.0 ); + float4 Aw = float4( 2.0, -6.0, -2.0, 6.0 ); + float4 Bw = float4( 6.0, 2.0, -6.0,-2.0 ); + float4 Cw = float4( 5.0, -1.0, -3.0, 3.0 ); + + // These inequations define the line below which interpolation occurs. + fx = (Ao*fp.y+Bo*fp.x > Co); + fx_left = (Ax*fp.y+Bx*fp.x > Cx); + fx_up = (Ay*fp.y+By*fp.x > Cy); + fx3_left = (Az*fp.y+Bz*fp.x > Cz); + fx3_up = (Aw*fp.y+Bw*fp.x > Cw); + + // It uses CORNER_C if none of the others are defined. + #ifdef CORNER_A + interp_restriction_lv1 = ((e!=f) && (e!=h)); + #endif + #ifdef CORNER_B + interp_restriction_lv1 = ((e!=f) && (e!=h) && ( !eq(f,b) && !eq(h,d) || eq(e,i) && !eq(f,i4) && !eq(h,i5) || eq(e,g) || eq(e,c) ) ); + #endif + #ifdef CORNER_D + interp_restriction_lv1 = ((e!=f) && (e!=h) && ( !eq(f,b) && !eq(h,d) || eq(e,i) && !eq(f,i4) && !eq(h,i5) || eq(e,g) || eq(e,c) ) && (f!=f4 && f!=i || h!=h5 && h!=i || h!=g || f!=c || eq(b,c1) && eq(d,g0))); + #endif + #ifdef CORNER_C + interp_restriction_lv1 = ((e!=f) && (e!=h) && ( !eq(f,b) && !eq(f,c) || !eq(h,d) && !eq(h,g) || eq(e,i) && (!eq(f,f4) && !eq(f,i4) || !eq(h,h5) && !eq(h,i5)) || eq(e,g) || eq(e,c)) ); + #endif + + interp_restriction_lv2_left = ((e!=g) && (d!=g)); + interp_restriction_lv2_up = ((e!=c) && (b!=c)); + interp_restriction_lv3_left = (eq2(g,g0) && (d0!=g0)); + interp_restriction_lv3_up = (eq2(c,c1) && (b1!=c1)); + + float4 wd1 = weighted_distance( e, c, g, i, h5, f4, h, f); + float4 wd2 = weighted_distance( h, d, i5, f, i4, b, e, i); + + edri = (wd1 <= wd2) && interp_restriction_lv1; + edr = (wd1 < wd2) && interp_restriction_lv1; + + edr = edr && (!edri.yzwx || !edri.wxyz); + edr_left = ((XBR_LV2_COEFFICIENT*df(f,g)) <= df(h,c)) && interp_restriction_lv2_left && edr && (!edri.yzwx && eq(e,c)); + edr_up = (df(f,g) >= (XBR_LV2_COEFFICIENT*df(h,c))) && interp_restriction_lv2_up && edr && (!edri.wxyz && eq(e,g)); + edr3_left = interp_restriction_lv3_left; + edr3_up = interp_restriction_lv3_up; + + nc = ( edr && ( fx || edr_left && (fx_left || edr3_left && fx3_left && eq(e,c4)) || edr_up && (fx_up || edr3_up && fx3_up && eq(e,g5))) ); + + px = (df(e,f) <= df(e,h)); + + float3 res1 = nc.x ? px.x ? F : H : nc.y ? px.y ? B : F : nc.z ? px.z ? D : B : nc.w ? px.w ? H : D : E; + float3 res2 = nc.w ? px.w ? H : D : nc.z ? px.z ? D : B : nc.y ? px.y ? B : F : nc.x ? px.x ? F : H : E; + + float2 df12 = abs(mul(float2x3(res1, res2), Y) - e.xy); + + float3 res = lerp(res1, res2, step(df12.x, df12.y)); + + return float4(res, 1.0); +} + +COMPAT_END \ No newline at end of file diff --git a/system/shaders/presets/HLSL/xbr/shaders/xbr-lv3.cg b/system/shaders/presets/HLSL/xbr/shaders/xbr-lv3.cg new file mode 100644 index 0000000000000..3147bab2466a9 --- /dev/null +++ b/system/shaders/presets/HLSL/xbr/shaders/xbr-lv3.cg @@ -0,0 +1,292 @@ +#pragma parameter XBR_Y_WEIGHT "Y Weight" 48.0 0.0 100.0 1.0 +#pragma parameter XBR_EQ_THRESHOLD "Eq Threshold" 10.0 0.0 50.0 1.0 +#pragma parameter XBR_EQ_THRESHOLD2 "Eq Threshold2" 2.0 0.0 4.0 0.1 +#pragma parameter XBR_LV2_COEFFICIENT "Lv2 Coefficient" 2.0 1.0 3.0 0.1 +#ifdef PARAMETER_UNIFORM +uniform float XBR_Y_WEIGHT; +uniform float XBR_EQ_THRESHOLD; +uniform float XBR_EQ_THRESHOLD2; +uniform float XBR_LV2_COEFFICIENT; +#else +#define XBR_Y_WEIGHT 48.0 +#define XBR_EQ_THRESHOLD 10.0 +#define XBR_EQ_THRESHOLD2 2.0 +#define XBR_LV2_COEFFICIENT 2.0 +#endif +// END PARAMETERS // + +/* COMPATIBILITY + - HLSL compilers + - Cg compilers + - FX11 compilers +*/ + +#include "../../compat_includes.inc" +uniform COMPAT_Texture2D(decal) : TEXUNIT0; +uniform float4x4 modelViewProj; + +/* + Hyllian's xBR-lv3 Shader + + Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + + Incorporates some of the ideas from SABR shader. Thanks to Joshua Street. +*/ + +const static float3x3 yuv = float3x3(0.299, 0.587, 0.114, -0.169, -0.331, 0.499, 0.499, -0.418, -0.0813); +const static float4 delta = float4(0.4, 0.4, 0.4, 0.4); + + +float4 df(float4 A, float4 B) +{ + return float4(abs(A-B)); +} + +float c_df(float3 c1, float3 c2) { + float3 df = abs(c1 - c2); + return df.r + df.g + df.b; + } + + + + +bool4 eq(float4 A, float4 B) +{ + return (df(A, B) < float4(XBR_EQ_THRESHOLD, XBR_EQ_THRESHOLD, XBR_EQ_THRESHOLD, XBR_EQ_THRESHOLD)); +} + +bool4 eq2(float4 A, float4 B) +{ + return (df(A, B) < float4(XBR_EQ_THRESHOLD2, XBR_EQ_THRESHOLD2, XBR_EQ_THRESHOLD2, XBR_EQ_THRESHOLD2)); +} + + +float4 weighted_distance(float4 a, float4 b, float4 c, float4 d, float4 e, float4 f, float4 g, float4 h) +{ + return (df(a,b) + df(a,c) + df(d,e) + df(d,f) + 4.0*df(g,h)); +} + + +struct out_vertex { + float4 position : COMPAT_POS; + float2 texCoord : TEXCOORD0; + float4 t1 : TEXCOORD1; + float4 t2 : TEXCOORD2; + float4 t3 : TEXCOORD3; + float4 t4 : TEXCOORD4; + float4 t5 : TEXCOORD5; + float4 t6 : TEXCOORD6; + float4 t7 : TEXCOORD7; +#ifndef HLSL_4 + float4 Color : COLOR; +#endif +}; + +/* VERTEX_SHADER */ +out_vertex main_vertex(COMPAT_IN_VERTEX) +{ + out_vertex OUT; +#ifdef HLSL_4 + float4 position = VIN.position; + float2 texCoord = VIN.texCoord; +#else + OUT.Color = color; +#endif + + OUT.position = mul(modelViewProj, position); + + float2 ps = float2(1.0/COMPAT_texture_size.x, 1.0/COMPAT_texture_size.y); + float dx = ps.x; + float dy = ps.y; + + // A1 B1 C1 + // A0 A B C C4 + // D0 D E F F4 + // G0 G H I I4 + // G5 H5 I5 + + // This line fix a bug in ATI cards. + texCoord = texCoord + float2(0.0000001, 0.0000001); + + OUT.texCoord = texCoord; + OUT.t1 = texCoord.xxxy + float4( -dx, 0, dx,-2.0*dy); // A1 B1 C1 + OUT.t2 = texCoord.xxxy + float4( -dx, 0, dx, -dy); // A B C + OUT.t3 = texCoord.xxxy + float4( -dx, 0, dx, 0); // D E F + OUT.t4 = texCoord.xxxy + float4( -dx, 0, dx, dy); // G H I + OUT.t5 = texCoord.xxxy + float4( -dx, 0, dx, 2.0*dy); // G5 H5 I5 + OUT.t6 = texCoord.xyyy + float4(-2.0*dx,-dy, 0, dy); // A0 D0 G0 + OUT.t7 = texCoord.xyyy + float4( 2.0*dx,-dy, 0, dy); // C4 F4 I4 + + return OUT; +} + + +/* FRAGMENT SHADER */ +float4 main_fragment(COMPAT_IN_FRAGMENT) : COMPAT_Output +{ + bool4 edr, edr_left, edr_up, edr3_left, edr3_up, px; // px = pixel, edr = edge detection rule + bool4 interp_restriction_lv1, interp_restriction_lv2_left, interp_restriction_lv2_up; + bool4 interp_restriction_lv3_left, interp_restriction_lv3_up; + bool4 nc, nc30, nc60, nc45, nc15, nc75; // new_color + float4 fx, fx_left, fx_up, final_fx, fx3_left, fx3_up; // inequations of straight lines. + float3 res1, res2, pix1, pix2; + float blend1, blend2; + + float2 fp = frac(VOUT.texCoord*COMPAT_texture_size); + + float3 A1 = COMPAT_SamplePoint(decal, VOUT.t1.xw).rgb; + float3 B1 = COMPAT_SamplePoint(decal, VOUT.t1.yw).rgb; + float3 C1 = COMPAT_SamplePoint(decal, VOUT.t1.zw).rgb; + + float3 A = COMPAT_SamplePoint(decal, VOUT.t2.xw).rgb; + float3 B = COMPAT_SamplePoint(decal, VOUT.t2.yw).rgb; + float3 C = COMPAT_SamplePoint(decal, VOUT.t2.zw).rgb; + + float3 D = COMPAT_SamplePoint(decal, VOUT.t3.xw).rgb; + float3 E = COMPAT_SamplePoint(decal, VOUT.t3.yw).rgb; + float3 F = COMPAT_SamplePoint(decal, VOUT.t3.zw).rgb; + + float3 G = COMPAT_SamplePoint(decal, VOUT.t4.xw).rgb; + float3 H = COMPAT_SamplePoint(decal, VOUT.t4.yw).rgb; + float3 I = COMPAT_SamplePoint(decal, VOUT.t4.zw).rgb; + + float3 G5 = COMPAT_SamplePoint(decal, VOUT.t5.xw).rgb; + float3 H5 = COMPAT_SamplePoint(decal, VOUT.t5.yw).rgb; + float3 I5 = COMPAT_SamplePoint(decal, VOUT.t5.zw).rgb; + + float3 A0 = COMPAT_SamplePoint(decal, VOUT.t6.xy).rgb; + float3 D0 = COMPAT_SamplePoint(decal, VOUT.t6.xz).rgb; + float3 G0 = COMPAT_SamplePoint(decal, VOUT.t6.xw).rgb; + + float3 C4 = COMPAT_SamplePoint(decal, VOUT.t7.xy).rgb; + float3 F4 = COMPAT_SamplePoint(decal, VOUT.t7.xz).rgb; + float3 I4 = COMPAT_SamplePoint(decal, VOUT.t7.xw).rgb; + + float4 b = mul( float4x3(B, D, H, F), XBR_Y_WEIGHT*yuv[0] ); + float4 c = mul( float4x3(C, A, G, I), XBR_Y_WEIGHT*yuv[0] ); + float4 e = mul( float4x3(E, E, E, E), XBR_Y_WEIGHT*yuv[0] ); + float4 d = b.yzwx; + float4 f = b.wxyz; + float4 g = c.zwxy; + float4 h = b.zwxy; + float4 i = c.wxyz; + + float4 i4 = mul( float4x3(I4, C1, A0, G5), XBR_Y_WEIGHT*yuv[0] ); + float4 i5 = mul( float4x3(I5, C4, A1, G0), XBR_Y_WEIGHT*yuv[0] ); + float4 h5 = mul( float4x3(H5, F4, B1, D0), XBR_Y_WEIGHT*yuv[0] ); + float4 f4 = h5.yzwx; + + float4 c1 = i4.yzwx; + float4 g0 = i5.wxyz; + float4 b1 = h5.zwxy; + float4 d0 = h5.wxyz; + + float4 Ao = float4( 1.0, -1.0, -1.0, 1.0 ); + float4 Bo = float4( 1.0, 1.0, -1.0,-1.0 ); + float4 Co = float4( 1.5, 0.5, -0.5, 0.5 ); + float4 Ax = float4( 1.0, -1.0, -1.0, 1.0 ); + float4 Bx = float4( 0.5, 2.0, -0.5,-2.0 ); + float4 Cx = float4( 1.0, 1.0, -0.5, 0.0 ); + float4 Ay = float4( 1.0, -1.0, -1.0, 1.0 ); + float4 By = float4( 2.0, 0.5, -2.0,-0.5 ); + float4 Cy = float4( 2.0, 0.0, -1.0, 0.5 ); + + float4 Az = float4( 6.0, -2.0, -6.0, 2.0 ); + float4 Bz = float4( 2.0, 6.0, -2.0, -6.0 ); + float4 Cz = float4( 5.0, 3.0, -3.0, -1.0 ); + float4 Aw = float4( 2.0, -6.0, -2.0, 6.0 ); + float4 Bw = float4( 6.0, 2.0, -6.0,-2.0 ); + float4 Cw = float4( 5.0, -1.0, -3.0, 3.0 ); + + // These inequations define the line below which interpolation occurs. + fx = (Ao*fp.y+Bo*fp.x); + fx_left = (Ax*fp.y+Bx*fp.x); + fx_up = (Ay*fp.y+By*fp.x); + fx3_left= (Az*fp.y+Bz*fp.x); + fx3_up = (Aw*fp.y+Bw*fp.x); + +// It uses CORNER_C if none of the others are defined. +#ifdef CORNER_A + interp_restriction_lv1 = ((e!=f) && (e!=h)); +#elif CORNER_B + interp_restriction_lv1 = ((e!=f) && (e!=h) && ( !eq(f,b) && !eq(h,d) || eq(e,i) && !eq(f,i4) && !eq(h,i5) || eq(e,g) || eq(e,c) ) ); +#elif CORNER_D + interp_restriction_lv1 = ((e!=f) && (e!=h) && ( !eq(f,b) && !eq(h,d) || eq(e,i) && !eq(f,i4) && !eq(h,i5) || eq(e,g) || eq(e,c) ) && (f!=f4 && f!=i || h!=h5 && h!=i || h!=g || f!=c || eq(b,c1) && eq(d,g0))); +#else + interp_restriction_lv1 = ((e!=f) && (e!=h) && ( !eq(f,b) && !eq(f,c) || !eq(h,d) && !eq(h,g) || eq(e,i) && (!eq(f,f4) && !eq(f,i4) || !eq(h,h5) && !eq(h,i5)) || eq(e,g) || eq(e,c)) ); +#endif +interp_restriction_lv2_left = ((e!=g) && (d!=g)); +interp_restriction_lv2_up = ((e!=c) && (b!=c)); +interp_restriction_lv3_left = (eq2(g,g0) && !eq2(d0,g0)); +interp_restriction_lv3_up = (eq2(c,c1) && !eq2(b1,c1)); + + float4 fx45 = smoothstep(Co - delta, Co + delta, fx); + float4 fx30 = smoothstep(Cx - delta, Cx + delta, fx_left); + float4 fx60 = smoothstep(Cy - delta, Cy + delta, fx_up); + float4 fx15 = smoothstep(Cz - delta, Cz + delta, fx3_left); + float4 fx75 = smoothstep(Cw - delta, Cw + delta, fx3_up); + + + edr = (weighted_distance( e, c, g, i, h5, f4, h, f) < weighted_distance( h, d, i5, f, i4, b, e, i)) && interp_restriction_lv1; + edr_left = ((XBR_LV2_COEFFICIENT*df(f,g)) <= df(h,c)) && interp_restriction_lv2_left; + edr_up = (df(f,g) >= (XBR_LV2_COEFFICIENT*df(h,c))) && interp_restriction_lv2_up; + edr3_left = interp_restriction_lv3_left; + edr3_up = interp_restriction_lv3_up; + + + nc45 = ( edr && bool4(fx45)); + nc30 = ( edr && edr_left && bool4(fx30)); + nc60 = ( edr && edr_up && bool4(fx60)); + nc15 = ( edr && edr_left && edr3_left && bool4(fx15)); + nc75 = ( edr && edr_up && edr3_up && bool4(fx75)); + + px = (df(e,f) <= df(e,h)); + + nc = ( nc75 || nc15 || nc30 || nc60 || nc45); + + float4 final45 = nc45*fx45; + float4 final30 = nc30*fx30; + float4 final60 = nc60*fx60; + float4 final15 = nc15*fx15; + float4 final75 = nc75*fx75; + + float4 maximo = max(max(max(final15, final75),max(final30, final60)), final45); + + if (nc.x) {pix1 = px.x ? F : H; blend1 = maximo.x;} + else if (nc.y) {pix1 = px.y ? B : F; blend1 = maximo.y;} + else if (nc.z) {pix1 = px.z ? D : B; blend1 = maximo.z;} + else if (nc.w) {pix1 = px.w ? H : D; blend1 = maximo.w;} + + if (nc.w) {pix2 = px.w ? H : D; blend2 = maximo.w;} + else if (nc.z) {pix2 = px.z ? D : B; blend2 = maximo.z;} + else if (nc.y) {pix2 = px.y ? B : F; blend2 = maximo.y;} + else if (nc.x) {pix2 = px.x ? F : H; blend2 = maximo.x;} + + res1 = lerp(E, pix1, blend1); + res2 = lerp(E, pix2, blend2); + + float3 res = lerp(res1, res2, step(c_df(E, res1), c_df(E, res2))); + + return float4(res, 1.0); +} + +COMPAT_END \ No newline at end of file diff --git a/system/shaders/presets/HLSL/xbr/xbr-lv2-fast.cgp b/system/shaders/presets/HLSL/xbr/xbr-lv2-fast.cgp new file mode 100644 index 0000000000000..fc2a386bbc8ec --- /dev/null +++ b/system/shaders/presets/HLSL/xbr/xbr-lv2-fast.cgp @@ -0,0 +1,5 @@ +shaders = 1 + +shader0 = shaders/xbr-lv2-fast.cg +filter_linear0 = false +scale_type_0 = source diff --git a/system/shaders/presets/HLSL/xbr/xbr-lv3-noblend.cgp b/system/shaders/presets/HLSL/xbr/xbr-lv3-noblend.cgp new file mode 100644 index 0000000000000..6c523fcfdb4e6 --- /dev/null +++ b/system/shaders/presets/HLSL/xbr/xbr-lv3-noblend.cgp @@ -0,0 +1,5 @@ +shaders = 1 + +shader0 = shaders/xbr-lv3-noblend.cg +filter_linear0 = false +scale_type_0 = source diff --git a/system/shaders/presets/HLSL/xbr/xbr-lv3.cgp b/system/shaders/presets/HLSL/xbr/xbr-lv3.cgp new file mode 100644 index 0000000000000..61c1a67522e02 --- /dev/null +++ b/system/shaders/presets/HLSL/xbr/xbr-lv3.cgp @@ -0,0 +1,5 @@ +shaders = 1 + +shader0 = shaders/xbr-lv3.cg +filter_linear0 = false +scale_type_0 = source diff --git a/system/shaders/presets/shader-manifest.xml b/system/shaders/presets/shader-manifest.xml new file mode 100644 index 0000000000000..516527a083fca --- /dev/null +++ b/system/shaders/presets/shader-manifest.xml @@ -0,0 +1,156 @@ + + + + HLSL/ntsc/ntsc.cgp + + 35413 + + 35411 + + 35412 + + + HLSL/cgp/tvout/tvout+ntsc-256px-composite.cgp + + 35413 + + 35414 + + 35416 + + + HLSL/cgp/tvout/tvout+ntsc-320px-svideo.cgp + + 35413 + + 35435 + + 35415 + + + HLSL/crt/4xbr-hybrid-crt-b.cgp + + 35404 + + 35403 + + 35405 + + + HLSL/crt/crt-geom.cgp + + 35404 + + 35410 + + 35436 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + HLSL/handheld/lcd-grid-v2-gba-color.cgp + + 35432 + + 35426 + + 35431 + + + HLSL/handheld/lcd-grid-v2-nds-color.cgp + + 35432 + + 35427 + + 35430 + + + HLSL/handheld/lcd-grid-v2-psp-color.cgp + + 35432 + + 35428 + + 35429 + + + HLSL/eagle/super-eagle.cgp + + 35418 + + 35424 + + 35425 + + + HLSL/xbr/xbr-lv2-fast.cgp + + 35418 + + 35419 + + 35420 + + + HLSL/xbr/xbr-lv3.cgp + + 35418 + + 35437 + + 35439 + + + HLSL/xbr/xbr-lv3-noblend.cgp + + 35418 + + 35438 + + 35440 + + + + + + + + + + + From 69e70214e495113adfe6b16d07df6cb03186a7f6 Mon Sep 17 00:00:00 2001 From: VelocityRa Date: Sat, 19 Aug 2017 00:44:01 +0300 Subject: [PATCH 3/4] RetroPlayer: Video Shaders --- .gitignore | 1 + .../addon.xml.in | 7 + cmake/treedata/common/retroplayer.txt | 2 +- cmake/treedata/windows/subdirs.txt | 2 +- project/Win32BuildSetup/genNsisIncludes.bat | 10 + system/addon-manifest.xml | 2 + xbmc/ServiceManager.cpp | 4 +- xbmc/addons/AddonBuilder.cpp | 5 +- xbmc/addons/AddonInfo.cpp | 1 + xbmc/addons/AddonInfo.h | 1 + xbmc/addons/BinaryAddonCache.cpp | 6 +- xbmc/addons/CMakeLists.txt | 2 + xbmc/addons/ShaderPreset.cpp | 290 ++++++++++ xbmc/addons/ShaderPreset.h | 113 ++++ .../kodi/addon-instance/CMakeLists.txt | 1 + .../kodi/addon-instance/ShaderPreset.h | 457 ++++++++++++++++ .../include/kodi/versions.h | 16 + .../RetroPlayer/guibridge/IRenderCallback.h | 2 + .../RetroPlayer/rendering/RPRenderManager.cpp | 10 +- .../rendering/RenderVideoSettings.cpp | 33 +- .../rendering/RenderVideoSettings.h | 7 + .../VideoRenderers/RPBaseRenderer.cpp | 49 +- .../rendering/VideoRenderers/RPBaseRenderer.h | 13 + .../VideoRenderers/RPRendererGuiTexture.cpp | 4 + .../VideoRenderers/RPWinRenderer.cpp | 74 ++- .../rendering/VideoRenderers/RPWinRenderer.h | 13 +- .../rendering/VideoShaders/CMakeLists.txt | 3 - .../VideoShaders/windows/CMakeLists.txt | 5 - xbmc/cores/RetroPlayer/shaders/CMakeLists.txt | 16 + xbmc/cores/RetroPlayer/shaders/IShader.h | 98 ++++ xbmc/cores/RetroPlayer/shaders/IShaderLut.h | 80 +++ .../cores/RetroPlayer/shaders/IShaderPreset.h | 79 +++ .../RetroPlayer/shaders/IShaderSampler.h | 21 + .../RetroPlayer/shaders/IShaderTexture.cpp | 14 + .../RetroPlayer/shaders/IShaderTexture.h | 33 ++ .../shaders/ShaderPresetFactory.cpp | 152 ++++++ .../RetroPlayer/shaders/ShaderPresetFactory.h | 66 +++ xbmc/cores/RetroPlayer/shaders/ShaderTypes.h | 135 +++++ .../cores/RetroPlayer/shaders/ShaderUtils.cpp | 27 + xbmc/cores/RetroPlayer/shaders/ShaderUtils.h | 36 ++ .../shaders/windows/CMakeLists.txt | 17 + .../windows/RPWinOutputShader.cpp | 12 +- .../windows/RPWinOutputShader.h | 17 +- .../RetroPlayer/shaders/windows/ShaderDX.cpp | 256 +++++++++ .../RetroPlayer/shaders/windows/ShaderDX.h | 110 ++++ .../shaders/windows/ShaderLutDX.cpp | 103 ++++ .../RetroPlayer/shaders/windows/ShaderLutDX.h | 55 ++ .../shaders/windows/ShaderPresetDX.cpp | 508 ++++++++++++++++++ .../shaders/windows/ShaderPresetDX.h | 128 +++++ .../shaders/windows/ShaderSamplerDX.cpp | 23 + .../shaders/windows/ShaderSamplerDX.h | 32 ++ .../shaders/windows/ShaderTextureDX.h | 52 ++ .../shaders/windows/ShaderTypesDX.h | 35 ++ .../shaders/windows/ShaderUtilsDX.cpp | 33 ++ .../shaders/windows/ShaderUtilsDX.h | 32 ++ xbmc/filesystem/AddonsDirectory.cpp | 13 +- xbmc/games/GameServices.cpp | 8 +- xbmc/games/GameServices.h | 18 +- xbmc/games/dialogs/CMakeLists.txt | 3 +- xbmc/games/dialogs/DialogGameDefines.h | 23 + .../dialogs/osd/DialogGameVideoFilter.cpp | 93 +++- .../games/dialogs/osd/DialogGameVideoFilter.h | 11 + xbmc/guilib/D3DResource.cpp | 48 +- xbmc/guilib/D3DResource.h | 4 + 64 files changed, 3460 insertions(+), 64 deletions(-) create mode 100644 addons/kodi.binary.instance.shaderpreset/addon.xml.in create mode 100644 xbmc/addons/ShaderPreset.cpp create mode 100644 xbmc/addons/ShaderPreset.h create mode 100644 xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/ShaderPreset.h delete mode 100644 xbmc/cores/RetroPlayer/rendering/VideoShaders/CMakeLists.txt delete mode 100644 xbmc/cores/RetroPlayer/rendering/VideoShaders/windows/CMakeLists.txt create mode 100644 xbmc/cores/RetroPlayer/shaders/CMakeLists.txt create mode 100644 xbmc/cores/RetroPlayer/shaders/IShader.h create mode 100644 xbmc/cores/RetroPlayer/shaders/IShaderLut.h create mode 100644 xbmc/cores/RetroPlayer/shaders/IShaderPreset.h create mode 100644 xbmc/cores/RetroPlayer/shaders/IShaderSampler.h create mode 100644 xbmc/cores/RetroPlayer/shaders/IShaderTexture.cpp create mode 100644 xbmc/cores/RetroPlayer/shaders/IShaderTexture.h create mode 100644 xbmc/cores/RetroPlayer/shaders/ShaderPresetFactory.cpp create mode 100644 xbmc/cores/RetroPlayer/shaders/ShaderPresetFactory.h create mode 100644 xbmc/cores/RetroPlayer/shaders/ShaderTypes.h create mode 100644 xbmc/cores/RetroPlayer/shaders/ShaderUtils.cpp create mode 100644 xbmc/cores/RetroPlayer/shaders/ShaderUtils.h create mode 100644 xbmc/cores/RetroPlayer/shaders/windows/CMakeLists.txt rename xbmc/cores/RetroPlayer/{rendering/VideoShaders => shaders}/windows/RPWinOutputShader.cpp (93%) rename xbmc/cores/RetroPlayer/{rendering/VideoShaders => shaders}/windows/RPWinOutputShader.h (81%) create mode 100644 xbmc/cores/RetroPlayer/shaders/windows/ShaderDX.cpp create mode 100644 xbmc/cores/RetroPlayer/shaders/windows/ShaderDX.h create mode 100644 xbmc/cores/RetroPlayer/shaders/windows/ShaderLutDX.cpp create mode 100644 xbmc/cores/RetroPlayer/shaders/windows/ShaderLutDX.h create mode 100644 xbmc/cores/RetroPlayer/shaders/windows/ShaderPresetDX.cpp create mode 100644 xbmc/cores/RetroPlayer/shaders/windows/ShaderPresetDX.h create mode 100644 xbmc/cores/RetroPlayer/shaders/windows/ShaderSamplerDX.cpp create mode 100644 xbmc/cores/RetroPlayer/shaders/windows/ShaderSamplerDX.h create mode 100644 xbmc/cores/RetroPlayer/shaders/windows/ShaderTextureDX.h create mode 100644 xbmc/cores/RetroPlayer/shaders/windows/ShaderTypesDX.h create mode 100644 xbmc/cores/RetroPlayer/shaders/windows/ShaderUtilsDX.cpp create mode 100644 xbmc/cores/RetroPlayer/shaders/windows/ShaderUtilsDX.h create mode 100644 xbmc/games/dialogs/DialogGameDefines.h diff --git a/.gitignore b/.gitignore index bd7eb50bc4fb0..06e61f17a57b0 100644 --- a/.gitignore +++ b/.gitignore @@ -125,6 +125,7 @@ cmake_install.cmake /addons/kodi.binary.instance.inputstream/addon.xml /addons/kodi.binary.instance.peripheral/addon.xml /addons/kodi.binary.instance.pvr/addon.xml +/addons/kodi.binary.instance.shaderpreset/addon.xml /addons/kodi.binary.instance.screensaver/addon.xml /addons/kodi.binary.instance.vfs/addon.xml /addons/kodi.binary.instance.videocodec/addon.xml diff --git a/addons/kodi.binary.instance.shaderpreset/addon.xml.in b/addons/kodi.binary.instance.shaderpreset/addon.xml.in new file mode 100644 index 0000000000000..0f59816e75f90 --- /dev/null +++ b/addons/kodi.binary.instance.shaderpreset/addon.xml.in @@ -0,0 +1,7 @@ + + + + + + + diff --git a/cmake/treedata/common/retroplayer.txt b/cmake/treedata/common/retroplayer.txt index 97fc849a0222a..5acff051802b2 100644 --- a/cmake/treedata/common/retroplayer.txt +++ b/cmake/treedata/common/retroplayer.txt @@ -10,7 +10,7 @@ xbmc/cores/RetroPlayer/playback cores/RetroPlaye xbmc/cores/RetroPlayer/process cores/RetroPlayer/process xbmc/cores/RetroPlayer/rendering cores/RetroPlayer/rendering xbmc/cores/RetroPlayer/rendering/VideoRenderers cores/RetroPlayer/rendering/VideoRenderers -xbmc/cores/RetroPlayer/rendering/VideoShaders cores/RetroPlayer/rendering/VideoShaders xbmc/cores/RetroPlayer/savestates cores/RetroPlayer/savestates +xbmc/cores/RetroPlayer/shaders cores/RetroPlayer/shaders xbmc/cores/RetroPlayer/streams cores/RetroPlayer/streams xbmc/cores/RetroPlayer/streams/memory cores/RetroPlayer/streams/memory diff --git a/cmake/treedata/windows/subdirs.txt b/cmake/treedata/windows/subdirs.txt index a2c8c29f14784..dc10f4c0f7330 100644 --- a/cmake/treedata/windows/subdirs.txt +++ b/cmake/treedata/windows/subdirs.txt @@ -13,5 +13,5 @@ xbmc/rendering/dx rendering/dx xbmc/threads/platform/win threads/win xbmc/windowing/windows windowing/windows xbmc/cores/RetroPlayer/process/windows cores/RetroPlayer/process/windows -xbmc/cores/RetroPlayer/rendering/VideoShaders/windows cores/RetroPlayer/rendering/VideoShaders/windows +xbmc/cores/RetroPlayer/shaders/windows cores/RetroPlayer/shaders/windows xbmc/cores/VideoPlayer/Process/windows cores/VideoPlayer/Process/windows diff --git a/project/Win32BuildSetup/genNsisIncludes.bat b/project/Win32BuildSetup/genNsisIncludes.bat index 498d2a686462f..8ccae63204165 100644 --- a/project/Win32BuildSetup/genNsisIncludes.bat +++ b/project/Win32BuildSetup/genNsisIncludes.bat @@ -40,6 +40,16 @@ IF EXIST BUILD_WIN32\addons\game.libretro.* ( SET /A Counter = !Counter! + 1 ) ) + FOR /F "tokens=*" %%P IN ('dir /B /AD BUILD_WIN32\addons\game.shader.*') DO ( + FOR /f "delims=<" %%N in ('powershell.exe -ExecutionPolicy Unrestricted -command "& {[xml]$a = get-content BUILD_WIN32\addons\%%P\addon.xml;$a.addon.name}"') do ( + ECHO Section "%%N" SecGameAddons!Counter! >> game-addons.nsi + ECHO SectionIn 1 2 >> game-addons.nsi + ECHO SetOutPath "$INSTDIR\addons\%%P" >> game-addons.nsi + ECHO File /r "${app_root}\addons\%%P\*.*" >> game-addons.nsi + ECHO SectionEnd >> game-addons.nsi + SET /A Counter = !Counter! + 1 + ) + ) ECHO SectionGroupEnd >> game-addons.nsi ) diff --git a/system/addon-manifest.xml b/system/addon-manifest.xml index bad919353aa98..c9a714e81a6ce 100644 --- a/system/addon-manifest.xml +++ b/system/addon-manifest.xml @@ -3,6 +3,7 @@ audioencoder.kodi.builtin.wma game.controller.default game.controller.snes + game.shader.presets kodi.binary.global.audioengine kodi.binary.global.main kodi.binary.global.general @@ -17,6 +18,7 @@ kodi.binary.instance.peripheral kodi.binary.instance.pvr kodi.binary.instance.screensaver + kodi.binary.instance.shaderpreset kodi.binary.instance.vfs kodi.binary.instance.videocodec kodi.binary.instance.visualization diff --git a/xbmc/ServiceManager.cpp b/xbmc/ServiceManager.cpp index 3dbf13983a930..45c655d4c2040 100644 --- a/xbmc/ServiceManager.cpp +++ b/xbmc/ServiceManager.cpp @@ -171,7 +171,9 @@ bool CServiceManager::InitStageThree(const std::shared_ptr& pro m_gameServices.reset(new GAME::CGameServices(*m_gameControllerManager, *m_gameRenderManager, *m_peripherals, - *profileManager)); + *profileManager, + *m_addonMgr, + *m_binaryAddonManager)); m_contextMenuManager->Init(); m_PVRManager->Init(); diff --git a/xbmc/addons/AddonBuilder.cpp b/xbmc/addons/AddonBuilder.cpp index 5831abca12efb..d5298d5f35a75 100644 --- a/xbmc/addons/AddonBuilder.cpp +++ b/xbmc/addons/AddonBuilder.cpp @@ -75,7 +75,8 @@ std::shared_ptr CAddonBuilder::Build() type == ADDON_IMAGEDECODER || type == ADDON_INPUTSTREAM || type == ADDON_PERIPHERALDLL || - type == ADDON_GAMEDLL) + type == ADDON_GAMEDLL || + type == ADDON_SHADERDLL) { std::string value = CServiceBroker::GetAddonMgr().GetPlatformLibraryName(m_extPoint->plugin->extensions->configuration); if (value.empty()) @@ -112,6 +113,7 @@ std::shared_ptr CAddonBuilder::Build() case ADDON_VFS: case ADDON_VIZ: case ADDON_SCREENSAVER: + case ADDON_SHADERDLL: return std::make_shared(std::move(m_addonInfo)); case ADDON_PVRDLL: return std::make_shared(std::move(m_addonInfo)); @@ -176,6 +178,7 @@ AddonPtr CAddonBuilder::FromProps(CAddonInfo addonInfo) case ADDON_IMAGEDECODER: case ADDON_INPUTSTREAM: case ADDON_PERIPHERALDLL: + case ADDON_SHADERDLL: case ADDON_VFS: case ADDON_VIZ: case ADDON_SCREENSAVER: diff --git a/xbmc/addons/AddonInfo.cpp b/xbmc/addons/AddonInfo.cpp index c4bdf7b8208b4..eaf835b08f845 100644 --- a/xbmc/addons/AddonInfo.cpp +++ b/xbmc/addons/AddonInfo.cpp @@ -46,6 +46,7 @@ static const TypeMapping types[] = {"xbmc.pvrclient", ADDON_PVRDLL, 24019, "DefaultAddonPVRClient.png" }, {"kodi.gameclient", ADDON_GAMEDLL, 35049, "DefaultAddonGame.png" }, {"kodi.peripheral", ADDON_PERIPHERALDLL, 35010, "DefaultAddonPeripheral.png" }, + {"kodi.shader.presets", ADDON_SHADERDLL, 35256, "DefaultGameAddon.png" }, {"xbmc.addon.video", ADDON_VIDEO, 1037, "DefaultAddonVideo.png" }, {"xbmc.addon.audio", ADDON_AUDIO, 1038, "DefaultAddonMusic.png" }, {"xbmc.addon.image", ADDON_IMAGE, 1039, "DefaultAddonPicture.png" }, diff --git a/xbmc/addons/AddonInfo.h b/xbmc/addons/AddonInfo.h index a476e422e9b56..58aad58464095 100644 --- a/xbmc/addons/AddonInfo.h +++ b/xbmc/addons/AddonInfo.h @@ -27,6 +27,7 @@ namespace ADDON ADDON_PVRDLL, ADDON_INPUTSTREAM, ADDON_GAMEDLL, + ADDON_SHADERDLL, ADDON_PERIPHERALDLL, ADDON_SCRIPT, ADDON_SCRIPT_WEATHER, diff --git a/xbmc/addons/BinaryAddonCache.cpp b/xbmc/addons/BinaryAddonCache.cpp index 9867f38464727..b0bad3b4885a5 100644 --- a/xbmc/addons/BinaryAddonCache.cpp +++ b/xbmc/addons/BinaryAddonCache.cpp @@ -14,7 +14,11 @@ namespace ADDON { -const std::vector ADDONS_TO_CACHE = { ADDON_PVRDLL, ADDON_GAMEDLL }; +const std::vector ADDONS_TO_CACHE = { + ADDON_PVRDLL, + ADDON_GAMEDLL, + ADDON_SHADERDLL, +}; CBinaryAddonCache::~CBinaryAddonCache() { diff --git a/xbmc/addons/CMakeLists.txt b/xbmc/addons/CMakeLists.txt index 3bed5a412d673..796b90f7c3673 100644 --- a/xbmc/addons/CMakeLists.txt +++ b/xbmc/addons/CMakeLists.txt @@ -29,6 +29,7 @@ set(SOURCES Addon.cpp Scraper.cpp ScreenSaver.cpp Service.cpp + ShaderPreset.cpp Skin.cpp UISoundsResource.cpp VFSEntry.cpp @@ -70,6 +71,7 @@ set(HEADERS Addon.h Scraper.h ScreenSaver.h Service.h + ShaderPreset.h Skin.h UISoundsResource.h VFSEntry.h diff --git a/xbmc/addons/ShaderPreset.cpp b/xbmc/addons/ShaderPreset.cpp new file mode 100644 index 0000000000000..7ecfbc8c6e738 --- /dev/null +++ b/xbmc/addons/ShaderPreset.cpp @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2017 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this Program; see the file COPYING. If not, see + * . + * + */ + +#include "ShaderPreset.h" +#include "addons/binary-addons/BinaryAddonBase.h" +#include "addons/AddonManager.h" +#include "filesystem/SpecialProtocol.h" +#include "utils/log.h" +#include "utils/URIUtils.h" + +using namespace KODI; +using namespace ADDON; + +// --- CShaderPreset ----------------------------------------------------------- + +CShaderPreset::CShaderPreset(preset_file file, AddonInstance_ShaderPreset &instanceStruct) : + m_file(file), + m_struct(instanceStruct) +{ +} + +CShaderPreset::~CShaderPreset() +{ + m_struct.toAddon.preset_file_free(&m_struct, m_file); +} + +bool CShaderPreset::ReadShaderPreset(video_shader &shader) +{ + return m_struct.toAddon.video_shader_read(&m_struct, m_file, &shader); +} + +void CShaderPreset::WriteShaderPreset(const video_shader &shader) +{ + return m_struct.toAddon.video_shader_write(&m_struct, m_file, &shader); +} + +/* +void CShaderPresetAddon::ShaderPresetResolveRelative(video_shader &shader, const std::string &ref_path) +{ + return m_struct.toAddon.video_shader_resolve_relative(&m_struct, &shader, ref_path.c_str()); +} + +bool CShaderPresetAddon::ShaderPresetResolveCurrentParameters(video_shader &shader) +{ + return m_struct.toAddon.video_shader_resolve_current_parameters(&m_struct, m_file, &shader); +} +*/ + +bool CShaderPreset::ResolveParameters(video_shader &shader) +{ + return m_struct.toAddon.video_shader_resolve_parameters(&m_struct, m_file, &shader); +} + +void CShaderPreset::FreeShaderPreset(video_shader &shader) +{ + m_struct.toAddon.video_shader_free(&m_struct, &shader); +} + +// --- CShaderPresetAddon ------------------------------------------------------ + +CShaderPresetAddon::CShaderPresetAddon(const BinaryAddonBasePtr& addonBase) + : IAddonInstanceHandler(ADDON_INSTANCE_SHADERPRESET, addonBase) +{ + ResetProperties(); + m_extensions = StringUtils::Split(addonBase->Type(ADDON_SHADERDLL)->GetValue("@extensions").asString(), "|"); +} + +CShaderPresetAddon::~CShaderPresetAddon(void) +{ + DestroyAddon(); +} + +bool CShaderPresetAddon::CreateAddon(void) +{ + CExclusiveLock lock(m_dllSection); + + // Reset all properties to defaults + ResetProperties(); + + // Initialise the add-on + CLog::Log(LOGDEBUG, "%s - creating ShaderPreset add-on instance '%s'", __FUNCTION__, Name().c_str()); + + if (CreateInstance(&m_struct) != ADDON_STATUS_OK) + return false; + + return true; +} + +void CShaderPresetAddon::DestroyAddon() +{ + CExclusiveLock lock(m_dllSection); + DestroyInstance(); +} + +void CShaderPresetAddon::ResetProperties(void) +{ + // Initialise members + m_struct = {{ 0 }}; + m_struct.toKodi.kodiInstance = this; +} + +bool CShaderPresetAddon::LoadPreset(const std::string &presetPath, SHADER::IShaderPreset& shaderPreset) +{ + bool bSuccess = false; + + std::string translatedPath = CSpecialProtocol::TranslatePath(presetPath); + + preset_file file = m_struct.toAddon.preset_file_new(&m_struct, translatedPath.c_str()); + + if (file != nullptr) + { + std::unique_ptr shaderPresetAddon(new CShaderPreset(file, m_struct)); + + video_shader videoShader = { }; + if (shaderPresetAddon->ReadShaderPreset(videoShader)) + { + if (shaderPresetAddon->ResolveParameters(videoShader)) + { + TranslateShaderPreset(videoShader, shaderPreset); + bSuccess = true; + } + shaderPresetAddon->FreeShaderPreset(videoShader); + } + } + + return bSuccess; +} + +// todo: instead of copying every parameter to every pass and resolving them later in +// GetShaderParameters, we should resolve which param goes to which shader in the add-on +void CShaderPresetAddon::TranslateShaderPreset(const video_shader &shader, SHADER::IShaderPreset &shaderPreset) +{ + if (shader.passes != nullptr) + { + for (unsigned int passIdx = 0; passIdx < shader.pass_count; passIdx++) + { + SHADER::ShaderPass shaderPass; + TranslateShaderPass(shader.passes[passIdx], shaderPass); + + if (shader.luts != nullptr) + { + for (unsigned int lutIdx = 0; lutIdx < shader.lut_count; lutIdx++) + { + SHADER::ShaderLut shaderLut; + TranslateShaderLut(shader.luts[lutIdx], shaderLut); + shaderPass.luts.emplace_back(std::move(shaderLut)); + } + } + + if (shader.parameters != nullptr) + { + for (unsigned int parIdx = 0; parIdx < shader.parameter_count; parIdx++) + { + SHADER::ShaderParameter shaderParam; + TranslateShaderParameter(shader.parameters[parIdx], shaderParam); + shaderPass.parameters.emplace_back(std::move(shaderParam)); + } + } + + shaderPreset.GetPasses().emplace_back(std::move(shaderPass)); + } + } +} + +void CShaderPresetAddon::TranslateShaderPass(const video_shader_pass &pass, SHADER::ShaderPass &shaderPass) +{ + shaderPass.sourcePath = pass.source_path ? pass.source_path : ""; + shaderPass.vertexSource = pass.vertex_source ? pass.vertex_source : ""; + shaderPass.fragmentSource = pass.fragment_source ? pass.fragment_source : ""; + shaderPass.filter = TranslateFilterType(pass.filter); + shaderPass.wrap = TranslateWrapType(pass.wrap); + shaderPass.frameCountMod = pass.frame_count_mod; + + const auto &fbo = pass.fbo; + auto &shaderFbo = shaderPass.fbo; + + shaderFbo.scaleX.type = TranslateScaleType(fbo.scale_x.type); + switch (fbo.scale_x.type) + { + case SHADER_SCALE_TYPE_ABSOLUTE: + shaderFbo.scaleX.abs = fbo.scale_x.abs; + break; + default: + shaderFbo.scaleX.scale = fbo.scale_x.scale; + break; + } + shaderFbo.scaleY.type = TranslateScaleType(fbo.scale_y.type); + switch (fbo.scale_y.type) + { + case SHADER_SCALE_TYPE_ABSOLUTE: + shaderFbo.scaleY.abs = fbo.scale_y.abs; + break; + default: + shaderFbo.scaleY.scale = fbo.scale_y.scale; + break; + } + + shaderFbo.floatFramebuffer = fbo.fp_fbo; + shaderFbo.sRgbFramebuffer = fbo.srgb_fbo; + + shaderPass.mipmap = pass.mipmap; +} + +void CShaderPresetAddon::TranslateShaderLut(const video_shader_lut &lut, SHADER::ShaderLut &shaderLut) +{ + shaderLut.strId = lut.id ? lut.id : ""; + shaderLut.path = lut.path ? lut.path : ""; + shaderLut.filter = TranslateFilterType(lut.filter); + shaderLut.wrap = TranslateWrapType(lut.wrap); + shaderLut.mipmap = lut.mipmap; +} + +void CShaderPresetAddon::TranslateShaderParameter(const video_shader_parameter ¶m, SHADER::ShaderParameter &shaderParam) +{ + shaderParam.strId = param.id ? param.id : ""; + shaderParam.description = param.desc ? param.desc : ""; + shaderParam.current = param.current; + shaderParam.minimum = param.minimum; + shaderParam.initial = param.initial; + shaderParam.maximum = param.maximum; + shaderParam.step = param.step; +} + +SHADER::FILTER_TYPE CShaderPresetAddon::TranslateFilterType(SHADER_FILTER_TYPE type) +{ + switch (type) + { + case SHADER_FILTER_TYPE_LINEAR: + return SHADER::FILTER_TYPE_LINEAR; + case SHADER_FILTER_TYPE_NEAREST: + return SHADER::FILTER_TYPE_NEAREST; + default: + break; + } + + return SHADER::FILTER_TYPE_NONE; +} + +SHADER::WRAP_TYPE CShaderPresetAddon::TranslateWrapType(SHADER_WRAP_TYPE type) +{ + switch (type) + { + case SHADER_WRAP_TYPE_BORDER: + return SHADER::WRAP_TYPE_BORDER; + case SHADER_WRAP_TYPE_EDGE: + return SHADER::WRAP_TYPE_EDGE; + case SHADER_WRAP_TYPE_REPEAT: + return SHADER::WRAP_TYPE_REPEAT; + case SHADER_WRAP_TYPE_MIRRORED_REPEAT: + return SHADER::WRAP_TYPE_MIRRORED_REPEAT; + default: + break; + } + + return SHADER::WRAP_TYPE_BORDER; +} + +SHADER::SCALE_TYPE CShaderPresetAddon::TranslateScaleType(SHADER_SCALE_TYPE type) +{ + switch (type) + { + case SHADER_SCALE_TYPE_INPUT: + return SHADER::SCALE_TYPE_INPUT; + case SHADER_SCALE_TYPE_ABSOLUTE: + return SHADER::SCALE_TYPE_ABSOLUTE; + case SHADER_SCALE_TYPE_VIEWPORT: + return SHADER::SCALE_TYPE_VIEWPORT; + default: + break; + } + + return SHADER::SCALE_TYPE_INPUT; +} diff --git a/xbmc/addons/ShaderPreset.h b/xbmc/addons/ShaderPreset.h new file mode 100644 index 0000000000000..b97264992620d --- /dev/null +++ b/xbmc/addons/ShaderPreset.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2017 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this Program; see the file COPYING. If not, see + * . + * + */ +#pragma once + +#include "addons/binary-addons/AddonInstanceHandler.h" +#include "addons/kodi-addon-dev-kit/include/kodi/addon-instance/ShaderPreset.h" +#include "cores/RetroPlayer/shaders/ShaderPresetFactory.h" +#include "threads/SharedSection.h" + +#include +#include + +namespace ADDON +{ + class CShaderPreset + { + public: + CShaderPreset(preset_file file, AddonInstance_ShaderPreset &instanceStruct); + ~CShaderPreset(); + + /*! + * \brief @todo document + */ + bool ReadShaderPreset(video_shader &shader); + + /*! + * \brief @todo document + */ + void WriteShaderPreset(const video_shader &shader); + + //void ResolveRelative(video_shader &shader, const std::string &ref_path); + + //bool ResolveCurrentParameters(video_shader &shader); + + /*! + * \brief @todo document + */ + bool ResolveParameters(video_shader &shader); + + void FreeShaderPreset(video_shader &shader); + + private: + preset_file m_file; + AddonInstance_ShaderPreset &m_struct; + }; + + /*! + * \brief Wrapper class that wraps the shader presets add-on + */ + class CShaderPresetAddon : public IAddonInstanceHandler, + public KODI::SHADER::IShaderPresetLoader + { + public: + CShaderPresetAddon(const BinaryAddonBasePtr& addonInfo); + ~CShaderPresetAddon(void) override; + + /*! + * \brief Initialise the instance of this add-on + */ + bool CreateAddon(void); + + /*! + * \brief Deinitialize the instance of this add-on + */ + void DestroyAddon(); + + /*! + * \brief Get the shader preset extensions supported by this add-on + */ + const std::vector &GetExtensions() const { return m_extensions; } + + // implementation of IShaderPresetLoader + bool LoadPreset(const std::string &presetPath, KODI::SHADER::IShaderPreset &shaderPreset) override; + + private: + /*! + * \brief Reset all class members to their defaults. Called by the constructors + */ + void ResetProperties(void); + + static void TranslateShaderPreset(const video_shader &shader, KODI::SHADER::IShaderPreset& shaderPreset); + static void TranslateShaderPass(const video_shader_pass &pass, KODI::SHADER::ShaderPass &shaderPass); + static void TranslateShaderLut(const video_shader_lut &lut, KODI::SHADER::ShaderLut &shaderLut); + static void TranslateShaderParameter(const video_shader_parameter ¶m, KODI::SHADER::ShaderParameter &shaderParam); + static KODI::SHADER::FILTER_TYPE TranslateFilterType(SHADER_FILTER_TYPE type); + static KODI::SHADER::WRAP_TYPE TranslateWrapType(SHADER_WRAP_TYPE type); + static KODI::SHADER::SCALE_TYPE TranslateScaleType(SHADER_SCALE_TYPE type); + + /* \brief Add-on properties */ + std::vector m_extensions; + + AddonInstance_ShaderPreset m_struct; + + CSharedSection m_dllSection; + }; +} diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/CMakeLists.txt b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/CMakeLists.txt index 44aaf054f0567..2199d8a6b6455 100644 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/CMakeLists.txt +++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/CMakeLists.txt @@ -5,6 +5,7 @@ set(HEADERS AudioDecoder.h Peripheral.h PeripheralUtils.h Screensaver.h + ShaderPreset.h VFS.h VideoCodec.h Visualization.h) diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/ShaderPreset.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/ShaderPreset.h new file mode 100644 index 0000000000000..afd24c93d409f --- /dev/null +++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/addon-instance/ShaderPreset.h @@ -0,0 +1,457 @@ +/* + * Copyright (C) 2017 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this Program; see the file COPYING. If not, see + * . + * + */ +#pragma once + +#include "../AddonBase.h" + +#include + +namespace kodi { namespace addon { class CInstanceShaderPreset; } } + +extern "C" +{ + typedef void *preset_file; + + /*! + * \brief Scale types + * + * If no scale type is specified, it is assumed that the scale type is + * relative to the input with a scaling factor of 1.0. + * + * Exceptions: If no scale type is set for the last pass, it is assumed to + * output at the full resolution rather than assuming of scale of 1.0, and + * bypasses any frame-buffer object rendering. + */ + typedef enum SHADER_SCALE_TYPE + { + /*! + * \brief Use the source size + * + * Output size of the shader pass is relative to the input size. Value is + * float. + */ + SHADER_SCALE_TYPE_INPUT, + + /*! + * \brief Use the window viewport size + * + * Output size of the shader pass is relative to the size of the window + * viewport. Value is float. This value can change over time if the user + * resizes his/her window! + */ + SHADER_SCALE_TYPE_ABSOLUTE, + + /*! + * \brief Use a statically defined size + * + * Output size is statically defined to a certain size. Useful for hi-res + * blenders or similar. + */ + SHADER_SCALE_TYPE_VIEWPORT + } SHADER_SCALE_TYPE; + + typedef enum SHADER_FILTER_TYPE + { + SHADER_FILTER_TYPE_UNSPEC, + SHADER_FILTER_TYPE_LINEAR, + SHADER_FILTER_TYPE_NEAREST + } SHADER_FILTER_TYPE; + + /*! + * \brief Texture wrapping mode + */ + typedef enum SHADER_WRAP_TYPE + { + SHADER_WRAP_TYPE_BORDER, /* Deprecated, will be translated to EDGE in GLES */ + SHADER_WRAP_TYPE_EDGE, + SHADER_WRAP_TYPE_REPEAT, + SHADER_WRAP_TYPE_MIRRORED_REPEAT + } SHADER_WRAP_TYPE; + + /*! + * \brief FBO scaling parameters for a single axis + */ + typedef struct fbo_scale_axis + { + SHADER_SCALE_TYPE type; + union + { + float scale; + unsigned abs; + }; + } fbo_scale_axis; + + /*! + * \brief FBO parameters + */ + typedef struct fbo_scale + { + /*! + * \brief sRGB framebuffer + */ + bool srgb_fbo; + + /*! + * \brief Float framebuffer + * + * This parameter defines if the pass should be rendered to a 32-bit + * floating point buffer. This only takes effect if the pass is actaully + * rendered to an FBO. This is useful for shaders which have to store FBO + * values outside the range [0, 1]. + */ + bool fp_fbo; + + /*! + * \brief Scaling parameters for X axis + */ + fbo_scale_axis scale_x; + + /*! + * \brief Scaling parameters for Y axis + */ + fbo_scale_axis scale_y; + } fbo_scale; + + typedef struct video_shader_parameter + { + char *id; + char *desc; + float current; + float minimum; + float initial; + float maximum; + float step; + } video_shader_parameter; + + typedef struct video_shader_pass + { + /*! + * \brief Path to the shader pass source + */ + char *source_path; + + /*! + * \brief The vertex shader source + */ + char *vertex_source; + + /*! + * \brief The fragment shader source, if separate from the vertex source, or + * NULL otherwise + */ + char *fragment_source; + + /*! + * \brief FBO parameters + */ + fbo_scale fbo; + + /*! + * \brief Defines how the result of this pass will be filtered + * + * @todo Define behavior for unspecified filter + */ + SHADER_FILTER_TYPE filter; + + /*! + * \brief Wrapping mode + */ + SHADER_WRAP_TYPE wrap; + + /*! + * \brief Frame count mod + */ + unsigned frame_count_mod; + + /*! + * \brief Mipmapping + */ + bool mipmap; + } video_shader_pass; + + typedef struct video_shader_lut + { + /*! + * \brief Name of the sampler uniform, e.g. `uniform sampler2D foo`. + */ + char *id; + + /*! + * \brief Path of the texture + */ + char *path; + + /*! + * \brief Filtering for the texture + */ + SHADER_FILTER_TYPE filter; + + /*! + * \brief Texture wrapping mode + */ + SHADER_WRAP_TYPE wrap; + + /*! + * \brief Use mipmapping for the texture + */ + bool mipmap; + } video_shader_lut; + + typedef struct video_shader + { + unsigned pass_count; + video_shader_pass *passes; + + unsigned lut_count; + video_shader_lut *luts; + + unsigned parameter_count; + video_shader_parameter *parameters; + } video_shader; + ///} + + typedef struct AddonProps_ShaderPreset + { + const char* user_path; /*!< @brief path to the user profile */ + const char* addon_path; /*!< @brief path to this add-on */ + } AddonProps_ShaderPreset; + + struct AddonInstance_ShaderPreset; + + typedef struct AddonToKodiFuncTable_ShaderPreset + { + KODI_HANDLE kodiInstance; + } AddonToKodiFuncTable_ShaderPreset; + + typedef struct KodiToAddonFuncTable_ShaderPreset + { + kodi::addon::CInstanceShaderPreset* addonInstance; + + preset_file (__cdecl* preset_file_new)(const AddonInstance_ShaderPreset* addonInstance, const char *path); + void (__cdecl* preset_file_free)(const AddonInstance_ShaderPreset* addonInstance, preset_file file); + + bool (__cdecl* video_shader_read)(const AddonInstance_ShaderPreset* addonInstance, preset_file file, video_shader *shader); + void (__cdecl* video_shader_write)(const AddonInstance_ShaderPreset* addonInstance, preset_file file, const video_shader *shader); + //void (__cdecl* video_shader_resolve_relative)(const AddonInstance_ShaderPreset* addonInstance, video_shader *shader, const char *ref_path); + //bool (__cdecl* video_shader_resolve_current_parameters)(const AddonInstance_ShaderPreset* addonInstance, video_shader *shader); + bool (__cdecl* video_shader_resolve_parameters)(const AddonInstance_ShaderPreset* addonInstance, preset_file file, video_shader *shader); + void (__cdecl* video_shader_free)(const AddonInstance_ShaderPreset* addonInstance, video_shader *shader); + } KodiToAddonFuncTable_ShaderPreset; + + typedef struct AddonInstance_ShaderPreset + { + AddonProps_ShaderPreset props; + AddonToKodiFuncTable_ShaderPreset toKodi; + KodiToAddonFuncTable_ShaderPreset toAddon; + } AddonInstance_ShaderPreset; + +} /* extern "C" */ + +namespace kodi +{ + namespace addon + { + + class CInstanceShaderPreset : public IAddonInstance + { + public: + CInstanceShaderPreset() + : IAddonInstance(ADDON_INSTANCE_SHADERPRESET) + { + if (CAddonBase::m_interface->globalSingleInstance != nullptr) + throw std::logic_error("kodi::addon::CInstanceShaderPreset: Creation of more as one in single instance way is not allowed!"); + + SetAddonStruct(CAddonBase::m_interface->firstKodiInstance); + CAddonBase::m_interface->globalSingleInstance = this; + } + + CInstanceShaderPreset(KODI_HANDLE instance) + : IAddonInstance(ADDON_INSTANCE_SHADERPRESET) + { + if (CAddonBase::m_interface->globalSingleInstance != nullptr) + throw std::logic_error("kodi::addon::CInstanceShaderPreset: Creation of multiple together with single instance way is not allowed!"); + + SetAddonStruct(instance); + } + + ~CInstanceShaderPreset() override { } + + /*! + * \brief Loads a preset file + * + * \param path The path to the preset file + * + * \return The preset file, or NULL if file doesn't exist + */ + virtual preset_file PresetFileNew(const char *path) { return nullptr; } + + /*! + * \brief Free a preset file + */ + virtual void PresetFileFree(preset_file file) { } + + /*! + * \brief Loads preset file and all associated state (passes, textures, + * imports, etc) + * + * \param file Preset file to read from + * \param shader Shader passes handle + * + * \return True if successful, otherwise false + **/ + virtual bool ShaderPresetRead(preset_file file, video_shader &shader) { return false; } + + /*! + * \brief Save preset and all associated state (passes, textures, imports, + * etc) to disk + * + * \param file Preset file to read from + * \param shader Shader passes handle + */ + virtual void ShaderPresetWrite(preset_file file, const video_shader &shader) { } + + /*! + * \brief Resolve relative shader path (@ref_path) into absolute shader path + * + * \param shader Shader pass handle + * \param ref_path Relative shader path + */ + //virtual void ShaderPresetResolveRelative(video_shader &shader, const char *ref_path) { } + + /*! + * \brief Read the current value for all parameters from preset file + * + * \param file Preset file to read from + * \param shader Shader passes handle + * + * \return True if successful, otherwise false + */ + //virtual bool ShaderPresetResolveCurrentParameters(preset_file file, video_shader &shader) { return false; } + + /*! + * \brief Resolve all shader parameters belonging to the shader preset + * + * \param file Preset file to read from + * \param shader Shader passes handle + * + * \return True if successful, otherwise false + */ + virtual bool ShaderPresetResolveParameters(preset_file file, video_shader &shader) { return false; } + + /*! + * \brief Free all state related to shader preset + * + * \param shader Object to free + */ + virtual void ShaderPresetFree(video_shader &shader) { } + + std::string AddonPath() const + { + if (m_instanceData->props.addon_path) + return m_instanceData->props.addon_path; + return ""; + } + + std::string UserPath() const + { + if (m_instanceData->props.user_path) + return m_instanceData->props.user_path; + return ""; + } + + private: + void SetAddonStruct(KODI_HANDLE instance) + { + if (instance == nullptr) + throw std::logic_error("kodi::addon::CInstanceShaderPreset: Creation with empty addon structure not allowed, table must be given from Kodi!"); + + m_instanceData = static_cast(instance); + m_instanceData->toAddon.addonInstance = this; + + m_instanceData->toAddon.preset_file_new = ADDON_preset_file_new; + m_instanceData->toAddon.preset_file_free = ADDON_preset_file_free; + + m_instanceData->toAddon.video_shader_read = ADDON_video_shader_read_file; + m_instanceData->toAddon.video_shader_write = ADDON_video_shader_write_file; + //m_instanceData->toAddon.video_shader_resolve_relative = ADDON_video_shader_resolve_relative; + //m_instanceData->toAddon.video_shader_resolve_current_parameters = ADDON_video_shader_resolve_current_parameters; + m_instanceData->toAddon.video_shader_resolve_parameters = ADDON_video_shader_resolve_parameters; + m_instanceData->toAddon.video_shader_free = ADDON_video_shader_free; + } + + inline static preset_file ADDON_preset_file_new(const AddonInstance_ShaderPreset* addonInstance, const char *path) + { + return addonInstance->toAddon.addonInstance->PresetFileNew(path); + } + + inline static void ADDON_preset_file_free(const AddonInstance_ShaderPreset* addonInstance, preset_file file) + { + return addonInstance->toAddon.addonInstance->PresetFileFree(file); + } + + inline static bool ADDON_video_shader_read_file(const AddonInstance_ShaderPreset* addonInstance, preset_file file, video_shader *shader) + { + if (shader != nullptr) + return addonInstance->toAddon.addonInstance->ShaderPresetRead(file, *shader); + + return false; + } + + inline static void ADDON_video_shader_write_file(const AddonInstance_ShaderPreset* addonInstance, preset_file file, const video_shader *shader) + { + if (shader != nullptr) + addonInstance->toAddon.addonInstance->ShaderPresetWrite(file, *shader); + } + + /* + inline static void ADDON_video_shader_resolve_relative(const AddonInstance_ShaderPreset* addonInstance, video_shader *shader, const char *ref_path) + { + if (shader != nullptr) + addonInstance->toAddon.addonInstance->ShaderPresetResolveRelative(*shader, ref_path); + } + + inline static bool ADDON_video_shader_resolve_current_parameters(const AddonInstance_ShaderPreset* addonInstance, preset_file file, video_shader *shader) + { + if (shader != nullptr) + return addonInstance->toAddon.addonInstance->ShaderPresetResolveCurrentParameters(file, *shader); + + return false; + } + */ + + inline static bool ADDON_video_shader_resolve_parameters(const AddonInstance_ShaderPreset* addonInstance, preset_file file, video_shader *shader) + { + if (shader != nullptr) + return addonInstance->toAddon.addonInstance->ShaderPresetResolveParameters(file, *shader); + + return false; + } + + inline static void ADDON_video_shader_free(const AddonInstance_ShaderPreset* addonInstance, video_shader *shader) + { + if (shader != nullptr) + addonInstance->toAddon.addonInstance->ShaderPresetFree(*shader); + } + + AddonInstance_ShaderPreset* m_instanceData; + }; + + } /* namespace addon */ +} /* namespace kodi */ diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h index 06d75e02c5ff1..ef1f1e97a6fa5 100644 --- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h +++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h @@ -128,6 +128,11 @@ "StreamCodec.h" \ "StreamCrypto.h" +#define ADDON_INSTANCE_VERSION_SHADERPRESET "0.0.4" +#define ADDON_INSTANCE_VERSION_SHADERPRESET_MIN "0.0.4" +#define ADDON_INSTANCE_VERSION_SHADERPRESET_XML_ID "kodi.binary.instance.shaderpreset" +#define ADDON_INSTANCE_VERSION_SHADERPRESET_DEPENDS "addon-instance/ShaderPreset.h" + /// /// The currently available instance types for Kodi add-ons /// @@ -159,6 +164,7 @@ typedef enum ADDON_TYPE ADDON_INSTANCE_VFS = 110, ADDON_INSTANCE_IMAGEDECODER = 111, ADDON_INSTANCE_VIDEOCODEC = 112, + ADDON_INSTANCE_SHADERPRESET = 113, } ADDON_TYPE; #ifdef __cplusplus @@ -239,6 +245,10 @@ inline const char* GetTypeVersion(int type) case ADDON_INSTANCE_SCREENSAVER: return ADDON_INSTANCE_VERSION_SCREENSAVER; #endif +#if !defined(BUILD_KODI_ADDON) || defined(ADDON_INSTANCE_VERSION_SHADERPRESET_USED) + case ADDON_INSTANCE_SHADERPRESET: + return ADDON_INSTANCE_VERSION_SHADERPRESET; +#endif #if !defined(BUILD_KODI_ADDON) || defined(ADDON_INSTANCE_VERSION_VFS_USED) case ADDON_INSTANCE_VFS: return ADDON_INSTANCE_VERSION_VFS; @@ -298,6 +308,8 @@ inline const char* GetTypeMinVersion(int type) return ADDON_INSTANCE_VERSION_PVR_MIN; case ADDON_INSTANCE_SCREENSAVER: return ADDON_INSTANCE_VERSION_SCREENSAVER_MIN; + case ADDON_INSTANCE_SHADERPRESET: + return ADDON_INSTANCE_VERSION_SHADERPRESET_MIN; case ADDON_INSTANCE_VFS: return ADDON_INSTANCE_VERSION_VFS_MIN; case ADDON_INSTANCE_VISUALIZATION: @@ -350,6 +362,8 @@ inline const char* GetTypeName(int type) return "PVR"; case ADDON_INSTANCE_SCREENSAVER: return "ScreenSaver"; + case ADDON_INSTANCE_SHADERPRESET: + return "ShaderPreset"; case ADDON_INSTANCE_VISUALIZATION: return "Visualization"; case ADDON_INSTANCE_VIDEOCODEC: @@ -399,6 +413,8 @@ inline int GetTypeId(const char* name) return ADDON_INSTANCE_PVR; else if (strcmp(name, "screensaver") == 0) return ADDON_INSTANCE_SCREENSAVER; + else if (strcmp(name, "shaderpreset") == 0) + return ADDON_INSTANCE_SHADERPRESET; else if (strcmp(name, "vfs") == 0) return ADDON_INSTANCE_VFS; else if (strcmp(name, "visualization") == 0) diff --git a/xbmc/cores/RetroPlayer/guibridge/IRenderCallback.h b/xbmc/cores/RetroPlayer/guibridge/IRenderCallback.h index 74421326740e2..17812e78f1f9e 100644 --- a/xbmc/cores/RetroPlayer/guibridge/IRenderCallback.h +++ b/xbmc/cores/RetroPlayer/guibridge/IRenderCallback.h @@ -10,6 +10,8 @@ #include "cores/GameSettings.h" +#include + namespace KODI { namespace RETRO diff --git a/xbmc/cores/RetroPlayer/rendering/RPRenderManager.cpp b/xbmc/cores/RetroPlayer/rendering/RPRenderManager.cpp index 873d6fd1f2945..146d9c3503f08 100644 --- a/xbmc/cores/RetroPlayer/rendering/RPRenderManager.cpp +++ b/xbmc/cores/RetroPlayer/rendering/RPRenderManager.cpp @@ -457,10 +457,14 @@ std::shared_ptr CRPRenderManager::GetRenderer(IRenderBufferPool // If buffer pool has no compatible renderers, create one now if (!renderer) { + const std::string &shaderPreset = renderSettings.VideoSettings().GetShaderPreset(); + CLog::Log(LOGERROR, "RetroPlayer[RENDER]: Creating renderer for %s", m_processInfo.GetRenderSystemName(bufferPool).c_str()); - renderer.reset(m_processInfo.CreateRenderer(bufferPool, renderSettings)); + // Try to create a renderer now, unless the shader preset has failed already + if (shaderPreset.empty() || m_failedShaderPresets.find(shaderPreset) == m_failedShaderPresets.end()) + renderer.reset(m_processInfo.CreateRenderer(bufferPool, renderSettings)); if (renderer && renderer->Configure(m_format)) { // Ensure we have a render buffer for this renderer @@ -470,6 +474,10 @@ std::shared_ptr CRPRenderManager::GetRenderer(IRenderBufferPool } else renderer.reset(); + + // If we failed to create a renderer, blacklist the shader preset + if (!renderer && !shaderPreset.empty()) + m_failedShaderPresets.insert(shaderPreset); } return renderer; diff --git a/xbmc/cores/RetroPlayer/rendering/RenderVideoSettings.cpp b/xbmc/cores/RetroPlayer/rendering/RenderVideoSettings.cpp index 4e7587271b8b5..b35f999d867d2 100644 --- a/xbmc/cores/RetroPlayer/rendering/RenderVideoSettings.cpp +++ b/xbmc/cores/RetroPlayer/rendering/RenderVideoSettings.cpp @@ -8,28 +8,37 @@ #include "RenderVideoSettings.h" +#include "utils/log.h" + using namespace KODI; using namespace RETRO; #define VIDEO_FILTER_NEAREST "nearest" #define VIDEO_FILTER_LINEAR "linear" +#define VIDEO_FILTER_DEFAULT VIDEO_FILTER_NEAREST + void CRenderVideoSettings::Reset() { m_scalingMethod = SCALINGMETHOD::AUTO; m_stretchMode = STRETCHMODE::Normal; m_rotationDegCCW = 0; + m_shaderPreset.clear(); } bool CRenderVideoSettings::operator==(const CRenderVideoSettings &rhs) const { return m_scalingMethod == rhs.m_scalingMethod && m_stretchMode == rhs.m_stretchMode && - m_rotationDegCCW == rhs.m_rotationDegCCW; + m_rotationDegCCW == rhs.m_rotationDegCCW && + m_shaderPreset == rhs.m_shaderPreset; } bool CRenderVideoSettings::operator<(const CRenderVideoSettings &rhs) const { + if (m_shaderPreset < rhs.m_shaderPreset) return true; + if (m_shaderPreset > rhs.m_shaderPreset) return false; + if (m_scalingMethod < rhs.m_scalingMethod) return true; if (m_scalingMethod > rhs.m_scalingMethod) return false; @@ -44,6 +53,13 @@ bool CRenderVideoSettings::operator<(const CRenderVideoSettings &rhs) const std::string CRenderVideoSettings::GetVideoFilter() const { + // Sanity check + if (!m_shaderPreset.empty() && m_scalingMethod != SCALINGMETHOD::AUTO) + CLog::Log(LOGWARNING, "%s - Shader preset selected but scaling method is not AUTO", __FUNCTION__); + + if (UsesShaderPreset()) + return m_shaderPreset; + switch (m_scalingMethod) { case SCALINGMETHOD::NEAREST: @@ -62,13 +78,28 @@ void CRenderVideoSettings::SetVideoFilter(const std::string &videoFilter) if (videoFilter == VIDEO_FILTER_NEAREST) { m_scalingMethod = SCALINGMETHOD::NEAREST; + ResetShaderPreset(); } else if (videoFilter == VIDEO_FILTER_LINEAR) { m_scalingMethod = SCALINGMETHOD::LINEAR; + ResetShaderPreset(); } else { m_scalingMethod = SCALINGMETHOD::AUTO; + + // Not a known video filter, assume it's a shader preset path + SetShaderPreset(videoFilter); } } + +void CRenderVideoSettings::ResetShaderPreset() +{ + m_shaderPreset.clear(); +} + +bool CRenderVideoSettings::UsesShaderPreset() const +{ + return !m_shaderPreset.empty() && m_scalingMethod == SCALINGMETHOD::AUTO; +} diff --git a/xbmc/cores/RetroPlayer/rendering/RenderVideoSettings.h b/xbmc/cores/RetroPlayer/rendering/RenderVideoSettings.h index 603721fcf6a46..0c99ba2df0ea0 100644 --- a/xbmc/cores/RetroPlayer/rendering/RenderVideoSettings.h +++ b/xbmc/cores/RetroPlayer/rendering/RenderVideoSettings.h @@ -43,13 +43,20 @@ namespace RETRO STRETCHMODE GetRenderStretchMode() const { return m_stretchMode; } void SetRenderStretchMode(STRETCHMODE mode) { m_stretchMode = mode; } + const std::string &GetShaderPreset() const { return m_shaderPreset; } + void SetShaderPreset(const std::string &shaderPreset) { m_shaderPreset = shaderPreset; } + void ResetShaderPreset(); + unsigned int GetRenderRotation() const { return m_rotationDegCCW; } void SetRenderRotation(unsigned int rotationDegCCW) { m_rotationDegCCW = rotationDegCCW; } private: + bool UsesShaderPreset() const; + SCALINGMETHOD m_scalingMethod; STRETCHMODE m_stretchMode; unsigned int m_rotationDegCCW; + std::string m_shaderPreset; }; } } diff --git a/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPBaseRenderer.cpp b/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPBaseRenderer.cpp index 48535180cbe6d..5f9000f0c89ff 100644 --- a/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPBaseRenderer.cpp +++ b/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPBaseRenderer.cpp @@ -11,6 +11,7 @@ #include "cores/RetroPlayer/buffers/IRenderBufferPool.h" #include "cores/RetroPlayer/rendering/RenderContext.h" #include "cores/RetroPlayer/rendering/RenderUtils.h" +#include "cores/RetroPlayer/shaders/IShaderPreset.h" #include "utils/log.h" using namespace KODI; @@ -22,7 +23,9 @@ using namespace RETRO; CRPBaseRenderer::CRPBaseRenderer(const CRenderSettings &renderSettings, CRenderContext &context, std::shared_ptr bufferPool) : m_context(context), m_bufferPool(std::move(bufferPool)), - m_renderSettings(renderSettings) + m_renderSettings(renderSettings), + m_shadersNeedUpdate(true), + m_bUseShaderPreset(false) { m_bufferPool->RegisterRenderer(this); } @@ -39,6 +42,14 @@ bool CRPBaseRenderer::IsCompatible(const CRenderVideoSettings &settings) const if (!m_bufferPool->IsCompatible(settings)) return false; + // Shader preset must match + std::string shaderPreset; + if (m_shaderPreset) + shaderPreset = m_shaderPreset->GetShaderPreset(); + + if (settings.GetShaderPreset() != shaderPreset) + return false; + return true; } @@ -126,6 +137,15 @@ void CRPBaseRenderer::SetRenderRotation(unsigned int rotationDegCCW) m_renderSettings.VideoSettings().SetRenderRotation(rotationDegCCW); } +void CRPBaseRenderer::SetShaderPreset(const std::string &presetPath) +{ + if (presetPath != m_renderSettings.VideoSettings().GetShaderPreset()) + { + m_renderSettings.VideoSettings().SetShaderPreset(presetPath); + m_shadersNeedUpdate = true; + } +} + void CRPBaseRenderer::ManageRenderArea(const IRenderBuffer &renderBuffer) { // Get texture parameters @@ -183,6 +203,31 @@ void CRPBaseRenderer::MarkDirty() //CServiceBroker::GetGUI()->GetWindowManager().MarkDirty(m_dimensions); //! @todo } +/** + * \brief Updates everything needed for video shaders (shader presets) + * Needs to be called after m_renderBuffer has been set + */ +void CRPBaseRenderer::Updateshaders() +{ + if (m_shadersNeedUpdate) + { + if (m_shaderPreset) + { + if (!m_renderBuffer) { + CLog::Log(LOGWARNING, "%s - Render buffer not set, can't update video shader source size!", __FUNCTION__); + return; + } + auto sourceWidth = m_renderBuffer->GetWidth(); + auto sourceHeight = m_renderBuffer->GetHeight(); + + // We need to set this here because m_sourceRect isn't valid on init/pre-init + m_shaderPreset->SetVideoSize(sourceWidth, sourceHeight); + m_bUseShaderPreset = m_shaderPreset->SetShaderPreset(m_renderSettings.VideoSettings().GetShaderPreset()); + } + m_shadersNeedUpdate = false; + } +} + void CRPBaseRenderer::PreRender(bool clear) { if (!m_bConfigured) @@ -191,6 +236,8 @@ void CRPBaseRenderer::PreRender(bool clear) // Clear screen if (clear) m_context.Clear(m_context.UseLimitedColor() ? 0x101010 : 0); + + //ManageRenderArea(*m_renderBuffer); } void CRPBaseRenderer::PostRender() diff --git a/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPBaseRenderer.h b/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPBaseRenderer.h index 129f0996dc671..0c7a41d242b43 100644 --- a/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPBaseRenderer.h +++ b/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPBaseRenderer.h @@ -22,6 +22,11 @@ extern "C" { namespace KODI { +namespace SHADER +{ + class IShaderPreset; +} + namespace RETRO { class CRenderContext; @@ -64,6 +69,7 @@ namespace RETRO void SetScalingMethod(SCALINGMETHOD method); void SetStretchMode(STRETCHMODE stretchMode); void SetRenderRotation(unsigned int rotationDegCCW); + void SetShaderPreset(const std::string &presetPath); bool IsVisible() const; @@ -89,6 +95,13 @@ namespace RETRO CRect m_sourceRect; std::array m_rotatedDestCoords{}; + // Video shaders + void Updateshaders(); + std::unique_ptr m_shaderPreset; + + bool m_shadersNeedUpdate; + bool m_bUseShaderPreset; + private: /*! * \brief Calculate driven dimensions diff --git a/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPRendererGuiTexture.cpp b/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPRendererGuiTexture.cpp index ad2bf1b98450a..244ffefaaeaf1 100644 --- a/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPRendererGuiTexture.cpp +++ b/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPRendererGuiTexture.cpp @@ -58,6 +58,10 @@ bool CRenderBufferPoolGuiTexture::IsCompatible(const CRenderVideoSettings &rende if (renderSettings.GetScalingMethod() != m_scalingMethod) return false; + // Shaders not supported + if (!renderSettings.GetShaderPreset().empty()) + return false; + return true; } diff --git a/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPWinRenderer.cpp b/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPWinRenderer.cpp index 7231252ea9ea9..db437fd06105b 100644 --- a/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPWinRenderer.cpp +++ b/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPWinRenderer.cpp @@ -10,7 +10,9 @@ #include "cores/RetroPlayer/rendering/RenderContext.h" #include "cores/RetroPlayer/rendering/RenderTranslator.h" #include "cores/RetroPlayer/rendering/RenderVideoSettings.h" -#include "cores/RetroPlayer/rendering/VideoShaders/windows/RPWinOutputShader.h" +#include "cores/RetroPlayer/shaders/windows/RPWinOutputShader.h" +#include "cores/RetroPlayer/shaders/windows/ShaderPresetDX.h" +#include "cores/RetroPlayer/shaders/windows/ShaderTextureDX.h" #include "guilib/D3DResource.h" #include "rendering/dx/RenderSystemDX.h" #include "utils/log.h" @@ -53,7 +55,7 @@ CWinRenderBuffer::CWinRenderBuffer(AVPixelFormat pixFormat, DXGI_FORMAT dxFormat bool CWinRenderBuffer::CreateTexture() { - if (!m_intermediateTarget->Create(m_width, m_height, 1, D3D11_USAGE_DYNAMIC, m_targetDxFormat)) + if (!m_intermediateTarget->GetPointer()->Create(m_width, m_height, 1, D3D11_USAGE_DYNAMIC, m_targetDxFormat)) { CLog::Log(LOGERROR, "WinRenderer: Intermediate render target creation failed"); return false; @@ -66,7 +68,7 @@ bool CWinRenderBuffer::GetTexture(uint8_t*& data, unsigned int& stride) { // Scale and upload texture D3D11_MAPPED_SUBRESOURCE destlr; - if (!m_intermediateTarget->LockRect(0, &destlr, D3D11_MAP_WRITE_DISCARD)) + if (!m_intermediateTarget->GetPointer()->LockRect(0, &destlr, D3D11_MAP_WRITE_DISCARD)) { CLog::Log(LOGERROR, "WinRenderer: Failed to lock swtarget texture into memory"); return false; @@ -80,7 +82,7 @@ bool CWinRenderBuffer::GetTexture(uint8_t*& data, unsigned int& stride) bool CWinRenderBuffer::ReleaseTexture() { - if (!m_intermediateTarget->UnlockRect(0)) + if (!m_intermediateTarget->GetPointer()->UnlockRect(0)) { CLog::Log(LOGERROR, "WinRenderer: Failed to unlock swtarget texture"); return false; @@ -103,7 +105,7 @@ bool CWinRenderBuffer::UploadTexture() // Create intermediate texture if (!m_intermediateTarget) { - m_intermediateTarget.reset(new CD3DTexture); + m_intermediateTarget.reset(new SHADER::CShaderTextureCD3D(new CD3DTexture)); if (!CreateTexture()) { m_intermediateTarget.reset(); @@ -166,6 +168,13 @@ CWinRenderBufferPool::CWinRenderBufferPool() bool CWinRenderBufferPool::IsCompatible(const CRenderVideoSettings &renderSettings) const { + //! @todo Move this logic to generic class + + // Shader presets are compatible + if (!renderSettings.GetShaderPreset().empty()) + return true; + + // If no shader preset is specified, scaling methods must match return GetShader(renderSettings.GetScalingMethod()) != nullptr; } @@ -184,7 +193,7 @@ bool CWinRenderBufferPool::ConfigureDX(DXGI_FORMAT dxFormat) return true; } -CRPWinOutputShader *CWinRenderBufferPool::GetShader(SCALINGMETHOD scalingMethod) const +SHADER::CRPWinOutputShader *CWinRenderBufferPool::GetShader(SCALINGMETHOD scalingMethod) const { auto it = m_outputShaders.find(scalingMethod); @@ -208,7 +217,7 @@ void CWinRenderBufferPool::CompileOutputShaders() { for (auto scalingMethod : GetScalingMethods()) { - std::unique_ptr outputShader(new CRPWinOutputShader); + std::unique_ptr outputShader(new SHADER::CRPWinOutputShader); if (outputShader->Create(scalingMethod)) m_outputShaders[scalingMethod] = std::move(outputShader); else @@ -222,6 +231,8 @@ void CWinRenderBufferPool::CompileOutputShaders() CRPWinRenderer::CRPWinRenderer(const CRenderSettings &renderSettings, CRenderContext &context, std::shared_ptr bufferPool) : CRPBaseRenderer(renderSettings, context, std::move(bufferPool)) { + // Initialize CRPBaseRenderer fields + m_shaderPreset.reset(new SHADER::CShaderPresetDX(m_context)); } bool CRPWinRenderer::ConfigureInternal() @@ -274,9 +285,50 @@ void CRPWinRenderer::Render(CD3DTexture *target) m_rotatedDestCoords[3] }; - if (m_renderBuffer != nullptr) + CWinRenderBuffer *renderBuffer = static_cast(m_renderBuffer); + if (renderBuffer == nullptr) + return; + + SHADER::CShaderTextureCD3D *renderBufferTarget = renderBuffer->GetTarget(); + if (renderBufferTarget == nullptr) + return; + + Updateshaders(); + + // Are we using video shaders? + if (m_bUseShaderPreset) + { + // TODO: Orientation? + /* + CPoint destPoints[4]; + // select destination rectangle + if (m_renderOrientation) + { + for (size_t i = 0; i < 4; i++) + destPoints[i] = m_rotatedDestCoords[i]; + } + else + { + CRect destRect = m_context.StereoCorrection(m_renderSettings.Geometry().Dimensions()); + destPoints[0] = { destRect.x1, destRect.y1 }; + destPoints[1] = { destRect.x2, destRect.y1 }; + destPoints[2] = { destRect.x2, destRect.y2 }; + destPoints[3] = { destRect.x1, destRect.y2 }; + } + */ + + // Render shaders and ouput to display + m_targetTexture.SetTexture(target); + if (!m_shaderPreset->RenderUpdate(destPoints, renderBufferTarget, &m_targetTexture)) + { + m_shadersNeedUpdate = false; + m_bUseShaderPreset = false; + } + } + else // Not using video shaders, output using output shader { - CD3DTexture *intermediateTarget = static_cast(m_renderBuffer)->GetTarget(); + CD3DTexture *intermediateTarget = renderBufferTarget->GetPointer(); + if (intermediateTarget != nullptr) { CRect viewPort; @@ -286,7 +338,7 @@ void CRPWinRenderer::Render(CD3DTexture *target) SCALINGMETHOD scalingMethod = m_renderSettings.VideoSettings().GetScalingMethod(); CWinRenderBufferPool *bufferPool = static_cast(m_bufferPool.get()); - CRPWinOutputShader *outputShader = bufferPool->GetShader(scalingMethod); + SHADER::CRPWinOutputShader *outputShader = bufferPool->GetShader(scalingMethod); // Use the picked output shader to render to the target if (outputShader != nullptr) @@ -294,7 +346,7 @@ void CRPWinRenderer::Render(CD3DTexture *target) outputShader->Render(*intermediateTarget, m_sourceRect, destPoints, viewPort, target, m_context.UseLimitedColor() ? 1 : 0); - } } } } +} diff --git a/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPWinRenderer.h b/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPWinRenderer.h index e45c80dd6b06c..ef4d4fdc27066 100644 --- a/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPWinRenderer.h +++ b/xbmc/cores/RetroPlayer/rendering/VideoRenderers/RPWinRenderer.h @@ -12,8 +12,11 @@ #include "cores/RetroPlayer/buffers/BaseRenderBufferPool.h" #include "cores/RetroPlayer/buffers/video/RenderBufferSysMem.h" #include "cores/RetroPlayer/process/RPProcessInfo.h" +#include "cores/RetroPlayer/shaders/windows/RPWinOutputShader.h" +#include "cores/RetroPlayer/shaders/windows/ShaderTextureDX.h" #include +#include #include #include #include @@ -48,7 +51,7 @@ namespace RETRO // implementation of IRenderBuffer via CRenderBufferSysMem bool UploadTexture() override; - CD3DTexture *GetTarget() { return m_intermediateTarget.get(); } + SHADER::CShaderTextureCD3D *GetTarget() { return m_intermediateTarget.get(); } private: bool CreateTexture(); @@ -65,7 +68,7 @@ namespace RETRO const DXGI_FORMAT m_targetDxFormat; AVPixelFormat m_targetPixFormat; - std::unique_ptr m_intermediateTarget; + std::unique_ptr m_intermediateTarget; SwsContext *m_swsContext = nullptr; }; @@ -84,7 +87,7 @@ namespace RETRO // DirectX interface bool ConfigureDX(DXGI_FORMAT dxFormat); - CRPWinOutputShader *GetShader(SCALINGMETHOD scalingMethod) const; + SHADER::CRPWinOutputShader *GetShader(SCALINGMETHOD scalingMethod) const; private: static const std::vector &GetScalingMethods(); @@ -92,7 +95,7 @@ namespace RETRO void CompileOutputShaders(); DXGI_FORMAT m_targetDxFormat = DXGI_FORMAT_UNKNOWN; - std::map> m_outputShaders; + std::map> m_outputShaders; }; class CRPWinRenderer : public CRPBaseRenderer @@ -119,6 +122,8 @@ namespace RETRO private: void Render(CD3DTexture *target); + + SHADER::CShaderTextureCD3D m_targetTexture; }; } } diff --git a/xbmc/cores/RetroPlayer/rendering/VideoShaders/CMakeLists.txt b/xbmc/cores/RetroPlayer/rendering/VideoShaders/CMakeLists.txt deleted file mode 100644 index d886000c09a3c..0000000000000 --- a/xbmc/cores/RetroPlayer/rendering/VideoShaders/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -if(NOT ENABLE_STATIC_LIBS) - core_add_library(rp-videoshaders) -endif() diff --git a/xbmc/cores/RetroPlayer/rendering/VideoShaders/windows/CMakeLists.txt b/xbmc/cores/RetroPlayer/rendering/VideoShaders/windows/CMakeLists.txt deleted file mode 100644 index 51fda4144c003..0000000000000 --- a/xbmc/cores/RetroPlayer/rendering/VideoShaders/windows/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -set(SOURCES RPWinOutputShader.cpp) - -set(HEADERS RPWinOutputShader.h) - -core_add_library(rp-videoshaders-windows) diff --git a/xbmc/cores/RetroPlayer/shaders/CMakeLists.txt b/xbmc/cores/RetroPlayer/shaders/CMakeLists.txt new file mode 100644 index 0000000000000..7abc092d9c8ba --- /dev/null +++ b/xbmc/cores/RetroPlayer/shaders/CMakeLists.txt @@ -0,0 +1,16 @@ +set(SOURCES IShaderTexture.cpp + ShaderPresetFactory.cpp + ShaderUtils.cpp +) + +set(HEADERS IShader.h + IShaderLut.h + IShaderPreset.h + IShaderSampler.h + IShaderTexture.h + ShaderPresetFactory.h + ShaderTypes.h + ShaderUtils.h +) + +core_add_library(rp-shaders) diff --git a/xbmc/cores/RetroPlayer/shaders/IShader.h b/xbmc/cores/RetroPlayer/shaders/IShader.h new file mode 100644 index 0000000000000..fcc314a0c1d7d --- /dev/null +++ b/xbmc/cores/RetroPlayer/shaders/IShader.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2017-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "ShaderTypes.h" +#include "utils/Geometry.h" + +#include +#include +#include + +namespace KODI +{ +namespace SHADER +{ + class IShaderSampler; + class IShaderTexture; + + class IShader + { + public: + /*! + * \brief Construct the vidoe shader instance + * \param shaderSource Source code of the shader (both vertex and pixel/fragment) + * \param shaderPath Full path to the shader file + * \param shaderParameters Struct with all parameters pertaining to the shader + * \param sampler Pointer to the sampler that the will be used when sampling textures + * \param luts Look-up textures pertaining to shader + * \param viewPortSize Size of the window/viewport + * \param frameCountMod Modulo that must be applied to the frame count before sendign it to the shader + * \return False if creating the shader failed, true otherwise. + */ + virtual bool Create(const std::string& shaderSource, const std::string& shaderPath, ShaderParameterMap shaderParameters, + IShaderSampler* sampler, ShaderLutVec luts, float2 viewPortSize, unsigned frameCountMod = 0) = 0; + + /*! + * \brief Renders the video shader to the target texture + * \param source Source texture to pass to the shader as input + * \param target Target texture to render the shader to + */ + virtual void Render(IShaderTexture* source, IShaderTexture* target) = 0; + + /*! + * \brief Sets the input and output sizes in pixels + * \param prevSize Input image size of the shader in pixels + * \param nextSize Output image size of the shader in pixels + */ + virtual void SetSizes(const float2& prevSize, const float2& nextSize) = 0; + + /*! + * \brief Construct the vertex buffer that will be used to render the shader + * \param vertCount Number of vertices to construct. Commonly 4, for rectangular screens. + * \param vertSize Size of each vertex's data in bytes + * \return False if creating the vertex buffer failed, true otherwise. + */ + virtual bool CreateVertexBuffer(unsigned vertCount, unsigned vertSize) = 0; + + /*! + * \brief Creates the data layout of the input-assembler stage + * \param layout Description of the inputs to the vertex shader + * \param numElements Number of inputs to the vertex shader + * \return False if creating the input layout failed, true otherwise. + */ + // TODO: the first argument is DX-specific (maybe the entire function is) + virtual bool CreateInputLayout(D3D11_INPUT_ELEMENT_DESC* layout, unsigned numElements) = 0; + + /*! + * \brief Creates the buffer that will be used to send "input" (as per the spec) data to the shader + * \return False if creating the input buffer failed, true otherwise. + */ + virtual bool CreateInputBuffer() = 0; + + /*! + * \brief Called before rendering. + * Updates any internal state needed to ensure that correct data is passed to the shader + * when rendering + * \param dest Coordinates of the 4 corners of the output viewport/window + * \param isLastPass True if the current shader is last one in the pipeline // TODO: this could be a member + * \param frameCount Number of frames that have passed + */ + virtual void PrepareParameters(CPoint dest[4], bool isLastPass, uint64_t frameCount) = 0; + + /*! + * \brief Updates the model view projection matrix. + * Should usually only be called when the viewport/window size changes + */ + virtual void UpdateMVP() = 0; + + virtual ~IShader() = default; + }; +} +} diff --git a/xbmc/cores/RetroPlayer/shaders/IShaderLut.h b/xbmc/cores/RetroPlayer/shaders/IShaderLut.h new file mode 100644 index 0000000000000..a4d1fca9b23db --- /dev/null +++ b/xbmc/cores/RetroPlayer/shaders/IShaderLut.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2017-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "ShaderTypes.h" + +#include +#include +#include + +namespace KODI +{ + +namespace RETRO +{ + class CRenderContext; +} + +namespace SHADER +{ + class IShaderSampler; + class IShaderTexture; + + /*! + * \brief A lookup table to apply color transforms in a shader + */ + class IShaderLut + { + public: + IShaderLut() = default; + IShaderLut(const std::string& id, const std::string& path) + : m_id(id), m_path(path) {} + + virtual ~IShaderLut() = default; + + /*! + * \brief Create the LUT and allocate resources + * \param context The render context + * \param lut The LUT information structure + * \return True if successful and the LUT can be used, false otherwise + */ + virtual bool Create(RETRO::CRenderContext &context, const ShaderLut &lut) = 0; + + /*! + * \brief Gets ID of LUT + * \return Unique name (ID) of look up texture + */ + const std::string& GetID() const { return m_id; } + + /*! + * \brief Gets full path of LUT + * \return Full path of look up texture + */ + const std::string& GetPath() const { return m_path; } + + /*! + * \brief Gets sampler of LUT + * \return Pointer to the sampler associated with the LUT + */ + virtual IShaderSampler* GetSampler() = 0; + + /*! + * \brief Gets sampler of LUT + * \return Pointer to the texture where the LUT data is stored in + */ + virtual IShaderTexture* GetTexture() = 0; + + protected: + std::string m_id; + std::string m_path; + }; +} +} + diff --git a/xbmc/cores/RetroPlayer/shaders/IShaderPreset.h b/xbmc/cores/RetroPlayer/shaders/IShaderPreset.h new file mode 100644 index 0000000000000..da4ee069b7f4c --- /dev/null +++ b/xbmc/cores/RetroPlayer/shaders/IShaderPreset.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2017-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "ShaderTypes.h" +#include "utils/Geometry.h" + +#include +#include + +namespace KODI +{ +namespace SHADER +{ + class IShaderTexture; + + class IShaderPreset + { + public: + virtual ~IShaderPreset() = default; + + //todo: impl once and for all + /*! + * \brief Reads/Parses a shader preset file and loads its state to the + * object. What this state is is implementation specific. + * \param presetPath Full path of the preset file. + * \return True on successful parsing, false on failed. + */ + virtual bool ReadPresetFile(const std::string &presetPath) = 0; + + /*! + * \brief Updates state if needed and renderes the preset to the target texture + * \param dest Coordinates of the 4 corners of the output viewport/window + * \param source Input texture. The source of the video frame, in is original resolution (unscaled) + * \param target The target texture. The texture that the final result will be rendered in. + * \return Returns false if updating or rendering failed, true if both succeeded. + */ + virtual bool RenderUpdate(const CPoint dest[], IShaderTexture* source, IShaderTexture* target) = 0; + + /*! + * \brief Informs about the speed of playback + * \param speed Commonly 1.0 for normal playback, and 0.0 if paused + */ + virtual void SetSpeed(double speed) = 0; + + /*! + * \brief Size of the input/source frame in pixels + * \param videoWidth Height of the source frame in pixels + * \param videoHeight Height of the source frame in pixels + */ + virtual void SetVideoSize(const unsigned videoWidth, const unsigned videoHeight) = 0; + + /*! + * \brief Set the preset to be rendered on the next frame + * \param shaderPresetPath Full path to the preset file to be loaded + * \return Returns false if loading the preset failed, true otherwise. + */ + virtual bool SetShaderPreset(const std::string& shaderPresetPath) = 0; + + /*! + * \brief Gets the full path to the shader preset + * \return The full path to the currently loaded preset file + */ + virtual const std::string& GetShaderPreset() const = 0; + + /*! + * \brief Gets the passes of the loaded preset + * \return All the video shader passes of the currently loaded preset + */ + virtual ShaderPassVec& GetPasses() = 0; + }; +} +} diff --git a/xbmc/cores/RetroPlayer/shaders/IShaderSampler.h b/xbmc/cores/RetroPlayer/shaders/IShaderSampler.h new file mode 100644 index 0000000000000..5800252d33351 --- /dev/null +++ b/xbmc/cores/RetroPlayer/shaders/IShaderSampler.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2017-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +namespace KODI +{ +namespace SHADER +{ + class IShaderSampler + { + public: + virtual ~IShaderSampler() = default; + }; +} +} diff --git a/xbmc/cores/RetroPlayer/shaders/IShaderTexture.cpp b/xbmc/cores/RetroPlayer/shaders/IShaderTexture.cpp new file mode 100644 index 0000000000000..588f199c59a14 --- /dev/null +++ b/xbmc/cores/RetroPlayer/shaders/IShaderTexture.cpp @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2017-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "IShaderTexture.h" + +using namespace KODI; +using namespace SHADER; + +IShaderTexture::~IShaderTexture() = default; diff --git a/xbmc/cores/RetroPlayer/shaders/IShaderTexture.h b/xbmc/cores/RetroPlayer/shaders/IShaderTexture.h new file mode 100644 index 0000000000000..4be1ec2480f3b --- /dev/null +++ b/xbmc/cores/RetroPlayer/shaders/IShaderTexture.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2017-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +namespace KODI +{ +namespace SHADER +{ + class IShaderTexture + { + public: + virtual ~IShaderTexture(); + + /*! + * \brief Return width of texture + * \return Width of the texture in texels + */ + virtual float GetWidth() const = 0; + + /*! + * \brief Return height of texture + * \return Height of the texture in texels + */ + virtual float GetHeight() const = 0; + }; +} +} diff --git a/xbmc/cores/RetroPlayer/shaders/ShaderPresetFactory.cpp b/xbmc/cores/RetroPlayer/shaders/ShaderPresetFactory.cpp new file mode 100644 index 0000000000000..461a938cba0b2 --- /dev/null +++ b/xbmc/cores/RetroPlayer/shaders/ShaderPresetFactory.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2017-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "ShaderPresetFactory.h" +#include "addons/binary-addons/BinaryAddonBase.h" +#include "addons/binary-addons/BinaryAddonManager.h" +#include "addons/AddonManager.h" +#include "addons/ShaderPreset.h" +#include "utils/log.h" +#include "utils/URIUtils.h" + +#include +#include + +using namespace KODI; +using namespace SHADER; + +CShaderPresetFactory::CShaderPresetFactory(ADDON::CAddonMgr &addons, ADDON::CBinaryAddonManager &binaryAddons) : + m_addons(addons), + m_binaryAddons(binaryAddons) +{ + UpdateAddons(); + + m_addons.Events().Subscribe(this, &CShaderPresetFactory::OnEvent); +} + +CShaderPresetFactory::~CShaderPresetFactory() +{ + m_addons.Events().Unsubscribe(this); +} + +void CShaderPresetFactory::RegisterLoader(IShaderPresetLoader *loader, const std::string &extension) +{ + if (!extension.empty()) + { + std::string strExtension = extension; + + // Canonicalize extension with leading "." + if (extension[0] != '.') + strExtension.insert(strExtension.begin(), '.'); + + m_loaders.insert(std::make_pair(std::move(strExtension), loader)); + } +} + +void CShaderPresetFactory::UnregisterLoader(IShaderPresetLoader *loader) +{ + for (auto it = m_loaders.begin(); it != m_loaders.end(); ) + { + if (it->second == loader) + m_loaders.erase(it++); + else + ++it; + } +} + +bool CShaderPresetFactory::LoadPreset(const std::string &presetPath, IShaderPreset &shaderPreset) +{ + bool bSuccess = false; + + std::string extension = URIUtils::GetExtension(presetPath); + if (!extension.empty()) + { + auto itLoader = m_loaders.find(extension); + if (itLoader != m_loaders.end()) + bSuccess = itLoader->second->LoadPreset(presetPath, shaderPreset); + } + + return bSuccess; +} + +void CShaderPresetFactory::OnEvent(const ADDON::AddonEvent &event) +{ + if (typeid(event) == typeid(ADDON::AddonEvents::Enabled) || + typeid(event) == typeid(ADDON::AddonEvents::Disabled) || + typeid(event) == typeid(ADDON::AddonEvents::UnInstalled)) //! @todo Other events? + UpdateAddons(); +} + +void CShaderPresetFactory::UpdateAddons() +{ + using namespace ADDON; + + BinaryAddonBaseList addonInfos; + m_binaryAddons.GetAddonInfos(addonInfos, true, ADDON_SHADERDLL); + + // Look for removed/disabled add-ons + auto oldAddons = std::move(m_shaderAddons); + for (auto &shaderAddon : oldAddons) + { + const bool bIsDisabled = std::find_if(addonInfos.begin(), addonInfos.end(), + [&shaderAddon](const BinaryAddonBasePtr &addon) + { + return shaderAddon->ID() == addon->ID(); + }) == addonInfos.end(); + + if (bIsDisabled) + UnregisterLoader(shaderAddon.get()); + else + m_shaderAddons.emplace_back(std::move(shaderAddon)); + } + + // Look for new add-ons + for (const auto &shaderAddon : addonInfos) + { + auto FindAddonById = [&shaderAddon](const std::unique_ptr &addon) + { + return shaderAddon->ID() == addon->ID(); + }; + + const bool bIsNew = std::find_if(m_shaderAddons.begin(), m_shaderAddons.end(), FindAddonById) == m_shaderAddons.end(); + + if (!bIsNew) + continue; + + const bool bIsFailed = std::find_if(m_failedAddons.begin(), m_failedAddons.end(), FindAddonById) != m_failedAddons.end(); + + if (bIsFailed) + continue; + + std::unique_ptr addonPtr(new CShaderPresetAddon(shaderAddon)); + if (addonPtr->CreateAddon()) + { + for (const auto &extension : addonPtr->GetExtensions()) + RegisterLoader(addonPtr.get(), extension); + m_shaderAddons.emplace_back(std::move(addonPtr)); + } + else + { + m_failedAddons.emplace_back(std::move(addonPtr)); + } + } +} + +bool CShaderPresetFactory::CanLoadPreset(const std::string &presetPath) +{ + bool bSuccess = false; + + std::string extension = URIUtils::GetExtension(presetPath); + if (!extension.empty()) + { + auto itLoader = m_loaders.find(extension); + bSuccess = itLoader != m_loaders.end(); + } + + return bSuccess; +} diff --git a/xbmc/cores/RetroPlayer/shaders/ShaderPresetFactory.h b/xbmc/cores/RetroPlayer/shaders/ShaderPresetFactory.h new file mode 100644 index 0000000000000..3a0431b6a6c0a --- /dev/null +++ b/xbmc/cores/RetroPlayer/shaders/ShaderPresetFactory.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2017-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "IShaderPreset.h" +#include "addons/Addon.h" + +#include +#include + +namespace ADDON +{ + struct AddonEvent; + class CAddonMgr; + class CBinaryAddonManager; + class CShaderPresetAddon; +} + +namespace KODI +{ +namespace SHADER +{ + class IShaderPresetLoader + { + public: + virtual ~IShaderPresetLoader() = default; + + virtual bool LoadPreset(const std::string &presetPath, IShaderPreset &shaderPreset) = 0; + }; + + class CShaderPresetFactory + { + public: + + /*! + * \brief Create the factory and register all shader preset add-ons + */ + CShaderPresetFactory(ADDON::CAddonMgr &addons, ADDON::CBinaryAddonManager &binaryAddons); + ~CShaderPresetFactory(); + + void RegisterLoader(IShaderPresetLoader *loader, const std::string &extension); + void UnregisterLoader(IShaderPresetLoader *loader); + + bool LoadPreset(const std::string &presetPath, IShaderPreset &shaderPreset); + bool CanLoadPreset(const std::string &presetPath); + + private: + void OnEvent(const ADDON::AddonEvent &event); + void UpdateAddons(); + + // Construction parameters + ADDON::CAddonMgr &m_addons; + ADDON::CBinaryAddonManager &m_binaryAddons; + + std::map m_loaders; + std::vector> m_shaderAddons; + std::vector> m_failedAddons; + }; +} +} diff --git a/xbmc/cores/RetroPlayer/shaders/ShaderTypes.h b/xbmc/cores/RetroPlayer/shaders/ShaderTypes.h new file mode 100644 index 0000000000000..e83ea4e5c275c --- /dev/null +++ b/xbmc/cores/RetroPlayer/shaders/ShaderTypes.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2017-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +// TODO: remove (see below) +#ifdef _WIN32 +#include +#endif + +namespace KODI +{ +namespace SHADER +{ + struct ShaderPass; + using ShaderPassVec = std::vector; + + class IShaderLut; + using ShaderLutPtr = std::shared_ptr; + using ShaderLutVec = std::vector; + + using ShaderParameterMap = std::map; + + enum FILTER_TYPE + { + FILTER_TYPE_NONE, + FILTER_TYPE_LINEAR, + FILTER_TYPE_NEAREST + }; + + enum WRAP_TYPE + { + WRAP_TYPE_BORDER, + WRAP_TYPE_EDGE, + WRAP_TYPE_REPEAT, + WRAP_TYPE_MIRRORED_REPEAT, + }; + + enum SCALE_TYPE + { + SCALE_TYPE_INPUT, + SCALE_TYPE_ABSOLUTE, + SCALE_TYPE_VIEWPORT, + }; + + struct FboScaleAxis + { + SCALE_TYPE type = SCALE_TYPE_INPUT; + float scale = 1.0; + unsigned int abs = 1; + }; + + struct FboScale + { + bool sRgbFramebuffer = false; + bool floatFramebuffer = false; + FboScaleAxis scaleX; + FboScaleAxis scaleY; + }; + + struct ShaderLut + { + std::string strId; + std::string path; + FILTER_TYPE filter = FILTER_TYPE_NONE; + WRAP_TYPE wrap = WRAP_TYPE_BORDER; + bool mipmap = false; + }; + + struct ShaderParameter + { + std::string strId; + std::string description; + float current = 0.0f; + float minimum = 0.0f; + float initial = 0.0f; + float maximum = 0.0f; + float step = 0.0f; + }; + + struct ShaderPass + { + std::string sourcePath; + std::string vertexSource; + std::string fragmentSource; + FILTER_TYPE filter = FILTER_TYPE_NONE; + WRAP_TYPE wrap = WRAP_TYPE_BORDER; + unsigned int frameCountMod = 0; + FboScale fbo; + bool mipmap = false; + + std::vector luts; + std::vector parameters; + }; + + struct float2 + { + float2() : x(0), y(0) {} + + template + float2(T x_, T y_) : x(static_cast(x_)), y(static_cast(y_)) + { + static_assert(std::is_arithmetic::value, "Not an arithmetic type"); + } + + template + T Max() { return static_cast(std::max(x, y)); } + template + T Min() { return static_cast(std::min(x, y)); } + + //TODO: move to CShaderUtilsDX +#ifdef _WIN32 + DirectX::XMFLOAT2 ToDXVector() const + { + return DirectX::XMFLOAT2(static_cast(x), static_cast(y)); + } +#endif + + float x; + float y; + }; +} +} diff --git a/xbmc/cores/RetroPlayer/shaders/ShaderUtils.cpp b/xbmc/cores/RetroPlayer/shaders/ShaderUtils.cpp new file mode 100644 index 0000000000000..763fa383e62de --- /dev/null +++ b/xbmc/cores/RetroPlayer/shaders/ShaderUtils.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2017-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "ShaderUtils.h" + +using namespace KODI; +using namespace SHADER; + +float2 CShaderUtils::GetOptimalTextureSize(float2 videoSize) +{ + unsigned sizeMax = videoSize.Max(); + unsigned size = 1; + + // Find smallest possible power-of-two size that can contain input texture + while (true) + { + if (size >= sizeMax) + break; + size *= 2; + } + return float2(size, size); +} diff --git a/xbmc/cores/RetroPlayer/shaders/ShaderUtils.h b/xbmc/cores/RetroPlayer/shaders/ShaderUtils.h new file mode 100644 index 0000000000000..5e0c384d4c212 --- /dev/null +++ b/xbmc/cores/RetroPlayer/shaders/ShaderUtils.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2017-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "ShaderTypes.h" + +namespace KODI +{ +namespace SHADER +{ + inline bool operator==(const float2& lhs, const float2& rhs) + { + return lhs.x == rhs.x && lhs.y == rhs.y; + } + + inline bool operator!=(const float2& lhs, const float2& rhs) + { + return !(lhs == rhs); + } + + class CShaderUtils + { + public: + /*! + * \brief Returns smallest possible power-of-two sized texture + */ + static float2 GetOptimalTextureSize(float2 videoSize); + }; +} +} diff --git a/xbmc/cores/RetroPlayer/shaders/windows/CMakeLists.txt b/xbmc/cores/RetroPlayer/shaders/windows/CMakeLists.txt new file mode 100644 index 0000000000000..6a5bf7716dfcc --- /dev/null +++ b/xbmc/cores/RetroPlayer/shaders/windows/CMakeLists.txt @@ -0,0 +1,17 @@ +set(SOURCES RPWinOutputShader.cpp + ShaderDX.cpp + ShaderLutDX.cpp + ShaderPresetDX.cpp + ShaderSamplerDX.cpp + ShaderUtilsDX.cpp) + +set(HEADERS RPWinOutputShader.h + ShaderDX.h + ShaderLutDX.h + ShaderPresetDX.h + ShaderSamplerDX.h + ShaderTextureDX.h + ShaderTypesDX.h + ShaderUtilsDX.h) + +core_add_library(rp-shaders-windows) diff --git a/xbmc/cores/RetroPlayer/rendering/VideoShaders/windows/RPWinOutputShader.cpp b/xbmc/cores/RetroPlayer/shaders/windows/RPWinOutputShader.cpp similarity index 93% rename from xbmc/cores/RetroPlayer/rendering/VideoShaders/windows/RPWinOutputShader.cpp rename to xbmc/cores/RetroPlayer/shaders/windows/RPWinOutputShader.cpp index c1364cade2ff2..fbbec5b9cde93 100644 --- a/xbmc/cores/RetroPlayer/rendering/VideoShaders/windows/RPWinOutputShader.cpp +++ b/xbmc/cores/RetroPlayer/shaders/windows/RPWinOutputShader.cpp @@ -1,27 +1,29 @@ /* - * Copyright (C) 2017-2018 Team Kodi + * Copyright (C) 2017-2019 Team Kodi * This file is part of Kodi - https://kodi.tv * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSES/README.md for more information. */ + #include "RPWinOutputShader.h" +#include "ShaderTypesDX.h" #include "utils/log.h" using namespace KODI; -using namespace RETRO; +using namespace SHADER; -bool CRPWinOutputShader::Create(SCALINGMETHOD scalingMethod) +bool CRPWinOutputShader::Create(RETRO::SCALINGMETHOD scalingMethod) { CWinShader::CreateVertexBuffer(4, sizeof(CUSTOMVERTEX)); DefinesMap defines; switch (scalingMethod) { - case SCALINGMETHOD::NEAREST: + case RETRO::SCALINGMETHOD::NEAREST: defines["SAMP_NEAREST"] = ""; break; - case SCALINGMETHOD::LINEAR: + case RETRO::SCALINGMETHOD::LINEAR: default: break; } diff --git a/xbmc/cores/RetroPlayer/rendering/VideoShaders/windows/RPWinOutputShader.h b/xbmc/cores/RetroPlayer/shaders/windows/RPWinOutputShader.h similarity index 81% rename from xbmc/cores/RetroPlayer/rendering/VideoShaders/windows/RPWinOutputShader.h rename to xbmc/cores/RetroPlayer/shaders/windows/RPWinOutputShader.h index 68466d9949fa6..312bd6396ab6e 100644 --- a/xbmc/cores/RetroPlayer/rendering/VideoShaders/windows/RPWinOutputShader.h +++ b/xbmc/cores/RetroPlayer/shaders/windows/RPWinOutputShader.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Team Kodi + * Copyright (C) 2017-2019 Team Kodi * This file is part of Kodi - https://kodi.tv * * SPDX-License-Identifier: GPL-2.0-or-later @@ -13,7 +13,7 @@ namespace KODI { -namespace RETRO +namespace SHADER { class CRPWinOutputShader : public CWinShader @@ -21,7 +21,7 @@ class CRPWinOutputShader : public CWinShader public: ~CRPWinOutputShader() = default; - bool Create(SCALINGMETHOD scalingMethod); + bool Create(RETRO::SCALINGMETHOD scalingMethod); void Render(CD3DTexture &sourceTexture, CRect sourceRect, const CPoint points[4] , CRect &viewPort, CD3DTexture *target, unsigned range = 0); @@ -39,16 +39,7 @@ class CRPWinOutputShader : public CWinShader { 0.f, 0.f }, { 0.f, 0.f }, }; - - struct CUSTOMVERTEX { - FLOAT x; - FLOAT y; - FLOAT z; - - FLOAT tu; - FLOAT tv; - }; }; -} // namespace RETRO +} // namespace SHADER } // namespace KODI diff --git a/xbmc/cores/RetroPlayer/shaders/windows/ShaderDX.cpp b/xbmc/cores/RetroPlayer/shaders/windows/ShaderDX.cpp new file mode 100644 index 0000000000000..1ad9ef4c4c4f9 --- /dev/null +++ b/xbmc/cores/RetroPlayer/shaders/windows/ShaderDX.cpp @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2017-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "ShaderDX.h" +#include "ShaderTextureDX.h" +#include "Application.h" +#include "cores/RetroPlayer/rendering/RenderContext.h" +#include "cores/RetroPlayer/rendering/RenderContext.h" +#include "cores/RetroPlayer/shaders/windows/ShaderTypesDX.h" +#include "cores/RetroPlayer/shaders/IShaderLut.h" +#include "cores/RetroPlayer/shaders/ShaderUtils.h" +#include "rendering/dx/RenderSystemDX.h" +#include "utils/log.h" +#include "utils/URIUtils.h" +#include "system.h" + +using namespace KODI; +using namespace SHADER; + +CShaderDX::CShaderDX(RETRO::CRenderContext &context) : + m_context(context) +{ +} + +CShaderDX::~CShaderDX() +{ + SAFE_RELEASE(m_pInputBuffer); +} + +bool CShaderDX::Create(const std::string& shaderSource, const std::string& shaderPath, ShaderParameterMap shaderParameters, + IShaderSampler* sampler, ShaderLutVec luts, float2 viewPortSize, unsigned frameCountMod) +{ + if (shaderPath.empty()) + { + CLog::Log(LOGERROR, "ShaderDX: Can't load empty shader path"); + return false; + } + + m_shaderSource = shaderSource; + m_shaderPath = shaderPath; + m_shaderParameters = shaderParameters; + m_pSampler = reinterpret_cast(sampler); + m_luts = luts; + m_viewportSize = viewPortSize; + m_frameCountMod = frameCountMod; + + DefinesMap defines; + + defines["HLSL_4"] = ""; // using Shader Model 4 + defines["HLSL_FX"] = ""; // and the FX11 framework + + // We implement runtime shader parameters ("#pragma parameter") + // NOTICE: Runtime shader parameters allow convenient experimentation with real-time + // feedback, as well as override-ability by presets, but sometimes they are + // much slower because they prevent static evaluation of a lot of math. + // Disabling them drastically speeds up shaders that use them heavily. + defines["PARAMETER_UNIFORM"] = ""; + + m_effect.AddIncludePath(URIUtils::GetBasePath(m_shaderPath)); + + if (!m_effect.Create(shaderSource, &defines)) + { + CLog::Log(LOGERROR, "%s: failed to load video shader: %s", __FUNCTION__, shaderPath.c_str()); + return false; + } + + return true; +} + +void CShaderDX::Render(IShaderTexture* source, IShaderTexture* target) +{ + auto* sourceDX = static_cast(source); + auto* targetDX = static_cast(target); + + // TODO: Doesn't work. Another PSSetSamplers gets called by FX11 right before rendering, overriding this + /* + CRenderSystemDX *renderingDx = static_cast(m_context.Rendering()); + renderingDx->Get3D11Context()->PSSetSamplers(2, 1, &m_pSampler); + */ + + SetShaderParameters( *sourceDX->GetPointer() ); + Execute({ targetDX->GetPointer() }, 4); +} + +void CShaderDX::SetShaderParameters(CD3DTexture& sourceTexture) +{ + m_effect.SetTechnique("TEQ"); + m_effect.SetResources("decal", { sourceTexture.GetAddressOfSRV() }, 1); + m_effect.SetMatrix("modelViewProj", reinterpret_cast(&m_MVP)); + // TODO(optimization): Add frame_count to separate cbuffer + m_effect.SetConstantBuffer("input", m_pInputBuffer); + for (const auto& param : m_shaderParameters) + m_effect.SetFloatArray(param.first.c_str(), ¶m.second, 1); + for (const auto& lut : m_luts) + { + auto* texture = dynamic_cast(lut->GetTexture()); + if (texture != nullptr) + m_effect.SetTexture(lut->GetID().c_str(), texture->GetShaderResource()); + } +} + +void CShaderDX::PrepareParameters(CPoint dest[4], bool isLastPass, uint64_t frameCount) +{ + UpdateInputBuffer(frameCount); + + CUSTOMVERTEX* v; + LockVertexBuffer(reinterpret_cast(&v)); + + if (!isLastPass) + { + // top left + v[0].x = -m_outputSize.x / 2; + v[0].y = -m_outputSize.y / 2; + // top right + v[1].x = m_outputSize.x / 2; + v[1].y = -m_outputSize.y / 2; + // bottom right + v[2].x = m_outputSize.x / 2; + v[2].y = m_outputSize.y / 2; + // bottom left + v[3].x = -m_outputSize.x / 2; + v[3].y = m_outputSize.y / 2; + } + else // last pass + { + // top left + v[0].x = dest[0].x - m_outputSize.x / 2; + v[0].y = dest[0].y - m_outputSize.y / 2; + // top right + v[1].x = dest[1].x - m_outputSize.x / 2; + v[1].y = dest[1].y - m_outputSize.y / 2; + // bottom right + v[2].x = dest[2].x - m_outputSize.x / 2; + v[2].y = dest[2].y - m_outputSize.y / 2; + // bottom left + v[3].x = dest[3].x - m_outputSize.x / 2; + v[3].y = dest[3].y - m_outputSize.y / 2; + } + + // top left + v[0].z = 0; + v[0].tu = 0; + v[0].tv = 0; + // top right + v[1].z = 0; + v[1].tu = 1; + v[1].tv = 0; + // bottom right + v[2].z = 0; + v[2].tu = 1; + v[2].tv = 1; + // bottom left + v[3].z = 0; + v[3].tu = 0; + v[3].tv = 1; + UnlockVertexBuffer(); +} + +bool CShaderDX::CreateVertexBuffer(unsigned vertCount, unsigned vertSize) +{ + return CWinShader::CreateVertexBuffer(vertCount, vertSize); +} + +bool CShaderDX::CreateInputLayout(D3D11_INPUT_ELEMENT_DESC* layout, unsigned numElements) +{ + return CWinShader::CreateInputLayout(layout, numElements); +} + +CD3DEffect& CShaderDX::GetEffect() +{ + return m_effect; +} + +void CShaderDX::UpdateMVP() +{ + float xScale = 1.0f / m_outputSize.x * 2.0f; + float yScale = -1.0f / m_outputSize.y * 2.0f; + + // Update projection matrix + m_MVP = XMFLOAT4X4( + xScale, 0, 0, 0, + 0, yScale, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + ); +} + +bool CShaderDX::CreateInputBuffer() +{ + CRenderSystemDX *renderingDx = static_cast(m_context.Rendering()); + + ID3D11Device* pDevice = DX::DeviceResources::Get()->GetD3DDevice(); + cbInput inputInitData = GetInputData(); + UINT inputBufSize = static_cast((sizeof(cbInput) + 15) & ~15); + CD3D11_BUFFER_DESC cbInputDesc(inputBufSize, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); + D3D11_SUBRESOURCE_DATA initInputSubresource = { &inputInitData, 0, 0 }; + if (FAILED(pDevice->CreateBuffer(&cbInputDesc, &initInputSubresource, &m_pInputBuffer))) + { + CLog::Log(LOGERROR, __FUNCTION__ " - Failed to create constant buffer for video shader input data."); + return false; + } + + return true; +} + +void CShaderDX::UpdateInputBuffer(uint64_t frameCount) +{ + ID3D11DeviceContext1 *pContext = DX::DeviceResources::Get()->GetD3DContext(); + + cbInput input = GetInputData(frameCount); + cbInput* pData; + void** ppData = reinterpret_cast(&pData); + + D3D11_MAPPED_SUBRESOURCE resource; + if (SUCCEEDED(pContext->Map(m_pInputBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource))) + { + *ppData = resource.pData; + + memcpy(*ppData, &input, sizeof(cbInput)); + pContext->Unmap(m_pInputBuffer, 0); + } +} + +CShaderDX::cbInput CShaderDX::GetInputData(uint64_t frameCount) +{ + if (m_frameCountMod != 0) + frameCount %= m_frameCountMod; + + cbInput input = { + // Resution of texture passed to the shader + { m_inputSize.ToDXVector() }, // video_size + // Shaders don't (and shouldn't) know about _actual_ texture + // size, because D3D gives them correct texture coordinates + { m_inputSize.ToDXVector() }, // texture_size + // As per the spec, this is the viewport resolution (not the + // output res of each shader + { m_viewportSize.ToDXVector() }, // output_size + // Current frame count that can be modulo'ed + { static_cast(frameCount) }, // frame_count + // Time always flows forward + { 1.0f } // frame_direction + }; + + return input; +} + +void CShaderDX::SetSizes(const float2& prevSize, const float2& nextSize) +{ + m_inputSize = prevSize; + m_outputSize = nextSize; +} diff --git a/xbmc/cores/RetroPlayer/shaders/windows/ShaderDX.h b/xbmc/cores/RetroPlayer/shaders/windows/ShaderDX.h new file mode 100644 index 0000000000000..2b5e574d61581 --- /dev/null +++ b/xbmc/cores/RetroPlayer/shaders/windows/ShaderDX.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2017-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "ShaderTextureDX.h" +#include "cores/RetroPlayer/shaders/IShader.h" +#include "cores/VideoPlayer/VideoRenderers/VideoShaders/WinVideoFilter.h" +#include "guilib/D3DResource.h" + +#include + +namespace KODI +{ +namespace RETRO +{ + class CRenderContext; +} + +namespace SHADER +{ + +// TODO: make renderer independent +// libretro's "Common shaders" +// Spec here: https://github.com/libretro/common-shaders/blob/master/docs/README +class CShaderDX : public CWinShader, public IShader +{ +public: + CShaderDX(RETRO::CRenderContext &context); + ~CShaderDX() override; + + // implementation of IShader + bool Create(const std::string& shaderSource, const std::string& shaderPath, ShaderParameterMap shaderParameters, + IShaderSampler* sampler, ShaderLutVec luts, float2 viewPortSize, unsigned frameCountMod = 0) override; + void Render(IShaderTexture* source, IShaderTexture* target) override; + void SetSizes(const float2& prevSize, const float2& nextSize) override; + void PrepareParameters(CPoint dest[4], bool isLastPass, uint64_t frameCount) override; + CD3DEffect& GetEffect(); + void UpdateMVP() override; + bool CreateInputBuffer() override; + void UpdateInputBuffer(uint64_t frameCount); + + // expose these from CWinShader + bool CreateVertexBuffer(unsigned vertCount, unsigned vertSize) override; + bool CreateInputLayout(D3D11_INPUT_ELEMENT_DESC *layout, unsigned numElements) override; + +protected: + void SetShaderParameters(CD3DTexture& sourceTexture); + +private: + struct cbInput + { + XMFLOAT2 video_size; + XMFLOAT2 texture_size; + XMFLOAT2 output_size; + float frame_count; + float frame_direction; + }; + + // Currently loaded shader's source code + std::string m_shaderSource; + + // Currently loaded shader's relative path + std::string m_shaderPath; + + // Array of shader parameters + ShaderParameterMap m_shaderParameters; + + // Sampler state + ID3D11SamplerState* m_pSampler = nullptr; + + // Look-up textures that the shader uses + ShaderLutVec m_luts; // todo: back to DX maybe + + // Resolution of the input of the shader + float2 m_inputSize; + + // Resolution of the output of the shader + float2 m_outputSize; + + // Resolution of the viewport/window + float2 m_viewportSize; + + // Resolution of the texture that holds the input + //float2 m_textureSize; + + // Holds the data bount to the input cbuffer (cbInput here) + ID3D11Buffer* m_pInputBuffer = nullptr; + + // Projection matrix + XMFLOAT4X4 m_MVP; + + // Value to modulo (%) frame count with + // Unused if 0 + unsigned m_frameCountMod = 0; + +private: + cbInput GetInputData(uint64_t frameCount = 0); + + // Construction parameters + RETRO::CRenderContext &m_context; +}; + +} +} diff --git a/xbmc/cores/RetroPlayer/shaders/windows/ShaderLutDX.cpp b/xbmc/cores/RetroPlayer/shaders/windows/ShaderLutDX.cpp new file mode 100644 index 0000000000000..0ce98f263bb6c --- /dev/null +++ b/xbmc/cores/RetroPlayer/shaders/windows/ShaderLutDX.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2017-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "ShaderLutDX.h" +#include "ShaderSamplerDX.h" +#include "ShaderTextureDX.h" +#include "ShaderUtilsDX.h" +#include "cores/RetroPlayer/rendering/RenderContext.h" +#include "cores/RetroPlayer/shaders/IShaderPreset.h" +#include "rendering/dx/RenderSystemDX.h" +#include "utils/log.h" + +#include + +using namespace KODI; +using namespace SHADER; + +CShaderLutDX::CShaderLutDX(const std::string& id, const std::string& path) : + IShaderLut(id, path) +{ +} + +CShaderLutDX::~CShaderLutDX() = default; + +bool CShaderLutDX::Create(RETRO::CRenderContext &context, const ShaderLut &lut) +{ + std::unique_ptr lutSampler(CreateLUTSampler(context, lut)); + if (!lutSampler) + { + CLog::Log(LOGWARNING, "%s - Couldn't create a LUT sampler for LUT %s", __FUNCTION__, lut.strId); + return false; + } + + std::unique_ptr lutTexture(CreateLUTexture(lut)); + if (!lutTexture) + { + CLog::Log(LOGWARNING, "%s - Couldn't create a LUT texture for LUT %s", __FUNCTION__, lut.strId); + return false; + } + + m_sampler = std::move(lutSampler); + m_texture = std::move(lutTexture); + + return true; +} + +std::unique_ptr CShaderLutDX::CreateLUTSampler(RETRO::CRenderContext &context, const ShaderLut &lut) +{ + CRenderSystemDX *renderingDx = static_cast(context.Rendering()); + + ID3D11SamplerState* samp; + D3D11_SAMPLER_DESC sampDesc; + + auto wrapType = CShaderUtilsDX::TranslateWrapType(lut.wrap); + auto filterType = lut.filter ? D3D11_FILTER_MIN_MAG_MIP_LINEAR : D3D11_FILTER_MIN_MAG_MIP_POINT; + + ZeroMemory(&sampDesc, sizeof(D3D11_SAMPLER_DESC)); + sampDesc.Filter = filterType; + sampDesc.AddressU = wrapType; + sampDesc.AddressV = wrapType; + sampDesc.AddressW = wrapType; + sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; + sampDesc.MinLOD = 0; + sampDesc.MaxLOD = D3D11_FLOAT32_MAX; + + FLOAT blackBorder[4] = { 0, 1, 0, 1 }; // TODO: turn this back to black + memcpy(sampDesc.BorderColor, &blackBorder, 4 * sizeof(FLOAT)); + + ID3D11Device* pDevice = DX::DeviceResources::Get()->GetD3DDevice(); + + if (FAILED(pDevice->CreateSamplerState(&sampDesc, &samp))) + { + CLog::Log(LOGWARNING, "%s - failed to create LUT sampler for LUT &s", __FUNCTION__, lut.path.c_str()); + return std::unique_ptr(); + } + + // todo: take care of allocation(?) + return std::unique_ptr(new CShaderSamplerDX(samp)); +} + +std::unique_ptr CShaderLutDX::CreateLUTexture(const ShaderLut &lut) +{ + CDXTexture* texture = static_cast(CDXTexture::LoadFromFile(lut.path)); + if (!texture) + { + CLog::Log(LOGERROR, "Couldn't open LUT %s", lut.path); + return std::unique_ptr(); + } + + if (lut.mipmap) + texture->SetMipmapping(); + + if (texture) + texture->LoadToGPU(); + + // todo: take care of allocation(?) + return std::unique_ptr(new CShaderTextureCDX(texture)); +} diff --git a/xbmc/cores/RetroPlayer/shaders/windows/ShaderLutDX.h b/xbmc/cores/RetroPlayer/shaders/windows/ShaderLutDX.h new file mode 100644 index 0000000000000..f45cf2ec5e7f8 --- /dev/null +++ b/xbmc/cores/RetroPlayer/shaders/windows/ShaderLutDX.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2017-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "cores/RetroPlayer/shaders/IShaderLut.h" +#include "cores/RetroPlayer/shaders/ShaderTypes.h" + +#include +#include +#include + +namespace KODI +{ +namespace RETRO +{ + class CRenderContext; +} + +namespace SHADER +{ + +class IShaderSampler; +class IShaderTexture; +struct ShaderLut; + +class CShaderLutDX: public IShaderLut +{ +public: + CShaderLutDX() = default; + CShaderLutDX(const std::string& id, const std::string& path); + + // Destructor + ~CShaderLutDX() override; + + // Implementation of IShaderLut + bool Create(RETRO::CRenderContext &context, const ShaderLut &lut) override; + IShaderSampler* GetSampler() override { return m_sampler.get(); } + IShaderTexture* GetTexture() override { return m_texture.get(); } + +private: + static std::unique_ptr CreateLUTSampler(RETRO::CRenderContext &context, const ShaderLut &lut); //! @todo Move context to class + static std::unique_ptr CreateLUTexture(const ShaderLut &lut); + + std::unique_ptr m_sampler; + std::unique_ptr m_texture; +}; + +} +} diff --git a/xbmc/cores/RetroPlayer/shaders/windows/ShaderPresetDX.cpp b/xbmc/cores/RetroPlayer/shaders/windows/ShaderPresetDX.cpp new file mode 100644 index 0000000000000..0298b1afe3aa4 --- /dev/null +++ b/xbmc/cores/RetroPlayer/shaders/windows/ShaderPresetDX.cpp @@ -0,0 +1,508 @@ +/* + * Copyright (C) 2017-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "ShaderPresetDX.h" +#include "addons/binary-addons/BinaryAddonBase.h" +#include "cores/RetroPlayer/rendering/RenderContext.h" +#include "cores/RetroPlayer/shaders/windows/ShaderDX.h" +#include "cores/RetroPlayer/shaders/windows/ShaderLutDX.h" +#include "cores/RetroPlayer/shaders/windows/ShaderTextureDX.h" +#include "cores/RetroPlayer/shaders/windows/ShaderTypesDX.h" +#include "cores/RetroPlayer/shaders/IShaderSampler.h" +#include "cores/RetroPlayer/shaders/ShaderPresetFactory.h" +#include "cores/RetroPlayer/shaders/ShaderUtils.h" +#include "rendering/dx/RenderSystemDX.h" +#include "utils/log.h" +#include "utils/URIUtils.h" +#include "ServiceBroker.h" + +#include + +using namespace KODI; +using namespace SHADER; + +CShaderPresetDX::CShaderPresetDX(RETRO::CRenderContext &context, unsigned videoWidth, unsigned videoHeight) + : m_context(context) + , m_videoSize(videoWidth, videoHeight) +{ + m_textureSize = CShaderUtils::GetOptimalTextureSize(m_videoSize); + + CRect viewPort; + m_context.GetViewPort(viewPort); + m_outputSize = { viewPort.Width(), viewPort.Height() }; +} + +ShaderParameterMap CShaderPresetDX::GetShaderParameters(const std::vector ¶meters, const std::string& sourceStr) const +{ + static const std::regex pragmaParamRegex("#pragma parameter ([a-zA-Z_][a-zA-Z0-9_]*)"); + std::smatch matches; + + std::vector validParams; + std::string::const_iterator searchStart(sourceStr.cbegin()); + while (regex_search(searchStart, sourceStr.cend(), matches, pragmaParamRegex)) + { + validParams.push_back(matches[1].str()); + searchStart += matches.position() + matches.length(); + } + + ShaderParameterMap matchParams; + for (const auto& match : validParams) // for each param found in the source code + { + for (const auto& parameter : parameters) // for each param found in the preset file + { + if (match == parameter.strId) // if they match + { + // The add-on has already handled parsing and overwriting default + // parameter values from the preset file. The final value we + // should use is in the 'current' field. + matchParams[match] = parameter.current; + break; + } + } + } + + return matchParams; +} + +CShaderPresetDX::~CShaderPresetDX() +{ + DisposeShaders(); + // The gui is going to render after this, so apply the state required + m_context.ApplyStateBlock(); +} + +bool CShaderPresetDX::ReadPresetFile(const std::string& presetPath) +{ + return CServiceBroker::GetGameServices().VideoShaders().LoadPreset(presetPath, *this); +} + +bool CShaderPresetDX::RenderUpdate(const CPoint dest[], IShaderTexture* source, IShaderTexture* target) +{ + // Save the viewport + CRect viewPort; + m_context.GetViewPort(viewPort); + + // Handle resizing of the viewport (window) + UpdateViewPort(viewPort); + + // Update shaders/shader textures if required + if (!Update()) + return false; + + PrepareParameters(target, dest); + + // At this point, the input video has been rendered to the first texture ("source", not m_pShaderTextures[0]) + + IShader* firstShader = m_pShaders.front().get(); + CShaderTextureCD3D* firstShaderTexture = m_pShaderTextures.front().get(); + IShader* lastShader = m_pShaders.back().get(); + + const unsigned passesNum = static_cast(m_pShaderTextures.size()); + + if (passesNum == 1) + m_pShaders.front()->Render(source, target); + else if (passesNum == 2) + { + // Apply first pass + RenderShader(firstShader, source, firstShaderTexture); + // Apply last pass + RenderShader(lastShader, firstShaderTexture, target); + } + else + { + // Apply first pass + RenderShader(firstShader, source, firstShaderTexture); + + // Apply all passes except the first and last one (which needs to be applied to the backbuffer) + for (unsigned int shaderIdx = 1; + shaderIdx < static_cast(m_pShaders.size()) - 1; + ++shaderIdx) + { + IShader* shader = m_pShaders[shaderIdx].get(); + CShaderTextureCD3D* prevTexture = m_pShaderTextures[shaderIdx - 1].get(); + CShaderTextureCD3D* texture = m_pShaderTextures[shaderIdx].get(); + RenderShader(shader, prevTexture, texture); + } + + // Apply last pass and write to target (backbuffer) instead of the last texture + CShaderTextureCD3D* secToLastTexture = m_pShaderTextures[m_pShaderTextures.size() - 2].get(); + RenderShader(lastShader, secToLastTexture, target); + } + + m_frameCount += static_cast(m_speed); + + // Restore our view port. + m_context.SetViewPort(viewPort); + + return true; +} + +void CShaderPresetDX::RenderShader(IShader* shader, IShaderTexture* source, IShaderTexture* target) const +{ + CRect newViewPort(0.f, 0.f, target->GetWidth(), target->GetHeight()); + m_context.SetViewPort(newViewPort); + m_context.SetScissors(newViewPort); + + shader->Render(source, target); +} + +bool CShaderPresetDX::Update() +{ + auto updateFailed = [this](const std::string& msg) + { + m_failedPaths.insert(m_presetPath); + auto message = "CShaderPresetDX::Update: " + msg + ". Disabling video shaders."; + CLog::Log(LOGWARNING, message.c_str()); + DisposeShaders(); + return false; + }; + + if (m_bPresetNeedsUpdate && !HasPathFailed(m_presetPath)) + { + DisposeShaders(); + + if (m_presetPath.empty()) + // No preset should load, just return false, we shouldn't add "" to the failed paths + return false; + + if (!ReadPresetFile(m_presetPath)) + { + CLog::Log(LOGERROR, "%s - couldn't load shader preset %s or the shaders it references", __FUNCTION__, m_presetPath.c_str()); + return false; + } + + if (!CreateShaders()) + return updateFailed("Failed to initialize shaders"); + + if (!CreateLayouts()) + return updateFailed("Failed to create layouts"); + + if (!CreateBuffers()) + return updateFailed("Failed to initialize buffers"); + + if (!CreateShaderTextures()) + return updateFailed("A shader texture failed to init"); + + if (!CreateSamplers()) + return updateFailed("Failed to create samplers"); + } + + if (m_pShaders.empty()) + return false; + + // Each pass must have its own texture and the opposite is also true + if (m_pShaders.size() != m_pShaderTextures.size()) + return updateFailed("A shader or texture failed to init"); + + m_bPresetNeedsUpdate = false; + return true; +} + +bool CShaderPresetDX::CreateShaderTextures() +{ + m_pShaderTextures.clear(); + + //CD3DTexture* fTexture(new CD3DTexture()); + //auto res = fTexture->Create(m_outputSize.x, m_outputSize.y, 1, + // D3D11_USAGE_DEFAULT, DXGI_FORMAT_B8G8R8A8_UNORM, nullptr, 0); + //if (!res) + //{ + // CLog::Log(LOGERROR, "Couldn't create a intial video shader texture"); + // return false; + //} + //firstTexture.reset(new CShaderTextureDX(fTexture)); + + float2 prevSize = m_videoSize; + + unsigned int numPasses = static_cast(m_passes.size()); + + for (unsigned shaderIdx = 0; shaderIdx < numPasses; ++shaderIdx) + { + ShaderPass& pass = m_passes[shaderIdx]; + + // resolve final texture resolution, taking scale type and scale multiplier into account + + float2 scaledSize; + switch (pass.fbo.scaleX.type) + { + case SCALE_TYPE_ABSOLUTE: + scaledSize.x = static_cast(pass.fbo.scaleX.abs); + break; + case SCALE_TYPE_VIEWPORT: + scaledSize.x = m_outputSize.x; + break; + case SCALE_TYPE_INPUT: + default: + scaledSize.x = prevSize.x; + break; + } + switch (pass.fbo.scaleY.type) + { + case SCALE_TYPE_ABSOLUTE: + scaledSize.y = static_cast(pass.fbo.scaleY.abs); + break; + case SCALE_TYPE_VIEWPORT: + scaledSize.y = m_outputSize.y; + break; + case SCALE_TYPE_INPUT: + default: + scaledSize.y = prevSize.y; + break; + } + + // if the scale was unspecified + if (pass.fbo.scaleX.scale == 0 && pass.fbo.scaleY.scale == 0) + { + // if the last shader has the scale unspecified + if (shaderIdx == numPasses - 1) + { + // we're supposed to output at full (viewport) res + // TODO: Thus, we can also (maybe) bypass rendering to an intermediate render target (on the last pass) + scaledSize.x = m_outputSize.x; + scaledSize.y = m_outputSize.y; + } + } + else + { + scaledSize.x *= pass.fbo.scaleX.scale; + scaledSize.y *= pass.fbo.scaleY.scale; + } + + // For reach pass, create the texture + + // Determine the framebuffer data format + DXGI_FORMAT textureFormat; + if (pass.fbo.floatFramebuffer) + { + // Give priority to float framebuffer parameter (we can't use both float and sRGB) + textureFormat = DXGI_FORMAT_R32G32B32A32_FLOAT; + } + else + { + if (pass.fbo.sRgbFramebuffer) + textureFormat = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; + else + textureFormat = DXGI_FORMAT_B8G8R8A8_UNORM; + } + + CD3DTexture* texture(new CD3DTexture()); + if (!texture->Create( + static_cast(scaledSize.x), + static_cast(scaledSize.y), + 1, + D3D11_USAGE_DEFAULT, + textureFormat, + nullptr, + 0)) + { + CLog::Log(LOGERROR, "Couldn't create a texture for video shader %s.", pass.sourcePath.c_str()); + return false; + } + m_pShaderTextures.emplace_back(new CShaderTextureCD3D(texture)); + + // notify shader of its source and dest size + m_pShaders[shaderIdx]->SetSizes(prevSize, scaledSize); + + prevSize = scaledSize; + } + return true; +} + +bool CShaderPresetDX::CreateShaders() +{ + auto numPasses = m_passes.size(); + // todo: replace with per-shader texture size + // todo: actually use this + m_textureSize = CShaderUtils::GetOptimalTextureSize(m_videoSize); + + // todo: is this pass specific? + ShaderLutVec passLUTsDX; + for (unsigned shaderIdx = 0; shaderIdx < numPasses; ++shaderIdx) + { + const auto& pass = m_passes[shaderIdx]; + + for (unsigned i = 0; i < pass.luts.size(); ++i) + { + auto& lutStruct = pass.luts[i]; + + ShaderLutPtr passLut(new CShaderLutDX(lutStruct.strId, lutStruct.path)); + if (passLut->Create(m_context, lutStruct)) + passLUTsDX.emplace_back(std::move(passLut)); + } + + // For reach pass, create the shader + std::unique_ptr videoShader(new CShaderDX(m_context)); + + auto shaderSrc = pass.vertexSource; // also contains fragment source + auto shaderPath = pass.sourcePath; + + // Get only the parameters belonging to this specific shader + ShaderParameterMap passParameters = GetShaderParameters(pass.parameters, pass.vertexSource); + IShaderSampler* passSampler = reinterpret_cast(pass.filter ? m_pSampLinear : m_pSampNearest); //! @todo Wrap in CShaderSamplerDX instead of reinterpret_cast + + if (!videoShader->Create(shaderSrc, shaderPath, passParameters, passSampler, passLUTsDX, m_outputSize, pass.frameCountMod)) + { + CLog::Log(LOGERROR, "Couldn't create a video shader"); + return false; + } + m_pShaders.push_back(std::move(videoShader)); + } + return true; +} + +bool CShaderPresetDX::CreateSamplers() +{ + CRenderSystemDX *renderingDx = static_cast(m_context.Rendering()); + + // Describe the Sampler States + // As specified in the common-shaders spec + D3D11_SAMPLER_DESC sampDesc; + ZeroMemory(&sampDesc, sizeof(D3D11_SAMPLER_DESC)); + sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; + sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER; + sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER; + sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER; + sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; + sampDesc.MinLOD = 0; + sampDesc.MaxLOD = D3D11_FLOAT32_MAX; + FLOAT blackBorder[4] = { 1, 0, 0, 1 }; // TODO: turn this back to black + memcpy(sampDesc.BorderColor, &blackBorder, 4 * sizeof(FLOAT)); + + ID3D11Device* pDevice = DX::DeviceResources::Get()->GetD3DDevice(); + + if (FAILED(pDevice->CreateSamplerState(&sampDesc, &m_pSampNearest))) + return false; + + D3D11_SAMPLER_DESC sampDescLinear = sampDesc; + sampDescLinear.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + if (FAILED(pDevice->CreateSamplerState(&sampDescLinear, &m_pSampLinear))) + return false; + + return true; +} + +bool CShaderPresetDX::CreateLayouts() +{ + for (auto& videoShader : m_pShaders) + { + videoShader->CreateVertexBuffer(4, sizeof(CUSTOMVERTEX)); + // Create input layout + D3D11_INPUT_ELEMENT_DESC layout[] = + { + { "SV_POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 1, DXGI_FORMAT_R32G32_FLOAT, 0, 20, D3D11_INPUT_PER_VERTEX_DATA, 0 } + }; + + if (!videoShader->CreateInputLayout(layout, ARRAYSIZE(layout))) + { + CLog::Log(LOGERROR, __FUNCTION__": Failed to create input layout for Input Assembler."); + return false; + } + } + return true; +} + +bool CShaderPresetDX::CreateBuffers() +{ + for (auto& videoShader : m_pShaders) + videoShader->CreateInputBuffer(); + return true; +} + +void CShaderPresetDX::PrepareParameters(const IShaderTexture* texture, const CPoint dest[]) +{ + if (m_dest[0] != dest[0] || m_dest[1] != dest[1] + || m_dest[2] != dest[2] || m_dest[3] != dest[3] + || texture->GetWidth() != m_outputSize.x + || texture->GetHeight() != m_outputSize.y) + { + for (size_t i = 0; i < 4; ++i) + m_dest[i] = dest[i]; + + m_outputSize = { texture->GetWidth(), texture->GetHeight() }; + + // Update projection matrix and update video shaders + UpdateMVPs(); + UpdateViewPort(); + } + + // prepare params for all shaders except the last (needs special flag) + for (unsigned shaderIdx = 0; shaderIdx < m_pShaders.size() - 1; ++shaderIdx) + { + auto& videoShader = m_pShaders[shaderIdx]; + videoShader->PrepareParameters(m_dest, false, static_cast(m_frameCount)); + } + + // prepare params for last shader + m_pShaders.back()->PrepareParameters(m_dest, true, static_cast(m_frameCount)); +} + +bool CShaderPresetDX::HasPathFailed(const std::string& path) const +{ + return m_failedPaths.find(path) != m_failedPaths.end(); +} + +void CShaderPresetDX::DisposeShaders() +{ + //firstTexture.reset(); + m_pShaders.clear(); + m_pShaderTextures.clear(); + m_passes.clear(); + m_bPresetNeedsUpdate = true; +} + +//CShaderTextureDX* CShaderPresetDX::GetFirstTexture() +//{ +// return firstTexture.get(); +//} + +bool CShaderPresetDX::SetShaderPreset(const std::string& shaderPresetPath) +{ + m_bPresetNeedsUpdate = true; + m_presetPath = shaderPresetPath; + return Update(); +} + +const std::string& CShaderPresetDX::GetShaderPreset() const +{ + return m_presetPath; +} + +void CShaderPresetDX::SetVideoSize(const unsigned videoWidth, const unsigned videoHeight) +{ + m_videoSize = { videoWidth, videoHeight }; + m_textureSize = CShaderUtils::GetOptimalTextureSize(m_videoSize); +} + +void CShaderPresetDX::UpdateMVPs() +{ + for (auto& videoShader : m_pShaders) + videoShader->UpdateMVP(); +} + +void CShaderPresetDX::UpdateViewPort() +{ + CRect viewPort; + m_context.GetViewPort(viewPort); + UpdateViewPort(viewPort); +} + +void CShaderPresetDX::UpdateViewPort(CRect viewPort) +{ + float2 currentViewPortSize = { viewPort.Width(), viewPort.Height() }; + if (currentViewPortSize != m_outputSize) + { + m_outputSize = currentViewPortSize; + //CreateShaderTextures(); + // Just re-make everything. Else we get resizing bugs. + // Could probably refine that to only rebuild certain things, for a tiny bit of perf. (only when resizing) + m_bPresetNeedsUpdate = true; + Update(); + } +} diff --git a/xbmc/cores/RetroPlayer/shaders/windows/ShaderPresetDX.h b/xbmc/cores/RetroPlayer/shaders/windows/ShaderPresetDX.h new file mode 100644 index 0000000000000..19ed6eca0ee28 --- /dev/null +++ b/xbmc/cores/RetroPlayer/shaders/windows/ShaderPresetDX.h @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2017-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "ShaderDX.h" +#include "ShaderTextureDX.h" +#include "cores/RetroPlayer/shaders/IShaderPreset.h" +#include "cores/RetroPlayer/shaders/ShaderTypes.h" +#include "games/GameServices.h" +#include "utils/Geometry.h" + +#include +#include +#include +#include + +namespace ADDON +{ + class CShaderPreset; + class CShaderPresetAddon; +} + +namespace KODI +{ +namespace RETRO +{ + class CRenderContext; +} + +namespace SHADER +{ + +class IShaderTexture; + +class CShaderPresetDX : public IShaderPreset +{ +public: + // Instance of CShaderPreset + explicit CShaderPresetDX(RETRO::CRenderContext &context, unsigned videoWidth = 0, unsigned videoHeight = 0); + ~CShaderPresetDX() override; + + // implementation of IShaderPreset + bool ReadPresetFile(const std::string& presetPath) override; + bool RenderUpdate(const CPoint dest[], IShaderTexture* source, IShaderTexture* target) override; + void SetSpeed(double speed) override { m_speed = speed; } + void SetVideoSize(const unsigned videoWidth, const unsigned videoHeight) override; + bool SetShaderPreset(const std::string& shaderPresetPath) override; + const std::string& GetShaderPreset() const override; + ShaderPassVec& GetPasses() override { return m_passes; } + + bool Update(); + //CShaderTextureDX* GetFirstTexture(); + +private: + bool CreateShaderTextures(); + bool CreateShaders(); + bool CreateSamplers(); + bool CreateLayouts(); + bool CreateBuffers(); + void UpdateViewPort(); + void UpdateViewPort(CRect viewPort); + void UpdateMVPs(); + void DisposeShaders(); + void PrepareParameters(const IShaderTexture* texture, const CPoint dest[]); + void RenderShader(IShader* shader, IShaderTexture* source, IShaderTexture* target) const; + bool HasPathFailed(const std::string& path) const; + + // Construction parameters + RETRO::CRenderContext &m_context; + + // Relative path of the currently loaded shader preset + // If empty, it means that a preset is not currently loaded + std::string m_presetPath; + + // Video shaders for the shader passes + std::vector> m_pShaders; + + // Intermediate textures used for pixel shader passes + std::vector> m_pShaderTextures; + + // First texture (this won't be needed when we have RGB rendering + std::unique_ptr firstTexture; + + // Was the shader preset changed during the last frame? + bool m_bPresetNeedsUpdate = true; + + // Size of the viewport + float2 m_outputSize; + + // The size of the input texture itself + // Power-of-two sized. + float2 m_textureSize; + + // Size of the actual source video data (ie. 160x144 for the Game Boy) + float2 m_videoSize; + + // Number of frames that have passed + float m_frameCount = 0.0f; + + // Point/nearest neighbor sampler + ID3D11SamplerState* m_pSampNearest = nullptr; + + // Linear sampler + ID3D11SamplerState* m_pSampLinear = nullptr; + + // Set of paths of presets that are known to not load correctly + // Should not contain "" (empty path) because this signifies that a preset is not loaded + std::set m_failedPaths; + + // Array of vertices that comprise the full viewport + CPoint m_dest[4]; + + // Playback speed + double m_speed = 0.0; + + ShaderParameterMap GetShaderParameters(const std::vector ¶meters, const std::string& sourceStr) const; + + ShaderPassVec m_passes; +}; + +} +} diff --git a/xbmc/cores/RetroPlayer/shaders/windows/ShaderSamplerDX.cpp b/xbmc/cores/RetroPlayer/shaders/windows/ShaderSamplerDX.cpp new file mode 100644 index 0000000000000..1f2670d87ee1f --- /dev/null +++ b/xbmc/cores/RetroPlayer/shaders/windows/ShaderSamplerDX.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2017-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "ShaderSamplerDX.h" +#include "system.h" + +using namespace KODI; +using namespace SHADER; + +CShaderSamplerDX::CShaderSamplerDX(ID3D11SamplerState* sampler) + : m_sampler(sampler) +{ +} + +CShaderSamplerDX::~CShaderSamplerDX() +{ + SAFE_RELEASE(m_sampler); +} diff --git a/xbmc/cores/RetroPlayer/shaders/windows/ShaderSamplerDX.h b/xbmc/cores/RetroPlayer/shaders/windows/ShaderSamplerDX.h new file mode 100644 index 0000000000000..0323341af8054 --- /dev/null +++ b/xbmc/cores/RetroPlayer/shaders/windows/ShaderSamplerDX.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2017-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "cores/RetroPlayer/shaders/IShaderSampler.h" + +#include + +namespace KODI +{ + +namespace SHADER +{ + +class CShaderSamplerDX : public IShaderSampler +{ +public: + CShaderSamplerDX(ID3D11SamplerState* sampler); + ~CShaderSamplerDX() override; + +private: + ID3D11SamplerState* m_sampler; +}; + +} +} diff --git a/xbmc/cores/RetroPlayer/shaders/windows/ShaderTextureDX.h b/xbmc/cores/RetroPlayer/shaders/windows/ShaderTextureDX.h new file mode 100644 index 0000000000000..320c96ef30444 --- /dev/null +++ b/xbmc/cores/RetroPlayer/shaders/windows/ShaderTextureDX.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2017-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "cores/RetroPlayer/shaders/IShaderTexture.h" +#include "guilib/D3DResource.h" +#include "guilib/Texture.h" + +#include + +namespace KODI +{ + +namespace SHADER +{ + +template +class CShaderTextureDX : public IShaderTexture +{ +public: + CShaderTextureDX() = default; + CShaderTextureDX(TextureType* texture) : m_texture(texture) {} + CShaderTextureDX(TextureType& texture) : m_texture(&texture) {} + + // Destructor + // Don't delete texture since it wasn't created here + ~CShaderTextureDX() override = default; + + float GetWidth() const override { return static_cast(m_texture->GetWidth()); } + float GetHeight() const override { return static_cast(m_texture->GetHeight()); } + + void SetTexture(TextureType* newTexture) { m_texture = newTexture; } + + ID3D11ShaderResourceView *GetShaderResource() const { return m_texture->GetShaderResource(); } + + TextureType* GetPointer() { return m_texture; } + +private: + TextureType* m_texture = nullptr; +}; + +using CShaderTextureCD3D = CShaderTextureDX; +using CShaderTextureCDX = CShaderTextureDX; + +} +} diff --git a/xbmc/cores/RetroPlayer/shaders/windows/ShaderTypesDX.h b/xbmc/cores/RetroPlayer/shaders/windows/ShaderTypesDX.h new file mode 100644 index 0000000000000..37ab692b338cf --- /dev/null +++ b/xbmc/cores/RetroPlayer/shaders/windows/ShaderTypesDX.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2017-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include +#include + +namespace KODI +{ +namespace SHADER +{ + +class CShaderLutDX; +using ShaderLutPtrDX = std::shared_ptr; +using ShaderLutVecDX = std::vector; + +struct CUSTOMVERTEX +{ + FLOAT x; + FLOAT y; + FLOAT z; + + FLOAT tu; + FLOAT tv; +}; + +} +} diff --git a/xbmc/cores/RetroPlayer/shaders/windows/ShaderUtilsDX.cpp b/xbmc/cores/RetroPlayer/shaders/windows/ShaderUtilsDX.cpp new file mode 100644 index 0000000000000..85de1aaf22ff3 --- /dev/null +++ b/xbmc/cores/RetroPlayer/shaders/windows/ShaderUtilsDX.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2017-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "ShaderUtilsDX.h" + +using namespace KODI; +using namespace SHADER; + +D3D11_TEXTURE_ADDRESS_MODE CShaderUtilsDX::TranslateWrapType(WRAP_TYPE wrap) +{ + D3D11_TEXTURE_ADDRESS_MODE dxWrap; + switch(wrap) + { + case WRAP_TYPE_EDGE: + dxWrap = D3D11_TEXTURE_ADDRESS_CLAMP; + break; + case WRAP_TYPE_REPEAT: + dxWrap = D3D11_TEXTURE_ADDRESS_WRAP; + break; + case WRAP_TYPE_MIRRORED_REPEAT: + dxWrap = D3D11_TEXTURE_ADDRESS_MIRROR; + break; + case WRAP_TYPE_BORDER: + default: + dxWrap = D3D11_TEXTURE_ADDRESS_BORDER; + } + return dxWrap; +} diff --git a/xbmc/cores/RetroPlayer/shaders/windows/ShaderUtilsDX.h b/xbmc/cores/RetroPlayer/shaders/windows/ShaderUtilsDX.h new file mode 100644 index 0000000000000..126008c4a1e02 --- /dev/null +++ b/xbmc/cores/RetroPlayer/shaders/windows/ShaderUtilsDX.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2017-2019 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "cores/RetroPlayer/shaders/ShaderTypes.h" + +#include + +namespace KODI +{ +namespace SHADER +{ + class CShaderUtilsDX + { + public: + static D3D11_TEXTURE_ADDRESS_MODE TranslateWrapType(WRAP_TYPE wrap); + }; + + /* todo + operator DirectX::XMFLOAT2(const float2& f) const + { + return DirectX::XMFLOAT2(static_cast(f.x), static_cast(f.y)); + } + */ +} +} diff --git a/xbmc/filesystem/AddonsDirectory.cpp b/xbmc/filesystem/AddonsDirectory.cpp index 544128b444a31..ba90c4cae355c 100644 --- a/xbmc/filesystem/AddonsDirectory.cpp +++ b/xbmc/filesystem/AddonsDirectory.cpp @@ -76,6 +76,7 @@ const std::set lookAndFeelTypes = { const std::set gameTypes = { ADDON_GAME_CONTROLLER, + ADDON_SHADERDLL, ADDON_GAMEDLL, ADDON_GAME, ADDON_RESOURCE_GAMES, @@ -128,9 +129,15 @@ static bool IsGameResource(const AddonPtr& addon) static bool IsGameSupportAddon(const AddonPtr& addon) { - return addon->Type() == ADDON_GAMEDLL && - !std::static_pointer_cast(addon)->SupportsPath() && - !std::static_pointer_cast(addon)->SupportsStandalone(); + if (addon->Type() == ADDON_GAMEDLL && + !std::static_pointer_cast(addon)->SupportsPath() && + !std::static_pointer_cast(addon)->SupportsStandalone()) + return true; + + if (addon->Type() == ADDON_SHADERDLL) + return true; + + return false; } static bool IsGameAddon(const AddonPtr& addon) diff --git a/xbmc/games/GameServices.cpp b/xbmc/games/GameServices.cpp index 5fbad15ae3b0e..88fa4769ae434 100644 --- a/xbmc/games/GameServices.cpp +++ b/xbmc/games/GameServices.cpp @@ -7,6 +7,7 @@ */ #include "GameServices.h" +#include "cores/RetroPlayer/shaders/ShaderPresetFactory.h" #include "controllers/Controller.h" #include "controllers/ControllerManager.h" #include "games/GameSettings.h" @@ -18,11 +19,14 @@ using namespace GAME; CGameServices::CGameServices(CControllerManager &controllerManager, RETRO:: CGUIGameRenderManager &renderManager, PERIPHERALS::CPeripherals &peripheralManager, - const CProfileManager &profileManager) : + const CProfileManager &profileManager, + ADDON::CAddonMgr &addons, + ADDON::CBinaryAddonManager &binaryAddons) : m_controllerManager(controllerManager), m_gameRenderManager(renderManager), m_profileManager(profileManager), - m_gameSettings(new CGameSettings()) + m_gameSettings(new CGameSettings()), + m_videoShaders(new SHADER::CShaderPresetFactory(addons, binaryAddons)) { } diff --git a/xbmc/games/GameServices.h b/xbmc/games/GameServices.h index 48f61b1bb1d6a..35f412bc31756 100644 --- a/xbmc/games/GameServices.h +++ b/xbmc/games/GameServices.h @@ -15,6 +15,12 @@ class CProfileManager; +namespace ADDON +{ + class CAddonMgr; + class CBinaryAddonManager; +} + namespace PERIPHERALS { class CPeripherals; @@ -27,6 +33,11 @@ namespace RETRO class CGUIGameRenderManager; } +namespace SHADER +{ + class CShaderPresetFactory; +} + namespace GAME { class CControllerManager; @@ -38,7 +49,9 @@ namespace GAME CGameServices(CControllerManager &controllerManager, RETRO::CGUIGameRenderManager &renderManager, PERIPHERALS::CPeripherals &peripheralManager, - const CProfileManager &profileManager); + const CProfileManager &profileManager, + ADDON::CAddonMgr &addons, + ADDON::CBinaryAddonManager &binaryAddons); ~CGameServices(); ControllerPtr GetController(const std::string& controllerId); @@ -53,6 +66,8 @@ namespace GAME RETRO::CGUIGameRenderManager &GameRenderManager() { return m_gameRenderManager; } + SHADER::CShaderPresetFactory &VideoShaders() { return *m_videoShaders; } + private: // Construction parameters CControllerManager &m_controllerManager; @@ -61,6 +76,7 @@ namespace GAME // Game services std::unique_ptr m_gameSettings; + std::unique_ptr m_videoShaders; }; } } diff --git a/xbmc/games/dialogs/CMakeLists.txt b/xbmc/games/dialogs/CMakeLists.txt index c1f7b46c7a5f2..c7f658c75102f 100644 --- a/xbmc/games/dialogs/CMakeLists.txt +++ b/xbmc/games/dialogs/CMakeLists.txt @@ -1,7 +1,8 @@ set(SOURCES GUIDialogSelectGameClient.cpp ) -set(HEADERS GUIDialogSelectGameClient.h +set(HEADERS DialogGameDefines.h + GUIDialogSelectGameClient.h ) core_add_library(gamedialogs) diff --git a/xbmc/games/dialogs/DialogGameDefines.h b/xbmc/games/dialogs/DialogGameDefines.h new file mode 100644 index 0000000000000..81165811eaa10 --- /dev/null +++ b/xbmc/games/dialogs/DialogGameDefines.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2017 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this Program; see the file COPYING. If not, see + * . + * + */ +#pragma once + +// String of list item property "game.videofilter" when no filter is set +#define PROPERTY_NO_VIDEO_FILTER "" diff --git a/xbmc/games/dialogs/osd/DialogGameVideoFilter.cpp b/xbmc/games/dialogs/osd/DialogGameVideoFilter.cpp index d599c9d97967b..48902e14d44da 100644 --- a/xbmc/games/dialogs/osd/DialogGameVideoFilter.cpp +++ b/xbmc/games/dialogs/osd/DialogGameVideoFilter.cpp @@ -9,16 +9,28 @@ #include "DialogGameVideoFilter.h" #include "cores/RetroPlayer/guibridge/GUIGameVideoHandle.h" #include "cores/RetroPlayer/rendering/RenderVideoSettings.h" +#include "cores/RetroPlayer/shaders/ShaderPresetFactory.h" +#include "games/dialogs/DialogGameDefines.h" #include "guilib/LocalizeStrings.h" #include "guilib/WindowIDs.h" #include "settings/GameSettings.h" #include "settings/MediaSettings.h" +#include "utils/log.h" #include "utils/StringUtils.h" +#include "utils/URIUtils.h" #include "utils/Variant.h" +#include "utils/XBMCTinyXML.h" +#include "URL.h" + +#include +#include "ServiceBroker.h" +#include "games/GameServices.h" using namespace KODI; using namespace GAME; +#define PRESETS_ADDON_NAME "game.shader.presets" + namespace { struct ScalingMethodProperties @@ -50,6 +62,7 @@ void CDialogGameVideoFilter::PreInit() { m_items.Clear(); + InitScalingMethods(); InitVideoFilters(); if (m_items.Size() == 0) @@ -61,7 +74,7 @@ void CDialogGameVideoFilter::PreInit() m_bHasDescription = false; } -void CDialogGameVideoFilter::InitVideoFilters() +void CDialogGameVideoFilter::InitScalingMethods() { if (m_gameVideoHandle) { @@ -82,6 +95,75 @@ void CDialogGameVideoFilter::InitVideoFilters() } } +void CDialogGameVideoFilter::InitVideoFilters() +{ + std::vector videoFilters; + + // TODO: Have the add-on give us the xml as a string (or parse it) + static const std::string addonPath = std::string("special://xbmcbinaddons/") + PRESETS_ADDON_NAME; + static const std::string xmlPath = addonPath + "/resources/ShaderPresetsDefault.xml"; + std::string basePath = URIUtils::GetBasePath(xmlPath); + + CXBMCTinyXML xml = CXBMCTinyXML(xmlPath); + + if (!xml.LoadFile()) + { + CLog::Log(LOGERROR, "%s - Couldn't load shader presets from default .xml, %s", __FUNCTION__, CURL::GetRedacted(xmlPath).c_str()); + return; + } + + auto root = xml.RootElement(); + TiXmlNode* child = nullptr; + + while ((child = root->IterateChildren(child))) + { + VideoFilterProperties videoFilter; + + if (child->FirstChild() == nullptr) + continue; + + TiXmlNode* pathNode; + if ((pathNode = child->FirstChild("path"))) + if ((pathNode = pathNode->FirstChild())) + videoFilter.path = URIUtils::AddFileToFolder(basePath, pathNode->Value()); + TiXmlNode* nameIndexNode; + if ((nameIndexNode = child->FirstChild("name"))) + if ((nameIndexNode = nameIndexNode->FirstChild())) + videoFilter.nameIndex = atoi(nameIndexNode->Value()); + TiXmlNode* categoryIndexNode; + if ((categoryIndexNode = child->FirstChild("category"))) + if ((categoryIndexNode = categoryIndexNode->FirstChild())) + videoFilter.categoryIndex = atoi(categoryIndexNode->Value()); + TiXmlNode* descriptionNode; + if ((descriptionNode = child->FirstChild("description"))) + if ((descriptionNode = descriptionNode->FirstChild())) + videoFilter.descriptionIndex = atoi(descriptionNode->Value()); + + videoFilters.emplace_back(videoFilter); + } + + CLog::Log(LOGDEBUG, "Loaded %d shader presets from default .xml, %s", videoFilters.size(), CURL::GetRedacted(xmlPath).c_str()); + + for (const auto &videoFilter : videoFilters) + { + bool canLoadPreset = CServiceBroker::GetGameServices().VideoShaders().CanLoadPreset(videoFilter.path); + + if (!canLoadPreset) + continue; + + auto localizedName = GetLocalizedString(videoFilter.nameIndex); + auto localizedCategory = GetLocalizedString(videoFilter.categoryIndex); + auto localizedDescription = GetLocalizedString(videoFilter.descriptionIndex); + + CFileItemPtr item = std::make_shared(localizedName); + item->SetLabel2(localizedCategory); + item->SetProperty("game.videofilter", CVariant{ videoFilter.path }); + item->SetProperty("game.videofilterdescription", CVariant{ localizedDescription }); + + m_items.Add(std::move(item)); + } +} + void CDialogGameVideoFilter::GetItems(CFileItemList &items) { for (const auto &item : m_items) @@ -98,7 +180,7 @@ void CDialogGameVideoFilter::OnItemFocus(unsigned int index) std::string description; GetProperties(*item, videoFilter, description); - CGameSettings &gameSettings = CMediaSettings::GetInstance().GetCurrentGameSettings(); + ::CGameSettings &gameSettings = CMediaSettings::GetInstance().GetCurrentGameSettings(); if (gameSettings.VideoFilter() != videoFilter) { @@ -118,7 +200,7 @@ void CDialogGameVideoFilter::OnItemFocus(unsigned int index) unsigned int CDialogGameVideoFilter::GetFocusedItem() const { - CGameSettings &gameSettings = CMediaSettings::GetInstance().GetCurrentGameSettings(); + ::CGameSettings &gameSettings = CMediaSettings::GetInstance().GetCurrentGameSettings(); for (int i = 0; i < m_items.Size(); i++) { @@ -140,6 +222,11 @@ void CDialogGameVideoFilter::PostExit() m_items.Clear(); } +std::string CDialogGameVideoFilter::GetLocalizedString(uint32_t code) +{ + return g_localizeStrings.GetAddonString(PRESETS_ADDON_NAME, code); +} + void CDialogGameVideoFilter::GetProperties(const CFileItem &item, std::string &videoFilter, std::string &description) { videoFilter = item.GetProperty("game.videofilter").asString(); diff --git a/xbmc/games/dialogs/osd/DialogGameVideoFilter.h b/xbmc/games/dialogs/osd/DialogGameVideoFilter.h index 1ba7eebc39046..a8014bf85d990 100644 --- a/xbmc/games/dialogs/osd/DialogGameVideoFilter.h +++ b/xbmc/games/dialogs/osd/DialogGameVideoFilter.h @@ -31,12 +31,23 @@ namespace GAME void PostExit() override; private: + void InitScalingMethods(); void InitVideoFilters(); static void GetProperties(const CFileItem &item, std::string &videoFilter, std::string &description); CFileItemList m_items; + static std::string GetLocalizedString(uint32_t code); + + struct VideoFilterProperties + { + std::string path; + int nameIndex; + int categoryIndex; + int descriptionIndex; + }; + //! \brief Set to true when a description has first been set bool m_bHasDescription = false; }; diff --git a/xbmc/guilib/D3DResource.cpp b/xbmc/guilib/D3DResource.cpp index bc87dd7b10682..1b4623952ee62 100644 --- a/xbmc/guilib/D3DResource.cpp +++ b/xbmc/guilib/D3DResource.cpp @@ -12,6 +12,7 @@ #include "utils/log.h" #include "rendering/dx/DeviceResources.h" #include "rendering/dx/RenderContext.h" +#include "utils/URIUtils.h" #include @@ -556,6 +557,7 @@ CD3DEffect::CD3DEffect() m_effect = nullptr; m_techniquie = nullptr; m_currentPass = nullptr; + m_includePaths.insert("special://xbmc/system/shaders/"); } CD3DEffect::~CD3DEffect() @@ -599,16 +601,39 @@ void CD3DEffect::OnCreateDevice() HRESULT CD3DEffect::Open(D3D_INCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID* ppData, UINT* pBytes) { XFILE::CFile includeFile; + bool found = false; + std::string fileName; - std::string fileName("special://xbmc/system/shaders/"); - fileName.append(pFileName); + for (const auto& includePath : m_includePaths) + { + fileName = includePath; + std::string includeURL = ""; + size_t endOfURL = 0; + if (URIUtils::IsURL(includePath)) + { + endOfURL = includePath.find(":") + 3; // include "://" + includeURL = includePath.substr(0, endOfURL); + fileName.erase(0, endOfURL); + } + + fileName = URIUtils::CanonicalizePath( + URIUtils::AddFileToFolder(fileName, pFileName)); + fileName.insert(0, includeURL); - if (!includeFile.Open(fileName)) + if (includeFile.Open(fileName)) + { + found = true; + break; + } + } + if (!found) { - CLog::LogF(LOGERROR, "Could not open 3DLUT file: %s", fileName); + CLog::LogF(LOGERROR, "Could not open include file: %s", fileName); return E_FAIL; } + m_includePaths.insert(URIUtils::GetBasePath(fileName)); + int64_t length = includeFile.GetLength(); void *pData = malloc(length); if (includeFile.Read(pData, length) != length) @@ -660,12 +685,17 @@ bool CD3DEffect::SetTechnique(LPCSTR handle) } bool CD3DEffect::SetTexture(LPCSTR handle, CD3DTexture &texture) +{ + return SetTexture(handle, texture.GetShaderResource()); +} + +bool CD3DEffect::SetTexture(LPCSTR handle, ID3D11ShaderResourceView* resourceView) { if (m_effect) { ID3DX11EffectShaderResourceVariable* var = m_effect->GetVariableByName(handle)->AsShaderResource(); if (var->IsValid()) - return SUCCEEDED(var->SetResource(texture.GetShaderResource())); + return SUCCEEDED(var->SetResource(resourceView)); } return false; } @@ -704,6 +734,11 @@ bool CD3DEffect::SetScalar(LPCSTR handle, float value) return false; } +void CD3DEffect::AddIncludePath(const std::string& includePath) +{ + m_includePaths.insert(includePath); +} + bool CD3DEffect::Begin(UINT *passes, DWORD flags) { if (m_effect && m_techniquie) @@ -779,6 +814,9 @@ bool CD3DEffect::CreateEffect() //dwShaderFlags |= D3DCOMPILE_DEBUG; // Disable optimizations to further improve shader debugging //dwShaderFlags |= D3DCOMPILE_SKIP_OPTIMIZATION; +#else + dwShaderFlags |= D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY; + dwShaderFlags |= D3DCOMPILE_OPTIMIZATION_LEVEL3; #endif hr = D3DX11CompileEffectFromMemory(m_effectString.c_str(), m_effectString.length(), "", &definemacros[0], this, diff --git a/xbmc/guilib/D3DResource.h b/xbmc/guilib/D3DResource.h index 53beeff717c6b..6822863974b91 100644 --- a/xbmc/guilib/D3DResource.h +++ b/xbmc/guilib/D3DResource.h @@ -13,6 +13,7 @@ #include "GUIColorManager.h" #include +#include #include #include #include @@ -167,9 +168,11 @@ class CD3DEffect : public ID3DResource, public ID3DInclude bool SetMatrix(LPCSTR handle, const float* mat); bool SetTechnique(LPCSTR handle); bool SetTexture(LPCSTR handle, CD3DTexture &texture); + bool SetTexture(LPCSTR handle, ID3D11ShaderResourceView* resourceView); bool SetResources(LPCSTR handle, ID3D11ShaderResourceView** ppSRViews, size_t count); bool SetConstantBuffer(LPCSTR handle, ID3D11Buffer *buffer); bool SetScalar(LPCSTR handle, float value); + void AddIncludePath(const std::string& includePath); bool Begin(UINT *passes, DWORD flags); bool BeginPass(UINT pass); bool EndPass(); @@ -192,6 +195,7 @@ class CD3DEffect : public ID3DResource, public ID3DInclude Microsoft::WRL::ComPtr m_effect; Microsoft::WRL::ComPtr m_techniquie; Microsoft::WRL::ComPtr m_currentPass; + std::set m_includePaths; }; class CD3DBuffer : public ID3DResource From 98b7055c3ba74c5019c6a83e79b975828549c201 Mon Sep 17 00:00:00 2001 From: Garrett Brown Date: Tue, 24 Oct 2017 13:16:22 -0700 Subject: [PATCH 4/4] Change video filter dialog to use imported shader preset strings --- xbmc/games/dialogs/osd/DialogGameVideoFilter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xbmc/games/dialogs/osd/DialogGameVideoFilter.cpp b/xbmc/games/dialogs/osd/DialogGameVideoFilter.cpp index 48902e14d44da..de67a9cde9d30 100644 --- a/xbmc/games/dialogs/osd/DialogGameVideoFilter.cpp +++ b/xbmc/games/dialogs/osd/DialogGameVideoFilter.cpp @@ -101,7 +101,7 @@ void CDialogGameVideoFilter::InitVideoFilters() // TODO: Have the add-on give us the xml as a string (or parse it) static const std::string addonPath = std::string("special://xbmcbinaddons/") + PRESETS_ADDON_NAME; - static const std::string xmlPath = addonPath + "/resources/ShaderPresetsDefault.xml"; + static const std::string xmlPath = "special://xbmc/system/shaders/presets/shader-manifest.xml"; std::string basePath = URIUtils::GetBasePath(xmlPath); CXBMCTinyXML xml = CXBMCTinyXML(xmlPath); @@ -224,7 +224,7 @@ void CDialogGameVideoFilter::PostExit() std::string CDialogGameVideoFilter::GetLocalizedString(uint32_t code) { - return g_localizeStrings.GetAddonString(PRESETS_ADDON_NAME, code); + return g_localizeStrings.Get(code); } void CDialogGameVideoFilter::GetProperties(const CFileItem &item, std::string &videoFilter, std::string &description)