video_core: Refactor GLSL fragment emitter (#7093)

* video_core: Refactor GLSL fragment emitter

* shader: Add back custom normal maps
This commit is contained in:
GPUCode
2023-11-06 22:26:28 +02:00
committed by GitHub
parent 9b2a5926a6
commit 1f6393e7d5
25 changed files with 2340 additions and 2098 deletions

View File

@@ -4,9 +4,9 @@
#include "common/thread_worker.h"
#include "video_core/rasterizer_cache/pixel_format.h"
#include "video_core/regs_pipeline.h"
#include "video_core/regs_rasterizer.h"
#include "video_core/renderer_vulkan/vk_common.h"
#include "video_core/shader/generator/glsl_shader_gen.h"
#include "video_core/shader/generator/spv_shader_gen.h"
namespace Common {

View File

@@ -15,8 +15,12 @@
#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_shader_util.h"
#include "video_core/shader/generator/glsl_fs_shader_gen.h"
#include "video_core/shader/generator/glsl_shader_gen.h"
#include "video_core/shader/generator/spv_fs_shader_gen.h"
using namespace Pica::Shader::Generator;
using Pica::Shader::FSConfig;
MICROPROFILE_DEFINE(Vulkan_Bind, "Vulkan", "Pipeline Bind", MP_RGB(192, 32, 32));
@@ -86,6 +90,17 @@ PipelineCache::PipelineCache(const Instance& instance_, Scheduler& scheduler_,
trivial_vertex_shader{
instance, vk::ShaderStageFlagBits::eVertex,
GLSL::GenerateTrivialVertexShader(instance.IsShaderClipDistanceSupported(), true)} {
profile = Pica::Shader::Profile{
.has_separable_shaders = true,
.has_clip_planes = instance.IsShaderClipDistanceSupported(),
.has_geometry_shader = instance.UseGeometryShaders(),
.has_custom_border_color = instance.IsCustomBorderColorSupported(),
.has_fragment_shader_interlock = instance.IsFragmentShaderInterlockSupported(),
.has_blend_minmax_factor = false,
.has_minus_one_to_one_range = false,
.has_logic_op = !instance.NeedsLogicOpEmulation(),
.is_vulkan = true,
};
BuildLayout();
}
@@ -403,35 +418,30 @@ void PipelineCache::UseTrivialGeometryShader() {
shader_hashes[ProgramType::GS] = 0;
}
void PipelineCache::UseFragmentShader(const Pica::Regs& regs) {
const PicaFSConfig config{regs, instance.IsFragmentShaderInterlockSupported(),
instance.NeedsLogicOpEmulation(),
!instance.IsCustomBorderColorSupported(), false};
const auto [it, new_shader] = fragment_shaders.try_emplace(config, instance);
void PipelineCache::UseFragmentShader(const Pica::Regs& regs,
const Pica::Shader::UserConfig& user) {
const FSConfig fs_config{regs, user, profile};
const auto [it, new_shader] = fragment_shaders.try_emplace(fs_config, instance);
auto& shader = it->second;
if (new_shader) {
const bool use_spirv = Settings::values.spirv_shader_gen.GetValue();
const auto texture0_type = config.state.texture0_type.Value();
const bool is_shadow = texture0_type == Pica::TexturingRegs::TextureConfig::Shadow2D ||
texture0_type == Pica::TexturingRegs::TextureConfig::ShadowCube ||
config.state.shadow_rendering.Value();
if (use_spirv && !is_shadow) {
const std::vector code = SPIRV::GenerateFragmentShader(config);
if (use_spirv && !fs_config.UsesShadowPipeline()) {
const std::vector code = SPIRV::GenerateFragmentShader(fs_config);
shader.module = CompileSPV(code, instance.GetDevice());
shader.MarkDone();
} else {
workers.QueueWork([config, device = instance.GetDevice(), &shader]() {
const std::string code = GLSL::GenerateFragmentShader(config, true);
shader.module = Compile(code, vk::ShaderStageFlagBits::eFragment, device);
workers.QueueWork([fs_config, this, &shader]() {
const std::string code = GLSL::GenerateFragmentShader(fs_config, profile);
shader.module =
Compile(code, vk::ShaderStageFlagBits::eFragment, instance.GetDevice());
shader.MarkDone();
});
}
}
current_shaders[ProgramType::FS] = &shader;
shader_hashes[ProgramType::FS] = config.Hash();
shader_hashes[ProgramType::FS] = fs_config.Hash();
}
void PipelineCache::BindTexture(u32 binding, vk::ImageView image_view, vk::Sampler sampler) {

View File

@@ -9,13 +9,18 @@
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
#include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
#include "video_core/shader/generator/glsl_shader_gen.h"
#include "video_core/shader/generator/spv_shader_gen.h"
#include "video_core/shader/generator/pica_fs_config.h"
#include "video_core/shader/generator/profile.h"
#include "video_core/shader/generator/shader_gen.h"
namespace Pica {
struct Regs;
}
namespace Pica::Shader {
struct ShaderSetup;
}
namespace Vulkan {
class Instance;
@@ -62,7 +67,7 @@ public:
void UseTrivialGeometryShader();
/// Binds a fragment shader generated from PICA state
void UseFragmentShader(const Pica::Regs& regs);
void UseFragmentShader(const Pica::Regs& regs, const Pica::Shader::UserConfig& user);
/// Binds a texture to the specified binding
void BindTexture(u32 binding, vk::ImageView image_view, vk::Sampler sampler);
@@ -98,6 +103,7 @@ private:
RenderpassCache& renderpass_cache;
DescriptorPool& pool;
Pica::Shader::Profile profile{};
vk::UniquePipelineCache pipeline_cache;
vk::UniquePipelineLayout pipeline_layout;
std::size_t num_worker_threads;
@@ -118,7 +124,7 @@ private:
std::unordered_map<Pica::Shader::Generator::PicaVSConfig, Shader*> programmable_vertex_map;
std::unordered_map<std::string, Shader> programmable_vertex_cache;
std::unordered_map<Pica::Shader::Generator::PicaFixedGSConfig, Shader> fixed_geometry_shaders;
std::unordered_map<Pica::Shader::Generator::PicaFSConfig, Shader> fragment_shaders;
std::unordered_map<Pica::Shader::FSConfig, Shader> fragment_shaders;
Shader trivial_vertex_shader;
};

View File

@@ -497,7 +497,7 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
// Sync and bind the shader
if (shader_dirty) {
pipeline_cache.UseFragmentShader(regs);
pipeline_cache.UseFragmentShader(regs, user_config);
shader_dirty = false;
}