VideoCommon: allow custom shaders to set the alpha value for use when blending is enabled

This commit is contained in:
iwubcode 2024-04-20 01:35:31 -05:00
parent efed26ceee
commit 9d28c371e7
4 changed files with 85 additions and 78 deletions

View File

@ -1315,6 +1315,23 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos
WriteFog(out, uid_data); 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) if (uid_data->logic_op_enable)
WriteLogicOp(out, uid_data); WriteLogicOp(out, uid_data);
else if (uid_data->emulate_logic_op_with_blend) 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; const bool use_dual_source = !uid_data->no_dual_src || uid_data->blend_enable;
WriteColor(out, api_type, uid_data, use_dual_source); 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) if (uid_data->blend_enable)
WriteBlend(out, uid_data); WriteBlend(out, uid_data);
else if (use_framebuffer_fetch) else if (use_framebuffer_fetch)

View File

@ -379,6 +379,11 @@ void WriteCustomShaderStructDef(ShaderCode* out, u32 numtexgens)
out->Write("const uint CUSTOM_SHADER_LIGHTING_ATTENUATION_TYPE_SPOT = {}u;\n", out->Write("const uint CUSTOM_SHADER_LIGHTING_ATTENUATION_TYPE_SPOT = {}u;\n",
static_cast<u32>(AttenuationFunc::Spot)); static_cast<u32>(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("struct CustomShaderLightData\n");
out->Write("{{\n"); out->Write("{{\n");
out->Write("\tfloat3 position;\n"); out->Write("\tfloat3 position;\n");

View File

@ -1506,6 +1506,24 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config,
" }}\n" " }}\n"
"\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) if (use_framebuffer_fetch)
{ {
static constexpr std::array<const char*, 16> logic_op_mode{ static constexpr std::array<const char*, 16> 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) if (bounding_box)
{ {
out.Write(" if (bpmem_bounding_box) {{\n" out.Write(" if (bpmem_bounding_box) {{\n"

View File

@ -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: 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: `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 | |Name | Type | Since | Description |
|-----------------------------|-------------------------|-------|-----------------------------------------------------------------------------------------------| |-----------------------------|-------------------------|-------|----------------------------------------------------------------------------------------------------------------------|
|``position`` | vec3 | v1 | The position of this pixel in _view space_ | |``position`` | vec3 | v1 | The position of this pixel in _view space_ |
|``normal`` | vec3 | v1 | The normal 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`` | vec3[] | v1 | An array of texture coordinates, the amount available is specified by ``texcoord_count`` |
|``texcoord_count`` | uint | v1 | The count of texture coordinates | |``texcoord_count`` | uint | v1 | The count of texture coordinates |
|``texmap_to_texcoord_index`` | uint[] | v1 | An array of texture units to texture coordinate values | |``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_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_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_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``| |``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 | |``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 | |``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_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 | |``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 | |``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 | |``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: `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: The following shader displays the color red on the screen:
```glsl ```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: The following shader displays the normal on the screen:
```glsl ```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: The following shader displays the contents of the texture denoted in the shader asset as `MY_TEX` with the first texture coordinate data:
```glsl ```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: 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 ```glsl
vec4 custom_main( in CustomShaderData data ) CustomShaderOutput custom_main( in CustomShaderData data )
{ {
vec4 final_color = data.final_color; vec4 final_color = data.final_color;
uint texture_set = 0; 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: 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 ```glsl
vec4 custom_main( in CustomShaderData data ) CustomShaderOutput custom_main( in CustomShaderData data )
{ {
float total_diffuse = 0; float total_diffuse = 0;
for (int i = 0; i < data.light_chan0_color_count; i++) 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)); 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;
} }
``` ```