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 = ¤t_option.min_value; 297 else if (key == "MaxValue") 298 dst_array = ¤t_option.max_value; 299 else if (key == "DefaultValue") 300 dst_array = ¤t_option.default_value; 301 else // if (key == "StepAmount") 302 dst_array = ¤t_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 }