dep/reshadefx: Update to 7bdfb03

This commit is contained in:
Stenzek 2024-09-08 19:19:58 +10:00
parent 0f8d512732
commit c63c4f58ef
No known key found for this signature in database
25 changed files with 6041 additions and 3244 deletions

View file

@ -0,0 +1,427 @@
/*
DisplayDepth by CeeJay.dk (with many updates and additions by the Reshade community)
Visualizes the depth buffer. The distance of pixels determine their brightness.
Close objects are dark. Far away objects are bright.
Use this to configure the depth input preprocessor definitions (RESHADE_DEPTH_INPUT_*).
*/
#include "ReShade.fxh"
// -- Basic options --
#if RESHADE_DEPTH_INPUT_IS_UPSIDE_DOWN
#define TEXT_UPSIDE_DOWN "1"
#define TEXT_UPSIDE_DOWN_ALTER "0"
#else
#define TEXT_UPSIDE_DOWN "0"
#define TEXT_UPSIDE_DOWN_ALTER "1"
#endif
#if RESHADE_DEPTH_INPUT_IS_REVERSED
#define TEXT_REVERSED "1"
#define TEXT_REVERSED_ALTER "0"
#else
#define TEXT_REVERSED "0"
#define TEXT_REVERSED_ALTER "1"
#endif
#if RESHADE_DEPTH_INPUT_IS_LOGARITHMIC
#define TEXT_LOGARITHMIC "1"
#define TEXT_LOGARITHMIC_ALTER "0"
#else
#define TEXT_LOGARITHMIC "0"
#define TEXT_LOGARITHMIC_ALTER "1"
#endif
// "ui_text" was introduced in ReShade 4.5, so cannot show instructions in older versions
uniform int iUIPresentType <
ui_label = "Present type";
ui_label_ja_jp = "画面効果";
ui_type = "combo";
ui_items = "Depth map\0Normal map\0Show both (Vertical 50/50)\0";
ui_items_ja_jp = "深度マップ\0法線マップ\0両方を表示 (左右分割)\0";
#if __RESHADE__ < 40500
ui_tooltip =
#else
ui_text =
#endif
"The right settings need to be set in the dialog that opens after clicking the \"Edit global preprocessor definitions\" button above.\n"
"\n"
"RESHADE_DEPTH_INPUT_IS_UPSIDE_DOWN is currently set to " TEXT_UPSIDE_DOWN ".\n"
"If the Depth map is shown upside down set it to " TEXT_UPSIDE_DOWN_ALTER ".\n"
"\n"
"RESHADE_DEPTH_INPUT_IS_REVERSED is currently set to " TEXT_REVERSED ".\n"
"If close objects in the Depth map are bright and far ones are dark set it to " TEXT_REVERSED_ALTER ".\n"
"Also try this if you can see the normals, but the depth view is all black.\n"
"\n"
"RESHADE_DEPTH_INPUT_IS_LOGARITHMIC is currently set to " TEXT_LOGARITHMIC ".\n"
"If the Normal map has banding artifacts (extra stripes) set it to " TEXT_LOGARITHMIC_ALTER ".";
ui_text_ja_jp =
#if ADDON_ADJUST_DEPTH
"Adjust Depthアドオンのインストールを検出しました。\n"
"'設定に保存して反映する'ボタンをクリックすると、このエフェクトで調節した全ての変数が共通設定に反映されます。\n"
"または、上の'プリプロセッサの定義を編集'ボタンをクリックした後に開くダイアログで直接編集する事もできます。";
#else
"調節が終わったら、上の'プリプロセッサの定義を編集'ボタンをクリックした後に開くダイアログに入力する必要があります。\n"
"\n"
"RESHADE_DEPTH_INPUT_IS_UPSIDE_DOWNは現在" TEXT_UPSIDE_DOWN "に設定されています。\n"
"深度マップが上下逆さまに表示されている場合は" TEXT_UPSIDE_DOWN_ALTER "に変更して下さい。\n"
"\n"
"RESHADE_DEPTH_INPUT_IS_REVERSEDは現在" TEXT_REVERSED "に設定されています。\n"
"画面効果が深度マップのとき、近くの形状がより白く、遠くの形状がより黒い場合は" TEXT_REVERSED_ALTER "に変更して下さい。\n"
"また、法線マップで形が判別出来るが、深度マップが真っ暗に見えるという場合も、この設定の変更を試して下さい。\n"
"\n"
"RESHADE_DEPTH_INPUT_IS_LOGARITHMICは現在" TEXT_LOGARITHMIC "に設定されています。\n"
"画面効果に実際のレンダリングと合致しない縞模様がある場合は" TEXT_LOGARITHMIC_ALTER "に変更して下さい。";
#endif
ui_tooltip_ja_jp =
"'深度マップ'は、形状の遠近を白黒で表現します。正しい見え方では、近くの形状ほど黒く、遠くの形状ほど白くなります。\n"
"'法線マップ'は、形状を滑らかに表現します。正しい見え方では、全体的に青緑風で、地平線を見たときに地面が緑掛かった色合いになります。\n"
"'両方を表示 (左右分割)'が選択された場合は、左に法線マップ、右に深度マップを表示します。";
> = 2;
uniform bool bUIShowOffset <
ui_label = "Blend Depth map into the image (to help with finding the right offset)";
ui_label_ja_jp = "透かし比較";
ui_tooltip_ja_jp = "補正作業を支援するために、画面効果を半透過で適用します。";
> = false;
uniform bool bUIUseLivePreview <
ui_category = "Preview settings";
ui_category_ja_jp = "基本的な補正";
#if __RESHADE__ <= 50902
ui_category_closed = true;
#elif !ADDON_ADJUST_DEPTH
ui_category_toggle = true;
#endif
ui_label = "Show live preview and ignore preprocessor definitions";
ui_label_ja_jp = "プリプロセッサの定義を無視 (補正プレビューをオン)";
ui_tooltip = "Enable this to preview with the current preset settings instead of the global preprocessor settings.";
ui_tooltip_ja_jp =
"共通設定に保存されたプリプロセッサの定義ではなく、これより下のプレビュー設定を使用するには、これを有効にします。\n"
#if ADDON_ADJUST_DEPTH
"設定の準備が出来たら、'設定に保存して反映する'ボタンをクリックしてから、このチェックボックスをオフにして下さい。"
#else
"設定の準備が出来たら、上の'プリプロセッサの定義を編集'ボタンをクリックした後に開くダイアログに入力して下さい。"
#endif
"\n\n"
"プレビューをオンにした場合と比較して画面効果がまったく同じになれば、正しく設定が反映されています。";
> = false;
#if __RESHADE__ <= 50902
uniform int iUIUpsideDown <
#else
uniform bool iUIUpsideDown <
#endif
ui_category = "Preview settings";
ui_label = "Upside Down";
ui_label_ja_jp = "深度バッファの上下反転を修正";
#if __RESHADE__ <= 50902
ui_type = "combo";
ui_items = "Off\0On\0";
#endif
ui_text_ja_jp =
"\n"
#if ADDON_ADJUST_DEPTH
"項目にカーソルを合わせると、設定が必要な状況の説明が表示されます。"
#else
"項目にカーソルを合わせると、設定が必要な状況の説明と、プリプロセッサの定義が表示されます。"
#endif
;
ui_tooltip_ja_jp =
"深度マップが上下逆さまに表示されている場合は変更して下さい。"
#if !ADDON_ADJUST_DEPTH
"\n\n"
"定義名は次の通りです。文字は完全に一致する必要があり、半角大文字の英字とアンダーバーを用いなければなりません。\n"
"RESHADE_DEPTH_INPUT_IS_UPSIDE_DOWN=値\n"
"定義値は次の通りです。オンの場合は1、オフの場合は0を指定して下さい。\n"
"RESHADE_DEPTH_INPUT_IS_UPSIDE_DOWN=1\n"
"RESHADE_DEPTH_INPUT_IS_UPSIDE_DOWN=0"
#endif
;
> = RESHADE_DEPTH_INPUT_IS_UPSIDE_DOWN;
#if __RESHADE__ <= 50902
uniform int iUIReversed <
#else
uniform bool iUIReversed <
#endif
ui_category = "Preview settings";
ui_label = "Reversed";
ui_label_ja_jp = "深度バッファの奥行反転を修正";
#if __RESHADE__ <= 50902
ui_type = "combo";
ui_items = "Off\0On\0";
#endif
ui_tooltip_ja_jp =
"画面効果が深度マップのとき、近くの形状が明るく、遠くの形状が暗い場合は変更して下さい。\n"
"また、法線マップで形が判別出来るが、深度マップが真っ暗に見えるという場合も、この設定の変更を試して下さい。"
#if !ADDON_ADJUST_DEPTH
"\n\n"
"定義名は次の通りです。文字は完全に一致する必要があり、半角大文字の英字とアンダーバーを用いなければなりません。\n"
"RESHADE_DEPTH_INPUT_IS_REVERSED=値\n"
"定義値は次の通りです。オンの場合は1、オフの場合は0を指定して下さい。\n"
"RESHADE_DEPTH_INPUT_IS_REVERSED=1\n"
"RESHADE_DEPTH_INPUT_IS_REVERSED=0"
#endif
;
> = RESHADE_DEPTH_INPUT_IS_REVERSED;
#if __RESHADE__ <= 50902
uniform int iUILogarithmic <
#else
uniform bool iUILogarithmic <
#endif
ui_category = "Preview settings";
ui_label = "Logarithmic";
ui_label_ja_jp = "深度バッファを対数分布として扱うように修正";
#if __RESHADE__ <= 50902
ui_type = "combo";
ui_items = "Off\0On\0";
#endif
ui_tooltip = "Change this setting if the displayed surface normals have stripes in them.";
ui_tooltip_ja_jp =
"画面効果に実際のゲーム画面と合致しない縞模様がある場合は変更して下さい。"
#if !ADDON_ADJUST_DEPTH
"\n\n"
"定義名は次の通りです。文字は完全に一致する必要があり、半角大文字の英字とアンダーバーを用いなければなりません。\n"
"RESHADE_DEPTH_INPUT_IS_LOGARITHMIC=値\n"
"定義値は次の通りです。オンの場合は1、オフの場合は0を指定して下さい。\n"
"RESHADE_DEPTH_INPUT_IS_LOGARITHMIC=1\n"
"RESHADE_DEPTH_INPUT_IS_LOGARITHMIC=0"
#endif
;
> = RESHADE_DEPTH_INPUT_IS_LOGARITHMIC;
// -- Advanced options --
uniform float2 fUIScale <
ui_category = "Preview settings";
ui_label = "Scale";
ui_label_ja_jp = "拡大率";
ui_type = "drag";
ui_text =
"\n"
" * Advanced options\n"
"\n"
"The following settings also need to be set using \"Edit global preprocessor definitions\" above in order to take effect.\n"
"You can preview how they will affect the Depth map using the controls below.\n"
"\n"
"It is rarely necessary to change these though, as their defaults fit almost all games.\n\n";
ui_text_ja_jp =
"\n"
" * その他の補正 (不定形またはその他)\n"
"\n"
"これより下は、深度バッファが不定形など、特別なケース向けの設定です。\n"
"通常はこれより上の'基本的な補正'のみでほとんどのゲームに適合します。\n"
"また、これらの設定は画質の向上にはまったく役に立ちません。\n\n";
ui_tooltip =
"Best use 'Present type'->'Depth map' and enable 'Offset' in the options below to set the scale.\n"
"Use these values for:\nRESHADE_DEPTH_INPUT_X_SCALE=<left value>\nRESHADE_DEPTH_INPUT_Y_SCALE=<right value>\n"
"\n"
"If you know the right resolution of the games depth buffer then this scale value is simply the ratio\n"
"between the correct resolution and the resolution Reshade thinks it is.\n"
"For example:\n"
"If it thinks the resolution is 1920 x 1080, but it's really 1280 x 720 then the right scale is (1.5 , 1.5)\n"
"because 1920 / 1280 is 1.5 and 1080 / 720 is also 1.5, so 1.5 is the right scale for both the x and the y";
ui_tooltip_ja_jp =
"深度バッファの解像度がクライアント解像度と異なる場合に変更して下さい。\n"
"このスケール値は、深度バッファの解像度とクライアント解像度との単純な比率になります。\n"
"深度バッファの解像度が1280×720でクライアント解像度が1920×1080の場合、横の比率が1920÷1280、縦の比率が1080÷720となります。\n"
"計算した結果を設定すると、値はそれぞれX_SCALE=1.5、Y_SCALE=1.5となります。"
#if !ADDON_ADJUST_DEPTH
"\n\n"
"定義名は次の通りです。文字は完全に一致する必要があり、半角大文字の英字とアンダーバーを用いなければなりません。\n"
"RESHADE_DEPTH_INPUT_X_SCALE=横の値\n"
"RESHADE_DEPTH_INPUT_Y_SCALE=縦の値\n"
"定義値は次の通りです。横の値はX_SCALE、縦の値はY_SCALEに指定して下さい。\n"
"RESHADE_DEPTH_INPUT_X_SCALE=1.0\n"
"RESHADE_DEPTH_INPUT_Y_SCALE=1.0"
#endif
;
ui_min = 0.0; ui_max = 2.0;
ui_step = 0.001;
> = float2(RESHADE_DEPTH_INPUT_X_SCALE, RESHADE_DEPTH_INPUT_Y_SCALE);
uniform int2 iUIOffset <
ui_category = "Preview settings";
ui_label = "Offset";
ui_label_ja_jp = "位置オフセット";
ui_type = "slider";
ui_tooltip =
"Best use 'Present type'->'Depth map' and enable 'Offset' in the options below to set the offset in pixels.\n"
"Use these values for:\nRESHADE_DEPTH_INPUT_X_PIXEL_OFFSET=<left value>\nRESHADE_DEPTH_INPUT_Y_PIXEL_OFFSET=<right value>";
ui_tooltip_ja_jp =
"深度バッファにレンダリングされた物体の形状が画面効果と重なり合っていない場合に変更して下さい。\n"
"この値は、ピクセル単位で指定します。"
#if !ADDON_ADJUST_DEPTH
"\n\n"
"定義名は次の通りです。文字は完全に一致する必要があり、半角大文字の英字とアンダーバーを用いなければなりません。\n"
"RESHADE_DEPTH_INPUT_X_PIXEL_OFFSET=横の値\n"
"RESHADE_DEPTH_INPUT_Y_PIXEL_OFFSET=縦の値\n"
"定義値は次の通りです。横の値はX_PIXEL_OFFSET、縦の値はY_PIXEL_OFFSETに指定して下さい。\n"
"RESHADE_DEPTH_INPUT_X_PIXEL_OFFSET=0.0\n"
"RESHADE_DEPTH_INPUT_Y_PIXEL_OFFSET=0.0"
#endif
;
ui_min = -BUFFER_SCREEN_SIZE;
ui_max = BUFFER_SCREEN_SIZE;
ui_step = 1;
> = int2(RESHADE_DEPTH_INPUT_X_PIXEL_OFFSET, RESHADE_DEPTH_INPUT_Y_PIXEL_OFFSET);
uniform float fUIFarPlane <
ui_category = "Preview settings";
ui_label = "Far Plane";
ui_label_ja_jp = "遠点距離";
ui_type = "drag";
ui_tooltip =
"RESHADE_DEPTH_LINEARIZATION_FAR_PLANE=<value>\n"
"Changing this value is not necessary in most cases.";
ui_tooltip_ja_jp =
"深度マップの色合いが距離感と合致しない、法線マップの表面が平面に見える、などの場合に変更して下さい。\n"
"遠点距離を1000に設定すると、ゲームの描画距離が1000メートルであると見なします。\n\n"
"このプレビュー画面はあくまでプレビューであり、ほとんどの場合、深度バッファは深度マップの色数より遥かに高い精度で表現されています。\n"
"例えば、10m前後の距離の形状が純粋な黒に見えるからという理由で値を変更しないで下さい。"
#if !ADDON_ADJUST_DEPTH
"\n\n"
"定義名は次の通りです。文字は完全に一致する必要があり、半角大文字の英字とアンダーバーを用いなければなりません。\n"
"RESHADE_DEPTH_LINEARIZATION_FAR_PLANE=値\n"
"定義値は次の通りです。\n"
"RESHADE_DEPTH_LINEARIZATION_FAR_PLANE=1000.0"
#endif
;
ui_min = 0.0; ui_max = 1000.0;
ui_step = 0.1;
> = RESHADE_DEPTH_LINEARIZATION_FAR_PLANE;
uniform float fUIDepthMultiplier <
ui_category = "Preview settings";
ui_label = "Multiplier";
ui_label_ja_jp = "深度乗数";
ui_type = "drag";
ui_tooltip = "RESHADE_DEPTH_MULTIPLIER=<value>";
ui_tooltip_ja_jp =
"特定のエミュレータソフトウェアにおける深度バッファを修正するため、特別に追加された変数です。\n"
"この値は僅かな変更でも計算式を破壊するため、設定すべき値を知らない場合は変更しないで下さい。"
#if !ADDON_ADJUST_DEPTH
"\n\n"
"定義名は次の通りです。文字は完全に一致する必要があり、半角大文字の英字とアンダーバーを用いなければなりません。\n"
"RESHADE_DEPTH_MULTIPLIER=値\n"
"定義値は次の通りです。\n"
"RESHADE_DEPTH_MULTIPLIER=1.0"
#endif
;
ui_min = 0.0; ui_max = 1000.0;
ui_step = 0.001;
> = RESHADE_DEPTH_MULTIPLIER;
float GetLinearizedDepth(float2 texcoord)
{
if (!bUIUseLivePreview)
{
return ReShade::GetLinearizedDepth(texcoord);
}
else
{
if (iUIUpsideDown) // RESHADE_DEPTH_INPUT_IS_UPSIDE_DOWN
texcoord.y = 1.0 - texcoord.y;
texcoord.x /= fUIScale.x; // RESHADE_DEPTH_INPUT_X_SCALE
texcoord.y /= fUIScale.y; // RESHADE_DEPTH_INPUT_Y_SCALE
texcoord.x -= iUIOffset.x * BUFFER_RCP_WIDTH; // RESHADE_DEPTH_INPUT_X_PIXEL_OFFSET
texcoord.y += iUIOffset.y * BUFFER_RCP_HEIGHT; // RESHADE_DEPTH_INPUT_Y_PIXEL_OFFSET
float depth = tex2Dlod(ReShade::DepthBuffer, float4(texcoord, 0, 0)).x * fUIDepthMultiplier;
const float C = 0.01;
if (iUILogarithmic) // RESHADE_DEPTH_INPUT_IS_LOGARITHMIC
depth = (exp(depth * log(C + 1.0)) - 1.0) / C;
if (iUIReversed) // RESHADE_DEPTH_INPUT_IS_REVERSED
depth = 1.0 - depth;
const float N = 1.0;
depth /= fUIFarPlane - depth * (fUIFarPlane - N);
return depth;
}
}
float3 GetScreenSpaceNormal(float2 texcoord)
{
float3 offset = float3(BUFFER_PIXEL_SIZE, 0.0);
float2 posCenter = texcoord.xy;
float2 posNorth = posCenter - offset.zy;
float2 posEast = posCenter + offset.xz;
float3 vertCenter = float3(posCenter - 0.5, 1) * GetLinearizedDepth(posCenter);
float3 vertNorth = float3(posNorth - 0.5, 1) * GetLinearizedDepth(posNorth);
float3 vertEast = float3(posEast - 0.5, 1) * GetLinearizedDepth(posEast);
return normalize(cross(vertCenter - vertNorth, vertCenter - vertEast)) * 0.5 + 0.5;
}
void PS_DisplayDepth(in float4 position : SV_Position, in float2 texcoord : TEXCOORD, out float3 color : SV_Target)
{
float3 depth = GetLinearizedDepth(texcoord).xxx;
float3 normal = GetScreenSpaceNormal(texcoord);
// Ordered dithering
#if 1
const float dither_bit = 8.0; // Number of bits per channel. Should be 8 for most monitors.
// Calculate grid position
float grid_position = frac(dot(texcoord, (BUFFER_SCREEN_SIZE * float2(1.0 / 16.0, 10.0 / 36.0)) + 0.25));
// Calculate how big the shift should be
float dither_shift = 0.25 * (1.0 / (pow(2, dither_bit) - 1.0));
// Shift the individual colors differently, thus making it even harder to see the dithering pattern
float3 dither_shift_RGB = float3(dither_shift, -dither_shift, dither_shift); // Subpixel dithering
// Modify shift acording to grid position.
dither_shift_RGB = lerp(2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position);
depth += dither_shift_RGB;
#endif
color = depth;
if (iUIPresentType == 1)
color = normal;
if (iUIPresentType == 2)
color = lerp(normal, depth, step(BUFFER_WIDTH * 0.5, position.x));
if (bUIShowOffset)
{
float3 color_orig = tex2D(ReShade::BackBuffer, texcoord).rgb;
// Blend depth and back buffer color with 'overlay' so the offset is more noticeable
color = lerp(2 * color * color_orig, 1.0 - 2.0 * (1.0 - color) * (1.0 - color_orig), max(color.r, max(color.g, color.b)) < 0.5 ? 0.0 : 1.0);
}
}
technique DisplayDepth <
ui_tooltip =
"This shader helps you set the right preprocessor settings for depth input.\n"
"To set the settings click on 'Edit global preprocessor definitions' and set them there - not in this shader.\n"
"The settings will then take effect for all shaders, including this one.\n"
"\n"
"By default calculated normals and depth are shown side by side.\n"
"Normals (on the left) should look smooth and the ground should be greenish when looking at the horizon.\n"
"Depth (on the right) should show close objects as dark and use gradually brighter shades the further away objects are.\n";
ui_tooltip_ja_jp =
"これは、深度バッファの入力をReShade側の計算式に合わせる調節をするための、設定作業の支援に特化した特殊な扱いのエフェクトです。\n"
"初期状態では「両方を表示」が選択されており、左に法線マップ、右に深度マップが表示されます。\n"
"\n"
"法線マップ(左側)は、形状を滑らかに表現します。正しい設定では、全体的に青緑風で、地平線を見たときに地面が緑を帯びた色になります。\n"
"深度マップ(右側)は、形状の遠近を白黒で表現します。正しい設定では、近くの形状ほど黒く、遠くの形状ほど白くなります。\n"
"\n"
#if ADDON_ADJUST_DEPTH
"設定を完了するには、DisplayDepth.fxエフェクトの変数の一覧にある'設定に保存して反映する'ボタンをクリックして下さい。\n"
#else
"設定を完了するには、エフェクト変数の編集画面にある'プリプロセッサの定義を編集'ボタンをクリックした後に開くダイアログに入力して下さい。\n"
#endif
"すると、インストール先のゲームに対して共通の設定として保存され、他のプリセットでも正しく表示されるようになります。";
>
{
pass
{
VertexShader = PostProcessVS;
PixelShader = PS_DisplayDepth;
}
}

