Skip to content

Commit

Permalink
VideoCommon: allow custom shaders to set the alpha value for use when…
Browse files Browse the repository at this point in the history
… blending is enabled
  • Loading branch information
iwubcode committed Apr 28, 2024
1 parent efed26c commit fb76b8f
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 77 deletions.
41 changes: 17 additions & 24 deletions Source/Core/VideoCommon/PixelShaderGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1315,41 +1315,34 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos

WriteFog(out, uid_data);

if (uid_data->logic_op_enable)
WriteLogicOp(out, uid_data);
else if (uid_data->emulate_logic_op_with_blend)
WriteLogicOpBlend(out, uid_data);

// Write the color and alpha values to the framebuffer
// If using shader blend, we still use the separate alpha
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\tcustom_data.final_color = float4(prev.x / 255.0, prev.y / 255.0, prev.z "
"/ 255.0, prev.w / 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)
WriteLogicOpBlend(out, uid_data);

// Write the color and alpha values to the framebuffer
// If using shader blend, we still use the separate alpha
const bool use_dual_source = !uid_data->no_dual_src || uid_data->blend_enable;
WriteColor(out, api_type, uid_data, use_dual_source);

if (uid_data->blend_enable)
WriteBlend(out, uid_data);
else if (use_framebuffer_fetch)
Expand Down
5 changes: 5 additions & 0 deletions Source/Core/VideoCommon/ShaderGenCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,11 @@ void WriteCustomShaderStructDef(ShaderCode* out, u32 numtexgens)
out->Write("const uint CUSTOM_SHADER_LIGHTING_ATTENUATION_TYPE_SPOT = {}u;\n",
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("{{\n");
out->Write("\tfloat3 position;\n");
Expand Down
42 changes: 17 additions & 25 deletions Source/Core/VideoCommon/UberShaderPixel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1506,6 +1506,23 @@ 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.x / 255.0, TevResult.y / 255.0, TevResult.z "
"/ 255.0, TevResult.w / 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<const char*, 16> logic_op_mode{
Expand Down Expand Up @@ -1594,31 +1611,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"
Expand Down
72 changes: 44 additions & 28 deletions docs/CustomPipelineGraphicsMod.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down Expand Up @@ -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;
}
```

Expand All @@ -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;
}
```

Expand All @@ -194,9 +204,10 @@ 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);
}
```

Expand All @@ -205,7 +216,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;
Expand All @@ -222,7 +233,9 @@ vec4 custom_main( in CustomShaderData data )
}
}
return final_color;
CustomShaderOutput custom_output;
custom_output.main_rt = final_color;
return custom_output;
}
```

Expand All @@ -231,7 +244,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++)
Expand All @@ -246,6 +259,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;
}
```

0 comments on commit fb76b8f

Please sign in to comment.