From 9d28c371e71586bbbf88a401cb3a160a9f139842 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Sat, 20 Apr 2024 01:35:31 -0500 Subject: [PATCH] VideoCommon: allow custom shaders to set the alpha value for use when blending is enabled --- Source/Core/VideoCommon/PixelShaderGen.cpp | 42 +++++------- Source/Core/VideoCommon/ShaderGenCommon.cpp | 5 ++ Source/Core/VideoCommon/UberShaderPixel.cpp | 43 +++++------- docs/CustomPipelineGraphicsMod.md | 73 +++++++++++++-------- 4 files changed, 85 insertions(+), 78 deletions(-) diff --git a/Source/Core/VideoCommon/PixelShaderGen.cpp b/Source/Core/VideoCommon/PixelShaderGen.cpp index bf574b8fda..b5090b362b 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/PixelShaderGen.cpp @@ -1315,6 +1315,23 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos WriteFog(out, uid_data); + for (std::size_t i = 0; i < custom_details.shaders.size(); i++) + { + const auto& shader_details = custom_details.shaders[i]; + + if (!shader_details.custom_shader.empty()) + { + out.Write("\t{{\n"); + out.Write("\t\tcustom_data.final_color = float4(prev.r / 255.0, prev.g / 255.0, prev.b " + "/ 255.0, prev.a / 255.0);\n"); + out.Write("\t\tCustomShaderOutput custom_output = {}_{}(custom_data);\n", + CUSTOM_PIXELSHADER_COLOR_FUNC, i); + out.Write("\t\tprev = int4(custom_output.main_rt.r * 255, custom_output.main_rt.g * 255, " + "custom_output.main_rt.b * 255, custom_output.main_rt.a * 255);\n"); + out.Write("\t}}\n\n"); + } + } + if (uid_data->logic_op_enable) WriteLogicOp(out, uid_data); else if (uid_data->emulate_logic_op_with_blend) @@ -1325,31 +1342,6 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos const bool use_dual_source = !uid_data->no_dual_src || uid_data->blend_enable; WriteColor(out, api_type, uid_data, use_dual_source); - for (std::size_t i = 0; i < custom_details.shaders.size(); i++) - { - const auto& shader_details = custom_details.shaders[i]; - - if (!shader_details.custom_shader.empty()) - { - out.Write("\t{{\n"); - if (uid_data->uint_output) - { - out.Write("\t\tcustom_data.final_color = float4(ocol0.x / 255.0, ocol0.y / 255.0, ocol0.z " - "/ 255.0, ocol0.w / 255.0);\n"); - out.Write("\t\tfloat3 custom_output = {}_{}(custom_data).xyz;\n", - CUSTOM_PIXELSHADER_COLOR_FUNC, i); - out.Write("\t\tocol0.xyz = uint3(custom_output.x * 255, custom_output.y * 255, " - "custom_output.z * 255);\n"); - } - else - { - out.Write("\t\tcustom_data.final_color = ocol0;\n"); - out.Write("\t\tocol0.xyz = {}_{}(custom_data).xyz;\n", CUSTOM_PIXELSHADER_COLOR_FUNC, i); - } - out.Write("\t}}\n\n"); - } - } - if (uid_data->blend_enable) WriteBlend(out, uid_data); else if (use_framebuffer_fetch) diff --git a/Source/Core/VideoCommon/ShaderGenCommon.cpp b/Source/Core/VideoCommon/ShaderGenCommon.cpp index 57d9c4567f..d132847f14 100644 --- a/Source/Core/VideoCommon/ShaderGenCommon.cpp +++ b/Source/Core/VideoCommon/ShaderGenCommon.cpp @@ -379,6 +379,11 @@ void WriteCustomShaderStructDef(ShaderCode* out, u32 numtexgens) out->Write("const uint CUSTOM_SHADER_LIGHTING_ATTENUATION_TYPE_SPOT = {}u;\n", static_cast(AttenuationFunc::Spot)); + out->Write("struct CustomShaderOutput\n"); + out->Write("{{\n"); + out->Write("\tfloat4 main_rt;\n"); + out->Write("}};\n\n"); + out->Write("struct CustomShaderLightData\n"); out->Write("{{\n"); out->Write("\tfloat3 position;\n"); diff --git a/Source/Core/VideoCommon/UberShaderPixel.cpp b/Source/Core/VideoCommon/UberShaderPixel.cpp index ca7658140f..ca8f42ec8f 100644 --- a/Source/Core/VideoCommon/UberShaderPixel.cpp +++ b/Source/Core/VideoCommon/UberShaderPixel.cpp @@ -1506,6 +1506,24 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config, " }}\n" "\n"); + for (std::size_t i = 0; i < custom_details.shaders.size(); i++) + { + const auto& shader_details = custom_details.shaders[i]; + + if (!shader_details.custom_shader.empty()) + { + out.Write("\t{{\n"); + out.Write("\t\tcustom_data.final_color = float4(TevResult.r / 255.0, TevResult.g / 255.0, " + "TevResult.b / 255.0, TevResult.a / 255.0);\n"); + out.Write("\t\tCustomShaderOutput custom_output = {}_{}(custom_data);\n", + CUSTOM_PIXELSHADER_COLOR_FUNC, i); + out.Write( + "\t\tTevResult = int4(custom_output.main_rt.r * 255, custom_output.main_rt.g * 255, " + "custom_output.main_rt.b * 255, custom_output.main_rt.a * 255);\n"); + out.Write("\t}}\n\n"); + } + } + if (use_framebuffer_fetch) { static constexpr std::array logic_op_mode{ @@ -1594,31 +1612,6 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config, } } - for (std::size_t i = 0; i < custom_details.shaders.size(); i++) - { - const auto& shader_details = custom_details.shaders[i]; - - if (!shader_details.custom_shader.empty()) - { - out.Write("\t{{\n"); - if (uid_data->uint_output) - { - out.Write("\t\tcustom_data.final_color = float4(ocol0.x / 255.0, ocol0.y / 255.0, ocol0.z " - "/ 255.0, ocol0.w / 255.0);\n"); - out.Write("\t\tfloat3 custom_output = {}_{}(custom_data).xyz;\n", - CUSTOM_PIXELSHADER_COLOR_FUNC, i); - out.Write("\t\tocol0.xyz = uint3(custom_output.x * 255, custom_output.y * 255, " - "custom_output.z * 255);\n"); - } - else - { - out.Write("\t\tcustom_data.final_color = ocol0;\n"); - out.Write("\t\tocol0.xyz = {}_{}(custom_data).xyz;\n", CUSTOM_PIXELSHADER_COLOR_FUNC, i); - } - out.Write("\t}}\n\n"); - } - } - if (bounding_box) { out.Write(" if (bpmem_bounding_box) {{\n" diff --git a/docs/CustomPipelineGraphicsMod.md b/docs/CustomPipelineGraphicsMod.md index 373b0a93a8..20d77dd720 100644 --- a/docs/CustomPipelineGraphicsMod.md +++ b/docs/CustomPipelineGraphicsMod.md @@ -84,28 +84,34 @@ A full example is given below: The shaders are written in GLSL and converted to the target shader that the backend uses internally. The user is expected to provide an entrypoint with the following signature: ``` -vec4 custom_main( in CustomShaderData data ) +CustomShaderOutput custom_main( in CustomShaderData data ) ``` +`CustomShaderOutput` is used to denote the final output that Dolphin will process and is what is returned by the function. It has the following structure: + +|Name | Type | Since | Description | +|-------------------------|-------------------------|-------|-------------------------------------------------------------------------------------------------| +|``main_rt`` | vec4 | v1 | The main render target's output color | + `CustomShaderData` encompasses all the data that Dolphin will pass to the user (in addition to the `samp` variable outlined above which is how textures are accessed). It has the following structure: -|Name | Type | Since | Description | -|-----------------------------|-------------------------|-------|-----------------------------------------------------------------------------------------------| -|``position`` | vec3 | v1 | The position of this pixel in _view space_ | -|``normal`` | vec3 | v1 | The normal of this pixel in _view space_ | -|``texcoord`` | vec3[] | v1 | An array of texture coordinates, the amount available is specified by ``texcoord_count`` | -|``texcoord_count`` | uint | v1 | The count of texture coordinates | -|``texmap_to_texcoord_index`` | uint[] | v1 | An array of texture units to texture coordinate values | -|``lights_chan0_color`` | CustomShaderLightData[] | v1 | An array of color lights for channel 0, the amount is specified by ``light_chan0_color_count``| -|``lights_chan0_alpha`` | CustomShaderLightData[] | v1 | An array of alpha lights for channel 0, the amount is specified by ``light_chan0_alpha_count``| -|``lights_chan1_color`` | CustomShaderLightData[] | v1 | An array of color lights for channel 1, the amount is specified by ``light_chan1_color_count``| -|``lights_chan1_alpha`` | CustomShaderLightData[] | v1 | An array of alpha lights for channel 1, the amount is specified by ``light_chan1_alpha_count``| -|``ambient_lighting`` | vec4[] | v1 | An array of ambient lighting values. Count is two, one for each color channel | -|``base_material`` | vec4[] | v1 | An array of the base material values. Count is two, one for each color channel | -|``tev_stages`` | CustomShaderTevStage[] | v1 | An array of TEV stages, the amount is specified by ``tev_stage_count`` | -|``tev_stage_count`` | uint | v1 | The count of TEV stages | -|``final_color`` | vec4 | v1 | The final color generated by Dolphin after all TEV stages are executed | -|``time_ms`` | uint | v1 | The time that has passed in milliseconds, since the game was started. Useful for animating | +|Name | Type | Since | Description | +|-----------------------------|-------------------------|-------|----------------------------------------------------------------------------------------------------------------------| +|``position`` | vec3 | v1 | The position of this pixel in _view space_ | +|``normal`` | vec3 | v1 | The normal of this pixel in _view space_ | +|``texcoord`` | vec3[] | v1 | An array of texture coordinates, the amount available is specified by ``texcoord_count`` | +|``texcoord_count`` | uint | v1 | The count of texture coordinates | +|``texmap_to_texcoord_index`` | uint[] | v1 | An array of texture units to texture coordinate values | +|``lights_chan0_color`` | CustomShaderLightData[] | v1 | An array of color lights for channel 0, the amount is specified by ``light_chan0_color_count`` | +|``lights_chan0_alpha`` | CustomShaderLightData[] | v1 | An array of alpha lights for channel 0, the amount is specified by ``light_chan0_alpha_count`` | +|``lights_chan1_color`` | CustomShaderLightData[] | v1 | An array of color lights for channel 1, the amount is specified by ``light_chan1_color_count`` | +|``lights_chan1_alpha`` | CustomShaderLightData[] | v1 | An array of alpha lights for channel 1, the amount is specified by ``light_chan1_alpha_count`` | +|``ambient_lighting`` | vec4[] | v1 | An array of ambient lighting values. Count is two, one for each color channel | +|``base_material`` | vec4[] | v1 | An array of the base material values. Count is two, one for each color channel | +|``tev_stages`` | CustomShaderTevStage[] | v1 | An array of TEV stages, the amount is specified by ``tev_stage_count`` | +|``tev_stage_count`` | uint | v1 | The count of TEV stages | +|``final_color`` | vec4 | v1 | The final color generated by Dolphin after all TEV stages are executed | +|``time_ms`` | uint | v1 | The time that has passed in milliseconds, since the game was started. Useful for animating | `CustomShaderLightData` is used to denote lighting data the game is applying when rendering the specific draw call. It has the following structure: @@ -172,9 +178,11 @@ Below are a handful of examples. The following shader displays the color red on the screen: ```glsl -vec4 custom_main( in CustomShaderData data ) +CustomShaderOutput custom_main( in CustomShaderData data ) { - return vec4(1.0, 0.0, 0.0, 1.0); + CustomShaderOutput custom_output; + custom_output.main_rt = vec4(1.0, 0.0, 0.0, 1.0); + return custom_output; } ``` @@ -183,9 +191,11 @@ vec4 custom_main( in CustomShaderData data ) The following shader displays the normal on the screen: ```glsl -vec4 custom_main( in CustomShaderData data ) +CustomShaderOutput custom_main( in CustomShaderData data ) { - return vec4(data.normal * 0.5 + 0.5, 1); + CustomShaderOutput custom_output; + custom_output.main_rt = vec4(data.normal * 0.5 + 0.5, 1); + return custom_output; } ``` @@ -194,9 +204,11 @@ vec4 custom_main( in CustomShaderData data ) The following shader displays the contents of the texture denoted in the shader asset as `MY_TEX` with the first texture coordinate data: ```glsl -vec4 custom_main( in CustomShaderData data ) +CustomShaderOutput custom_main( in CustomShaderData data ) { - return texture(samp_MY_TEX, TEX_COORD0); + CustomShaderOutput custom_output; + custom_output.main_rt = texture(samp_MY_TEX, TEX_COORD0); + return custom_output; } ``` @@ -205,7 +217,7 @@ vec4 custom_main( in CustomShaderData data ) The following shader would display the contents of the first texture the game uses, ignoring any other operations. If no stages are available or none exist with a texture it would use the final color of all the staging operations: ```glsl -vec4 custom_main( in CustomShaderData data ) +CustomShaderOutput custom_main( in CustomShaderData data ) { vec4 final_color = data.final_color; uint texture_set = 0; @@ -222,7 +234,9 @@ vec4 custom_main( in CustomShaderData data ) } } - return final_color; + CustomShaderOutput custom_output; + custom_output.main_rt = final_color; + return custom_output; } ``` @@ -231,7 +245,7 @@ vec4 custom_main( in CustomShaderData data ) The following shader would apply the lighting for any point lights used during the draw for channel 0's color lights, using blue as a base color: ```glsl -vec4 custom_main( in CustomShaderData data ) +CustomShaderOutput custom_main( in CustomShaderData data ) { float total_diffuse = 0; for (int i = 0; i < data.light_chan0_color_count; i++) @@ -246,6 +260,9 @@ vec4 custom_main( in CustomShaderData data ) total_diffuse += attn * max(0.0, dot(normal, light_dir)); } } - return vec4(total_diffuse * vec3(0, 0, 1), 1); + + CustomShaderOutput custom_output; + custom_output.main_rt = vec4(total_diffuse * vec3(0, 0, 1), 1); + return custom_output; } ``` \ No newline at end of file