duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

postprocessing_shader_glsl.cpp (18404B)


      1 // SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
      2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
      3 
      4 #include "postprocessing_shader_glsl.h"
      5 #include "shadergen.h"
      6 
      7 #include "common/file_system.h"
      8 #include "common/log.h"
      9 #include "common/string_util.h"
     10 
     11 #include <cctype>
     12 #include <cstring>
     13 #include <sstream>
     14 
     15 Log_SetChannel(PostProcessing);
     16 
     17 namespace {
     18 class PostProcessingGLSLShaderGen : public ShaderGen
     19 {
     20 public:
     21   PostProcessingGLSLShaderGen(RenderAPI render_api, bool supports_dual_source_blend, bool supports_framebuffer_fetch);
     22   ~PostProcessingGLSLShaderGen();
     23 
     24   std::string GeneratePostProcessingVertexShader(const PostProcessing::GLSLShader& shader);
     25   std::string GeneratePostProcessingFragmentShader(const PostProcessing::GLSLShader& shader);
     26 
     27 private:
     28   void WriteUniformBuffer(std::stringstream& ss, const PostProcessing::GLSLShader& shader, bool use_push_constants);
     29 };
     30 } // namespace
     31 
     32 PostProcessing::GLSLShader::GLSLShader() = default;
     33 
     34 PostProcessing::GLSLShader::GLSLShader(std::string name, std::string code) : m_code(code)
     35 {
     36   m_name = std::move(name);
     37   LoadOptions();
     38 }
     39 
     40 PostProcessing::GLSLShader::~GLSLShader() = default;
     41 
     42 bool PostProcessing::GLSLShader::LoadFromFile(std::string name, const char* filename, Error* error)
     43 {
     44   std::optional<std::string> code = FileSystem::ReadFileToString(filename, error);
     45   if (!code.has_value() || code->empty())
     46     return false;
     47 
     48   return LoadFromString(std::move(name), code.value(), error);
     49 }
     50 
     51 bool PostProcessing::GLSLShader::LoadFromString(std::string name, std::string code, Error* error)
     52 {
     53   m_name = std::move(name);
     54   m_code = std::move(code);
     55   m_options.clear();
     56   LoadOptions();
     57   return true;
     58 }
     59 
     60 bool PostProcessing::GLSLShader::IsValid() const
     61 {
     62   return !m_name.empty() && !m_code.empty();
     63 }
     64 
     65 bool PostProcessing::GLSLShader::WantsDepthBuffer() const
     66 {
     67   return false;
     68 }
     69 
     70 u32 PostProcessing::GLSLShader::GetUniformsSize() const
     71 {
     72   // lazy packing. todo improve.
     73   return sizeof(CommonUniforms) + (sizeof(ShaderOption::ValueVector) * static_cast<u32>(m_options.size()));
     74 }
     75 
     76 void PostProcessing::GLSLShader::FillUniformBuffer(void* buffer, s32 viewport_x, s32 viewport_y, s32 viewport_width,
     77                                                    s32 viewport_height, u32 window_width, u32 window_height,
     78                                                    s32 original_width, s32 original_height, s32 native_width,
     79                                                    s32 native_height, float time) const
     80 {
     81   CommonUniforms* common = static_cast<CommonUniforms*>(buffer);
     82 
     83   const float internal_pixel_width = static_cast<float>(viewport_width) / static_cast<float>(original_width);
     84   const float internal_pixel_height = static_cast<float>(viewport_height) / static_cast<float>(original_height);
     85   const float native_pixel_width = (static_cast<float>(viewport_width) / static_cast<float>(native_width));
     86   const float native_pixel_height = (static_cast<float>(viewport_height) / static_cast<float>(native_height));
     87   common->src_rect[0] = static_cast<float>(viewport_x) / static_cast<float>(window_width);
     88   common->src_rect[1] = static_cast<float>(viewport_y) / static_cast<float>(window_height);
     89   common->src_rect[2] = (static_cast<float>(viewport_x + viewport_width - 1)) / static_cast<float>(window_width);
     90   common->src_rect[3] = (static_cast<float>(viewport_y + viewport_height - 1)) / static_cast<float>(window_height);
     91   common->src_size[0] = static_cast<float>(viewport_width) / static_cast<float>(window_width);
     92   common->src_size[1] = static_cast<float>(viewport_height) / static_cast<float>(window_height);
     93   common->window_size[0] = static_cast<float>(window_width);
     94   common->window_size[1] = static_cast<float>(window_height);
     95   common->rcp_window_size[0] = 1.0f / static_cast<float>(window_width);
     96   common->rcp_window_size[1] = 1.0f / static_cast<float>(window_height);
     97   common->viewport_size[0] = static_cast<float>(viewport_width);
     98   common->viewport_size[1] = static_cast<float>(viewport_height);
     99   common->window_to_viewport_ratio[0] = static_cast<float>(window_width) / static_cast<float>(viewport_width);
    100   common->window_to_viewport_ratio[1] = static_cast<float>(window_height) / static_cast<float>(viewport_height);
    101   common->internal_size[0] = static_cast<float>(original_width);
    102   common->internal_size[1] = static_cast<float>(original_height);
    103   common->internal_pixel_size[0] = internal_pixel_width;
    104   common->internal_pixel_size[1] = internal_pixel_height;
    105   common->norm_internal_pixel_size[0] = internal_pixel_width / static_cast<float>(window_width);
    106   common->norm_internal_pixel_size[1] = internal_pixel_height / static_cast<float>(window_height);
    107   common->native_size[0] = static_cast<float>(native_width);
    108   common->native_size[1] = static_cast<float>(native_height);
    109   common->native_pixel_size[0] = native_pixel_width;
    110   common->native_pixel_size[1] = native_pixel_height;
    111   common->norm_native_pixel_size[0] = native_pixel_width / static_cast<float>(window_width);
    112   common->norm_native_pixel_size[1] = native_pixel_height / static_cast<float>(window_height);
    113   common->upscale_multiplier = static_cast<float>(original_width) / static_cast<float>(native_width);
    114   common->time = time;
    115 
    116   u8* option_values = reinterpret_cast<u8*>(common + 1);
    117   for (const ShaderOption& option : m_options)
    118   {
    119     std::memcpy(option_values, option.value.data(), sizeof(ShaderOption::ValueVector));
    120     option_values += sizeof(ShaderOption::ValueVector);
    121   }
    122 }
    123 
    124 bool PostProcessing::GLSLShader::CompilePipeline(GPUTexture::Format format, u32 width, u32 height,
    125                                                  ProgressCallback* progress)
    126 {
    127   if (m_pipeline)
    128     m_pipeline.reset();
    129 
    130   PostProcessingGLSLShaderGen shadergen(g_gpu_device->GetRenderAPI(), g_gpu_device->GetFeatures().dual_source_blend,
    131                                         g_gpu_device->GetFeatures().framebuffer_fetch);
    132 
    133   std::unique_ptr<GPUShader> vs = g_gpu_device->CreateShader(GPUShaderStage::Vertex, shadergen.GetLanguage(),
    134                                                              shadergen.GeneratePostProcessingVertexShader(*this));
    135   std::unique_ptr<GPUShader> fs = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
    136                                                              shadergen.GeneratePostProcessingFragmentShader(*this));
    137   if (!vs || !fs)
    138     return false;
    139 
    140   GPUPipeline::GraphicsConfig plconfig;
    141   plconfig.layout = GPUPipeline::Layout::SingleTextureAndUBO;
    142   plconfig.primitive = GPUPipeline::Primitive::Triangles;
    143   plconfig.SetTargetFormats(format);
    144   plconfig.rasterization = GPUPipeline::RasterizationState::GetNoCullState();
    145   plconfig.depth = GPUPipeline::DepthState::GetNoTestsState();
    146   plconfig.blend = GPUPipeline::BlendState::GetNoBlendingState();
    147   plconfig.samples = 1;
    148   plconfig.per_sample_shading = false;
    149   plconfig.render_pass_flags = GPUPipeline::NoRenderPassFlags;
    150   plconfig.vertex_shader = vs.get();
    151   plconfig.fragment_shader = fs.get();
    152   plconfig.geometry_shader = nullptr;
    153 
    154   if (!(m_pipeline = g_gpu_device->CreatePipeline(plconfig)))
    155     return false;
    156 
    157   if (!m_sampler)
    158   {
    159     GPUSampler::Config config = GPUSampler::GetNearestConfig();
    160     config.address_u = GPUSampler::AddressMode::ClampToBorder;
    161     config.address_v = GPUSampler::AddressMode::ClampToBorder;
    162     config.border_color = 0xFF000000u;
    163     if (!(m_sampler = g_gpu_device->CreateSampler(config)))
    164       return false;
    165   }
    166 
    167   return true;
    168 }
    169 
    170 bool PostProcessing::GLSLShader::Apply(GPUTexture* input_color, GPUTexture* input_depth, GPUTexture* final_target,
    171                                        GSVector4i final_rect, s32 orig_width, s32 orig_height, s32 native_width,
    172                                        s32 native_height, u32 target_width, u32 target_height)
    173 {
    174   GL_SCOPE_FMT("GLSL Shader {}", m_name);
    175 
    176   // Assumes final stage has been cleared already.
    177   if (!final_target)
    178   {
    179     if (!g_gpu_device->BeginPresent(false))
    180       return false;
    181   }
    182   else
    183   {
    184     g_gpu_device->SetRenderTargets(&final_target, 1, nullptr);
    185     g_gpu_device->ClearRenderTarget(final_target, 0); // TODO: Could use an invalidate here too.
    186   }
    187 
    188   g_gpu_device->SetPipeline(m_pipeline.get());
    189   g_gpu_device->SetTextureSampler(0, input_color, m_sampler.get());
    190   g_gpu_device->SetViewportAndScissor(final_rect);
    191 
    192   const u32 uniforms_size = GetUniformsSize();
    193   void* uniforms = g_gpu_device->MapUniformBuffer(uniforms_size);
    194   FillUniformBuffer(uniforms, final_rect.left, final_rect.top, final_rect.width(), final_rect.height(), target_width,
    195                     target_height, orig_width, orig_height, native_width, native_height,
    196                     static_cast<float>(PostProcessing::GetTimer().GetTimeSeconds()));
    197   g_gpu_device->UnmapUniformBuffer(uniforms_size);
    198   g_gpu_device->Draw(3, 0);
    199   return true;
    200 }
    201 
    202 bool PostProcessing::GLSLShader::ResizeOutput(GPUTexture::Format format, u32 width, u32 height)
    203 {
    204   return true;
    205 }
    206 
    207 void PostProcessing::GLSLShader::LoadOptions()
    208 {
    209   // Adapted from Dolphin's PostProcessingConfiguration::LoadOptions().
    210   constexpr char config_start_delimiter[] = "[configuration]";
    211   constexpr char config_end_delimiter[] = "[/configuration]";
    212   size_t configuration_start = m_code.find(config_start_delimiter);
    213   size_t configuration_end = m_code.find(config_end_delimiter);
    214   if (configuration_start == std::string::npos || configuration_end == std::string::npos)
    215   {
    216     // Issue loading configuration or there isn't one.
    217     return;
    218   }
    219 
    220   std::string configuration_string =
    221     m_code.substr(configuration_start + std::strlen(config_start_delimiter),
    222                   configuration_end - configuration_start - std::strlen(config_start_delimiter));
    223 
    224   std::istringstream in(configuration_string);
    225 
    226   ShaderOption current_option = {};
    227   while (!in.eof())
    228   {
    229     std::string line_str;
    230     if (std::getline(in, line_str))
    231     {
    232       std::string_view line_view = line_str;
    233 
    234       // Check for CRLF eol and convert it to LF
    235       if (!line_view.empty() && line_view.at(line_view.size() - 1) == '\r')
    236         line_view.remove_suffix(1);
    237 
    238       if (line_view.empty())
    239         continue;
    240 
    241       if (line_view[0] == '[')
    242       {
    243         size_t endpos = line_view.find("]");
    244         if (endpos != std::string::npos)
    245         {
    246           if (current_option.type != ShaderOption::Type::Invalid)
    247           {
    248             current_option.value = current_option.default_value;
    249             if (current_option.ui_name.empty())
    250               current_option.ui_name = current_option.name;
    251 
    252             if (!current_option.name.empty() && current_option.vector_size > 0)
    253               m_options.push_back(std::move(current_option));
    254 
    255             current_option = {};
    256           }
    257 
    258           // New section!
    259           std::string_view sub = line_view.substr(1, endpos - 1);
    260           if (sub == "OptionBool")
    261             current_option.type = ShaderOption::Type::Bool;
    262           else if (sub == "OptionRangeFloat")
    263             current_option.type = ShaderOption::Type::Float;
    264           else if (sub == "OptionRangeInteger")
    265             current_option.type = ShaderOption::Type::Int;
    266           else
    267             ERROR_LOG("Invalid option type: '{}'", line_str);
    268 
    269           continue;
    270         }
    271       }
    272 
    273       if (current_option.type == ShaderOption::Type::Invalid)
    274         continue;
    275 
    276       std::string_view key, value;
    277       ParseKeyValue(line_view, &key, &value);
    278       if (!key.empty() && !value.empty())
    279       {
    280         if (key == "GUIName")
    281         {
    282           current_option.ui_name = value;
    283         }
    284         else if (key == "OptionName")
    285         {
    286           current_option.name = value;
    287         }
    288         else if (key == "DependentOption")
    289         {
    290           current_option.dependent_option = value;
    291         }
    292         else if (key == "MinValue" || key == "MaxValue" || key == "DefaultValue" || key == "StepAmount")
    293         {
    294           ShaderOption::ValueVector* dst_array;
    295           if (key == "MinValue")
    296             dst_array = &current_option.min_value;
    297           else if (key == "MaxValue")
    298             dst_array = &current_option.max_value;
    299           else if (key == "DefaultValue")
    300             dst_array = &current_option.default_value;
    301           else // if (key == "StepAmount")
    302             dst_array = &current_option.step_value;
    303 
    304           u32 size = 0;
    305           if (current_option.type == ShaderOption::Type::Bool)
    306             (*dst_array)[size++].int_value = StringUtil::FromChars<bool>(value).value_or(false) ? 1 : 0;
    307           else if (current_option.type == ShaderOption::Type::Float)
    308             size = PostProcessing::ShaderOption::ParseFloatVector(value, dst_array);
    309           else if (current_option.type == ShaderOption::Type::Int)
    310             size = PostProcessing::ShaderOption::ParseIntVector(value, dst_array);
    311 
    312           current_option.vector_size =
    313             (current_option.vector_size == 0) ? size : std::min(current_option.vector_size, size);
    314         }
    315         else
    316         {
    317           ERROR_LOG("Invalid option key: '{}'", line_str);
    318         }
    319       }
    320     }
    321   }
    322 
    323   if (current_option.type != ShaderOption::Type::Invalid && !current_option.name.empty() &&
    324       current_option.vector_size > 0)
    325   {
    326     current_option.value = current_option.default_value;
    327     if (current_option.ui_name.empty())
    328       current_option.ui_name = current_option.name;
    329 
    330     m_options.push_back(std::move(current_option));
    331   }
    332 }
    333 
    334 PostProcessingGLSLShaderGen::PostProcessingGLSLShaderGen(RenderAPI render_api, bool supports_dual_source_blend,
    335                                                          bool supports_framebuffer_fetch)
    336   : ShaderGen(render_api, GPUShaderLanguage::GLSLVK, supports_dual_source_blend, supports_framebuffer_fetch)
    337 {
    338 }
    339 
    340 PostProcessingGLSLShaderGen::~PostProcessingGLSLShaderGen() = default;
    341 
    342 std::string PostProcessingGLSLShaderGen::GeneratePostProcessingVertexShader(const PostProcessing::GLSLShader& shader)
    343 {
    344   std::stringstream ss;
    345 
    346   WriteHeader(ss);
    347   WriteUniformBuffer(ss, shader, false);
    348   DeclareTexture(ss, "samp0", 0);
    349 
    350   DeclareVertexEntryPoint(ss, {}, 0, 1, {}, true);
    351   ss << R"(
    352 {
    353   v_tex0 = float2(float((v_id << 1) & 2u), float(v_id & 2u));
    354   v_pos = float4(v_tex0 * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0.0f, 1.0f);
    355   #if API_OPENGL || API_OPENGL_ES || API_VULKAN
    356     v_pos.y = -v_pos.y;
    357   #endif
    358   v_tex0 = u_src_rect.xy + (u_src_size * v_tex0);
    359 }
    360 )";
    361 
    362   return ss.str();
    363 }
    364 
    365 std::string PostProcessingGLSLShaderGen::GeneratePostProcessingFragmentShader(const PostProcessing::GLSLShader& shader)
    366 {
    367   std::stringstream ss;
    368 
    369   WriteHeader(ss);
    370   WriteUniformBuffer(ss, shader, false);
    371   DeclareTexture(ss, "samp0", 0);
    372 
    373   ss << R"(
    374 layout(location = 0) in VertexData {
    375   vec2 v_tex0;
    376 };
    377 
    378 layout(location = 0) out float4 o_col0;
    379 
    380 float4 Sample() { return texture(samp0, v_tex0); }
    381 float4 SampleLocation(float2 location) { return texture(samp0, location); }
    382 #define SampleOffset(offset) textureOffset(samp0, v_tex0, offset)
    383 float2 GetFragCoord() { return gl_FragCoord.xy; }
    384 float2 GetCoordinates() { return v_tex0; }
    385 float2 GetWindowSize() { return u_window_size; }
    386 float2 GetInvWindowSize() { return u_rcp_window_size; }
    387 float2 GetViewportSize() { return u_viewport_size; }
    388 float2 GetWindowToViewportRatio() { return u_window_to_viewport_ratio; }
    389 float2 GetInternalSize() { return u_internal_size; }
    390 float2 GetInternalPixelSize() { return u_internal_pixel_size; }
    391 float2 GetInvInternalPixelSize() { return u_norm_internal_pixel_size; }
    392 float2 GetNativeSize() { return u_native_size; }
    393 float2 GetNativePixelSize() { return u_native_pixel_size; }
    394 float2 GetInvNativePixelSize() { return u_norm_native_pixel_size; }
    395 float GetUpscaleMultiplier() { return u_upscale_multiplier; }
    396 float GetTime() { return u_time; }
    397 void SetOutput(float4 color) { o_col0 = color; }
    398 
    399 // Deprecated, only present for backwards compatibility.
    400 float2 GetResolution() { return u_window_size; }
    401 float2 GetInvResolution() { return u_rcp_window_size; }
    402 float2 GetOriginalSize() { return u_internal_size; }
    403 float2 GetPaddedOriginalSize() { return u_internal_size * u_window_to_viewport_ratio; }
    404 float2 GetWindowResolution() { return u_window_size; }
    405 
    406 #define GetOption(x) (x)
    407 #define OptionEnabled(x) ((x) != 0)
    408 )";
    409 
    410   ss << shader.GetCode();
    411   return ss.str();
    412 }
    413 
    414 void PostProcessingGLSLShaderGen::WriteUniformBuffer(std::stringstream& ss, const PostProcessing::GLSLShader& shader,
    415                                                      bool use_push_constants)
    416 {
    417   u32 pad_counter = 0;
    418 
    419   WriteUniformBufferDeclaration(ss, use_push_constants);
    420   ss << "{\n";
    421   ss << "  float4 u_src_rect;\n";
    422   ss << "  float2 u_src_size;\n";
    423   ss << "  float2 u_window_size;\n";
    424   ss << "  float2 u_rcp_window_size;\n";
    425   ss << "  float2 u_viewport_size;\n";
    426   ss << "  float2 u_window_to_viewport_ratio;\n";
    427   ss << "  float2 u_internal_size;\n";
    428   ss << "  float2 u_internal_pixel_size;\n";
    429   ss << "  float2 u_norm_internal_pixel_size;\n";
    430   ss << "  float2 u_native_size;\n";
    431   ss << "  float2 u_native_pixel_size;\n";
    432   ss << "  float2 u_norm_native_pixel_size;\n";
    433   ss << "  float u_upscale_multiplier;\n";
    434   ss << "  float u_time;\n";
    435   ss << "\n";
    436 
    437   static constexpr std::array<const char*, PostProcessing::ShaderOption::MAX_VECTOR_COMPONENTS + 1> vector_size_suffix =
    438     {{"", "", "2", "3", "4"}};
    439   for (const PostProcessing::ShaderOption& option : shader.GetOptions())
    440   {
    441     switch (option.type)
    442     {
    443       case PostProcessing::ShaderOption::Type::Bool:
    444         ss << "  int " << option.name << ";\n";
    445         for (u32 i = option.vector_size; i < PostProcessing::ShaderOption::MAX_VECTOR_COMPONENTS; i++)
    446           ss << "  int u_ubo_pad" << (pad_counter++) << ";\n";
    447         break;
    448 
    449       case PostProcessing::ShaderOption::Type::Int:
    450       {
    451         ss << "  int" << vector_size_suffix[option.vector_size] << " " << option.name << ";\n";
    452         for (u32 i = option.vector_size; i < PostProcessing::ShaderOption::MAX_VECTOR_COMPONENTS; i++)
    453           ss << "  int u_ubo_pad" << (pad_counter++) << ";\n";
    454       }
    455       break;
    456 
    457       case PostProcessing::ShaderOption::Type::Float:
    458       default:
    459       {
    460         ss << "  float" << vector_size_suffix[option.vector_size] << " " << option.name << ";\n";
    461         for (u32 i = option.vector_size; i < PostProcessing::ShaderOption::MAX_VECTOR_COMPONENTS; i++)
    462           ss << "  float u_ubo_pad" << (pad_counter++) << ";\n";
    463       }
    464       break;
    465     }
    466   }
    467 
    468   ss << "};\n\n";
    469 }