View file

@ -1,3 +1,7 @@
/*
* SPDX-License-Identifier: CC0-1.0
*/
#pragma once #pragma once
#if !defined(__RESHADE__) || __RESHADE__ < 30000 #if !defined(__RESHADE__) || __RESHADE__ < 30000
@ -105,6 +109,7 @@ namespace ReShade
} }
// Vertex shader generating a triangle covering the entire screen // Vertex shader generating a triangle covering the entire screen
// See also https://www.reddit.com/r/gamedev/comments/2j17wk/a_slightly_faster_bufferless_vertex_shader_trick/
void PostProcessVS(in uint id : SV_VertexID, out float4 position : SV_Position, out float2 texcoord : TEXCOORD) void PostProcessVS(in uint id : SV_VertexID, out float4 position : SV_Position, out float2 texcoord : TEXCOORD)
{ {
texcoord.x = (id == 2) ? 2.0 : 0.0; texcoord.x = (id == 2) ? 2.0 : 0.0;

View file

@ -7,27 +7,27 @@
#define RESHADE_VERSION(major,minor,build) (10000 * (major) + 100 * (minor) + (build)) #define RESHADE_VERSION(major,minor,build) (10000 * (major) + 100 * (minor) + (build))
#define SUPPORTED_VERSION(major,minor,build) (__RESHADE__ >= RESHADE_VERSION(major,minor,build)) #define SUPPORTED_VERSION(major,minor,build) (__RESHADE__ >= RESHADE_VERSION(major,minor,build))
// Since 3.0.0 // >= 3.0.0
// Commit current in-game user interface status // Commit current in-game user interface status
// https://github.com/crosire/reshade/commit/302bacc49ae394faedc2e29a296c1cebf6da6bb2#diff-82cf230afdb2a0d5174111e6f17548a5R1183 // https://github.com/crosire/reshade/commit/302bacc49ae394faedc2e29a296c1cebf6da6bb2#diff-82cf230afdb2a0d5174111e6f17548a5R1183
// Added various GUI related uniform variable annotations // Added various GUI related uniform variable annotations
// https://reshade.me/forum/releases/2341-3-0 // https://reshade.me/forum/releases/2341-3-0
#define __UNIFORM_INPUT_ANY ui_type = "input"; #define __UNIFORM_INPUT_ANY ui_type = "input";
#define __UNIFORM_INPUT_BOOL1 __UNIFORM_INPUT_ANY // It is unsupported on all version #define __UNIFORM_INPUT_BOOL1 __UNIFORM_INPUT_ANY
#define __UNIFORM_INPUT_BOOL2 __UNIFORM_INPUT_ANY // It is unsupported on all version #define __UNIFORM_INPUT_BOOL2 __UNIFORM_INPUT_ANY
#define __UNIFORM_INPUT_BOOL3 __UNIFORM_INPUT_ANY // It is unsupported on all version #define __UNIFORM_INPUT_BOOL3 __UNIFORM_INPUT_ANY
#define __UNIFORM_INPUT_BOOL4 __UNIFORM_INPUT_ANY // It is unsupported on all version #define __UNIFORM_INPUT_BOOL4 __UNIFORM_INPUT_ANY
#define __UNIFORM_INPUT_INT1 __UNIFORM_INPUT_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_INPUT_INT1 __UNIFORM_INPUT_ANY
#define __UNIFORM_INPUT_INT2 __UNIFORM_INPUT_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_INPUT_INT2 __UNIFORM_INPUT_ANY
#define __UNIFORM_INPUT_INT3 __UNIFORM_INPUT_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_INPUT_INT3 __UNIFORM_INPUT_ANY
#define __UNIFORM_INPUT_INT4 __UNIFORM_INPUT_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_INPUT_INT4 __UNIFORM_INPUT_ANY
#define __UNIFORM_INPUT_FLOAT1 __UNIFORM_INPUT_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_INPUT_FLOAT1 __UNIFORM_INPUT_ANY
#define __UNIFORM_INPUT_FLOAT2 __UNIFORM_INPUT_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_INPUT_FLOAT2 __UNIFORM_INPUT_ANY
#define __UNIFORM_INPUT_FLOAT3 __UNIFORM_INPUT_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_INPUT_FLOAT3 __UNIFORM_INPUT_ANY
#define __UNIFORM_INPUT_FLOAT4 __UNIFORM_INPUT_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_INPUT_FLOAT4 __UNIFORM_INPUT_ANY
// Since 4.0.1 // >= 4.0.1
// Change slider widget to be used with new "slider" instead of a "drag" type annotation // Change slider widget to be used with new "slider" instead of a "drag" type annotation
// https://github.com/crosire/reshade/commit/746229f31cd6f311a3e72a543e4f1f23faa23f11#diff-59405a313bd8cbfb0ca6dd633230e504R1701 // https://github.com/crosire/reshade/commit/746229f31cd6f311a3e72a543e4f1f23faa23f11#diff-59405a313bd8cbfb0ca6dd633230e504R1701
// Changed slider widget to be used with < ui_type = "slider"; > instead of < ui_type = "drag"; > // Changed slider widget to be used with < ui_type = "slider"; > instead of < ui_type = "drag"; >
@ -35,7 +35,7 @@
#if SUPPORTED_VERSION(4,0,1) #if SUPPORTED_VERSION(4,0,1)
#define __UNIFORM_DRAG_ANY ui_type = "drag"; #define __UNIFORM_DRAG_ANY ui_type = "drag";
// Since 4.0.0 // >= 4.0.0
// Rework statistics tab and add drag widgets back // Rework statistics tab and add drag widgets back
// https://github.com/crosire/reshade/commit/1b2c38795f00efd66c007da1f483f1441b230309 // https://github.com/crosire/reshade/commit/1b2c38795f00efd66c007da1f483f1441b230309
// Changed drag widget to a slider widget (old one is still available via < ui_type = "drag2"; >) // Changed drag widget to a slider widget (old one is still available via < ui_type = "drag2"; >)
@ -43,7 +43,7 @@
#elif SUPPORTED_VERSION(4,0,0) #elif SUPPORTED_VERSION(4,0,0)
#define __UNIFORM_DRAG_ANY ui_type = "drag2"; #define __UNIFORM_DRAG_ANY ui_type = "drag2";
// Since 3.0.0 // >= 3.0.0
// Commit current in-game user interface status // Commit current in-game user interface status
// https://github.com/crosire/reshade/commit/302bacc49ae394faedc2e29a296c1cebf6da6bb2#diff-82cf230afdb2a0d5174111e6f17548a5R1187 // https://github.com/crosire/reshade/commit/302bacc49ae394faedc2e29a296c1cebf6da6bb2#diff-82cf230afdb2a0d5174111e6f17548a5R1187
// Added various GUI related uniform variable annotations // Added various GUI related uniform variable annotations
@ -52,20 +52,20 @@
#define __UNIFORM_DRAG_ANY ui_type = "drag"; #define __UNIFORM_DRAG_ANY ui_type = "drag";
#endif #endif
#define __UNIFORM_DRAG_BOOL1 __UNIFORM_DRAG_ANY // It is unsupported on all version #define __UNIFORM_DRAG_BOOL1 __UNIFORM_DRAG_ANY
#define __UNIFORM_DRAG_BOOL2 __UNIFORM_DRAG_ANY // It is unsupported on all version #define __UNIFORM_DRAG_BOOL2 __UNIFORM_DRAG_ANY
#define __UNIFORM_DRAG_BOOL3 __UNIFORM_DRAG_ANY // It is unsupported on all version #define __UNIFORM_DRAG_BOOL3 __UNIFORM_DRAG_ANY
#define __UNIFORM_DRAG_BOOL4 __UNIFORM_DRAG_ANY // It is unsupported on all version #define __UNIFORM_DRAG_BOOL4 __UNIFORM_DRAG_ANY
#define __UNIFORM_DRAG_INT1 __UNIFORM_DRAG_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_DRAG_INT1 __UNIFORM_DRAG_ANY
#define __UNIFORM_DRAG_INT2 __UNIFORM_DRAG_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_DRAG_INT2 __UNIFORM_DRAG_ANY
#define __UNIFORM_DRAG_INT3 __UNIFORM_DRAG_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_DRAG_INT3 __UNIFORM_DRAG_ANY
#define __UNIFORM_DRAG_INT4 __UNIFORM_DRAG_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_DRAG_INT4 __UNIFORM_DRAG_ANY
#define __UNIFORM_DRAG_FLOAT1 __UNIFORM_DRAG_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_DRAG_FLOAT1 __UNIFORM_DRAG_ANY
#define __UNIFORM_DRAG_FLOAT2 __UNIFORM_DRAG_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_DRAG_FLOAT2 __UNIFORM_DRAG_ANY
#define __UNIFORM_DRAG_FLOAT3 __UNIFORM_DRAG_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_DRAG_FLOAT3 __UNIFORM_DRAG_ANY
#define __UNIFORM_DRAG_FLOAT4 __UNIFORM_DRAG_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_DRAG_FLOAT4 __UNIFORM_DRAG_ANY
// Since 4.0.1 // >= 4.0.1
// Change slider widget to be used with new "slider" instead of a "drag" type annotation // Change slider widget to be used with new "slider" instead of a "drag" type annotation
// https://github.com/crosire/reshade/commit/746229f31cd6f311a3e72a543e4f1f23faa23f11#diff-59405a313bd8cbfb0ca6dd633230e504R1699 // https://github.com/crosire/reshade/commit/746229f31cd6f311a3e72a543e4f1f23faa23f11#diff-59405a313bd8cbfb0ca6dd633230e504R1699
// Changed slider widget to be used with < ui_type = "slider"; > instead of < ui_type = "drag"; > // Changed slider widget to be used with < ui_type = "slider"; > instead of < ui_type = "drag"; >
@ -73,7 +73,7 @@
#if SUPPORTED_VERSION(4,0,1) #if SUPPORTED_VERSION(4,0,1)
#define __UNIFORM_SLIDER_ANY ui_type = "slider"; #define __UNIFORM_SLIDER_ANY ui_type = "slider";
// Since 4.0.0 // >= 4.0.0
// Rework statistics tab and add drag widgets back // Rework statistics tab and add drag widgets back
// https://github.com/crosire/reshade/commit/1b2c38795f00efd66c007da1f483f1441b230309 // https://github.com/crosire/reshade/commit/1b2c38795f00efd66c007da1f483f1441b230309
// Changed drag widget to a slider widget (old one is still available via < ui_type = "drag2"; >) // Changed drag widget to a slider widget (old one is still available via < ui_type = "drag2"; >)
@ -84,20 +84,20 @@
#define __UNIFORM_SLIDER_ANY __UNIFORM_DRAG_ANY #define __UNIFORM_SLIDER_ANY __UNIFORM_DRAG_ANY
#endif #endif
#define __UNIFORM_SLIDER_BOOL1 __UNIFORM_SLIDER_ANY // It is unsupported on all version #define __UNIFORM_SLIDER_BOOL1 __UNIFORM_SLIDER_ANY
#define __UNIFORM_SLIDER_BOOL2 __UNIFORM_SLIDER_ANY // It is unsupported on all version #define __UNIFORM_SLIDER_BOOL2 __UNIFORM_SLIDER_ANY
#define __UNIFORM_SLIDER_BOOL3 __UNIFORM_SLIDER_ANY // It is unsupported on all version #define __UNIFORM_SLIDER_BOOL3 __UNIFORM_SLIDER_ANY
#define __UNIFORM_SLIDER_BOOL4 __UNIFORM_SLIDER_ANY // It is unsupported on all version #define __UNIFORM_SLIDER_BOOL4 __UNIFORM_SLIDER_ANY
#define __UNIFORM_SLIDER_INT1 __UNIFORM_SLIDER_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_SLIDER_INT1 __UNIFORM_SLIDER_ANY
#define __UNIFORM_SLIDER_INT2 __UNIFORM_SLIDER_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_SLIDER_INT2 __UNIFORM_SLIDER_ANY
#define __UNIFORM_SLIDER_INT3 __UNIFORM_SLIDER_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_SLIDER_INT3 __UNIFORM_SLIDER_ANY
#define __UNIFORM_SLIDER_INT4 __UNIFORM_SLIDER_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_SLIDER_INT4 __UNIFORM_SLIDER_ANY
#define __UNIFORM_SLIDER_FLOAT1 __UNIFORM_SLIDER_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_SLIDER_FLOAT1 __UNIFORM_SLIDER_ANY
#define __UNIFORM_SLIDER_FLOAT2 __UNIFORM_SLIDER_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_SLIDER_FLOAT2 __UNIFORM_SLIDER_ANY
#define __UNIFORM_SLIDER_FLOAT3 __UNIFORM_SLIDER_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_SLIDER_FLOAT3 __UNIFORM_SLIDER_ANY
#define __UNIFORM_SLIDER_FLOAT4 __UNIFORM_SLIDER_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_SLIDER_FLOAT4 __UNIFORM_SLIDER_ANY
// Since 3.0.0 // >= 3.0.0
// Add combo box display type for uniform variables and fix displaying of integer variable under Direct3D 9 // Add combo box display type for uniform variables and fix displaying of integer variable under Direct3D 9
// https://github.com/crosire/reshade/commit/b025bfae5f7343509ec0cacf6df0cff537c499f2#diff-82cf230afdb2a0d5174111e6f17548a5R1631 // https://github.com/crosire/reshade/commit/b025bfae5f7343509ec0cacf6df0cff537c499f2#diff-82cf230afdb2a0d5174111e6f17548a5R1631
// Added various GUI related uniform variable annotations // Added various GUI related uniform variable annotations
@ -105,19 +105,19 @@
#define __UNIFORM_COMBO_ANY ui_type = "combo"; #define __UNIFORM_COMBO_ANY ui_type = "combo";
// __UNIFORM_COMBO_BOOL1 // __UNIFORM_COMBO_BOOL1
#define __UNIFORM_COMBO_BOOL2 __UNIFORM_COMBO_ANY // It is unsupported on all version #define __UNIFORM_COMBO_BOOL2 __UNIFORM_COMBO_ANY
#define __UNIFORM_COMBO_BOOL3 __UNIFORM_COMBO_ANY // It is unsupported on all version #define __UNIFORM_COMBO_BOOL3 __UNIFORM_COMBO_ANY
#define __UNIFORM_COMBO_BOOL4 __UNIFORM_COMBO_ANY // It is unsupported on all version #define __UNIFORM_COMBO_BOOL4 __UNIFORM_COMBO_ANY
#define __UNIFORM_COMBO_INT1 __UNIFORM_COMBO_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_COMBO_INT1 __UNIFORM_COMBO_ANY
#define __UNIFORM_COMBO_INT2 __UNIFORM_COMBO_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_COMBO_INT2 __UNIFORM_COMBO_ANY
#define __UNIFORM_COMBO_INT3 __UNIFORM_COMBO_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_COMBO_INT3 __UNIFORM_COMBO_ANY
#define __UNIFORM_COMBO_INT4 __UNIFORM_COMBO_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_COMBO_INT4 __UNIFORM_COMBO_ANY
#define __UNIFORM_COMBO_FLOAT1 __UNIFORM_COMBO_ANY // It is unsupported on all version #define __UNIFORM_COMBO_FLOAT1 __UNIFORM_COMBO_ANY
#define __UNIFORM_COMBO_FLOAT2 __UNIFORM_COMBO_ANY // It is unsupported on all version #define __UNIFORM_COMBO_FLOAT2 __UNIFORM_COMBO_ANY
#define __UNIFORM_COMBO_FLOAT3 __UNIFORM_COMBO_ANY // It is unsupported on all version #define __UNIFORM_COMBO_FLOAT3 __UNIFORM_COMBO_ANY
#define __UNIFORM_COMBO_FLOAT4 __UNIFORM_COMBO_ANY // It is unsupported on all version #define __UNIFORM_COMBO_FLOAT4 __UNIFORM_COMBO_ANY
// Since 4.0.0 (but the ui_items force set "Off\0On\0"), and if less than it force converted to checkbox // >= 4.0.0
// Add option to display boolean values as combo box instead of checkbox // Add option to display boolean values as combo box instead of checkbox
// https://github.com/crosire/reshade/commit/aecb757c864c9679e77edd6f85a1521c49e489c1#diff-59405a313bd8cbfb0ca6dd633230e504R1147 // https://github.com/crosire/reshade/commit/aecb757c864c9679e77edd6f85a1521c49e489c1#diff-59405a313bd8cbfb0ca6dd633230e504R1147
// https://github.com/crosire/reshade/blob/v4.0.0/source/gui.cpp // https://github.com/crosire/reshade/blob/v4.0.0/source/gui.cpp
@ -125,7 +125,7 @@
// https://reshade.me/forum/releases/4772-4-0 // https://reshade.me/forum/releases/4772-4-0
#define __UNIFORM_COMBO_BOOL1 __UNIFORM_COMBO_ANY #define __UNIFORM_COMBO_BOOL1 __UNIFORM_COMBO_ANY
// Since 4.0.0 // >= 4.0.0
// Cleanup GUI code and rearrange some widgets // Cleanup GUI code and rearrange some widgets
// https://github.com/crosire/reshade/commit/6751f7bd50ea7c0556cf0670f10a4b4ba912ee7d#diff-59405a313bd8cbfb0ca6dd633230e504R1711 // https://github.com/crosire/reshade/commit/6751f7bd50ea7c0556cf0670f10a4b4ba912ee7d#diff-59405a313bd8cbfb0ca6dd633230e504R1711
// Added radio button widget (via < ui_type = "radio"; ui_items = "Button 1\0Button 2\0...\0"; >) // Added radio button widget (via < ui_type = "radio"; ui_items = "Button 1\0Button 2\0...\0"; >)
@ -136,48 +136,46 @@
#define __UNIFORM_RADIO_ANY __UNIFORM_COMBO_ANY #define __UNIFORM_RADIO_ANY __UNIFORM_COMBO_ANY
#endif #endif
#define __UNIFORM_RADIO_BOOL1 __UNIFORM_RADIO_ANY // It is unsupported on all version #define __UNIFORM_RADIO_BOOL1 __UNIFORM_RADIO_ANY
#define __UNIFORM_RADIO_BOOL2 __UNIFORM_RADIO_ANY // It is unsupported on all version #define __UNIFORM_RADIO_BOOL2 __UNIFORM_RADIO_ANY
#define __UNIFORM_RADIO_BOOL3 __UNIFORM_RADIO_ANY // It is unsupported on all version #define __UNIFORM_RADIO_BOOL3 __UNIFORM_RADIO_ANY
#define __UNIFORM_RADIO_BOOL4 __UNIFORM_RADIO_ANY // It is unsupported on all version #define __UNIFORM_RADIO_BOOL4 __UNIFORM_RADIO_ANY
#define __UNIFORM_RADIO_INT1 __UNIFORM_RADIO_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_RADIO_INT1 __UNIFORM_RADIO_ANY
#define __UNIFORM_RADIO_INT2 __UNIFORM_RADIO_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_RADIO_INT2 __UNIFORM_RADIO_ANY
#define __UNIFORM_RADIO_INT3 __UNIFORM_RADIO_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_RADIO_INT3 __UNIFORM_RADIO_ANY
#define __UNIFORM_RADIO_INT4 __UNIFORM_RADIO_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_RADIO_INT4 __UNIFORM_RADIO_ANY
#define __UNIFORM_RADIO_FLOAT1 __UNIFORM_RADIO_ANY // It is unsupported on all version #define __UNIFORM_RADIO_FLOAT1 __UNIFORM_RADIO_ANY
#define __UNIFORM_RADIO_FLOAT2 __UNIFORM_RADIO_ANY // It is unsupported on all version #define __UNIFORM_RADIO_FLOAT2 __UNIFORM_RADIO_ANY
#define __UNIFORM_RADIO_FLOAT3 __UNIFORM_RADIO_ANY // It is unsupported on all version #define __UNIFORM_RADIO_FLOAT3 __UNIFORM_RADIO_ANY
#define __UNIFORM_RADIO_FLOAT4 __UNIFORM_RADIO_ANY // It is unsupported on all version #define __UNIFORM_RADIO_FLOAT4 __UNIFORM_RADIO_ANY
// Since 4.1.0 // >= 4.1.0
// Fix floating point uniforms with unknown "ui_type" not showing up in UI // Fix floating point uniforms with unknown "ui_type" not showing up in UI
// https://github.com/crosire/reshade/commit/50e5bf44dfc84bc4220c2b9f19d5f50c7a0fda66#diff-59405a313bd8cbfb0ca6dd633230e504R1788 // https://github.com/crosire/reshade/commit/50e5bf44dfc84bc4220c2b9f19d5f50c7a0fda66#diff-59405a313bd8cbfb0ca6dd633230e504R1788
// Fixed floating point uniforms with unknown "ui_type" not showing up in UI // Fixed floating point uniforms with unknown "ui_type" not showing up in UI
// https://reshade.me/forum/releases/5021-4-1 // https://reshade.me/forum/releases/5021-4-1
#define __UNIFORM_COLOR_ANY ui_type = "color"; #define __UNIFORM_COLOR_ANY ui_type = "color";
// Since 3.0.0 // >= 3.0.0
// Move technique list to preset configuration file // Move technique list to preset configuration file
// https://github.com/crosire/reshade/blob/84bba3aa934c1ebe4c6419b69dfe1690d9ab9d34/source/runtime.cpp#L1328 // https://github.com/crosire/reshade/blob/84bba3aa934c1ebe4c6419b69dfe1690d9ab9d34/source/runtime.cpp#L1328
// Added various GUI related uniform variable annotations // Added various GUI related uniform variable annotations
// https://reshade.me/forum/releases/2341-3-0 // https://reshade.me/forum/releases/2341-3-0
// If empty, these versions before 4.1.0 are decide that the type is color from the number of components #define __UNIFORM_COLOR_BOOL1 __UNIFORM_COLOR_ANY
#define __UNIFORM_COLOR_BOOL2 __UNIFORM_COLOR_ANY
#define __UNIFORM_COLOR_BOOL1 __UNIFORM_COLOR_ANY // It is unsupported on all version #define __UNIFORM_COLOR_BOOL3 __UNIFORM_COLOR_ANY
#define __UNIFORM_COLOR_BOOL2 __UNIFORM_COLOR_ANY // It is unsupported on all version #define __UNIFORM_COLOR_BOOL4 __UNIFORM_COLOR_ANY
#define __UNIFORM_COLOR_BOOL3 __UNIFORM_COLOR_ANY // It is unsupported on all version #define __UNIFORM_COLOR_INT1 __UNIFORM_COLOR_ANY
#define __UNIFORM_COLOR_BOOL4 __UNIFORM_COLOR_ANY // It is unsupported on all version #define __UNIFORM_COLOR_INT2 __UNIFORM_COLOR_ANY
#define __UNIFORM_COLOR_INT1 __UNIFORM_COLOR_ANY // It is unsupported on all version #define __UNIFORM_COLOR_INT3 __UNIFORM_COLOR_ANY
#define __UNIFORM_COLOR_INT2 __UNIFORM_COLOR_ANY // It is unsupported on all version #define __UNIFORM_COLOR_INT4 __UNIFORM_COLOR_ANY
#define __UNIFORM_COLOR_INT3 __UNIFORM_COLOR_ANY // It is unsupported on all version
#define __UNIFORM_COLOR_INT4 __UNIFORM_COLOR_ANY // It is unsupported on all version
// __UNIFORM_COLOR_FLOAT1 // __UNIFORM_COLOR_FLOAT1
#define __UNIFORM_COLOR_FLOAT2 __UNIFORM_COLOR_ANY // It is unsupported on all version #define __UNIFORM_COLOR_FLOAT2 __UNIFORM_COLOR_ANY
#define __UNIFORM_COLOR_FLOAT3 __UNIFORM_COLOR_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_COLOR_FLOAT3 __UNIFORM_COLOR_ANY
#define __UNIFORM_COLOR_FLOAT4 __UNIFORM_COLOR_ANY // If it was not supported in someday or now, please add information #define __UNIFORM_COLOR_FLOAT4 __UNIFORM_COLOR_ANY
// Since 4.2.0 // >= 4.2.0
// Add alpha slider widget for single component uniform variables (#86) // Add alpha slider widget for single component uniform variables (#86)
// https://github.com/crosire/reshade/commit/87a740a8e3c4dcda1dd4eeec8d5cff7fa35fe829#diff-59405a313bd8cbfb0ca6dd633230e504R1820 // https://github.com/crosire/reshade/commit/87a740a8e3c4dcda1dd4eeec8d5cff7fa35fe829#diff-59405a313bd8cbfb0ca6dd633230e504R1820
// Added alpha slider widget for single component uniform variables // Added alpha slider widget for single component uniform variables
@ -188,7 +186,7 @@
#define __UNIFORM_COLOR_FLOAT1 __UNIFORM_SLIDER_ANY #define __UNIFORM_COLOR_FLOAT1 __UNIFORM_SLIDER_ANY
#endif #endif
// Since 4.3.0 // >= 4.3.0
// Add new "list" GUI widget (#103) // Add new "list" GUI widget (#103)
// https://github.com/crosire/reshade/commit/515287d20ce615c19cf3d4c21b49f83896f04ddc#diff-59405a313bd8cbfb0ca6dd633230e504R1894 // https://github.com/crosire/reshade/commit/515287d20ce615c19cf3d4c21b49f83896f04ddc#diff-59405a313bd8cbfb0ca6dd633230e504R1894
// Added new "list" GUI widget // Added new "list" GUI widget
@ -200,17 +198,17 @@
#endif #endif
// __UNIFORM_LIST_BOOL1 // __UNIFORM_LIST_BOOL1
#define __UNIFORM_LIST_BOOL2 __UNIFORM_LIST_ANY // Not supported in all versions #define __UNIFORM_LIST_BOOL2 __UNIFORM_LIST_ANY
#define __UNIFORM_LIST_BOOL3 __UNIFORM_LIST_ANY // Not supported in all versions #define __UNIFORM_LIST_BOOL3 __UNIFORM_LIST_ANY
#define __UNIFORM_LIST_BOOL4 __UNIFORM_LIST_ANY // Not supported in all versions #define __UNIFORM_LIST_BOOL4 __UNIFORM_LIST_ANY
#define __UNIFORM_LIST_INT1 __UNIFORM_LIST_ANY // Supported in 4.3.0 #define __UNIFORM_LIST_INT1 __UNIFORM_LIST_ANY // >= 4.3.0
#define __UNIFORM_LIST_INT2 __UNIFORM_LIST_ANY // Not supported in all versions #define __UNIFORM_LIST_INT2 __UNIFORM_LIST_ANY
#define __UNIFORM_LIST_INT3 __UNIFORM_LIST_ANY // Not supported in all versions #define __UNIFORM_LIST_INT3 __UNIFORM_LIST_ANY
#define __UNIFORM_LIST_INT4 __UNIFORM_LIST_ANY // Not supported in all versions #define __UNIFORM_LIST_INT4 __UNIFORM_LIST_ANY
#define __UNIFORM_LIST_FLOAT1 __UNIFORM_LIST_ANY // Not supported in all versions #define __UNIFORM_LIST_FLOAT1 __UNIFORM_LIST_ANY
#define __UNIFORM_LIST_FLOAT2 __UNIFORM_LIST_ANY // Not supported in all versions #define __UNIFORM_LIST_FLOAT2 __UNIFORM_LIST_ANY
#define __UNIFORM_LIST_FLOAT3 __UNIFORM_LIST_ANY // Not supported in all versions #define __UNIFORM_LIST_FLOAT3 __UNIFORM_LIST_ANY
#define __UNIFORM_LIST_FLOAT4 __UNIFORM_LIST_ANY // Not supported in all versions #define __UNIFORM_LIST_FLOAT4 __UNIFORM_LIST_ANY
// For compatible with ComboBox // For compatible with 'combo'
#define __UNIFORM_LIST_BOOL1 __UNIFORM_COMBO_ANY #define __UNIFORM_LIST_BOOL1 __UNIFORM_COMBO_ANY

View file

@ -0,0 +1,289 @@
/*
Simple UIMask shader by luluco250
I have no idea why this was never ported back to ReShade 3.0 from 2.0,
but if you missed it, here it is.
It doesn't feature the auto mask from the original shader.
It does feature a new multi-channnel masking feature. UI masks can now contain
separate 'modes' within each of the three color channels.
For example, you can have the regular hud on the red channel (the default one),
a mask for an inventory screen on the green channel and a mask for a quest menu
on the blue channel. You can then use keyboard keys to toggle each channel on or off.
Multiple channels can be active at once, they'll just add up to mask the image.
Simple/legacy masks are not affected by this, they'll work just as you'd expect,
so you can still make simple black and white masks that use all color channels, it'll
be no different than just having it on a single channel.
Tips:
--You can adjust how much it will affect your HUD by changing "Mask Intensity".
--You don't actually need to place the UIMask_Bottom technique at the bottom of
your shader pipeline, if you have any effects that don't necessarily affect
the visibility of the HUD you can place it before that.
For instance, if you use color correction shaders like LUT, you might want
to place UIMask_Bottom just before that.
--Preprocessor flags:
--UIMASK_MULTICHANNEL:
Enables having up to three different masks on each color channel.
--Refer to this page for keycodes:
https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
--To make a custom mask:
1-Take a screenshot of your game with the HUD enabled,
preferrably with any effects disabled for maximum visibility.
2-Open the screenshot with your preferred image editor program, I use GIMP.
3-Make a background white layer if there isn't one already.
Be sure to leave it behind your actual screenshot for the while.
4-Make an empty layer for the mask itself, you can call it "mask".
5-Having selected the mask layer, paint the places where HUD constantly is,
such as health bars, important messages, minimaps etc.
6-Delete or make your screenshot layer invisible.
7-Before saving your mask, let's do some gaussian blurring to improve it's look and feel:
For every step of blurring you want to do, make a new layer, such as:
Mask - Blur16x16
Mask - Blur8x8
Mask - Blur4x4
Mask - Blur2x2
Mask - NoBlur
You should use your image editor's default gaussian blurring filter, if there is one.
This avoids possible artifacts and makes the mask blend more easily on the eyes.
You may not need this if your mask is accurate enough and/or the HUD is simple enough.
8-Now save the final image with a unique name such as "MyUIMask.png" in your textures folder.
9-Set the preprocessor definition UIMASK_TEXTURE to the unique name of your image, with quotes.
You're done!
MIT Licensed:
Copyright (c) 2017 Lucas Melo
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.
*/
//#region Preprocessor
#include "ReShade.fxh"
#include "ReShadeUI.fxh"
#ifndef UIMASK_MULTICHANNEL
#define UIMASK_MULTICHANNEL 0
#endif
#if !UIMASK_MULTICHANNEL
#define TEXFORMAT R8
#else
#define TEXFORMAT RGBA8
#endif
#ifndef UIMASK_TEXTURE
#define UIMASK_TEXTURE "UIMask.png"
#endif
//#endregion
namespace UIMask
{
//#region Uniforms
uniform int _Help
<
ui_label = " ";
ui_text =
"For more detailed instructions, see the text at the top of this "
"effect's shader file (UIMask.fx).\n"
"\n"
"Available preprocessor definitions:\n"
" UIMASK_MULTICHANNEL:\n"
" If set to 1, each of the RGB color channels in the texture is "
"treated as a separate mask.\n"
"\n"
"How to create a mask:\n"
"\n"
"1. Take a screenshot with the game's UI appearing.\n"
"2. Open the screenshot in an image editor, GIMP or Photoshop are "
"recommended.\n"
"3. Create a new layer over the screenshot layer, fill it with black.\n"
"4. Reduce the layer opacity so you can see the screenshot layer "
"below.\n"
"5. Cover the UI with white to mask it from effects. The stronger the "
"mask white color, the more opaque the mask will be.\n"
"6. Set the mask layer opacity back to 100%.\n"
"7. Save the image in one of your texture folders, making sure to "
"use a unique name such as: \"MyUIMask.png\"\n"
"8. Set the preprocessor definition UIMASK_TEXTURE to the name of "
"your image, with quotes: \"MyUIMask.png\"\n"
;
ui_category = "Help";
ui_category_closed = true;
ui_type = "radio";
>;
uniform float fMask_Intensity
<
__UNIFORM_SLIDER_FLOAT1
ui_label = "Mask Intensity";
ui_tooltip =
"How much to mask effects from affecting the original image.\n"
"\nDefault: 1.0";
ui_min = 0.0;
ui_max = 1.0;
ui_step = 0.001;
> = 1.0;
uniform bool bDisplayMask <
ui_label = "Display Mask";
ui_tooltip =
"Display the mask texture.\n"
"Useful for testing multiple channels or simply the mask itself.\n"
"\nDefault: Off";
> = false;
#if UIMASK_MULTICHANNEL
uniform bool bToggleRed <
ui_label = "Toggle Red Channel";
ui_tooltip = "Toggle UI masking for the red channel.\n"
"Right click to assign a hotkey.\n"
"\nDefault: On";
> = true;
uniform bool bToggleGreen <
ui_label = "Toggle Green Channel";
ui_tooltip = "Toggle UI masking for the green channel.\n"
"Right click to assign a hotkey."
"\nDefault: On";
> = true;
uniform bool bToggleBlue <
ui_label = "Toggle Blue Channel";
ui_tooltip = "Toggle UI masking for the blue channel.\n"
"Right click to assign a hotkey."
"\nDefault: On";
> = true;
#endif
//#endregion
//#region Textures
texture BackupTex
{
Width = BUFFER_WIDTH;
Height = BUFFER_HEIGHT;
};
sampler Backup
{
Texture = BackupTex;
};
texture MaskTex <source=UIMASK_TEXTURE;>
{
Width = BUFFER_WIDTH;
Height = BUFFER_HEIGHT;
Format = TEXFORMAT;
};
sampler Mask
{
Texture = MaskTex;
};
//#endregion
//#region Shaders
float4 BackupPS(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target {
return tex2D(ReShade::BackBuffer, uv);
}
float4 MainPS(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target {
float4 color = tex2D(ReShade::BackBuffer, uv);
float4 backup = tex2D(Backup, uv);
#if !UIMASK_MULTICHANNEL
float mask = tex2D(Mask, uv).r;
#else
float3 mask_rgb = tex2D(Mask, uv).rgb;
// This just works, it basically adds masking with each channel that has
// been toggled.
float mask = saturate(
1.0 - dot(1.0 - mask_rgb,
float3(bToggleRed, bToggleGreen, bToggleBlue)));
#endif
color = lerp(color, backup, mask * fMask_Intensity);
color = bDisplayMask ? mask : color;
return color;
}
//#endregion
//#region Techniques
technique UIMask_Top
<
ui_tooltip = "Place this *above* the effects to be masked.";
>
{
pass
{
VertexShader = PostProcessVS;
PixelShader = BackupPS;
RenderTarget = BackupTex;
}
}
technique UIMask_Bottom
<
ui_tooltip =
"Place this *below* the effects to be masked.\n"
"If you want to add a toggle key for the effect, set it to this one.";
>
{
pass
{
VertexShader = PostProcessVS;
PixelShader = MainPS;
}
}
//#endregion
} // Namespace.

View file

@ -16,6 +16,8 @@ namespace reshadefx
/// </summary> /// </summary>
class codegen class codegen
{ {
friend class parser;
public: public:
/// <summary> /// <summary>
/// Virtual destructor to guarantee that memory of the implementations deriving from this interface is properly destroyed. /// Virtual destructor to guarantee that memory of the implementations deriving from this interface is properly destroyed.
@ -23,12 +25,21 @@ namespace reshadefx
virtual ~codegen() {} virtual ~codegen() {}
/// <summary> /// <summary>
/// Writes result of the code generation to the specified <paramref name="module"/>. /// Gets the module describing the generated code.
/// </summary> /// </summary>
/// <param name="module">Target module to fill.</param> const effect_module &module() const { return _module; }
virtual void write_result(module &module) = 0;
public: /// <summary>
/// Finalizes and returns the generated code for the entire module (all entry points).
/// </summary>
virtual std::basic_string<char> finalize_code() const = 0;
/// <summary>
/// Finalizes and returns the generated code for the specified entry point (and no other entry points).
/// </summary>
/// <param name="entry_point_name">Name of the entry point function to generate code for.</param>
virtual std::basic_string<char> finalize_code_for_entry_point(const std::string &entry_point_name) const = 0;
protected:
/// <summary> /// <summary>
/// An opaque ID referring to a SSA value or basic block. /// An opaque ID referring to a SSA value or basic block.
/// </summary> /// </summary>
@ -40,14 +51,14 @@ namespace reshadefx
/// <param name="loc">Source location matching this definition (for debugging).</param> /// <param name="loc">Source location matching this definition (for debugging).</param>
/// <param name="info">Description of the type.</param> /// <param name="info">Description of the type.</param>
/// <returns>New SSA ID of the type.</returns> /// <returns>New SSA ID of the type.</returns>
virtual id define_struct(const location &loc, struct_info &info) = 0; virtual id define_struct(const location &loc, struct_type &info) = 0;
/// <summary> /// <summary>
/// Defines a new texture binding. /// Defines a new texture binding.
/// </summary> /// </summary>
/// <param name="loc">Source location matching this definition (for debugging).</param> /// <param name="loc">Source location matching this definition (for debugging).</param>
/// <param name="info">Description of the texture object.</param> /// <param name="info">Description of the texture object.</param>
/// <returns>New SSA ID of the binding.</returns> /// <returns>New SSA ID of the binding.</returns>
virtual id define_texture(const location &loc, texture_info &info) = 0; virtual id define_texture(const location &loc, texture &info) = 0;
/// <summary> /// <summary>
/// Defines a new sampler binding. /// Defines a new sampler binding.
/// </summary> /// </summary>
@ -55,7 +66,7 @@ namespace reshadefx
/// <param name="tex_info">Description of the texture this sampler object references.</param> /// <param name="tex_info">Description of the texture this sampler object references.</param>
/// <param name="info">Description of the sampler object.</param> /// <param name="info">Description of the sampler object.</param>
/// <returns>New SSA ID of the binding.</returns> /// <returns>New SSA ID of the binding.</returns>
virtual id define_sampler(const location &loc, const texture_info &tex_info, sampler_info &info) = 0; virtual id define_sampler(const location &loc, const texture &tex_info, sampler &info) = 0;
/// <summary> /// <summary>
/// Defines a new storage binding. /// Defines a new storage binding.
/// </summary> /// </summary>
@ -63,14 +74,14 @@ namespace reshadefx
/// <param name="tex_info">Description of the texture this storage object references.</param> /// <param name="tex_info">Description of the texture this storage object references.</param>
/// <param name="info">Description of the storage object.</param> /// <param name="info">Description of the storage object.</param>
/// <returns>New SSA ID of the binding.</returns> /// <returns>New SSA ID of the binding.</returns>
virtual id define_storage(const location &loc, const texture_info &tex_info, storage_info &info) = 0; virtual id define_storage(const location &loc, const texture &tex_info, storage &info) = 0;
/// <summary> /// <summary>
/// Defines a new uniform variable. /// Defines a new uniform variable.
/// </summary> /// </summary>
/// <param name="loc">Source location matching this definition (for debugging).</param> /// <param name="loc">Source location matching this definition (for debugging).</param>
/// <param name="info">Description of the uniform variable.</param> /// <param name="info">Description of the uniform variable.</param>
/// <returns>New SSA ID of the variable.</returns> /// <returns>New SSA ID of the variable.</returns>
virtual id define_uniform(const location &loc, uniform_info &info) = 0; virtual id define_uniform(const location &loc, uniform &info) = 0;
/// <summary> /// <summary>
/// Defines a new variable. /// Defines a new variable.
/// </summary> /// </summary>
@ -82,26 +93,25 @@ namespace reshadefx
/// <returns>New SSA ID of the variable.</returns> /// <returns>New SSA ID of the variable.</returns>
virtual id define_variable(const location &loc, const type &type, std::string name = std::string(), bool global = false, id initializer_value = 0) = 0; virtual id define_variable(const location &loc, const type &type, std::string name = std::string(), bool global = false, id initializer_value = 0) = 0;
/// <summary> /// <summary>
/// Defines a new function and its function parameters and make it current. Any code added after this call is added to this function. /// Defines a new function and its function parameters and make it current.
/// Any code added after this call is added to this function.
/// </summary> /// </summary>
/// <param name="loc">Source location matching this definition (for debugging).</param> /// <param name="loc">Source location matching this definition (for debugging).</param>
/// <param name="info">Description of the function.</param> /// <param name="info">Description of the function.</param>
/// <returns>New SSA ID of the function.</returns> /// <returns>New SSA ID of the function.</returns>
virtual id define_function(const location &loc, function_info &info) = 0; virtual id define_function(const location &loc, function &info) = 0;
/// <summary> /// <summary>
/// Defines a new effect technique. /// Defines a new effect technique.
/// </summary> /// </summary>
/// <param name="loc">Source location matching this definition (for debugging).</param> /// <param name="loc">Source location matching this definition (for debugging).</param>
/// <param name="info">Description of the technique.</param> /// <param name="info">Description of the technique.</param>
void define_technique(technique_info &&info) { _module.techniques.push_back(std::move(info)); } void define_technique(technique &&info) { _module.techniques.push_back(std::move(info)); }
/// <summary> /// <summary>
/// Makes a function a shader entry point. /// Makes a function a shader entry point.
/// </summary> /// </summary>
/// <param name="function">Function to use as entry point. May be overwritten to point to a new unique function for this entry point.</param> /// <param name="function">Function to use as entry point. May be overwritten to point to a new uniquely generated function.</param>
/// <param name="type">Shader type (vertex, pixel or compute shader).</param> virtual void define_entry_point(function &function) = 0;
/// <param name="num_threads">Number of local threads it this is a compute entry point.</param>
virtual void define_entry_point(function_info &function, shader_type type, int num_threads[3] = nullptr) = 0;
/// <summary> /// <summary>
/// Resolves the access chain and add a load operation to the output. /// Resolves the access chain and add a load operation to the output.
@ -131,6 +141,19 @@ namespace reshadefx
/// <param name="data">Actual constant data to convert into a SSA ID.</param> /// <param name="data">Actual constant data to convert into a SSA ID.</param>
/// <returns>New SSA ID with the constant value.</returns> /// <returns>New SSA ID with the constant value.</returns>
virtual id emit_constant(const type &type, const constant &data) = 0; virtual id emit_constant(const type &type, const constant &data) = 0;
id emit_constant(const type &data_type, uint32_t value)
{
// Create a constant value of the specified type
constant data = {}; // Initialize to zero, so that components not set below still have a defined value for lookup via std::memcmp
for (unsigned int i = 0; i < data_type.components(); ++i)
{
if (data_type.is_integral())
data.as_uint[i] = value;
else
data.as_float[i] = static_cast<float>(value);
}
return emit_constant(data_type, data);
}
/// <summary> /// <summary>
/// Adds an unary operation to the output (built-in operation with one argument). /// Adds an unary operation to the output (built-in operation with one argument).
@ -222,7 +245,7 @@ namespace reshadefx
/// <summary> /// <summary>
/// Returns <see langword="true"/> if code is currently added to a function. /// Returns <see langword="true"/> if code is currently added to a function.
/// </summary> /// </summary>
virtual bool is_in_function() const { return is_in_block(); } bool is_in_function() const { return _current_function != nullptr; }
/// <summary> /// <summary>
/// Creates a new basic block. /// Creates a new basic block.
@ -272,93 +295,96 @@ namespace reshadefx
/// <param name="false_target">ID of the basic block to jump to when the condition is false.</param> /// <param name="false_target">ID of the basic block to jump to when the condition is false.</param>
/// <returns>ID of the current basic block.</returns> /// <returns>ID of the current basic block.</returns>
virtual id leave_block_and_branch_conditional(id condition, id true_target, id false_target) = 0; virtual id leave_block_and_branch_conditional(id condition, id true_target, id false_target) = 0;
/// <summary> /// <summary>
/// Leaves the current function. Any code added after this call is added in the global scope. /// Leaves the current function. Any code added after this call is added in the global scope.
/// </summary> /// </summary>
virtual void leave_function() = 0; virtual void leave_function() = 0;
/// <summary>
/// Recalculates sampler and storage bindings to take as little binding space as possible for each entry point.
/// </summary>
virtual void optimize_bindings();
/// <summary> /// <summary>
/// Looks up an existing struct type. /// Looks up an existing struct type.
/// </summary> /// </summary>
/// <param name="id">SSA ID of the type to find.</param> /// <param name="id">SSA ID of the type to find.</param>
/// <returns>Reference to the struct description.</returns> /// <returns>Reference to the struct description.</returns>
const struct_info &get_struct(id id) const const struct_type &get_struct(id id) const
{ {
return *std::find_if(_structs.begin(), _structs.end(), return *std::find_if(_structs.begin(), _structs.end(),
[id](const auto &it) { return it.definition == id; }); [id](const struct_type &info) { return info.id == id; });
} }
/// <summary> /// <summary>
/// Looks up an existing texture binding. /// Looks up an existing texture binding.
/// </summary> /// </summary>
/// <param name="id">SSA ID of the texture binding to find.</param> /// <param name="id">SSA ID of the texture binding to find.</param>
/// <returns>Reference to the texture description.</returns> /// <returns>Reference to the texture description.</returns>
texture_info &get_texture(id id) texture &get_texture(id id)
{ {
return *std::find_if(_module.textures.begin(), _module.textures.end(), return *std::find_if(_module.textures.begin(), _module.textures.end(),
[id](const auto &it) { return it.id == id; }); [id](const texture &info) { return info.id == id; });
} }
/// <summary> /// <summary>
/// Looks up an existing sampler binding. /// Looks up an existing sampler binding.
/// </summary> /// </summary>
/// <param name="id">SSA ID of the sampler binding to find.</param> /// <param name="id">SSA ID of the sampler binding to find.</param>
/// <returns>Reference to the sampler description.</returns> /// <returns>Reference to the sampler description.</returns>
const sampler_info &get_sampler(id id) const const sampler &get_sampler(id id) const
{ {
return *std::find_if(_module.samplers.begin(), _module.samplers.end(), return *std::find_if(_module.samplers.begin(), _module.samplers.end(),
[id](const auto &it) { return it.id == id; }); [id](const sampler &info) { return info.id == id; });
} }
/// <summary> /// <summary>
/// Looks up an existing storage binding. /// Looks up an existing storage binding.
/// </summary> /// </summary>
/// <param name="id">SSA ID of the storage binding to find.</param> /// <param name="id">SSA ID of the storage binding to find.</param>
/// <returns>Reference to the storage description.</returns> /// <returns>Reference to the storage description.</returns>
const storage_info &get_storage(id id) const const storage &get_storage(id id) const
{ {
return *std::find_if(_module.storages.begin(), _module.storages.end(), return *std::find_if(_module.storages.begin(), _module.storages.end(),
[id](const auto &it) { return it.id == id; }); [id](const storage &info) { return info.id == id; });
} }
/// <summary> /// <summary>
/// Looks up an existing function definition. /// Looks up an existing function definition.
/// </summary> /// </summary>
/// <param name="id">SSA ID of the function variable to find.</param> /// <param name="id">SSA ID of the function variable to find.</param>
/// <returns>Reference to the function description.</returns> /// <returns>Reference to the function description.</returns>
function_info &get_function(id id) function &get_function(id id)
{ {
return *std::find_if(_functions.begin(), _functions.end(), return *std::find_if(_functions.begin(), _functions.end(),
[id](const auto &it) { return it->definition == id; })->get(); [id](const std::unique_ptr<function> &info) { return info->id == id; })->get();
}
function &get_function(const std::string &unique_name)
{
return *std::find_if(_functions.begin(), _functions.end(),
[&unique_name](const std::unique_ptr<function> &info) { return info->unique_name == unique_name; })->get();
} }
protected:
id make_id() { return _next_id++; } id make_id() { return _next_id++; }
static uint32_t align_up(uint32_t size, uint32_t alignment) effect_module _module;
{ std::vector<struct_type> _structs;
alignment -= 1; std::vector<std::unique_ptr<function>> _functions;
return ((size + alignment) & ~alignment);
}
static uint32_t align_up(uint32_t size, uint32_t alignment, uint32_t elements)
{
return align_up(size, alignment) * (elements - 1) + size;
}
reshadefx::module _module;
std::vector<struct_info> _structs;
std::vector<std::unique_ptr<function_info>> _functions;
id _next_id = 1; id _next_id = 1;
id _last_block = 0; id _last_block = 0;
id _current_block = 0; id _current_block = 0;
function *_current_function = nullptr;
}; };
/// <summary> /// <summary>
/// Creates a back-end implementation for GLSL code generation. /// Creates a back-end implementation for GLSL code generation.
/// </summary> /// </summary>
/// <param name="version">GLSL version to insert at the beginning of the file.</param>
/// <param name="gles">Generate GLSL ES code instead of core OpenGL.</param> /// <param name="gles">Generate GLSL ES code instead of core OpenGL.</param>
/// <param name="vulkan_semantics">Generate GLSL for OpenGL or for Vulkan.</param> /// <param name="vulkan_semantics">Generate GLSL for OpenGL or for Vulkan.</param>
/// <param name="debug_info">Whether to append debug information like line directives to the generated code.</param> /// <param name="debug_info">Whether to append debug information like line directives to the generated code.</param>
/// <param name="uniforms_to_spec_constants">Whether to convert uniform variables to specialization constants.</param> /// <param name="uniforms_to_spec_constants">Whether to convert uniform variables to specialization constants.</param>
/// <param name="enable_16bit_types">Use real 16-bit types for the minimum precision types "min16int", "min16uint" and "min16float".</param> /// <param name="enable_16bit_types">Use real 16-bit types for the minimum precision types "min16int", "min16uint" and "min16float".</param>
/// <param name="flip_vert_y">Insert code to flip the Y component of the output position in vertex shaders.</param> /// <param name="flip_vert_y">Insert code to flip the Y component of the output position in vertex shaders.</param>
codegen *create_codegen_glsl(bool gles, bool vulkan_semantics, bool debug_info, bool uniforms_to_spec_constants, bool enable_16bit_types = false, bool flip_vert_y = false); codegen *create_codegen_glsl(unsigned version, bool gles, bool vulkan_semantics, bool debug_info, bool uniforms_to_spec_constants, bool enable_16bit_types = false, bool flip_vert_y = false);
/// <summary> /// <summary>
/// Creates a back-end implementation for HLSL code generation. /// Creates a back-end implementation for HLSL code generation.
/// </summary> /// </summary>

View file

@ -15,7 +15,7 @@ namespace reshadefx
/// </summary> /// </summary>
struct type struct type
{ {
enum datatype : uint8_t enum datatype : uint32_t
{ {
t_void, t_void,
t_bool, t_bool,
@ -101,6 +101,8 @@ namespace reshadefx
bool is_function() const { return base == t_function; } bool is_function() const { return base == t_function; }
bool is_array() const { return array_length != 0; } bool is_array() const { return array_length != 0; }
bool is_bounded_array() const { return is_array() && array_length != 0xFFFFFFFF; }
bool is_unbounded_array() const { return array_length == 0xFFFFFFFF; }
bool is_scalar() const { return is_numeric() && !is_matrix() && !is_vector() && !is_array(); } bool is_scalar() const { return is_numeric() && !is_matrix() && !is_vector() && !is_array(); }
bool is_vector() const { return is_numeric() && rows > 1 && cols == 1; } bool is_vector() const { return is_numeric() && rows > 1 && cols == 1; }
bool is_matrix() const { return is_numeric() && rows >= 1 && cols > 1; } bool is_matrix() const { return is_numeric() && rows >= 1 && cols > 1; }
@ -109,27 +111,27 @@ namespace reshadefx
unsigned int components() const { return rows * cols; } unsigned int components() const { return rows * cols; }
unsigned int texture_dimension() const { return base >= t_texture1d && base <= t_storage3d_float ? ((base - t_texture1d) % 3) + 1 : 0; } unsigned int texture_dimension() const { return base >= t_texture1d && base <= t_storage3d_float ? ((base - t_texture1d) % 3) + 1 : 0; }
friend inline bool operator==(const type &lhs, const type &rhs) friend bool operator==(const type &lhs, const type &rhs)
{ {
return lhs.base == rhs.base && lhs.rows == rhs.rows && lhs.cols == rhs.cols && lhs.array_length == rhs.array_length && lhs.definition == rhs.definition; return lhs.base == rhs.base && lhs.rows == rhs.rows && lhs.cols == rhs.cols && lhs.array_length == rhs.array_length && lhs.struct_definition == rhs.struct_definition;
} }
friend inline bool operator!=(const type &lhs, const type &rhs) friend bool operator!=(const type &lhs, const type &rhs)
{ {
return !operator==(lhs, rhs); return !operator==(lhs, rhs);
} }
// Underlying base type ('int', 'float', ...) // Underlying base type ('int', 'float', ...)
datatype base = t_void; datatype base : 8;
// Number of rows if this is a vector type // Number of rows if this is a vector type
unsigned int rows = 0; uint32_t rows : 4;
// Number of columns if this is a matrix type // Number of columns if this is a matrix type
unsigned int cols = 0; uint32_t cols : 4;
// Bit mask of all the qualifiers decorating the type // Bit mask of all the qualifiers decorating the type
unsigned int qualifiers = 0; uint32_t qualifiers : 16;
// Negative if an unsized array, otherwise the number of elements if this is an array type // Number of elements if this is an array type, 0xFFFFFFFF if it is an unsized array
int array_length = 0; uint32_t array_length;
// ID of the matching struct if this is a struct type // ID of the matching struct if this is a struct type
uint32_t definition = 0; uint32_t struct_definition;
}; };
/// <summary> /// <summary>
@ -168,8 +170,8 @@ namespace reshadefx
op_type op; op_type op;
reshadefx::type from, to; reshadefx::type from, to;
uint32_t index = 0; uint32_t index;
signed char swizzle[4] = {}; signed char swizzle[4];
}; };
uint32_t base = 0; uint32_t base = 0;

View file

@ -7,14 +7,48 @@
#include "effect_expression.hpp" #include "effect_expression.hpp"
#include <cstdint> #include <cstdint>
#include <unordered_set>
namespace reshadefx namespace reshadefx
{ {
/// <summary> /// <summary>
/// A list of supported texture types. /// Describes an annotation attached to a variable.
/// </summary> /// </summary>
enum class texture_type struct annotation
{
reshadefx::type type = {};
std::string name;
reshadefx::constant value = {};
};
/// <summary>
/// Describes a struct member or parameter.
/// </summary>
struct member_type
{
reshadefx::type type = {};
uint32_t id = 0;
std::string name;
std::string semantic;
reshadefx::location location;
bool has_default_value = false;
reshadefx::constant default_value = {};
};
/// <summary>
/// Describes a struct type defined in effect code.
/// </summary>
struct struct_type
{
uint32_t id = 0;
std::string name;
std::string unique_name;
std::vector<member_type> member_list;
};
/// <summary>
/// Available texture types.
/// </summary>
enum class texture_type : uint8_t
{ {
texture_1d = 1, texture_1d = 1,
texture_2d = 2, texture_2d = 2,
@ -22,9 +56,9 @@ namespace reshadefx
}; };
/// <summary> /// <summary>
/// A list of supported texture formats. /// Available texture formats.
/// </summary> /// </summary>
enum class texture_format enum class texture_format : uint8_t
{ {
unknown, unknown,
@ -46,9 +80,46 @@ namespace reshadefx
}; };
/// <summary> /// <summary>
/// A filtering type used for texture lookups. /// Describes the properties of a <see cref="texture"/> object.
/// </summary> /// </summary>
enum class filter_mode struct texture_desc
{
uint32_t width = 1;
uint32_t height = 1;
uint16_t depth = 1;
uint16_t levels = 1;
texture_type type = texture_type::texture_2d;
texture_format format = texture_format::rgba8;
};
/// <summary>
/// Describes a texture object defined in effect code.
/// </summary>
struct texture : texture_desc
{
uint32_t id = 0;
std::string name;
std::string unique_name;
std::string semantic;
std::vector<annotation> annotations;
bool render_target = false;
bool storage_access = false;
};
/// <summary>
/// Describes the binding of a <see cref="texture"/> object.
/// </summary>
struct texture_binding
{
uint32_t binding = 0;
std::string texture_name;
bool srgb = false;
};
/// <summary>
/// Texture filtering modes available for texture sampling operations.
/// </summary>
enum class filter_mode : uint8_t
{ {
min_mag_mip_point = 0, min_mag_mip_point = 0,
min_mag_point_mip_linear = 0x1, min_mag_point_mip_linear = 0x1,
@ -57,13 +128,14 @@ namespace reshadefx
min_linear_mag_mip_point = 0x10, min_linear_mag_mip_point = 0x10,
min_linear_mag_point_mip_linear = 0x11, min_linear_mag_point_mip_linear = 0x11,
min_mag_linear_mip_point = 0x14, min_mag_linear_mip_point = 0x14,
min_mag_mip_linear = 0x15 min_mag_mip_linear = 0x15,
anisotropic = 0x55
}; };
/// <summary> /// <summary>
/// Specifies behavior of sampling with texture coordinates outside an image. /// Sampling behavior at texture coordinates outside the bounds of a texture resource.
/// </summary> /// </summary>
enum class texture_address_mode enum class texture_address_mode : uint8_t
{ {
wrap = 1, wrap = 1,
mirror = 2, mirror = 2,
@ -72,9 +144,117 @@ namespace reshadefx
}; };
/// <summary> /// <summary>
/// Specifies RGB or alpha blending operations. /// Describes the properties of a <see cref="sampler"/> object.
/// </summary> /// </summary>
enum class pass_blend_op : uint8_t struct sampler_desc
{
filter_mode filter = filter_mode::min_mag_mip_linear;
texture_address_mode address_u = texture_address_mode::clamp;
texture_address_mode address_v = texture_address_mode::clamp;
texture_address_mode address_w = texture_address_mode::clamp;
float min_lod = -3.402823466e+38f;
float max_lod = +3.402823466e+38f; // FLT_MAX
float lod_bias = 0.0f;
};
/// <summary>
/// Describes a texture sampler object defined in effect code.
/// </summary>
struct sampler : sampler_desc
{
reshadefx::type type = {};
uint32_t id = 0;
std::string name;
std::string unique_name;
std::string texture_name;
std::vector<annotation> annotations;
bool srgb = false;
};
/// <summary>
/// Describes the binding of a <see cref="sampler"/> object.
/// </summary>
struct sampler_binding : sampler_desc
{
uint32_t binding = 0;
};
/// <summary>
/// Describes the properties of a <see cref="storage"/> object.
/// </summary>
struct storage_desc
{
uint16_t level = 0;
};
/// <summary>
/// Describes a texture storage object defined in effect code.
/// </summary>
struct storage : storage_desc
{
reshadefx::type type = {};
uint32_t id = 0;
std::string name;
std::string unique_name;
std::string texture_name;
};
/// <summary>
/// Describes the binding of a <see cref="storage"/> object.
/// </summary>
struct storage_binding : storage_desc
{
uint32_t binding = 0;
std::string texture_name;
};
/// <summary>
/// Describes a uniform variable defined in effect code.
/// </summary>
struct uniform
{
reshadefx::type type = {};
std::string name;
uint32_t size = 0;
uint32_t offset = 0;
std::vector<annotation> annotations;
bool has_initializer_value = false;
reshadefx::constant initializer_value = {};
};
/// <summary>
/// Type of a shader entry point.
/// </summary>
enum class shader_type
{
unknown,
vertex,
pixel,
compute
};
/// <summary>
/// Describes a function defined in effect code.
/// </summary>
struct function
{
reshadefx::type return_type = {};
uint32_t id = 0;
std::string name;
std::string unique_name;
std::string return_semantic;
std::vector<member_type> parameter_list;
shader_type type = shader_type::unknown;
int num_threads[3] = {};
std::vector<uint32_t> referenced_samplers;
std::vector<uint32_t> referenced_storages;
std::vector<uint32_t> referenced_functions;
};
/// <summary>
/// Color or alpha blending operations.
/// </summary>
enum class blend_op : uint8_t
{ {
add = 1, add = 1,
subtract, subtract,
@ -84,9 +264,9 @@ namespace reshadefx
}; };
/// <summary> /// <summary>
/// Specifies blend factors, which modulate values between the pixel shader output and render target. /// Blend factors in color or alpha blending operations, which modulate values between the pixel shader output and render target.
/// </summary> /// </summary>
enum class pass_blend_factor : uint8_t enum class blend_factor : uint8_t
{ {
zero = 0, zero = 0,
one = 1, one = 1,
@ -101,9 +281,9 @@ namespace reshadefx
}; };
/// <summary> /// <summary>
/// Specifies the stencil operations that can be performed during depth-stencil testing. /// Stencil operations that can be performed during depth-stencil testing.
/// </summary> /// </summary>
enum class pass_stencil_op : uint8_t enum class stencil_op : uint8_t
{ {
zero = 0, zero = 0,
keep, keep,
@ -116,9 +296,9 @@ namespace reshadefx
}; };
/// <summary> /// <summary>
/// Specifies comparison options for depth-stencil testing. /// Comparison operations for depth-stencil testing.
/// </summary> /// </summary>
enum class pass_stencil_func : uint8_t enum class stencil_func : uint8_t
{ {
never, never,
less, less,
@ -143,205 +323,70 @@ namespace reshadefx
}; };
/// <summary> /// <summary>
/// A struct type defined in the effect code. /// Describes a render pass with all its state info.
/// </summary> /// </summary>
struct struct_info struct pass
{
std::string name;
std::string unique_name;
std::vector<struct struct_member_info> member_list;
uint32_t definition = 0;
};
/// <summary>
/// A struct field defined in the effect code.
/// </summary>
struct struct_member_info
{
reshadefx::type type;
std::string name;
std::string semantic;
reshadefx::location location;
uint32_t definition = 0;
};
/// <summary>
/// An annotation attached to a variable.
/// </summary>
struct annotation
{
reshadefx::type type;
std::string name;
reshadefx::constant value;
};
/// <summary>
/// A texture defined in the effect code.
/// </summary>
struct texture_info
{
uint32_t id = 0;
uint32_t binding = 0;
std::string name;
std::string semantic;
std::string unique_name;
std::vector<annotation> annotations;
texture_type type = texture_type::texture_2d;
uint32_t width = 1;
uint32_t height = 1;
uint16_t depth = 1;
uint16_t levels = 1;
texture_format format = texture_format::rgba8;
bool render_target = false;
bool storage_access = false;
};
/// <summary>
/// A texture sampler defined in the effect code.
/// </summary>
struct sampler_info
{
uint32_t id = 0;
uint32_t binding = 0;
uint32_t texture_binding = 0;
std::string name;
reshadefx::type type;
std::string unique_name;
std::string texture_name;
std::vector<annotation> annotations;
filter_mode filter = filter_mode::min_mag_mip_linear;
texture_address_mode address_u = texture_address_mode::clamp;
texture_address_mode address_v = texture_address_mode::clamp;
texture_address_mode address_w = texture_address_mode::clamp;
float min_lod = -3.402823466e+38f;
float max_lod = +3.402823466e+38f; // FLT_MAX
float lod_bias = 0.0f;
uint8_t srgb = false;
};
/// <summary>
/// A texture storage object defined in the effect code.
/// </summary>
struct storage_info
{
uint32_t id = 0;
uint32_t binding = 0;
std::string name;
reshadefx::type type;
std::string unique_name;
std::string texture_name;
uint16_t level = 0;
};
/// <summary>
/// An uniform variable defined in the effect code.
/// </summary>
struct uniform_info
{
std::string name;
reshadefx::type type;
uint32_t size = 0;
uint32_t offset = 0;
std::vector<annotation> annotations;
bool has_initializer_value = false;
reshadefx::constant initializer_value;
};
/// <summary>
/// Type of a shader entry point.
/// </summary>
enum class shader_type
{
vs,
ps,
cs,
};
/// <summary>
/// A shader entry point function.
/// </summary>
struct entry_point
{
std::string name;
shader_type type;
};
/// <summary>
/// A function defined in the effect code.
/// </summary>
struct function_info
{
uint32_t definition;
std::string name;
std::string unique_name;
reshadefx::type return_type;
std::string return_semantic;
std::vector<struct_member_info> parameter_list;
std::unordered_set<uint32_t> referenced_samplers;
std::unordered_set<uint32_t> referenced_storages;
};
/// <summary>
/// A render pass with all its state info.
/// </summary>
struct pass_info
{ {
std::string name; std::string name;
std::string render_target_names[8] = {}; std::string render_target_names[8] = {};
std::string vs_entry_point; std::string vs_entry_point;
std::string ps_entry_point; std::string ps_entry_point;
std::string cs_entry_point; std::string cs_entry_point;
uint8_t generate_mipmaps = true; bool generate_mipmaps = true;
uint8_t clear_render_targets = false; bool clear_render_targets = false;
uint8_t srgb_write_enable = false; bool blend_enable[8] = { false, false, false, false, false, false, false, false };
uint8_t blend_enable[8] = { false, false, false, false, false, false, false, false }; blend_factor source_color_blend_factor[8] = { blend_factor::one, blend_factor::one, blend_factor::one, blend_factor::one, blend_factor::one, blend_factor::one, blend_factor::one, blend_factor::one };
uint8_t stencil_enable = false; blend_factor dest_color_blend_factor[8] = { blend_factor::zero, blend_factor::zero, blend_factor::zero, blend_factor::zero, blend_factor::zero, blend_factor::zero, blend_factor::zero, blend_factor::zero };
uint8_t color_write_mask[8] = { 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF }; blend_op color_blend_op[8] = { blend_op::add, blend_op::add, blend_op::add, blend_op::add, blend_op::add, blend_op::add, blend_op::add, blend_op::add };
blend_factor source_alpha_blend_factor[8] = { blend_factor::one, blend_factor::one, blend_factor::one, blend_factor::one, blend_factor::one, blend_factor::one, blend_factor::one, blend_factor::one };
blend_factor dest_alpha_blend_factor[8] = { blend_factor::zero, blend_factor::zero, blend_factor::zero, blend_factor::zero, blend_factor::zero, blend_factor::zero, blend_factor::zero, blend_factor::zero };
blend_op alpha_blend_op[8] = { blend_op::add, blend_op::add, blend_op::add, blend_op::add, blend_op::add, blend_op::add, blend_op::add, blend_op::add };
bool srgb_write_enable = false;
uint8_t render_target_write_mask[8] = { 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF };
bool stencil_enable = false;
uint8_t stencil_read_mask = 0xFF; uint8_t stencil_read_mask = 0xFF;
uint8_t stencil_write_mask = 0xFF; uint8_t stencil_write_mask = 0xFF;
pass_blend_op blend_op[8] = { pass_blend_op::add, pass_blend_op::add, pass_blend_op::add, pass_blend_op::add, pass_blend_op::add, pass_blend_op::add, pass_blend_op::add, pass_blend_op::add }; stencil_func stencil_comparison_func = stencil_func::always;
pass_blend_op blend_op_alpha[8] = { pass_blend_op::add, pass_blend_op::add, pass_blend_op::add, pass_blend_op::add, pass_blend_op::add, pass_blend_op::add, pass_blend_op::add, pass_blend_op::add }; stencil_op stencil_pass_op = stencil_op::keep;
pass_blend_factor src_blend[8] = { pass_blend_factor::one, pass_blend_factor::one, pass_blend_factor::one, pass_blend_factor::one, pass_blend_factor::one, pass_blend_factor::one, pass_blend_factor::one, pass_blend_factor::one }; stencil_op stencil_fail_op = stencil_op::keep;
pass_blend_factor dest_blend[8] = { pass_blend_factor::zero, pass_blend_factor::zero, pass_blend_factor::zero, pass_blend_factor::zero, pass_blend_factor::zero, pass_blend_factor::zero, pass_blend_factor::zero, pass_blend_factor::zero }; stencil_op stencil_depth_fail_op = stencil_op::keep;
pass_blend_factor src_blend_alpha[8] = { pass_blend_factor::one, pass_blend_factor::one, pass_blend_factor::one, pass_blend_factor::one, pass_blend_factor::one, pass_blend_factor::one, pass_blend_factor::one, pass_blend_factor::one };
pass_blend_factor dest_blend_alpha[8] = { pass_blend_factor::zero, pass_blend_factor::zero, pass_blend_factor::zero, pass_blend_factor::zero, pass_blend_factor::zero, pass_blend_factor::zero, pass_blend_factor::zero, pass_blend_factor::zero };
pass_stencil_func stencil_comparison_func = pass_stencil_func::always;
uint32_t stencil_reference_value = 0;
pass_stencil_op stencil_op_pass = pass_stencil_op::keep;
pass_stencil_op stencil_op_fail = pass_stencil_op::keep;
pass_stencil_op stencil_op_depth_fail = pass_stencil_op::keep;
uint32_t num_vertices = 3;
primitive_topology topology = primitive_topology::triangle_list; primitive_topology topology = primitive_topology::triangle_list;
uint32_t stencil_reference_value = 0;
uint32_t num_vertices = 3;
uint32_t viewport_width = 0; uint32_t viewport_width = 0;
uint32_t viewport_height = 0; uint32_t viewport_height = 0;
uint32_t viewport_dispatch_z = 1; uint32_t viewport_dispatch_z = 1;
std::vector<sampler_info> samplers;
std::vector<storage_info> storages; // Bindings specific for the code generation target (in case of combined texture and sampler, 'texture_bindings' and 'sampler_bindings' will be the same size and point to the same bindings, otherwise they are independent)
std::vector<texture_binding> texture_bindings;
std::vector<sampler_binding> sampler_bindings;
std::vector<storage_binding> storage_bindings;
}; };
/// <summary> /// <summary>
/// A collection of passes that make up an effect. /// A collection of passes that make up an effect.
/// </summary> /// </summary>
struct technique_info struct technique
{ {
std::string name; std::string name;
std::vector<pass_info> passes; std::vector<pass> passes;
std::vector<annotation> annotations; std::vector<annotation> annotations;
}; };
/// <summary> /// <summary>
/// In-memory representation of an effect file. /// In-memory representation of an effect file.
/// </summary> /// </summary>
struct module struct effect_module
{ {
std::vector<char> code; std::vector<std::pair<std::string, shader_type>> entry_points;
std::vector<entry_point> entry_points; std::vector<texture> textures;
std::vector<texture_info> textures; std::vector<sampler> samplers;
std::vector<sampler_info> samplers; std::vector<storage> storages;
std::vector<storage_info> storages;
std::vector<uniform_info> uniforms, spec_constants; std::vector<uniform> uniforms;
std::vector<technique_info> techniques; std::vector<uniform> spec_constants;
std::vector<technique> techniques;
uint32_t total_uniform_size = 0; uint32_t total_uniform_size = 0;
uint32_t num_texture_bindings = 0; uint32_t num_texture_bindings = 0;

View file

@ -58,14 +58,14 @@ namespace reshadefx
bool peek_multary_op(unsigned int &precedence) const; bool peek_multary_op(unsigned int &precedence) const;
bool accept_assignment_op(); bool accept_assignment_op();
void parse_top(bool &parse_success); bool parse_top(bool &parse_success);
bool parse_struct(); bool parse_struct();
bool parse_function(type type, std::string name); bool parse_function(type type, std::string name, shader_type stype, int num_threads[3]);
bool parse_variable(type type, std::string name, bool global = false); bool parse_variable(type type, std::string name, bool global = false);
bool parse_technique(); bool parse_technique();
bool parse_technique_pass(pass_info &info); bool parse_technique_pass(pass &info);
bool parse_type(type &type); bool parse_type(type &type);
bool parse_array_size(type &type); bool parse_array_length(type &type);
bool parse_expression(expression &expression); bool parse_expression(expression &expression);
bool parse_expression_unary(expression &expression); bool parse_expression_unary(expression &expression);
bool parse_expression_multary(expression &expression, unsigned int precedence = 0); bool parse_expression_multary(expression &expression, unsigned int precedence = 0);
@ -74,15 +74,16 @@ namespace reshadefx
bool parse_statement(bool scoped); bool parse_statement(bool scoped);
bool parse_statement_block(bool scoped); bool parse_statement_block(bool scoped);
codegen *_codegen = nullptr;
std::string _errors; std::string _errors;
token _token, _token_next, _token_backup;
std::unique_ptr<class lexer> _lexer; std::unique_ptr<class lexer> _lexer;
size_t _lexer_backup_offset = 0; class codegen *_codegen = nullptr;
token _token;
token _token_next;
token _token_backup;
std::vector<uint32_t> _loop_break_target_stack; std::vector<uint32_t> _loop_break_target_stack;
std::vector<uint32_t> _loop_continue_target_stack; std::vector<uint32_t> _loop_continue_target_stack;
reshadefx::function_info *_current_function = nullptr;
}; };
} }

View file

@ -154,17 +154,16 @@ namespace reshadefx
void expand_macro(const std::string &name, const macro &macro, const std::vector<std::string> &arguments); void expand_macro(const std::string &name, const macro &macro, const std::vector<std::string> &arguments);
void create_macro_replacement_list(macro &macro); void create_macro_replacement_list(macro &macro);
bool _success = true;
include_file_exists_callback _file_exists_cb; include_file_exists_callback _file_exists_cb;
include_read_file_callback _read_file_cb; include_read_file_callback _read_file_cb;
std::string _output, _errors; std::string _output, _errors;
std::string _current_token_raw_data;
reshadefx::token _token;
location _output_location;
std::vector<input_level> _input_stack; std::vector<input_level> _input_stack;
size_t _next_input_index = 0; size_t _next_input_index = 0;
size_t _current_input_index = 0; size_t _current_input_index = 0;
reshadefx::token _token;
std::string _current_token_raw_data;
reshadefx::location _output_location;
std::vector<if_level> _if_stack; std::vector<if_level> _if_stack;

View file

@ -42,7 +42,7 @@ namespace reshadefx
uint32_t id = 0; uint32_t id = 0;
reshadefx::type type = {}; reshadefx::type type = {};
reshadefx::constant constant = {}; reshadefx::constant constant = {};
const reshadefx::function_info *function = nullptr; const reshadefx::function *function = nullptr;
}; };
struct scoped_symbol : symbol struct scoped_symbol : symbol
{ {

View file

@ -8,6 +8,7 @@
#include <cstdint> #include <cstdint>
#include <string> #include <string>
#include <vector> #include <vector>
#include <cstdint>
namespace reshadefx namespace reshadefx
{ {
@ -246,7 +247,7 @@ namespace reshadefx
}; };
std::string literal_as_string; std::string literal_as_string;
inline operator tokenid() const { return id; } operator tokenid() const { return id; }
static std::string id_to_name(tokenid id); static std::string id_to_name(tokenid id);
}; };

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -3,16 +3,16 @@
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*/ */
#include "effect_lexer.hpp" #include "effect_expression.hpp"
#include "effect_codegen.hpp" #include <cmath> // std::fmod
#include <cmath> // fmod
#include <cassert> #include <cassert>
#include <cstring> // memcpy, memset #include <cstring> // std::memcpy, std::memset
#include <algorithm> // std::min, std::max #include <algorithm> // std::max, std::min
reshadefx::type reshadefx::type::merge(const type &lhs, const type &rhs) reshadefx::type reshadefx::type::merge(const type &lhs, const type &rhs)
{ {
type result = { std::max(lhs.base, rhs.base) }; type result;
result.base = std::max(lhs.base, rhs.base);
// Non-numeric types cannot be vectors or matrices // Non-numeric types cannot be vectors or matrices
if (!result.is_numeric()) if (!result.is_numeric())
@ -35,11 +35,14 @@ reshadefx::type reshadefx::type::merge(const type &lhs, const type &rhs)
// Some qualifiers propagate to the result // Some qualifiers propagate to the result
result.qualifiers = (lhs.qualifiers & type::q_precise) | (rhs.qualifiers & type::q_precise); result.qualifiers = (lhs.qualifiers & type::q_precise) | (rhs.qualifiers & type::q_precise);
// In case this is a structure, assume they are the same // Cannot merge array types, assume no arrays
result.definition = rhs.definition; result.array_length = 0;
assert(lhs.definition == rhs.definition || lhs.definition == 0);
assert(lhs.array_length == 0 && rhs.array_length == 0); assert(lhs.array_length == 0 && rhs.array_length == 0);
// In case this is a structure, assume they are the same
result.struct_definition = rhs.struct_definition;
assert(lhs.struct_definition == rhs.struct_definition || lhs.struct_definition == 0);
return result; return result;
} }
@ -48,101 +51,101 @@ std::string reshadefx::type::description() const
std::string result; std::string result;
switch (base) switch (base)
{ {
case reshadefx::type::t_void: case t_void:
result = "void"; result = "void";
break; break;
case reshadefx::type::t_bool: case t_bool:
result = "bool"; result = "bool";
break; break;
case reshadefx::type::t_min16int: case t_min16int:
result = "min16int"; result = "min16int";
break; break;
case reshadefx::type::t_int: case t_int:
result = "int"; result = "int";
break; break;
case reshadefx::type::t_min16uint: case t_min16uint:
result = "min16uint"; result = "min16uint";
break; break;
case reshadefx::type::t_uint: case t_uint:
result = "uint"; result = "uint";
break; break;
case reshadefx::type::t_min16float: case t_min16float:
result = "min16float"; result = "min16float";
break; break;
case reshadefx::type::t_float: case t_float:
result = "float"; result = "float";
break; break;
case reshadefx::type::t_string: case t_string:
result = "string"; result = "string";
break; break;
case reshadefx::type::t_struct: case t_struct:
result = "struct"; result = "struct";
break; break;
case reshadefx::type::t_texture1d: case t_texture1d:
result = "texture1D"; result = "texture1D";
break; break;
case reshadefx::type::t_texture2d: case t_texture2d:
result = "texture2D"; result = "texture2D";
break; break;
case reshadefx::type::t_texture3d: case t_texture3d:
result = "texture3D"; result = "texture3D";
break; break;
case reshadefx::type::t_sampler1d_int: case t_sampler1d_int:
result = "sampler1D<int" + std::to_string(rows) + '>'; result = "sampler1D<int" + std::to_string(rows) + '>';
break; break;
case reshadefx::type::t_sampler2d_int: case t_sampler2d_int:
result = "sampler2D<int" + std::to_string(rows) + '>'; result = "sampler2D<int" + std::to_string(rows) + '>';
break; break;
case reshadefx::type::t_sampler3d_int: case t_sampler3d_int:
result = "sampler3D<int" + std::to_string(rows) + '>'; result = "sampler3D<int" + std::to_string(rows) + '>';
break; break;
case reshadefx::type::t_sampler1d_uint: case t_sampler1d_uint:
result = "sampler1D<uint" + std::to_string(rows) + '>'; result = "sampler1D<uint" + std::to_string(rows) + '>';
break; break;
case reshadefx::type::t_sampler2d_uint: case t_sampler2d_uint:
result = "sampler2D<uint" + std::to_string(rows) + '>'; result = "sampler2D<uint" + std::to_string(rows) + '>';
break; break;
case reshadefx::type::t_sampler3d_uint: case t_sampler3d_uint:
result = "sampler3D<uint" + std::to_string(rows) + '>'; result = "sampler3D<uint" + std::to_string(rows) + '>';
break; break;
case reshadefx::type::t_sampler1d_float: case t_sampler1d_float:
result = "sampler1D<float" + std::to_string(rows) + '>'; result = "sampler1D<float" + std::to_string(rows) + '>';
break; break;
case reshadefx::type::t_sampler2d_float: case t_sampler2d_float:
result = "sampler2D<float" + std::to_string(rows) + '>'; result = "sampler2D<float" + std::to_string(rows) + '>';
break; break;
case reshadefx::type::t_sampler3d_float: case t_sampler3d_float:
result = "sampler3D<float" + std::to_string(rows) + '>'; result = "sampler3D<float" + std::to_string(rows) + '>';
break; break;
case reshadefx::type::t_storage1d_int: case t_storage1d_int:
result = "storage1D<int" + std::to_string(rows) + '>'; result = "storage1D<int" + std::to_string(rows) + '>';
break; break;
case reshadefx::type::t_storage2d_int: case t_storage2d_int:
result = "storage2D<int" + std::to_string(rows) + '>'; result = "storage2D<int" + std::to_string(rows) + '>';
break; break;
case reshadefx::type::t_storage3d_int: case t_storage3d_int:
result = "storage3D<int" + std::to_string(rows) + '>'; result = "storage3D<int" + std::to_string(rows) + '>';
break; break;
case reshadefx::type::t_storage1d_uint: case t_storage1d_uint:
result = "storage1D<uint" + std::to_string(rows) + '>'; result = "storage1D<uint" + std::to_string(rows) + '>';
break; break;
case reshadefx::type::t_storage2d_uint: case t_storage2d_uint:
result = "storage2D<uint" + std::to_string(rows) + '>'; result = "storage2D<uint" + std::to_string(rows) + '>';
break; break;
case reshadefx::type::t_storage3d_uint: case t_storage3d_uint:
result = "storage3D<uint" + std::to_string(rows) + '>'; result = "storage3D<uint" + std::to_string(rows) + '>';
break; break;
case reshadefx::type::t_storage1d_float: case t_storage1d_float:
result = "storage1D<float" + std::to_string(rows) + '>'; result = "storage1D<float" + std::to_string(rows) + '>';
break; break;
case reshadefx::type::t_storage2d_float: case t_storage2d_float:
result = "storage2D<float" + std::to_string(rows) + '>'; result = "storage2D<float" + std::to_string(rows) + '>';
break; break;
case reshadefx::type::t_storage3d_float: case t_storage3d_float:
result = "storage3D<float" + std::to_string(rows) + '>'; result = "storage3D<float" + std::to_string(rows) + '>';
break; break;
case reshadefx::type::t_function: case t_function:
result = "function"; assert(false);
break; break;
} }
@ -157,7 +160,7 @@ std::string reshadefx::type::description() const
if (is_array()) if (is_array())
{ {
result += '['; result += '[';
if (array_length > 0) if (is_bounded_array())
result += std::to_string(array_length); result += std::to_string(array_length);
result += ']'; result += ']';
} }
@ -179,7 +182,7 @@ void reshadefx::expression::reset_to_lvalue(const reshadefx::location &loc, uint
type.qualifiers |= type::q_const; type.qualifiers |= type::q_const;
// Strip away global variable qualifiers // Strip away global variable qualifiers
type.qualifiers &= ~(reshadefx::type::q_extern | reshadefx::type::q_static | reshadefx::type::q_uniform | reshadefx::type::q_groupshared); type.qualifiers &= ~(type::q_extern | type::q_static | type::q_uniform | type::q_groupshared);
} }
void reshadefx::expression::reset_to_rvalue(const reshadefx::location &loc, uint32_t in_base, const reshadefx::type &in_type) void reshadefx::expression::reset_to_rvalue(const reshadefx::location &loc, uint32_t in_base, const reshadefx::type &in_type)
{ {
@ -192,7 +195,7 @@ void reshadefx::expression::reset_to_rvalue(const reshadefx::location &loc, uint
chain.clear(); chain.clear();
// Strip away global variable qualifiers // Strip away global variable qualifiers
type.qualifiers &= ~(reshadefx::type::q_extern | reshadefx::type::q_static | reshadefx::type::q_uniform | reshadefx::type::q_groupshared); type.qualifiers &= ~(type::q_extern | type::q_static | type::q_uniform | type::q_groupshared);
} }
void reshadefx::expression::reset_to_rvalue_constant(const reshadefx::location &loc, bool data) void reshadefx::expression::reset_to_rvalue_constant(const reshadefx::location &loc, bool data)
@ -290,7 +293,7 @@ void reshadefx::expression::add_cast_operation(const reshadefx::type &cast_type)
constant.as_float[i] = static_cast<float>(constant.as_int[i]); constant.as_float[i] = static_cast<float>(constant.as_int[i]);
}; };
for (auto &element : constant.array_data) for (struct constant &element : constant.array_data)
cast_constant(element, type, cast_type); cast_constant(element, type, cast_type);
cast_constant(constant, type, cast_type); cast_constant(constant, type, cast_type);
@ -320,7 +323,7 @@ void reshadefx::expression::add_dynamic_index_access(uint32_t index_expression)
assert(!is_constant); // Cannot have dynamic indexing into constant in SPIR-V assert(!is_constant); // Cannot have dynamic indexing into constant in SPIR-V
assert(type.is_array() || (type.is_numeric() && !type.is_scalar())); assert(type.is_array() || (type.is_numeric() && !type.is_scalar()));
auto prev_type = type; struct type prev_type = type;
if (type.is_array()) if (type.is_array())
{ {
@ -342,11 +345,11 @@ void reshadefx::expression::add_constant_index_access(unsigned int index)
{ {
assert(type.is_array() || (type.is_numeric() && !type.is_scalar())); assert(type.is_array() || (type.is_numeric() && !type.is_scalar()));
auto prev_type = type; struct type prev_type = type;
if (type.is_array()) if (type.is_array())
{ {
assert(type.array_length < 0 || index < static_cast<unsigned int>(type.array_length)); assert(index < type.array_length);
type.array_length = 0; type.array_length = 0;
} }
@ -389,7 +392,7 @@ void reshadefx::expression::add_swizzle_access(const signed char swizzle[4], uns
{ {
assert(type.is_numeric() && !type.is_array()); assert(type.is_numeric() && !type.is_array());
const auto prev_type = type; const struct type prev_type = type;
type.rows = length; type.rows = length;
type.cols = 1; type.cols = 1;

View file

@ -18,7 +18,7 @@ enum token_type
}; };
// Lookup table which translates a given char to a token type // Lookup table which translates a given char to a token type
static const unsigned type_lookup[256] = { static const unsigned int s_type_lookup[256] = {
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, SPACE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, SPACE,
'\n', SPACE, SPACE, SPACE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, '\n', SPACE, SPACE, SPACE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -35,7 +35,7 @@ static const unsigned type_lookup[256] = {
}; };
// Lookup tables which translate a given string literal to a token and backwards // Lookup tables which translate a given string literal to a token and backwards
static const std::unordered_map<tokenid, std::string_view> token_lookup = { static const std::unordered_map<tokenid, std::string_view> s_token_lookup = {
{ tokenid::end_of_file, "end of file" }, { tokenid::end_of_file, "end of file" },
{ tokenid::exclaim, "!" }, { tokenid::exclaim, "!" },
{ tokenid::hash, "#" }, { tokenid::hash, "#" },
@ -205,7 +205,7 @@ static const std::unordered_map<tokenid, std::string_view> token_lookup = {
{ tokenid::storage2d, "storage2D" }, { tokenid::storage2d, "storage2D" },
{ tokenid::storage3d, "storage3D" }, { tokenid::storage3d, "storage3D" },
}; };
static const std::unordered_map<std::string_view, tokenid> keyword_lookup = { static const std::unordered_map<std::string_view, tokenid> s_keyword_lookup = {
{ "asm", tokenid::reserved }, { "asm", tokenid::reserved },
{ "asm_fragment", tokenid::reserved }, { "asm_fragment", tokenid::reserved },
{ "auto", tokenid::reserved }, { "auto", tokenid::reserved },
@ -439,7 +439,7 @@ static const std::unordered_map<std::string_view, tokenid> keyword_lookup = {
{ "volatile", tokenid::volatile_ }, { "volatile", tokenid::volatile_ },
{ "while", tokenid::while_ } { "while", tokenid::while_ }
}; };
static const std::unordered_map<std::string_view, tokenid> pp_directive_lookup = { static const std::unordered_map<std::string_view, tokenid> s_pp_directive_lookup = {
{ "define", tokenid::hash_def }, { "define", tokenid::hash_def },
{ "undef", tokenid::hash_undef }, { "undef", tokenid::hash_undef },
{ "if", tokenid::hash_if }, { "if", tokenid::hash_if },
@ -454,15 +454,15 @@ static const std::unordered_map<std::string_view, tokenid> pp_directive_lookup =
{ "include", tokenid::hash_include }, { "include", tokenid::hash_include },
}; };
static inline bool is_octal_digit(char c) static bool is_octal_digit(char c)
{ {
return static_cast<unsigned>(c - '0') < 8; return static_cast<unsigned>(c - '0') < 8;
} }
static inline bool is_decimal_digit(char c) static bool is_decimal_digit(char c)
{ {
return static_cast<unsigned>(c - '0') < 10; return static_cast<unsigned>(c - '0') < 10;
} }
static inline bool is_hexadecimal_digit(char c) static bool is_hexadecimal_digit(char c)
{ {
return is_decimal_digit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); return is_decimal_digit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
} }
@ -504,8 +504,8 @@ static long long octal_to_decimal(long long n)
std::string reshadefx::token::id_to_name(tokenid id) std::string reshadefx::token::id_to_name(tokenid id)
{ {
const auto it = token_lookup.find(id); const auto it = s_token_lookup.find(id);
if (it != token_lookup.end()) if (it != s_token_lookup.end())
return std::string(it->second); return std::string(it->second);
return "unknown"; return "unknown";
} }
@ -526,7 +526,7 @@ next_token:
assert(_cur <= _end); assert(_cur <= _end);
// Do a character type lookup for the current character // Do a character type lookup for the current character
switch (type_lookup[uint8_t(*_cur)]) switch (s_type_lookup[uint8_t(*_cur)])
{ {
case 0xFF: // EOF case 0xFF: // EOF
tok.id = tokenid::end_of_file; tok.id = tokenid::end_of_file;
@ -635,7 +635,7 @@ next_token:
tok.id = tokenid::minus; tok.id = tokenid::minus;
break; break;
case '.': case '.':
if (type_lookup[uint8_t(_cur[1])] == DIGIT) if (s_type_lookup[uint8_t(_cur[1])] == DIGIT)
parse_numeric_literal(tok); parse_numeric_literal(tok);
else if (_cur[1] == '.' && _cur[2] == '.') else if (_cur[1] == '.' && _cur[2] == '.')
tok.id = tokenid::ellipsis, tok.id = tokenid::ellipsis,
@ -805,7 +805,7 @@ void reshadefx::lexer::skip_space()
continue; continue;
} }
if (type_lookup[uint8_t(*_cur)] == SPACE) if (s_type_lookup[uint8_t(*_cur)] == SPACE)
skip(1); skip(1);
else else
break; break;
@ -841,7 +841,7 @@ void reshadefx::lexer::parse_identifier(token &tok) const
auto *const begin = _cur, *end = begin; auto *const begin = _cur, *end = begin;
// Skip to the end of the identifier sequence // Skip to the end of the identifier sequence
while (type_lookup[uint8_t(*end)] == IDENT || type_lookup[uint8_t(*end)] == DIGIT) while (s_type_lookup[uint8_t(*end)] == IDENT || s_type_lookup[uint8_t(*end)] == DIGIT)
end++; end++;
tok.id = tokenid::identifier; tok.id = tokenid::identifier;
@ -852,8 +852,8 @@ void reshadefx::lexer::parse_identifier(token &tok) const
if (_ignore_keywords) if (_ignore_keywords)
return; return;
if (const auto it = keyword_lookup.find(tok.literal_as_string); if (const auto it = s_keyword_lookup.find(tok.literal_as_string);
it != keyword_lookup.end()) it != s_keyword_lookup.end())
tok.id = it->second; tok.id = it->second;
} }
bool reshadefx::lexer::parse_pp_directive(token &tok) bool reshadefx::lexer::parse_pp_directive(token &tok)
@ -862,8 +862,8 @@ bool reshadefx::lexer::parse_pp_directive(token &tok)
skip_space(); // Skip any space between the '#' and directive skip_space(); // Skip any space between the '#' and directive
parse_identifier(tok); parse_identifier(tok);
if (const auto it = pp_directive_lookup.find(tok.literal_as_string); if (const auto it = s_pp_directive_lookup.find(tok.literal_as_string);
it != pp_directive_lookup.end()) it != s_pp_directive_lookup.end())
{ {
tok.id = it->second; tok.id = it->second;
return true; return true;
@ -999,6 +999,9 @@ void reshadefx::lexer::parse_string_literal(token &tok, bool escape)
tok.id = tokenid::string_literal; tok.id = tokenid::string_literal;
tok.length = end - begin + 1; tok.length = end - begin + 1;
// Free up unused memory
tok.literal_as_string.shrink_to_fit();
} }
void reshadefx::lexer::parse_numeric_literal(token &tok) const void reshadefx::lexer::parse_numeric_literal(token &tok) const
{ {

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -5,8 +5,8 @@
#include "effect_lexer.hpp" #include "effect_lexer.hpp"
#include "effect_preprocessor.hpp" #include "effect_preprocessor.hpp"
#include <cstdio> // fclose, fopen, fread, fseek
#include <cassert> #include <cassert>
#include <fstream>
#include <algorithm> // std::find_if #include <algorithm> // std::find_if
#ifndef _WIN32 #ifndef _WIN32
@ -52,7 +52,7 @@ enum macro_replacement
macro_replacement_stringize = '\xFE', macro_replacement_stringize = '\xFE',
}; };
static const int precedence_lookup[] = { static const int s_precedence_lookup[] = {
0, 1, 2, 3, 4, // bitwise operators 0, 1, 2, 3, 4, // bitwise operators
5, 6, 7, 7, 7, 7, // logical operators 5, 6, 7, 7, 7, 7, // logical operators
8, 8, // left shift, right shift 8, 8, // left shift, right shift
@ -61,9 +61,8 @@ static const int precedence_lookup[] = {
11, 11, 11, 11 // unary operators 11, 11, 11, 11 // unary operators
}; };
static bool read_file(const std::string &path, std::string &data, reshadefx::preprocessor::include_read_file_callback &cb) static bool read_file(const std::string &path, std::string &file_data, reshadefx::preprocessor::include_read_file_callback &cb)
{ {
std::string file_data;
if (!cb(path, file_data)) if (!cb(path, file_data))
return false; return false;
@ -77,29 +76,33 @@ static bool read_file(const std::string &path, std::string &data, reshadefx::pre
static_cast<unsigned char>(file_data[2]) == 0xbf) static_cast<unsigned char>(file_data[2]) == 0xbf)
file_data.erase(0, 3); file_data.erase(0, 3);
data = std::move(file_data);
return true; return true;
} }
bool reshadefx::preprocessor::stdfs_read_file_callback(const std::string &path, std::string &data) bool reshadefx::preprocessor::stdfs_read_file_callback(const std::string &path, std::string &data)
{ {
std::ifstream file(std::filesystem::path(path), std::ios::binary); // Read file contents into memory
if (!file) const std::filesystem::path fspath(path);
return false; #ifndef _WIN32
FILE *const file = fopen(fspath.c_str(), "rb");
#else
FILE *const file = _wfsopen(fspath.generic_wstring().c_str(), L"rb", SH_DENYWR);
#endif
if (file == nullptr)
return false;
// Read file contents into memory fseek(file, 0, SEEK_END);
std::error_code ec; const size_t file_size = ftell(file);
const uintmax_t file_size = std::filesystem::file_size(path, ec); fseek(file, 0, SEEK_SET);
if (ec)
return false;
data.reserve(file_size + 1); const size_t file_size_read = fread(data.data(), 1, file_size, file);
data.resize(static_cast<size_t>(file_size), '\0');
if (!file.read(data.data(), file_size)) // No longer need to have a handle open to the file, since all data was read, so can safely close it
return false; fclose(file);
if (file_size_read != file_size)
return false;
// No longer need to have a handle open to the file, since all data was read, so can safely close it
file.close();
return true; return true;
} }
@ -156,7 +159,8 @@ bool reshadefx::preprocessor::append_string(std::string source_code, const std::
// Enforce all input strings to end with a line feed // Enforce all input strings to end with a line feed
assert(!source_code.empty() && source_code.back() == '\n'); assert(!source_code.empty() && source_code.back() == '\n');
_success = true; // Clear success flag before parsing a new string // Only consider new errors added below for the success of this call
const size_t errors_offset = _errors.length();
// Give this push a name, so that lexer location starts at a new line // Give this push a name, so that lexer location starts at a new line
// This is necessary in case this string starts with a preprocessor directive, since the lexer only reports those as such if they appear at the beginning of a new line // This is necessary in case this string starts with a preprocessor directive, since the lexer only reports those as such if they appear at the beginning of a new line
@ -164,15 +168,15 @@ bool reshadefx::preprocessor::append_string(std::string source_code, const std::
push(std::move(source_code), path.empty() ? "unknown" : path); push(std::move(source_code), path.empty() ? "unknown" : path);
parse(); parse();
return _success; return _errors.find(": preprocessor error: ", errors_offset) == std::string::npos;
} }
std::vector<std::filesystem::path> reshadefx::preprocessor::included_files() const std::vector<std::filesystem::path> reshadefx::preprocessor::included_files() const
{ {
std::vector<std::filesystem::path> files; std::vector<std::filesystem::path> files;
files.reserve(_file_cache.size()); files.reserve(_file_cache.size());
for (const auto &it : _file_cache) for (const std::pair<std::string, std::string> &cache_entry : _file_cache)
files.push_back(std::filesystem::u8path(it.first)); files.push_back(std::filesystem::u8path(cache_entry.first));
return files; return files;
} }
std::vector<std::pair<std::string, std::string>> reshadefx::preprocessor::used_macro_definitions() const std::vector<std::pair<std::string, std::string>> reshadefx::preprocessor::used_macro_definitions() const
@ -189,12 +193,19 @@ std::vector<std::pair<std::string, std::string>> reshadefx::preprocessor::used_m
void reshadefx::preprocessor::error(const location &location, const std::string &message) void reshadefx::preprocessor::error(const location &location, const std::string &message)
{ {
_errors += location.source + '(' + std::to_string(location.line) + ", " + std::to_string(location.column) + ')' + ": preprocessor error: " + message + '\n'; _errors += location.source;
_success = false; // Unset success flag _errors += '(' + std::to_string(location.line) + ", " + std::to_string(location.column) + ')';
_errors += ": preprocessor error: ";
_errors += message;
_errors += '\n';
} }
void reshadefx::preprocessor::warning(const location &location, const std::string &message) void reshadefx::preprocessor::warning(const location &location, const std::string &message)
{ {
_errors += location.source + '(' + std::to_string(location.line) + ", " + std::to_string(location.column) + ')' + ": preprocessor warning: " + message + '\n'; _errors += location.source;
_errors += '(' + std::to_string(location.line) + ", " + std::to_string(location.column) + ')';
_errors += ": preprocessor warning: ";
_errors += message;
_errors += '\n';
} }
void reshadefx::preprocessor::push(std::string input, const std::string &name) void reshadefx::preprocessor::push(std::string input, const std::string &name)
@ -357,32 +368,32 @@ void reshadefx::preprocessor::parse()
{ {
case tokenid::hash_if: case tokenid::hash_if:
parse_if(); parse_if();
if (!expect(tokenid::end_of_line)) if (!skip && !expect(tokenid::end_of_line))
consume_until(tokenid::end_of_line); consume_until(tokenid::end_of_line);
continue; continue;
case tokenid::hash_ifdef: case tokenid::hash_ifdef:
parse_ifdef(); parse_ifdef();
if (!expect(tokenid::end_of_line)) if (!skip && !expect(tokenid::end_of_line))
consume_until(tokenid::end_of_line); consume_until(tokenid::end_of_line);
continue; continue;
case tokenid::hash_ifndef: case tokenid::hash_ifndef:
parse_ifndef(); parse_ifndef();
if (!expect(tokenid::end_of_line)) if (!skip && !expect(tokenid::end_of_line))
consume_until(tokenid::end_of_line); consume_until(tokenid::end_of_line);
continue; continue;
case tokenid::hash_else: case tokenid::hash_else:
parse_else(); parse_else();
if (!expect(tokenid::end_of_line)) if (!skip && !expect(tokenid::end_of_line))
consume_until(tokenid::end_of_line); consume_until(tokenid::end_of_line);
continue; continue;
case tokenid::hash_elif: case tokenid::hash_elif:
parse_elif(); parse_elif();
if (!expect(tokenid::end_of_line)) if (!skip && !expect(tokenid::end_of_line))
consume_until(tokenid::end_of_line); consume_until(tokenid::end_of_line);
continue; continue;
case tokenid::hash_endif: case tokenid::hash_endif:
parse_endif(); parse_endif();
if (!expect(tokenid::end_of_line)) if (!skip && !expect(tokenid::end_of_line))
consume_until(tokenid::end_of_line); consume_until(tokenid::end_of_line);
continue; continue;
default: default:
@ -511,11 +522,18 @@ void reshadefx::preprocessor::parse_if()
level.pp_token = _token; level.pp_token = _token;
level.input_index = _current_input_index; level.input_index = _current_input_index;
// Evaluate expression after updating 'pp_token', so that it points at the beginning # token
level.value = evaluate_expression();
const bool parent_skipping = !_if_stack.empty() && _if_stack.back().skipping; const bool parent_skipping = !_if_stack.empty() && _if_stack.back().skipping;
level.skipping = parent_skipping || !level.value; if (parent_skipping)
{
level.value = false;
level.skipping = true;
}
else
{
// Evaluate expression after updating 'pp_token', so that it points at the beginning # token
level.value = evaluate_expression();
level.skipping = !level.value;
}
_if_stack.push_back(std::move(level)); _if_stack.push_back(std::move(level));
} }
@ -528,16 +546,23 @@ void reshadefx::preprocessor::parse_ifdef()
if (!expect(tokenid::identifier)) if (!expect(tokenid::identifier))
return; return;
level.value = is_defined(_token.literal_as_string);
const bool parent_skipping = !_if_stack.empty() && _if_stack.back().skipping; const bool parent_skipping = !_if_stack.empty() && _if_stack.back().skipping;
level.skipping = parent_skipping || !level.value; if (parent_skipping)
{
level.value = false;
level.skipping = true;
}
else
{
level.value = is_defined(_token.literal_as_string);
level.skipping = !level.value;
_if_stack.push_back(std::move(level)); // Only add to used macro list if this #ifdef is active and the macro was not defined before
// Only add to used macro list if this #ifdef is active and the macro was not defined before
if (!parent_skipping)
if (const auto it = _macros.find(_token.literal_as_string); it == _macros.end() || it->second.is_predefined) if (const auto it = _macros.find(_token.literal_as_string); it == _macros.end() || it->second.is_predefined)
_used_macros.emplace(_token.literal_as_string); _used_macros.emplace(_token.literal_as_string);
}
_if_stack.push_back(std::move(level));
} }
void reshadefx::preprocessor::parse_ifndef() void reshadefx::preprocessor::parse_ifndef()
{ {
@ -548,16 +573,23 @@ void reshadefx::preprocessor::parse_ifndef()
if (!expect(tokenid::identifier)) if (!expect(tokenid::identifier))
return; return;
level.value = !is_defined(_token.literal_as_string);
const bool parent_skipping = !_if_stack.empty() && _if_stack.back().skipping; const bool parent_skipping = !_if_stack.empty() && _if_stack.back().skipping;
level.skipping = parent_skipping || !level.value; if (parent_skipping)
{
level.value = false;
level.skipping = true;
}
else
{
level.value = !is_defined(_token.literal_as_string);
level.skipping = !level.value;
_if_stack.push_back(std::move(level)); // Only add to used macro list if this #ifndef is active and the macro was not defined before
// Only add to used macro list if this #ifndef is active and the macro was not defined before
if (!parent_skipping)
if (const auto it = _macros.find(_token.literal_as_string); it == _macros.end() || it->second.is_predefined) if (const auto it = _macros.find(_token.literal_as_string); it == _macros.end() || it->second.is_predefined)
_used_macros.emplace(_token.literal_as_string); _used_macros.emplace(_token.literal_as_string);
}
_if_stack.push_back(std::move(level));
} }
void reshadefx::preprocessor::parse_elif() void reshadefx::preprocessor::parse_elif()
{ {
@ -573,10 +605,19 @@ void reshadefx::preprocessor::parse_elif()
level.input_index = _current_input_index; level.input_index = _current_input_index;
const bool parent_skipping = _if_stack.size() > 1 && _if_stack[_if_stack.size() - 2].skipping; const bool parent_skipping = _if_stack.size() > 1 && _if_stack[_if_stack.size() - 2].skipping;
const bool condition_result = evaluate_expression(); if (parent_skipping)
level.skipping = parent_skipping || level.value || !condition_result; {
level.value = false;
level.skipping = true;
}
else
{
const bool condition_result = evaluate_expression();
level.skipping = level.value || !condition_result;
if (!level.value) level.value = condition_result; if (!level.value)
level.value = condition_result;
}
} }
void reshadefx::preprocessor::parse_else() void reshadefx::preprocessor::parse_else()
{ {
@ -591,16 +632,25 @@ void reshadefx::preprocessor::parse_else()
level.input_index = _current_input_index; level.input_index = _current_input_index;
const bool parent_skipping = _if_stack.size() > 1 && _if_stack[_if_stack.size() - 2].skipping; const bool parent_skipping = _if_stack.size() > 1 && _if_stack[_if_stack.size() - 2].skipping;
level.skipping = parent_skipping || level.value; if (parent_skipping)
{
level.value = false;
level.skipping = true;
}
else
{
level.skipping = parent_skipping || level.value;
if (!level.value) level.value = true; if (!level.value)
level.value = true;
}
} }
void reshadefx::preprocessor::parse_endif() void reshadefx::preprocessor::parse_endif()
{ {
if (_if_stack.empty()) if (_if_stack.empty())
error(_token.location, "missing #if for #endif"); return error(_token.location, "missing #if for #endif");
else
_if_stack.pop_back(); _if_stack.pop_back();
} }
void reshadefx::preprocessor::parse_error() void reshadefx::preprocessor::parse_error()
@ -927,8 +977,8 @@ bool reshadefx::preprocessor::evaluate_expression()
break; break;
if (left_associative ? if (left_associative ?
(precedence_lookup[op] > precedence_lookup[prev_op]) : (s_precedence_lookup[op] > s_precedence_lookup[prev_op]) :
(precedence_lookup[op] >= precedence_lookup[prev_op])) (s_precedence_lookup[op] >= s_precedence_lookup[prev_op]))
break; break;
stack_index--; stack_index--;
@ -1016,9 +1066,13 @@ bool reshadefx::preprocessor::evaluate_expression()
BINARY_OPERATION(-); BINARY_OPERATION(-);
break; break;
case op_modulo: case op_modulo:
if (stack[stack_index - 1] == 0)
return error(_token.location, "right operand of '%' is zero"), 0;
BINARY_OPERATION(%); BINARY_OPERATION(%);
break; break;
case op_divide: case op_divide:
if (stack[stack_index - 1] == 0)
return error(_token.location, "division by zero"), 0;
BINARY_OPERATION(/); BINARY_OPERATION(/);
break; break;
case op_multiply: case op_multiply:
@ -1068,12 +1122,24 @@ bool reshadefx::preprocessor::evaluate_identifier_as_macro()
push(escape_string(file_stem.u8string())); push(escape_string(file_stem.u8string()));
return true; return true;
} }
if (_token.literal_as_string == "__FILE_STEM_HASH__")
{
const std::filesystem::path file_stem = std::filesystem::u8path(_token.location.source).stem();
push(std::to_string(std::hash<std::string>()(file_stem.u8string()) & 0xFFFFFFFF));
return true;
}
if (_token.literal_as_string == "__FILE_NAME__") if (_token.literal_as_string == "__FILE_NAME__")
{ {
const std::filesystem::path file_name = std::filesystem::u8path(_token.location.source).filename(); const std::filesystem::path file_name = std::filesystem::u8path(_token.location.source).filename();
push(escape_string(file_name.u8string())); push(escape_string(file_name.u8string()));
return true; return true;
} }
if (_token.literal_as_string == "__FILE_NAME_HASH__")
{
const std::filesystem::path file_name = std::filesystem::u8path(_token.location.source).filename();
push(std::to_string(std::hash<std::string>()(file_name.u8string()) & 0xFFFFFFFF));
return true;
}
const auto it = _macros.find(_token.literal_as_string); const auto it = _macros.find(_token.literal_as_string);
if (it == _macros.end()) if (it == _macros.end())

View file

@ -13,25 +13,23 @@
#include <algorithm> // std::upper_bound, std::sort #include <algorithm> // std::upper_bound, std::sort
#include <functional> // std::greater #include <functional> // std::greater
enum class intrinsic_id : uint32_t enum class intrinsic_id
{ {
#define IMPLEMENT_INTRINSIC_SPIRV(name, i, code) name##i, #define IMPLEMENT_INTRINSIC_SPIRV(name, i, code) name##i,
#include "effect_symbol_table_intrinsics.inl" #include "effect_symbol_table_intrinsics.inl"
}; };
struct intrinsic struct intrinsic : reshadefx::function
{ {
intrinsic(const char *name, intrinsic_id id, const reshadefx::type &ret_type, std::initializer_list<reshadefx::type> arg_types) : id(id) intrinsic(const char *name, intrinsic_id id, const reshadefx::type &ret_type, std::initializer_list<reshadefx::type> arg_types)
{ {
function.name = name; function::return_type = ret_type;
function.return_type = ret_type; function::id = static_cast<uint32_t>(id);
function.parameter_list.reserve(arg_types.size()); function::name = name;
function::parameter_list.reserve(arg_types.size());
for (const reshadefx::type &arg_type : arg_types) for (const reshadefx::type &arg_type : arg_types)
function.parameter_list.push_back({ arg_type }); function::parameter_list.push_back({ arg_type });
} }
intrinsic_id id;
reshadefx::function_info function;
}; };
#define void { reshadefx::type::t_void } #define void { reshadefx::type::t_void }
@ -130,48 +128,17 @@ static const intrinsic s_intrinsics[] =
#undef uint2 #undef uint2
#undef uint3 #undef uint3
#undef uint4 #undef uint4
#undef float1 #undef float
#undef float2 #undef float2
#undef float3 #undef float3
#undef float4 #undef float4
#undef float2x2
#undef float3x3
#undef float4x4
#undef out_float
#undef out_float2
#undef out_float3
#undef out_float4
#undef sampler1d_int
#undef sampler2d_int
#undef sampler3d_int
#undef sampler1d_uint
#undef sampler2d_uint
#undef sampler3d_uint
#undef sampler1d_float4
#undef sampler2d_float4
#undef sampler3d_float4
#undef storage1d_int
#undef storage2d_int
#undef storage3d_int
#undef storage1d_uint
#undef storage2d_uint
#undef storage3d_uint
#undef storage1d_float4
#undef storage2d_float4
#undef storage3d_float4
#undef inout_storage1d_int
#undef inout_storage2d_int
#undef inout_storage3d_int
#undef inout_storage1d_uint
#undef inout_storage2d_uint
#undef inout_storage3d_uint
unsigned int reshadefx::type::rank(const type &src, const type &dst) unsigned int reshadefx::type::rank(const type &src, const type &dst)
{ {
if (src.is_array() != dst.is_array() || (src.array_length != dst.array_length && src.array_length > 0 && dst.array_length > 0)) if (src.is_array() != dst.is_array() || (src.array_length != dst.array_length && src.is_bounded_array() && dst.is_bounded_array()))
return 0; // Arrays of different sizes are not compatible return 0; // Arrays of different sizes are not compatible
if (src.is_struct() || dst.is_struct()) if (src.is_struct() || dst.is_struct())
return src.definition == dst.definition ? 32 : 0; // Structs are only compatible if they are the same type return src.struct_definition == dst.struct_definition ? 32 : 0; // Structs are only compatible if they are the same type
if (!src.is_numeric() || !dst.is_numeric()) if (!src.is_numeric() || !dst.is_numeric())
return src.base == dst.base && src.rows == dst.rows && src.cols == dst.cols ? 32 : 0; // Numeric values are not compatible with other types return src.base == dst.base && src.rows == dst.rows && src.cols == dst.cols ? 32 : 0; // Numeric values are not compatible with other types
if (src.is_matrix() && (!dst.is_matrix() || src.rows != dst.rows || src.cols != dst.cols)) if (src.is_matrix() && (!dst.is_matrix() || src.rows != dst.rows || src.cols != dst.cols))
@ -181,7 +148,7 @@ unsigned int reshadefx::type::rank(const type &src, const type &dst)
// - Floating point has a higher rank than integer types // - Floating point has a higher rank than integer types
// - Integer to floating point promotion has a higher rank than floating point to integer conversion // - Integer to floating point promotion has a higher rank than floating point to integer conversion
// - Signed to unsigned integer conversion has a higher rank than unsigned to signed integer conversion // - Signed to unsigned integer conversion has a higher rank than unsigned to signed integer conversion
static const int ranks[7][7] = { static const unsigned int ranks[7][7] = {
{ 5, 4, 4, 4, 4, 4, 4 }, // bool { 5, 4, 4, 4, 4, 4, 4 }, // bool
{ 3, 5, 5, 2, 2, 4, 4 }, // min16int { 3, 5, 5, 2, 2, 4, 4 }, // min16int
{ 3, 5, 5, 2, 2, 4, 4 }, // int { 3, 5, 5, 2, 2, 4, 4 }, // int
@ -194,7 +161,7 @@ unsigned int reshadefx::type::rank(const type &src, const type &dst)
assert(src.base > 0 && src.base <= 7); // bool - float assert(src.base > 0 && src.base <= 7); // bool - float
assert(dst.base > 0 && dst.base <= 7); assert(dst.base > 0 && dst.base <= 7);
const int rank = ranks[src.base - 1][dst.base - 1] << 2; const unsigned int rank = ranks[src.base - 1][dst.base - 1] << 2;
if ((src.is_scalar() && dst.is_vector())) if ((src.is_scalar() && dst.is_vector()))
return rank >> 1; // Scalar to vector promotion has a lower rank return rank >> 1; // Scalar to vector promotion has a lower rank
@ -284,7 +251,7 @@ bool reshadefx::symbol_table::insert_symbol(const std::string &name, const symbo
{ {
// Extract scope name // Extract scope name
scope.name = _current_scope.name.substr(0, pos += 2); scope.name = _current_scope.name.substr(0, pos += 2);
const auto previous_scope_name = _current_scope.name.substr(pos); const std::string previous_scope_name = _current_scope.name.substr(pos);
// Insert symbol into this scope // Insert symbol into this scope
insert_sorted(_symbol_stack[previous_scope_name + name], scoped_symbol { symbol, scope }); insert_sorted(_symbol_stack[previous_scope_name + name], scoped_symbol { symbol, scope });
@ -335,7 +302,7 @@ reshadefx::scoped_symbol reshadefx::symbol_table::find_symbol(const std::string
return result; return result;
} }
static int compare_functions(const std::vector<reshadefx::expression> &arguments, const reshadefx::function_info *function1, const reshadefx::function_info *function2) static int compare_functions(const std::vector<reshadefx::expression> &arguments, const reshadefx::function *function1, const reshadefx::function *function2)
{ {
const size_t num_arguments = arguments.size(); const size_t num_arguments = arguments.size();
@ -388,7 +355,7 @@ bool reshadefx::symbol_table::resolve_function_call(const std::string &name, con
{ {
out_data.op = symbol_type::function; out_data.op = symbol_type::function;
const function_info *result = nullptr; const function *result = nullptr;
unsigned int num_overloads = 0; unsigned int num_overloads = 0;
unsigned int overload_namespace = scope.namespace_level; unsigned int overload_namespace = scope.namespace_level;
@ -405,7 +372,7 @@ bool reshadefx::symbol_table::resolve_function_call(const std::string &name, con
it->scope.namespace_level > scope.namespace_level || (it->scope.namespace_level == scope.namespace_level && it->scope.name != scope.name)) it->scope.namespace_level > scope.namespace_level || (it->scope.namespace_level == scope.namespace_level && it->scope.name != scope.name))
continue; continue;
const function_info *const function = it->function; const function *const function = it->function;
if (function == nullptr) if (function == nullptr)
continue; continue;
@ -425,7 +392,7 @@ bool reshadefx::symbol_table::resolve_function_call(const std::string &name, con
continue; continue;
} }
} }
else if (arguments.size() != function->parameter_list.size()) else if (arguments.size() > function->parameter_list.size() || (arguments.size() < function->parameter_list.size() && !function->parameter_list[arguments.size()].has_default_value))
{ {
continue; continue;
} }
@ -453,18 +420,18 @@ bool reshadefx::symbol_table::resolve_function_call(const std::string &name, con
{ {
for (const intrinsic &intrinsic : s_intrinsics) for (const intrinsic &intrinsic : s_intrinsics)
{ {
if (intrinsic.function.name != name || intrinsic.function.parameter_list.size() != arguments.size()) if (intrinsic.name != name || intrinsic.parameter_list.size() != arguments.size())
continue; continue;
// A new possibly-matching intrinsic function was found, compare it against the current result // A new possibly-matching intrinsic function was found, compare it against the current result
const int comparison = compare_functions(arguments, &intrinsic.function, result); const int comparison = compare_functions(arguments, &intrinsic, result);
if (comparison < 0) // The new function is a better match if (comparison < 0) // The new function is a better match
{ {
out_data.op = symbol_type::intrinsic; out_data.op = symbol_type::intrinsic;
out_data.id = static_cast<uint32_t>(intrinsic.id); out_data.id = intrinsic.id;
out_data.type = intrinsic.function.return_type; out_data.type = intrinsic.return_type;
out_data.function = &intrinsic.function; out_data.function = &intrinsic;
result = out_data.function; result = out_data.function;
num_overloads = 1; num_overloads = 1;
} }

File diff suppressed because it is too large Load diff

View file

@ -83,15 +83,16 @@ static std::unique_ptr<reshadefx::codegen> CreateRFXCodegen()
case RenderAPI::Metal: case RenderAPI::Metal:
{ {
return std::unique_ptr<reshadefx::codegen>(reshadefx::create_codegen_glsl( return std::unique_ptr<reshadefx::codegen>(reshadefx::create_codegen_glsl(
false, true, debug_info, uniforms_to_spec_constants, false, (rapi == RenderAPI::Vulkan))); 460, false, true, debug_info, uniforms_to_spec_constants, false, (rapi == RenderAPI::Vulkan)));
} }
case RenderAPI::OpenGL: case RenderAPI::OpenGL:
case RenderAPI::OpenGLES: case RenderAPI::OpenGLES:
default: default:
{ {
return std::unique_ptr<reshadefx::codegen>(reshadefx::create_codegen_glsl( return std::unique_ptr<reshadefx::codegen>(
(rapi == RenderAPI::OpenGLES), false, debug_info, uniforms_to_spec_constants, false, true)); reshadefx::create_codegen_glsl(ShaderGen::GetGLSLVersion(rapi), (rapi == RenderAPI::OpenGLES), false,
debug_info, uniforms_to_spec_constants, false, true));
} }
} }
} }
@ -120,7 +121,7 @@ static GPUTexture::Format MapTextureFormat(reshadefx::texture_format format)
return s_mapping[static_cast<u32>(format)]; return s_mapping[static_cast<u32>(format)];
} }
static GPUSampler::Config MapSampler(const reshadefx::sampler_info& si) static GPUSampler::Config MapSampler(const reshadefx::sampler_desc& si)
{ {
GPUSampler::Config config = GPUSampler::GetNearestConfig(); GPUSampler::Config config = GPUSampler::GetNearestConfig();
@ -200,44 +201,44 @@ static GPUSampler::Config MapSampler(const reshadefx::sampler_info& si)
return config; return config;
} }
static GPUPipeline::BlendState MapBlendState(const reshadefx::pass_info& pi) static GPUPipeline::BlendState MapBlendState(const reshadefx::pass& pi)
{ {
static constexpr auto map_blend_op = [](const reshadefx::pass_blend_op o) { static constexpr auto map_blend_op = [](const reshadefx::blend_op o) {
switch (o) switch (o)
{ {
case reshadefx::pass_blend_op::add: case reshadefx::blend_op::add:
return GPUPipeline::BlendOp::Add; return GPUPipeline::BlendOp::Add;
case reshadefx::pass_blend_op::subtract: case reshadefx::blend_op::subtract:
return GPUPipeline::BlendOp::Subtract; return GPUPipeline::BlendOp::Subtract;
case reshadefx::pass_blend_op::reverse_subtract: case reshadefx::blend_op::reverse_subtract:
return GPUPipeline::BlendOp::ReverseSubtract; return GPUPipeline::BlendOp::ReverseSubtract;
case reshadefx::pass_blend_op::min: case reshadefx::blend_op::min:
return GPUPipeline::BlendOp::Min; return GPUPipeline::BlendOp::Min;
case reshadefx::pass_blend_op::max: case reshadefx::blend_op::max:
default: default:
return GPUPipeline::BlendOp::Max; return GPUPipeline::BlendOp::Max;
} }
}; };
static constexpr auto map_blend_factor = [](const reshadefx::pass_blend_factor f) { static constexpr auto map_blend_factor = [](const reshadefx::blend_factor f) {
switch (f) switch (f)
{ {
case reshadefx::pass_blend_factor::zero: case reshadefx::blend_factor::zero:
return GPUPipeline::BlendFunc::Zero; return GPUPipeline::BlendFunc::Zero;
case reshadefx::pass_blend_factor::one: case reshadefx::blend_factor::one:
return GPUPipeline::BlendFunc::One; return GPUPipeline::BlendFunc::One;
case reshadefx::pass_blend_factor::source_color: case reshadefx::blend_factor::source_color:
return GPUPipeline::BlendFunc::SrcColor; return GPUPipeline::BlendFunc::SrcColor;
case reshadefx::pass_blend_factor::one_minus_source_color: case reshadefx::blend_factor::one_minus_source_color:
return GPUPipeline::BlendFunc::InvSrcColor; return GPUPipeline::BlendFunc::InvSrcColor;
case reshadefx::pass_blend_factor::dest_color: case reshadefx::blend_factor::dest_color:
return GPUPipeline::BlendFunc::DstColor; return GPUPipeline::BlendFunc::DstColor;
case reshadefx::pass_blend_factor::one_minus_dest_color: case reshadefx::blend_factor::one_minus_dest_color:
return GPUPipeline::BlendFunc::InvDstColor; return GPUPipeline::BlendFunc::InvDstColor;
case reshadefx::pass_blend_factor::source_alpha: case reshadefx::blend_factor::source_alpha:
return GPUPipeline::BlendFunc::SrcAlpha; return GPUPipeline::BlendFunc::SrcAlpha;
case reshadefx::pass_blend_factor::one_minus_source_alpha: case reshadefx::blend_factor::one_minus_source_alpha:
return GPUPipeline::BlendFunc::InvSrcAlpha; return GPUPipeline::BlendFunc::InvSrcAlpha;
case reshadefx::pass_blend_factor::dest_alpha: case reshadefx::blend_factor::dest_alpha:
default: default:
return GPUPipeline::BlendFunc::DstAlpha; return GPUPipeline::BlendFunc::DstAlpha;
} }
@ -245,13 +246,13 @@ static GPUPipeline::BlendState MapBlendState(const reshadefx::pass_info& pi)
GPUPipeline::BlendState bs = GPUPipeline::BlendState::GetNoBlendingState(); GPUPipeline::BlendState bs = GPUPipeline::BlendState::GetNoBlendingState();
bs.enable = (pi.blend_enable[0] != 0); bs.enable = (pi.blend_enable[0] != 0);
bs.blend_op = map_blend_op(pi.blend_op[0]); bs.blend_op = map_blend_op(pi.color_blend_op[0]);
bs.src_blend = map_blend_factor(pi.src_blend[0]); bs.src_blend = map_blend_factor(pi.source_color_blend_factor[0]);
bs.dst_blend = map_blend_factor(pi.dest_blend[0]); bs.dst_blend = map_blend_factor(pi.dest_color_blend_factor[0]);
bs.alpha_blend_op = map_blend_op(pi.blend_op_alpha[0]); bs.alpha_blend_op = map_blend_op(pi.alpha_blend_op[0]);
bs.src_alpha_blend = map_blend_factor(pi.src_blend_alpha[0]); bs.src_alpha_blend = map_blend_factor(pi.source_alpha_blend_factor[0]);
bs.dst_alpha_blend = map_blend_factor(pi.dest_blend_alpha[0]); bs.dst_alpha_blend = map_blend_factor(pi.dest_alpha_blend_factor[0]);
bs.write_mask = pi.color_write_mask[0]; bs.write_mask = pi.render_target_write_mask[0];
return bs; return bs;
} }
@ -306,14 +307,19 @@ bool PostProcessing::ReShadeFXShader::LoadFromString(std::string name, std::stri
if (code.empty() || code.back() != '\n') if (code.empty() || code.back() != '\n')
code.push_back('\n'); code.push_back('\n');
reshadefx::module temp_module; // TODO: This could use spv, it's probably fastest.
std::unique_ptr<reshadefx::codegen> cg = CreateRFXCodegen();
if (!cg)
return false;
if (!CreateModule(only_config ? DEFAULT_BUFFER_WIDTH : g_gpu_device->GetWindowWidth(), if (!CreateModule(only_config ? DEFAULT_BUFFER_WIDTH : g_gpu_device->GetWindowWidth(),
only_config ? DEFAULT_BUFFER_HEIGHT : g_gpu_device->GetWindowHeight(), &temp_module, only_config ? DEFAULT_BUFFER_HEIGHT : g_gpu_device->GetWindowHeight(), cg.get(), std::move(code),
std::move(code), error)) error))
{ {
return false; return false;
} }
const reshadefx::effect_module& temp_module = cg->module();
if (!CreateOptions(temp_module, error)) if (!CreateOptions(temp_module, error))
return false; return false;
@ -321,9 +327,9 @@ bool PostProcessing::ReShadeFXShader::LoadFromString(std::string name, std::stri
if (!temp_module.techniques.empty()) if (!temp_module.techniques.empty())
{ {
bool has_passes = false; bool has_passes = false;
for (const reshadefx::technique_info& tech : temp_module.techniques) for (const reshadefx::technique& tech : temp_module.techniques)
{ {
for (const reshadefx::pass_info& pi : tech.passes) for (const reshadefx::pass& pi : tech.passes)
{ {
has_passes = true; has_passes = true;
@ -338,15 +344,15 @@ bool PostProcessing::ReShadeFXShader::LoadFromString(std::string name, std::stri
if (max_rt > GPUDevice::MAX_RENDER_TARGETS) if (max_rt > GPUDevice::MAX_RENDER_TARGETS)
{ {
Error::SetString(error, fmt::format("Too many render targets ({}) in pass {}, only {} are supported.", max_rt, Error::SetStringFmt(error, "Too many render targets ({}) in pass {}, only {} are supported.", max_rt, pi.name,
pi.name, GPUDevice::MAX_RENDER_TARGETS)); GPUDevice::MAX_RENDER_TARGETS);
return false; return false;
} }
if (pi.samplers.size() > GPUDevice::MAX_TEXTURE_SAMPLERS) if (pi.sampler_bindings.size() > GPUDevice::MAX_TEXTURE_SAMPLERS)
{ {
Error::SetString(error, fmt::format("Too many samplers ({}) in pass {}, only {} are supported.", Error::SetStringFmt(error, "Too many samplers ({}) in pass {}, only {} are supported.",
pi.samplers.size(), pi.name, GPUDevice::MAX_TEXTURE_SAMPLERS)); pi.sampler_bindings.size(), pi.name, GPUDevice::MAX_TEXTURE_SAMPLERS);
return false; return false;
} }
} }
@ -373,7 +379,7 @@ bool PostProcessing::ReShadeFXShader::WantsDepthBuffer() const
return m_wants_depth_buffer; return m_wants_depth_buffer;
} }
bool PostProcessing::ReShadeFXShader::CreateModule(s32 buffer_width, s32 buffer_height, reshadefx::module* mod, bool PostProcessing::ReShadeFXShader::CreateModule(s32 buffer_width, s32 buffer_height, reshadefx::codegen* cg,
std::string code, Error* error) std::string code, Error* error)
{ {
reshadefx::preprocessor pp; reshadefx::preprocessor pp;
@ -427,26 +433,21 @@ bool PostProcessing::ReShadeFXShader::CreateModule(s32 buffer_width, s32 buffer_
if (!pp.append_string(std::move(code), m_filename)) if (!pp.append_string(std::move(code), m_filename))
{ {
Error::SetString(error, fmt::format("Failed to preprocess:\n{}", pp.errors())); Error::SetStringFmt(error, "Failed to preprocess:\n{}", pp.errors());
return false; return false;
} }
std::unique_ptr<reshadefx::codegen> cg = CreateRFXCodegen();
if (!cg)
return false;
reshadefx::parser parser; reshadefx::parser parser;
if (!parser.parse(pp.output(), cg.get())) if (!parser.parse(pp.output(), cg))
{ {
Error::SetString(error, fmt::format("Failed to parse:\n{}", parser.errors())); Error::SetStringFmt(error, "Failed to parse:\n{}", parser.errors());
return false; return false;
} }
cg->write_result(*mod);
return true; return true;
} }
static bool HasAnnotationWithName(const reshadefx::uniform_info& uniform, const std::string_view annotation_name) static bool HasAnnotationWithName(const reshadefx::uniform& uniform, const std::string_view annotation_name)
{ {
for (const reshadefx::annotation& an : uniform.annotations) for (const reshadefx::annotation& an : uniform.annotations)
{ {
@ -493,7 +494,7 @@ static bool GetBooleanAnnotationValue(const std::vector<reshadefx::annotation>&
} }
static PostProcessing::ShaderOption::ValueVector static PostProcessing::ShaderOption::ValueVector
GetVectorAnnotationValue(const reshadefx::uniform_info& uniform, const std::string_view annotation_name, GetVectorAnnotationValue(const reshadefx::uniform& uniform, const std::string_view annotation_name,
const PostProcessing::ShaderOption::ValueVector& default_value) const PostProcessing::ShaderOption::ValueVector& default_value)
{ {
PostProcessing::ShaderOption::ValueVector vv = default_value; PostProcessing::ShaderOption::ValueVector vv = default_value;
@ -575,9 +576,9 @@ GetVectorAnnotationValue(const reshadefx::uniform_info& uniform, const std::stri
return vv; return vv;
} }
bool PostProcessing::ReShadeFXShader::CreateOptions(const reshadefx::module& mod, Error* error) bool PostProcessing::ReShadeFXShader::CreateOptions(const reshadefx::effect_module& mod, Error* error)
{ {
for (const reshadefx::uniform_info& ui : mod.uniforms) for (const reshadefx::uniform& ui : mod.uniforms)
{ {
SourceOptionType so; SourceOptionType so;
if (!GetSourceOption(ui, &so, error)) if (!GetSourceOption(ui, &so, error))
@ -639,7 +640,7 @@ bool PostProcessing::ReShadeFXShader::CreateOptions(const reshadefx::module& mod
break; break;
default: default:
Error::SetString(error, fmt::format("Unhandled uniform type {} ({})", static_cast<u32>(ui.type.base), ui.name)); Error::SetStringFmt(error, "Unhandled uniform type {} ({})", static_cast<u32>(ui.type.base), ui.name);
return false; return false;
} }
@ -648,8 +649,7 @@ bool PostProcessing::ReShadeFXShader::CreateOptions(const reshadefx::module& mod
opt.vector_size = ui.type.components(); opt.vector_size = ui.type.components();
if (opt.vector_size == 0 || opt.vector_size > ShaderOption::MAX_VECTOR_COMPONENTS) if (opt.vector_size == 0 || opt.vector_size > ShaderOption::MAX_VECTOR_COMPONENTS)
{ {
Error::SetString(error, Error::SetStringFmt(error, "Unhandled vector size {} ({})", static_cast<u32>(ui.type.components()), ui.name);
fmt::format("Unhandled vector size {} ({})", static_cast<u32>(ui.type.components()), ui.name));
return false; return false;
} }
@ -762,8 +762,7 @@ bool PostProcessing::ReShadeFXShader::CreateOptions(const reshadefx::module& mod
return true; return true;
} }
bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_info& ui, SourceOptionType* si, bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform& ui, SourceOptionType* si, Error* error)
Error* error)
{ {
// TODO: Rewrite these to a lookup table instead, this if chain is terrible. // TODO: Rewrite these to a lookup table instead, this if chain is terrible.
const std::string_view source = GetStringAnnotationValue(ui.annotations, "source", {}); const std::string_view source = GetStringAnnotationValue(ui.annotations, "source", {});
@ -773,8 +772,8 @@ bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_i
{ {
if (ui.type.base != reshadefx::type::t_float || ui.type.components() > 1) if (ui.type.base != reshadefx::type::t_float || ui.type.components() > 1)
{ {
Error::SetString( Error::SetStringFmt(error, "Unexpected type '{}' for timer source in uniform '{}'", ui.type.description(),
error, fmt::format("Unexpected type '{}' for timer source in uniform '{}'", ui.type.description(), ui.name)); ui.name);
return false; return false;
} }
@ -785,8 +784,8 @@ bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_i
{ {
if ((!ui.type.is_integral() && !ui.type.is_floating_point()) || ui.type.components() > 1) if ((!ui.type.is_integral() && !ui.type.is_floating_point()) || ui.type.components() > 1)
{ {
Error::SetString( Error::SetStringFmt(error, "Unexpected type '{}' for timer source in uniform '{}'", ui.type.description(),
error, fmt::format("Unexpected type '{}' for timer source in uniform '{}'", ui.type.description(), ui.name)); ui.name);
return false; return false;
} }
@ -797,8 +796,8 @@ bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_i
{ {
if (ui.type.base != reshadefx::type::t_float || ui.type.components() > 1) if (ui.type.base != reshadefx::type::t_float || ui.type.components() > 1)
{ {
Error::SetString( Error::SetStringFmt(error, "Unexpected type '{}' for timer source in uniform '{}'", ui.type.description(),
error, fmt::format("Unexpected type '{}' for timer source in uniform '{}'", ui.type.description(), ui.name)); ui.name);
return false; return false;
} }
@ -809,8 +808,8 @@ bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_i
{ {
if (!ui.type.is_floating_point() || ui.type.components() < 2) if (!ui.type.is_floating_point() || ui.type.components() < 2)
{ {
Error::SetString(error, fmt::format("Unexpected type '{}' for pingpong source in uniform '{}'", Error::SetStringFmt(error, "Unexpected type '{}' for pingpong source in uniform '{}'", ui.type.description(),
ui.type.description(), ui.name)); ui.name);
return false; return false;
} }
@ -821,8 +820,8 @@ bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_i
{ {
if (!ui.type.is_floating_point() || ui.type.components() < 2) if (!ui.type.is_floating_point() || ui.type.components() < 2)
{ {
Error::SetString(error, fmt::format("Unexpected type '{}' for mousepoint source in uniform '{}'", Error::SetStringFmt(error, "Unexpected type '{}' for mousepoint source in uniform '{}'", ui.type.description(),
ui.type.description(), ui.name)); ui.name);
return false; return false;
} }
@ -839,8 +838,8 @@ bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_i
{ {
if ((!ui.type.is_floating_point() && !ui.type.is_integral()) || ui.type.components() != 1) if ((!ui.type.is_floating_point() && !ui.type.is_integral()) || ui.type.components() != 1)
{ {
Error::SetString(error, fmt::format("Unexpected type '{}' ({} components) for random source in uniform '{}'", Error::SetStringFmt(error, "Unexpected type '{}' ({} components) for random source in uniform '{}'",
ui.type.description(), ui.type.components(), ui.name)); ui.type.description(), ui.type.components(), ui.name);
return false; return false;
} }
@ -896,8 +895,8 @@ bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_i
{ {
if (!ui.type.is_floating_point() || ui.type.components() != 1) if (!ui.type.is_floating_point() || ui.type.components() != 1)
{ {
Error::SetString(error, fmt::format("Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(), Error::SetStringFmt(error, "Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(), source,
source, ui.name)); ui.name);
return false; return false;
} }
@ -908,8 +907,8 @@ bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_i
{ {
if (!ui.type.is_floating_point() || ui.type.components() != 1) if (!ui.type.is_floating_point() || ui.type.components() != 1)
{ {
Error::SetString(error, fmt::format("Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(), Error::SetStringFmt(error, "Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(), source,
source, ui.name)); ui.name);
return false; return false;
} }
@ -920,8 +919,8 @@ bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_i
{ {
if (!ui.type.is_floating_point() || ui.type.components() != 1) if (!ui.type.is_floating_point() || ui.type.components() != 1)
{ {
Error::SetString(error, fmt::format("Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(), Error::SetStringFmt(error, "Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(), source,
source, ui.name)); ui.name);
return false; return false;
} }
@ -932,8 +931,8 @@ bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_i
{ {
if (!ui.type.is_floating_point() || ui.type.components() != 1) if (!ui.type.is_floating_point() || ui.type.components() != 1)
{ {
Error::SetString(error, fmt::format("Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(), Error::SetStringFmt(error, "Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(), source,
source, ui.name)); ui.name);
return false; return false;
} }
@ -944,8 +943,8 @@ bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_i
{ {
if (!ui.type.is_floating_point() || ui.type.components() != 1) if (!ui.type.is_floating_point() || ui.type.components() != 1)
{ {
Error::SetString(error, fmt::format("Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(), Error::SetStringFmt(error, "Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(), source,
source, ui.name)); ui.name);
return false; return false;
} }
@ -956,8 +955,8 @@ bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_i
{ {
if (!ui.type.is_floating_point() || ui.type.components() != 2) if (!ui.type.is_floating_point() || ui.type.components() != 2)
{ {
Error::SetString(error, fmt::format("Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(), Error::SetStringFmt(error, "Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(), source,
source, ui.name)); ui.name);
return false; return false;
} }
@ -968,8 +967,8 @@ bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_i
{ {
if (!ui.type.is_floating_point() || ui.type.components() != 2) if (!ui.type.is_floating_point() || ui.type.components() != 2)
{ {
Error::SetString(error, fmt::format("Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(), Error::SetStringFmt(error, "Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(), source,
source, ui.name)); ui.name);
return false; return false;
} }
@ -980,8 +979,8 @@ bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_i
{ {
if (!ui.type.is_floating_point() || ui.type.components() != 2) if (!ui.type.is_floating_point() || ui.type.components() != 2)
{ {
Error::SetString(error, fmt::format("Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(), Error::SetStringFmt(error, "Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(), source,
source, ui.name)); ui.name);
return false; return false;
} }
@ -992,8 +991,8 @@ bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_i
{ {
if (!ui.type.is_floating_point() || ui.type.components() != 2) if (!ui.type.is_floating_point() || ui.type.components() != 2)
{ {
Error::SetString(error, fmt::format("Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(), Error::SetStringFmt(error, "Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(), source,
source, ui.name)); ui.name);
return false; return false;
} }
@ -1004,8 +1003,8 @@ bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_i
{ {
if (!ui.type.is_floating_point() || ui.type.components() != 2) if (!ui.type.is_floating_point() || ui.type.components() != 2)
{ {
Error::SetString(error, fmt::format("Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(), Error::SetStringFmt(error, "Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(), source,
source, ui.name)); ui.name);
return false; return false;
} }
@ -1016,8 +1015,8 @@ bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_i
{ {
if (!ui.type.is_floating_point() || ui.type.components() != 2) if (!ui.type.is_floating_point() || ui.type.components() != 2)
{ {
Error::SetString(error, fmt::format("Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(), Error::SetStringFmt(error, "Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(), source,
source, ui.name)); ui.name);
return false; return false;
} }
@ -1028,8 +1027,8 @@ bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_i
{ {
if (!ui.type.is_floating_point() || ui.type.components() != 2) if (!ui.type.is_floating_point() || ui.type.components() != 2)
{ {
Error::SetString(error, fmt::format("Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(), Error::SetStringFmt(error, "Unexpected type '{}' for {} source in uniform '{}'", ui.type.description(), source,
source, ui.name)); ui.name);
return false; return false;
} }
@ -1038,7 +1037,7 @@ bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_i
} }
else else
{ {
Error::SetString(error, fmt::format("Unknown source '{}' in uniform '{}'", source, ui.name)); Error::SetStringFmt(error, "Unknown source '{}' in uniform '{}'", source, ui.name);
return false; return false;
} }
} }
@ -1062,11 +1061,11 @@ bool PostProcessing::ReShadeFXShader::GetSourceOption(const reshadefx::uniform_i
return true; return true;
} }
bool PostProcessing::ReShadeFXShader::CreatePasses(GPUTexture::Format backbuffer_format, reshadefx::module& mod, bool PostProcessing::ReShadeFXShader::CreatePasses(GPUTexture::Format backbuffer_format,
Error* error) const reshadefx::effect_module& mod, Error* error)
{ {
u32 total_passes = 0; u32 total_passes = 0;
for (const reshadefx::technique_info& tech : mod.techniques) for (const reshadefx::technique& tech : mod.techniques)
total_passes += static_cast<u32>(tech.passes.size()); total_passes += static_cast<u32>(tech.passes.size());
if (total_passes == 0) if (total_passes == 0)
{ {
@ -1077,7 +1076,7 @@ bool PostProcessing::ReShadeFXShader::CreatePasses(GPUTexture::Format backbuffer
m_passes.reserve(total_passes); m_passes.reserve(total_passes);
// Named render targets. // Named render targets.
for (const reshadefx::texture_info& ti : mod.textures) for (const reshadefx::texture& ti : mod.textures)
{ {
Texture tex; Texture tex;
@ -1097,7 +1096,7 @@ bool PostProcessing::ReShadeFXShader::CreatePasses(GPUTexture::Format backbuffer
const std::string_view source = GetStringAnnotationValue(ti.annotations, "source", {}); const std::string_view source = GetStringAnnotationValue(ti.annotations, "source", {});
if (source.empty()) if (source.empty())
{ {
Error::SetString(error, fmt::format("Non-render target texture '{}' is missing source.", ti.unique_name)); Error::SetStringFmt(error, "Non-render target texture '{}' is missing source.", ti.unique_name);
return false; return false;
} }
@ -1111,7 +1110,7 @@ bool PostProcessing::ReShadeFXShader::CreatePasses(GPUTexture::Format backbuffer
if (std::optional<DynamicHeapArray<u8>> resdata = Host::ReadResourceFile(resource_name.c_str(), true); if (std::optional<DynamicHeapArray<u8>> resdata = Host::ReadResourceFile(resource_name.c_str(), true);
!resdata.has_value() || !image.LoadFromBuffer(resource_name.c_str(), resdata->data(), resdata->size())) !resdata.has_value() || !image.LoadFromBuffer(resource_name.c_str(), resdata->data(), resdata->size()))
{ {
Error::SetString(error, fmt::format("Failed to load image '{}' (from '{}')", source, image_path).c_str()); Error::SetStringFmt(error, "Failed to load image '{}' (from '{}')", source, image_path);
return false; return false;
} }
} }
@ -1121,8 +1120,7 @@ bool PostProcessing::ReShadeFXShader::CreatePasses(GPUTexture::Format backbuffer
GPUTexture::Format::RGBA8, image.GetPixels(), image.GetPitch()); GPUTexture::Format::RGBA8, image.GetPixels(), image.GetPitch());
if (!tex.texture) if (!tex.texture)
{ {
Error::SetString( Error::SetStringFmt(error, "Failed to create {}x{} texture ({})", image.GetWidth(), image.GetHeight(), source);
error, fmt::format("Failed to create {}x{} texture ({})", image.GetWidth(), image.GetHeight(), source));
return false; return false;
} }
@ -1133,9 +1131,9 @@ bool PostProcessing::ReShadeFXShader::CreatePasses(GPUTexture::Format backbuffer
m_textures.push_back(std::move(tex)); m_textures.push_back(std::move(tex));
} }
for (reshadefx::technique_info& tech : mod.techniques) for (const reshadefx::technique& tech : mod.techniques)
{ {
for (reshadefx::pass_info& pi : tech.passes) for (const reshadefx::pass& pi : tech.passes)
{ {
const bool is_final = (&tech == &mod.techniques.back() && &pi == &tech.passes.back()); const bool is_final = (&tech == &mod.techniques.back() && &pi == &tech.passes.back());
@ -1164,8 +1162,7 @@ bool PostProcessing::ReShadeFXShader::CreatePasses(GPUTexture::Format backbuffer
} }
if (rt == static_cast<TextureID>(m_textures.size())) if (rt == static_cast<TextureID>(m_textures.size()))
{ {
Error::SetString(error, Error::SetStringFmt(error, "Unknown texture '{}' used as render target in pass '{}'", rtname, pi.name);
fmt::format("Unknown texture '{}' used as render target in pass '{}'", rtname, pi.name));
return false; return false;
} }
@ -1182,17 +1179,22 @@ bool PostProcessing::ReShadeFXShader::CreatePasses(GPUTexture::Format backbuffer
} }
u32 texture_slot = 0; u32 texture_slot = 0;
for (const reshadefx::sampler_info& si : pi.samplers) Assert(pi.texture_bindings.size() == pi.sampler_bindings.size());
for (size_t tb_index = 0; tb_index < pi.texture_bindings.size(); tb_index++)
{ {
const reshadefx::texture_binding& tb = pi.texture_bindings[tb_index];
const reshadefx::sampler_binding& sb = pi.sampler_bindings[tb_index];
Sampler sampler; Sampler sampler;
sampler.slot = texture_slot++; sampler.slot = texture_slot++;
sampler.reshade_name = si.unique_name;
sampler.texture_id = static_cast<TextureID>(m_textures.size()); sampler.texture_id = static_cast<TextureID>(m_textures.size());
for (const reshadefx::texture_info& ti : mod.textures) for (const reshadefx::texture& ti : mod.textures)
{ {
if (ti.unique_name == si.texture_name) if (ti.unique_name == tb.texture_name)
{ {
sampler.reshade_name = ti.unique_name; // TODO: REMOVE THIS
// found the texture, now look for our side of it // found the texture, now look for our side of it
if (ti.semantic == "COLOR") if (ti.semantic == "COLOR")
{ {
@ -1207,14 +1209,14 @@ bool PostProcessing::ReShadeFXShader::CreatePasses(GPUTexture::Format backbuffer
} }
else if (!ti.semantic.empty()) else if (!ti.semantic.empty())
{ {
Error::SetString(error, fmt::format("Unknown semantic {} in texture {}", ti.semantic, ti.name)); Error::SetStringFmt(error, "Unknown semantic {} in texture {}", ti.semantic, ti.name);
return false; return false;
} }
// must be a render target, or another texture // must be a render target, or another texture
for (u32 i = 0; i < static_cast<u32>(m_textures.size()); i++) for (u32 i = 0; i < static_cast<u32>(m_textures.size()); i++)
{ {
if (m_textures[i].reshade_name == si.texture_name) if (m_textures[i].reshade_name == ti.unique_name)
{ {
// hook it up // hook it up
sampler.texture_id = static_cast<TextureID>(i); sampler.texture_id = static_cast<TextureID>(i);
@ -1225,16 +1227,16 @@ bool PostProcessing::ReShadeFXShader::CreatePasses(GPUTexture::Format backbuffer
break; break;
} }
} }
if (sampler.texture_id == static_cast<TextureID>(m_textures.size())) if (sampler.texture_id == static_cast<TextureID>(m_textures.size()))
{ {
Error::SetString( Error::SetStringFmt(error, "Unknown texture {} in pass {}", tb.texture_name, pi.name);
error, fmt::format("Unknown texture {} (sampler {}) in pass {}", si.texture_name, si.name, pi.name));
return false; return false;
} }
DEV_LOG("Pass {} Texture {} => {}", pi.name, si.texture_name, sampler.texture_id); DEV_LOG("Pass {} Texture {} => {}", pi.name, tb.texture_name, sampler.texture_id);
sampler.sampler = GetSampler(MapSampler(si)); sampler.sampler = GetSampler(MapSampler(sb));
if (!sampler.sampler) if (!sampler.sampler)
{ {
Error::SetString(error, "Failed to create sampler."); Error::SetString(error, "Failed to create sampler.");
@ -1320,14 +1322,18 @@ bool PostProcessing::ReShadeFXShader::CompilePipeline(GPUTexture::Format format,
if (fxcode.empty() || fxcode.back() != '\n') if (fxcode.empty() || fxcode.back() != '\n')
fxcode.push_back('\n'); fxcode.push_back('\n');
std::unique_ptr<reshadefx::codegen> cg = CreateRFXCodegen();
if (!cg)
return false;
Error error; Error error;
reshadefx::module mod; if (!CreateModule(width, height, cg.get(), std::move(fxcode), &error))
if (!CreateModule(width, height, &mod, std::move(fxcode), &error))
{ {
ERROR_LOG("Failed to create module for '{}': {}", m_name, error.GetDescription()); ERROR_LOG("Failed to create module for '{}': {}", m_name, error.GetDescription());
return false; return false;
} }
const reshadefx::effect_module& mod = cg->module();
DebugAssert(!mod.techniques.empty()); DebugAssert(!mod.techniques.empty());
if (!CreatePasses(format, mod, &error)) if (!CreatePasses(format, mod, &error))
@ -1336,53 +1342,16 @@ bool PostProcessing::ReShadeFXShader::CompilePipeline(GPUTexture::Format format,
return false; return false;
} }
const std::string_view code(mod.code.data(), mod.code.size()); // TODO: If using spv, this will be populated.
// const std::string effect_code = cg->finalize_code();
auto get_shader = [api, needs_main_defn, &code](const std::string& name, const std::span<Sampler> samplers, auto get_shader = [api, needs_main_defn, &cg](const std::string& name, const std::span<Sampler> samplers,
GPUShaderStage stage) { GPUShaderStage stage) {
std::string real_code; const std::string real_code = cg->finalize_code_for_entry_point(name);
if (needs_main_defn)
{
// dFdx/dFdy are not defined in the vertex shader.
const char* defns =
(stage == GPUShaderStage::Vertex) ? "#define dFdx(x) x\n#define dFdy(x) x\n#define discard\n" : "";
const char* precision = (api == RenderAPI::OpenGLES) ?
"precision highp float;\nprecision highp int;\nprecision highp sampler2D;\n" :
"";
TinyString version_string = "#version 460 core\n"; #if 0
#ifdef ENABLE_OPENGL FileSystem::WriteStringToFile(fmt::format("D:\\reshade_{}.txt", Path::SanitizeFileName(name)).c_str(), real_code);
if (api == RenderAPI::OpenGL || api == RenderAPI::OpenGLES)
version_string = ShaderGen::GetGLSLVersionString(api, ShaderGen::GetGLSLVersion(api));
#endif #endif
real_code = fmt::format("{}\n#define ENTRY_POINT_{}\n{}\n{}\n{}", version_string, name, defns, precision, code);
for (const Sampler& sampler : samplers)
{
std::string decl = fmt::format("binding = /*SAMPLER:{}*/0", sampler.reshade_name);
std::string replacement = fmt::format("binding = {}", sampler.slot);
StringUtil::ReplaceAll(&real_code, decl, replacement);
}
}
else
{
real_code = std::string(code);
for (const Sampler& sampler : samplers)
{
std::string decl = fmt::format("__{}_t : register( t0);", sampler.reshade_name);
std::string replacement =
fmt::format("__{}_t : register({}t{});", sampler.reshade_name, (sampler.slot < 10) ? " " : "", sampler.slot);
StringUtil::ReplaceAll(&real_code, decl, replacement);
decl = fmt::format("__{}_s : register( s0);", sampler.reshade_name);
replacement =
fmt::format("__{}_s : register({}s{});", sampler.reshade_name, (sampler.slot < 10) ? " " : "", sampler.slot);
StringUtil::ReplaceAll(&real_code, decl, replacement);
}
}
// FileSystem::WriteStringToFile("D:\\foo.txt", real_code);
Error error; Error error;
std::unique_ptr<GPUShader> sshader = g_gpu_device->CreateShader( std::unique_ptr<GPUShader> sshader = g_gpu_device->CreateShader(
@ -1407,15 +1376,15 @@ bool PostProcessing::ReShadeFXShader::CompilePipeline(GPUTexture::Format format,
progress->PushState(); progress->PushState();
size_t total_passes = 0; size_t total_passes = 0;
for (const reshadefx::technique_info& tech : mod.techniques) for (const reshadefx::technique& tech : mod.techniques)
total_passes += tech.passes.size(); total_passes += tech.passes.size();
progress->SetProgressRange(static_cast<u32>(total_passes)); progress->SetProgressRange(static_cast<u32>(total_passes));
progress->SetProgressValue(0); progress->SetProgressValue(0);
u32 passnum = 0; u32 passnum = 0;
for (const reshadefx::technique_info& tech : mod.techniques) for (const reshadefx::technique& tech : mod.techniques)
{ {
for (const reshadefx::pass_info& info : tech.passes) for (const reshadefx::pass& info : tech.passes)
{ {
DebugAssert(passnum < m_passes.size()); DebugAssert(passnum < m_passes.size());
Pass& pass = m_passes[passnum++]; Pass& pass = m_passes[passnum++];

View file

@ -13,6 +13,10 @@
#include <random> #include <random>
namespace reshadefx {
class codegen;
}
class Error; class Error;
namespace PostProcessing { namespace PostProcessing {
@ -94,10 +98,10 @@ private:
ShaderOption::ValueVector value; ShaderOption::ValueVector value;
}; };
bool CreateModule(s32 buffer_width, s32 buffer_height, reshadefx::module* mod, std::string code, Error* error); bool CreateModule(s32 buffer_width, s32 buffer_height, reshadefx::codegen* cg, std::string code, Error* error);
bool CreateOptions(const reshadefx::module& mod, Error* error); bool CreateOptions(const reshadefx::effect_module& mod, Error* error);
bool GetSourceOption(const reshadefx::uniform_info& ui, SourceOptionType* si, Error* error); bool GetSourceOption(const reshadefx::uniform& ui, SourceOptionType* si, Error* error);
bool CreatePasses(GPUTexture::Format backbuffer_format, reshadefx::module& mod, Error* error); bool CreatePasses(GPUTexture::Format backbuffer_format, const reshadefx::effect_module& mod, Error* error);
const char* GetTextureNameForID(TextureID id) const; const char* GetTextureNameForID(TextureID id) const;
GPUTexture* GetTextureByID(TextureID id, GPUTexture* input_color, GPUTexture* input_depth, GPUTexture* GetTextureByID(TextureID id, GPUTexture* input_color, GPUTexture* input_depth,

View file

@ -98,9 +98,9 @@ void ShaderGen::DefineMacro(std::stringstream& ss, const char* name, s32 value)
ss << "#define " << name << " " << value << "\n"; ss << "#define " << name << " " << value << "\n";
} }
#ifdef ENABLE_OPENGL
u32 ShaderGen::GetGLSLVersion(RenderAPI render_api) u32 ShaderGen::GetGLSLVersion(RenderAPI render_api)
{ {
#ifdef ENABLE_OPENGL
const char* glsl_version = reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION)); const char* glsl_version = reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION));
const bool glsl_es = (render_api == RenderAPI::OpenGLES); const bool glsl_es = (render_api == RenderAPI::OpenGLES);
Assert(glsl_version != nullptr); Assert(glsl_version != nullptr);
@ -136,6 +136,9 @@ u32 ShaderGen::GetGLSLVersion(RenderAPI render_api)
} }
return (static_cast<u32>(major_version) * 100) + static_cast<u32>(minor_version); return (static_cast<u32>(major_version) * 100) + static_cast<u32>(minor_version);
#else
return 460;
#endif
} }
TinyString ShaderGen::GetGLSLVersionString(RenderAPI render_api, u32 version) TinyString ShaderGen::GetGLSLVersionString(RenderAPI render_api, u32 version)
@ -147,7 +150,6 @@ TinyString ShaderGen::GetGLSLVersionString(RenderAPI render_api, u32 version)
return TinyString::from_format("#version {}{:02d}{}", major_version, minor_version, return TinyString::from_format("#version {}{:02d}{}", major_version, minor_version,
(glsl_es && major_version >= 3) ? " es" : ""); (glsl_es && major_version >= 3) ? " es" : "");
} }
#endif
void ShaderGen::WriteHeader(std::stringstream& ss, bool enable_rov /* = false */) void ShaderGen::WriteHeader(std::stringstream& ss, bool enable_rov /* = false */)
{ {

View file

@ -20,10 +20,8 @@ public:
static GPUShaderLanguage GetShaderLanguageForAPI(RenderAPI api); static GPUShaderLanguage GetShaderLanguageForAPI(RenderAPI api);
static bool UseGLSLBindingLayout(); static bool UseGLSLBindingLayout();
#ifdef ENABLE_OPENGL
static u32 GetGLSLVersion(RenderAPI render_api); static u32 GetGLSLVersion(RenderAPI render_api);
static TinyString GetGLSLVersionString(RenderAPI render_api, u32 version); static TinyString GetGLSLVersionString(RenderAPI render_api, u32 version);
#endif
ALWAYS_INLINE GPUShaderLanguage GetLanguage() const { return m_shader_language; } ALWAYS_INLINE GPUShaderLanguage GetLanguage() const { return m_shader_language; }