141 lines
3.7 KiB
C++
141 lines
3.7 KiB
C++
#pragma once
|
|
#include "glutils/program.h"
|
|
#include "../Program/ProgramStateCache.h"
|
|
#include "../Program/ShaderInterpreter.h"
|
|
#include "../Common/TextureUtils.h"
|
|
|
|
#include <unordered_map>
|
|
|
|
namespace rsx
|
|
{
|
|
struct shader_loading_dialog;
|
|
}
|
|
|
|
namespace gl
|
|
{
|
|
using namespace ::glsl;
|
|
|
|
namespace interpreter
|
|
{
|
|
using program_metadata = program_hash_util::fragment_program_utils::fragment_program_metadata;
|
|
|
|
enum class texture_pool_flags
|
|
{
|
|
dirty = 1
|
|
};
|
|
|
|
struct texture_pool
|
|
{
|
|
int pool_size = 0;
|
|
int num_used = 0;
|
|
u32 flags = 0;
|
|
std::vector<int> allocated;
|
|
|
|
bool allocate(int value)
|
|
{
|
|
if (num_used >= pool_size)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (allocated.size() == unsigned(num_used))
|
|
{
|
|
allocated.push_back(value);
|
|
}
|
|
else
|
|
{
|
|
allocated[num_used] = value;
|
|
}
|
|
|
|
num_used++;
|
|
flags |= static_cast<u32>(texture_pool_flags::dirty);
|
|
return true;
|
|
}
|
|
};
|
|
|
|
struct bindless_textures_t
|
|
{
|
|
std::array<handle64_t, 16> sampler1D;
|
|
std::array<handle64_t, 16> sampler2D;
|
|
std::array<handle64_t, 16> sampler3D;
|
|
std::array<handle64_t, 16> samplerCUBE;
|
|
|
|
u8 dirty = 0xff;
|
|
|
|
std::span<handle64_t> get(rsx::texture_dimension_extended type)
|
|
{
|
|
using enum rsx::texture_dimension_extended;
|
|
switch (type)
|
|
{
|
|
default:
|
|
case texture_dimension_2d:
|
|
return sampler2D;
|
|
case texture_dimension_cubemap:
|
|
return samplerCUBE;
|
|
case texture_dimension_1d:
|
|
return sampler1D;
|
|
case texture_dimension_3d:
|
|
return sampler3D;
|
|
}
|
|
}
|
|
};
|
|
|
|
struct cached_program
|
|
{
|
|
u32 flags = program_common::interpreter::CACHED_PIPE_UNINITIALIZED;
|
|
|
|
// Compiler options mask - May not always match the storage compiler options in case of compatible pipelines
|
|
// However the storage mask must be a subset of this options mask
|
|
u64 build_compiler_options = 0;
|
|
|
|
std::shared_ptr<glsl::shader> vertex_shader;
|
|
std::shared_ptr<glsl::shader> fragment_shader;
|
|
std::shared_ptr<glsl::program> prog;
|
|
};
|
|
}
|
|
|
|
class shader_interpreter
|
|
{
|
|
using shader_cache_t = std::unordered_map<u64, std::shared_ptr<glsl::shader>>;
|
|
using pipeline_cache_t = std::unordered_map<u64, std::shared_ptr<interpreter::cached_program>>;
|
|
using async_build_callback_t = std::function<void(const std::shared_ptr<interpreter::cached_program>&)>;
|
|
|
|
shared_mutex m_vs_cache_lock;
|
|
shared_mutex m_fs_cache_lock;
|
|
shared_mutex m_program_cache_lock;
|
|
|
|
shader_cache_t m_vs_cache;
|
|
shader_cache_t m_fs_cache;
|
|
pipeline_cache_t m_program_cache;
|
|
|
|
// Texture binding information.
|
|
interpreter::bindless_textures_t m_texture_bindings{};
|
|
|
|
void build_vs(u64 compiler_options, interpreter::cached_program& prog_data);
|
|
void build_fs(u64 compiler_options, interpreter::cached_program& prog_data);
|
|
|
|
std::shared_ptr<interpreter::cached_program> build_program(u64 compiler_options);
|
|
void build_program_async(u64 compiler_options, async_build_callback_t callback);
|
|
void init_program(const std::shared_ptr<interpreter::cached_program>& data, u64 compiler_options);
|
|
void store_program(const std::shared_ptr<interpreter::cached_program>& data, u64 compiler_options);
|
|
|
|
std::shared_ptr<interpreter::cached_program> m_current_interpreter;
|
|
|
|
public:
|
|
shader_interpreter()
|
|
{
|
|
std::memset(&m_texture_bindings, 0, sizeof(m_texture_bindings));
|
|
}
|
|
|
|
void create(rsx::shader_loading_dialog* dlg);
|
|
void destroy();
|
|
|
|
// Update texture bindings based on the incoming descriptor structures
|
|
void bind_fragment_texture(int i, handle64_t handle, const rsx::sampled_image_descriptor_base& descriptor);
|
|
void flush_texture_bindings(glsl::program* program = nullptr);
|
|
|
|
glsl::program* get(const interpreter::program_metadata& fp_metadata, u32 vp_ctrl, u32 fp_ctrl);
|
|
bool is_interpreter(const glsl::program* program) const;
|
|
};
|
|
}
|