mirror of https://github.com/RPCS3/rpcs3.git
rsx: Rewrite async decompiler
This commit is contained in:
parent
609c0d46af
commit
2985a39d2e
|
@ -111,7 +111,6 @@ class program_state_cache
|
||||||
using binary_to_vertex_program = std::unordered_map<RSXVertexProgram, vertex_program_type, program_hash_util::vertex_program_storage_hash, program_hash_util::vertex_program_compare> ;
|
using binary_to_vertex_program = std::unordered_map<RSXVertexProgram, vertex_program_type, program_hash_util::vertex_program_storage_hash, program_hash_util::vertex_program_compare> ;
|
||||||
using binary_to_fragment_program = std::unordered_map<RSXFragmentProgram, fragment_program_type, program_hash_util::fragment_program_storage_hash, program_hash_util::fragment_program_compare>;
|
using binary_to_fragment_program = std::unordered_map<RSXFragmentProgram, fragment_program_type, program_hash_util::fragment_program_storage_hash, program_hash_util::fragment_program_compare>;
|
||||||
|
|
||||||
|
|
||||||
struct pipeline_key
|
struct pipeline_key
|
||||||
{
|
{
|
||||||
u32 vertex_program_id;
|
u32 vertex_program_id;
|
||||||
|
@ -139,41 +138,26 @@ class program_state_cache
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
struct async_decompiler_job
|
||||||
struct async_link_task_entry
|
|
||||||
{
|
{
|
||||||
const vertex_program_type& vp;
|
RSXVertexProgram vertex_program;
|
||||||
const fragment_program_type& fp;
|
RSXFragmentProgram fragment_program;
|
||||||
pipeline_properties props;
|
pipeline_properties properties;
|
||||||
|
|
||||||
async_link_task_entry(const vertex_program_type& _V, const fragment_program_type& _F, pipeline_properties _P)
|
std::vector<u8> local_storage;
|
||||||
: vp(_V), fp(_F), props(std::move(_P))
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct async_decompile_task_entry
|
async_decompiler_job(RSXVertexProgram v, const RSXFragmentProgram f, pipeline_properties p) :
|
||||||
|
vertex_program(std::move(v)), fragment_program(f), properties(std::move(p))
|
||||||
{
|
{
|
||||||
RSXVertexProgram vp;
|
local_storage.resize(fragment_program.ucode_length);
|
||||||
RSXFragmentProgram fp;
|
std::memcpy(local_storage.data(), fragment_program.addr, fragment_program.ucode_length);
|
||||||
bool is_fp;
|
fragment_program.addr = local_storage.data();
|
||||||
|
|
||||||
std::vector<u8> tmp_cache;
|
|
||||||
|
|
||||||
async_decompile_task_entry(RSXVertexProgram _V)
|
|
||||||
: vp(std::move(_V)), is_fp(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
async_decompile_task_entry(const RSXFragmentProgram& _F)
|
|
||||||
: fp(_F), is_fp(true)
|
|
||||||
{
|
|
||||||
tmp_cache.resize(fp.ucode_length);
|
|
||||||
std::memcpy(tmp_cache.data(), fp.addr, fp.ucode_length);
|
|
||||||
fp.addr = tmp_cache.data();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
using decompiler_callback_t = std::function<void(const pipeline_properties&, const RSXVertexProgram&, const RSXFragmentProgram&)>;
|
||||||
|
|
||||||
shared_mutex m_vertex_mutex;
|
shared_mutex m_vertex_mutex;
|
||||||
shared_mutex m_fragment_mutex;
|
shared_mutex m_fragment_mutex;
|
||||||
shared_mutex m_pipeline_mutex;
|
shared_mutex m_pipeline_mutex;
|
||||||
|
@ -181,14 +165,14 @@ protected:
|
||||||
|
|
||||||
atomic_t<size_t> m_next_id = 0;
|
atomic_t<size_t> m_next_id = 0;
|
||||||
bool m_cache_miss_flag; // Set if last lookup did not find any usable cached programs
|
bool m_cache_miss_flag; // Set if last lookup did not find any usable cached programs
|
||||||
bool m_program_compiled_flag; // Set if last lookup caused program to be linked
|
|
||||||
|
|
||||||
binary_to_vertex_program m_vertex_shader_cache;
|
binary_to_vertex_program m_vertex_shader_cache;
|
||||||
binary_to_fragment_program m_fragment_shader_cache;
|
binary_to_fragment_program m_fragment_shader_cache;
|
||||||
std::unordered_map <pipeline_key, pipeline_storage_type, pipeline_key_hash, pipeline_key_compare> m_storage;
|
std::unordered_map<pipeline_key, pipeline_storage_type, pipeline_key_hash, pipeline_key_compare> m_storage;
|
||||||
|
|
||||||
std::unordered_map <pipeline_key, std::unique_ptr<async_link_task_entry>, pipeline_key_hash, pipeline_key_compare> m_link_queue;
|
std::deque<async_decompiler_job> m_decompile_queue;
|
||||||
std::deque<async_decompile_task_entry> m_decompile_queue;
|
std::unordered_map<pipeline_key, bool, pipeline_key_hash, pipeline_key_compare> m_decompiler_map;
|
||||||
|
decompiler_callback_t notify_pipeline_compiled;
|
||||||
|
|
||||||
vertex_program_type __null_vertex_program;
|
vertex_program_type __null_vertex_program;
|
||||||
fragment_program_type __null_fragment_program;
|
fragment_program_type __null_fragment_program;
|
||||||
|
@ -349,12 +333,7 @@ public:
|
||||||
public:
|
public:
|
||||||
program_state_cache() = default;
|
program_state_cache() = default;
|
||||||
~program_state_cache()
|
~program_state_cache()
|
||||||
{
|
{}
|
||||||
for (auto& pair : m_fragment_shader_cache)
|
|
||||||
{
|
|
||||||
free(pair.first.addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns 2 booleans.
|
// Returns 2 booleans.
|
||||||
// First flag hints that there is more work to do (busy hint)
|
// First flag hints that there is more work to do (busy hint)
|
||||||
|
@ -366,31 +345,58 @@ public:
|
||||||
// NOTE: Linking is much slower than decompilation step, so always decompile at least 1 unit
|
// NOTE: Linking is much slower than decompilation step, so always decompile at least 1 unit
|
||||||
// TODO: Use try_lock instead
|
// TODO: Use try_lock instead
|
||||||
bool busy = false;
|
bool busy = false;
|
||||||
|
bool sync = false;
|
||||||
u32 count = 0;
|
u32 count = 0;
|
||||||
std::unique_ptr<async_decompile_task_entry> decompile_task;
|
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
std::lock_guard lock(m_decompiler_mutex);
|
reader_lock lock(m_decompiler_mutex);
|
||||||
if (m_decompile_queue.empty())
|
if (m_decompile_queue.empty())
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
|
||||||
|
// Decompile
|
||||||
|
const auto& vp_search = search_vertex_program(m_decompile_queue.front().vertex_program, true);
|
||||||
|
const auto& fp_search = search_fragment_program(m_decompile_queue.front().fragment_program, true);
|
||||||
|
|
||||||
|
const bool already_existing_fragment_program = std::get<1>(fp_search);
|
||||||
|
const bool already_existing_vertex_program = std::get<1>(vp_search);
|
||||||
|
const vertex_program_type& vertex_program = std::get<0>(vp_search);
|
||||||
|
const fragment_program_type& fragment_program = std::get<0>(fp_search);
|
||||||
|
const pipeline_key key = { vertex_program.id, fragment_program.id, m_decompile_queue.front().properties };
|
||||||
|
|
||||||
|
// Retest
|
||||||
|
bool found = false;
|
||||||
|
if (already_existing_vertex_program && already_existing_fragment_program)
|
||||||
{
|
{
|
||||||
decompile_task = std::make_unique<async_decompile_task_entry>(std::move(m_decompile_queue.front()));
|
if (auto I = m_storage.find(key); I != m_storage.end())
|
||||||
m_decompile_queue.pop_front();
|
{
|
||||||
|
found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decompile_task->is_fp)
|
if (!found)
|
||||||
{
|
{
|
||||||
search_fragment_program(decompile_task->fp);
|
pipeline_storage_type pipeline = backend_traits::build_pipeline(vertex_program, fragment_program, m_decompile_queue.front().properties, std::forward<Args>(args)...);
|
||||||
|
rsx_log.success("New program compiled successfully");
|
||||||
|
sync = true;
|
||||||
|
|
||||||
|
if (notify_pipeline_compiled)
|
||||||
|
{
|
||||||
|
notify_pipeline_compiled(m_decompile_queue.front().properties, m_decompile_queue.front().vertex_program, m_decompile_queue.front().fragment_program);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
std::scoped_lock lock(m_pipeline_mutex);
|
||||||
|
m_storage[key] = std::move(pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
search_vertex_program(decompile_task->vp);
|
std::scoped_lock lock(m_decompiler_mutex);
|
||||||
|
m_decompile_queue.pop_front();
|
||||||
|
m_decompiler_map.erase(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (++count >= max_decompile_count)
|
if (++count >= max_decompile_count)
|
||||||
|
@ -402,30 +408,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async_link_task_entry* link_entry;
|
return { busy, sync };
|
||||||
pipeline_key key;
|
|
||||||
{
|
|
||||||
reader_lock lock(m_pipeline_mutex);
|
|
||||||
if (!m_link_queue.empty())
|
|
||||||
{
|
|
||||||
auto It = m_link_queue.begin();
|
|
||||||
link_entry = It->second.get();
|
|
||||||
key = It->first;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return { busy, false };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pipeline_storage_type pipeline = backend_traits::build_pipeline(link_entry->vp, link_entry->fp, link_entry->props, std::forward<Args>(args)...);
|
|
||||||
rsx_log.success("New program compiled successfully");
|
|
||||||
|
|
||||||
std::lock_guard lock(m_pipeline_mutex);
|
|
||||||
m_storage[key] = std::move(pipeline);
|
|
||||||
m_link_queue.erase(key);
|
|
||||||
|
|
||||||
return { (busy || !m_link_queue.empty()), true };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
|
@ -434,6 +417,7 @@ public:
|
||||||
const RSXFragmentProgram& fragmentShader,
|
const RSXFragmentProgram& fragmentShader,
|
||||||
pipeline_properties& pipelineProperties,
|
pipeline_properties& pipelineProperties,
|
||||||
bool allow_async,
|
bool allow_async,
|
||||||
|
bool allow_notification,
|
||||||
Args&& ...args
|
Args&& ...args
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
@ -442,100 +426,66 @@ public:
|
||||||
|
|
||||||
const bool already_existing_fragment_program = std::get<1>(fp_search);
|
const bool already_existing_fragment_program = std::get<1>(fp_search);
|
||||||
const bool already_existing_vertex_program = std::get<1>(vp_search);
|
const bool already_existing_vertex_program = std::get<1>(vp_search);
|
||||||
|
const vertex_program_type& vertex_program = std::get<0>(vp_search);
|
||||||
|
const fragment_program_type& fragment_program = std::get<0>(fp_search);
|
||||||
|
const pipeline_key key = { vertex_program.id, fragment_program.id, pipelineProperties };
|
||||||
|
|
||||||
bool link_only = false;
|
|
||||||
m_cache_miss_flag = true;
|
m_cache_miss_flag = true;
|
||||||
m_program_compiled_flag = false;
|
|
||||||
|
|
||||||
if (!allow_async || (already_existing_vertex_program && already_existing_fragment_program))
|
if (!allow_async || (already_existing_vertex_program && already_existing_fragment_program))
|
||||||
{
|
{
|
||||||
const vertex_program_type &vertex_program = std::get<0>(vp_search);
|
|
||||||
const fragment_program_type &fragment_program = std::get<0>(fp_search);
|
|
||||||
|
|
||||||
backend_traits::validate_pipeline_properties(vertex_program, fragment_program, pipelineProperties);
|
backend_traits::validate_pipeline_properties(vertex_program, fragment_program, pipelineProperties);
|
||||||
pipeline_key key = { vertex_program.id, fragment_program.id, pipelineProperties };
|
|
||||||
|
|
||||||
{
|
{
|
||||||
reader_lock lock(m_pipeline_mutex);
|
reader_lock lock(m_pipeline_mutex);
|
||||||
const auto I = m_storage.find(key);
|
if (const auto I = m_storage.find(key); I != m_storage.end())
|
||||||
if (I != m_storage.end())
|
|
||||||
{
|
{
|
||||||
m_cache_miss_flag = false;
|
m_cache_miss_flag = false;
|
||||||
return I->second;
|
return I->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allow_async)
|
if (!allow_async)
|
||||||
{
|
|
||||||
// Programs already exist, only linking required
|
|
||||||
link_only = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
rsx_log.notice("Add program (vp id = %d, fp id = %d)", vertex_program.id, fragment_program.id);
|
rsx_log.notice("Add program (vp id = %d, fp id = %d)", vertex_program.id, fragment_program.id);
|
||||||
m_program_compiled_flag = true;
|
|
||||||
|
|
||||||
pipeline_storage_type pipeline = backend_traits::build_pipeline(vertex_program, fragment_program, pipelineProperties, std::forward<Args>(args)...);
|
pipeline_storage_type pipeline = backend_traits::build_pipeline(vertex_program, fragment_program, pipelineProperties, std::forward<Args>(args)...);
|
||||||
|
|
||||||
|
if (allow_notification && notify_pipeline_compiled)
|
||||||
|
{
|
||||||
|
notify_pipeline_compiled(pipelineProperties, vertexShader, fragmentShader);
|
||||||
|
rsx_log.success("New program compiled successfully");
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard lock(m_pipeline_mutex);
|
std::lock_guard lock(m_pipeline_mutex);
|
||||||
auto &rtn = m_storage[key] = std::move(pipeline);
|
auto &rtn = m_storage[key] = std::move(pipeline);
|
||||||
rsx_log.success("New program compiled successfully");
|
|
||||||
return rtn;
|
return rtn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
verify(HERE), allow_async;
|
verify(HERE), allow_async;
|
||||||
|
|
||||||
if (link_only)
|
std::scoped_lock lock(m_decompiler_mutex, m_pipeline_mutex);
|
||||||
|
|
||||||
|
// Rechecks
|
||||||
|
if (already_existing_vertex_program && already_existing_fragment_program)
|
||||||
{
|
{
|
||||||
const vertex_program_type &vertex_program = std::get<0>(vp_search);
|
if (const auto I = m_storage.find(key); I != m_storage.end())
|
||||||
const fragment_program_type &fragment_program = std::get<0>(fp_search);
|
{
|
||||||
pipeline_key key = { vertex_program.id, fragment_program.id, pipelineProperties };
|
m_cache_miss_flag = false;
|
||||||
|
return I->second;
|
||||||
|
}
|
||||||
|
|
||||||
reader_lock lock(m_pipeline_mutex);
|
if (const auto I = m_decompiler_map.find(key); I != m_decompiler_map.end())
|
||||||
|
|
||||||
if (m_link_queue.find(key) != m_link_queue.end())
|
|
||||||
{
|
{
|
||||||
// Already in queue
|
// Already in queue
|
||||||
return __null_pipeline_handle;
|
return __null_pipeline_handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
rsx_log.notice("Add program (vp id = %d, fp id = %d)", vertex_program.id, fragment_program.id);
|
m_decompiler_map[key] = true;
|
||||||
m_program_compiled_flag = true;
|
|
||||||
|
|
||||||
lock.upgrade();
|
|
||||||
m_link_queue[key] = std::make_unique<async_link_task_entry>(vertex_program, fragment_program, pipelineProperties);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
reader_lock lock(m_decompiler_mutex);
|
|
||||||
|
|
||||||
auto vertex_program_found = std::find_if(m_decompile_queue.begin(), m_decompile_queue.end(), [&](const auto& V)
|
|
||||||
{
|
|
||||||
if (V.is_fp) return false;
|
|
||||||
return program_hash_util::vertex_program_compare()(V.vp, vertexShader);
|
|
||||||
});
|
|
||||||
|
|
||||||
auto fragment_program_found = std::find_if(m_decompile_queue.begin(), m_decompile_queue.end(), [&](const auto& F)
|
|
||||||
{
|
|
||||||
if (!F.is_fp) return false;
|
|
||||||
return program_hash_util::fragment_program_compare()(F.fp, fragmentShader);
|
|
||||||
});
|
|
||||||
|
|
||||||
const bool add_vertex_program = (vertex_program_found == m_decompile_queue.end());
|
|
||||||
const bool add_fragment_program = (fragment_program_found == m_decompile_queue.end());
|
|
||||||
|
|
||||||
if (add_vertex_program)
|
|
||||||
{
|
|
||||||
lock.upgrade();
|
|
||||||
m_decompile_queue.emplace_back(vertexShader);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (add_fragment_program)
|
// Enqueue if not already queued
|
||||||
{
|
m_decompile_queue.emplace_back(vertexShader, fragmentShader, pipelineProperties);
|
||||||
lock.upgrade();
|
|
||||||
m_decompile_queue.emplace_back(fragmentShader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return __null_pipeline_handle;
|
return __null_pipeline_handle;
|
||||||
}
|
}
|
||||||
|
@ -599,6 +549,16 @@ public:
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
|
std::scoped_lock lock(m_vertex_mutex, m_fragment_mutex, m_decompiler_mutex, m_pipeline_mutex);
|
||||||
|
|
||||||
|
for (auto& pair : m_fragment_shader_cache)
|
||||||
|
{
|
||||||
|
free(pair.first.addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
notify_pipeline_compiled = {};
|
||||||
|
m_fragment_shader_cache.clear();
|
||||||
|
m_vertex_shader_cache.clear();
|
||||||
m_storage.clear();
|
m_storage.clear();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -412,15 +412,8 @@ void GLFragmentProgram::Delete()
|
||||||
shader.clear();
|
shader.clear();
|
||||||
|
|
||||||
if (id)
|
if (id)
|
||||||
{
|
|
||||||
if (Emu.IsStopped())
|
|
||||||
{
|
|
||||||
rsx_log.warning("GLFragmentProgram::Delete(): glDeleteShader(%d) avoided", id);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
glDeleteShader(id);
|
glDeleteShader(id);
|
||||||
}
|
|
||||||
id = 0;
|
id = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -903,6 +903,15 @@ void GLGSRender::on_init_thread()
|
||||||
|
|
||||||
m_gl_texture_cache.initialize();
|
m_gl_texture_cache.initialize();
|
||||||
|
|
||||||
|
m_prog_buffer.initialize
|
||||||
|
(
|
||||||
|
[this](void* const& props, const RSXVertexProgram& vp, const RSXFragmentProgram& fp)
|
||||||
|
{
|
||||||
|
// Program was linked or queued for linking
|
||||||
|
m_shaders_cache->store(props, vp, fp);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
if (!m_overlay_manager)
|
if (!m_overlay_manager)
|
||||||
{
|
{
|
||||||
m_frame->hide();
|
m_frame->hide();
|
||||||
|
@ -1196,16 +1205,10 @@ bool GLGSRender::load_program()
|
||||||
|
|
||||||
void* pipeline_properties = nullptr;
|
void* pipeline_properties = nullptr;
|
||||||
m_program = m_prog_buffer.get_graphics_pipeline(current_vertex_program, current_fragment_program, pipeline_properties,
|
m_program = m_prog_buffer.get_graphics_pipeline(current_vertex_program, current_fragment_program, pipeline_properties,
|
||||||
!g_cfg.video.disable_asynchronous_shader_compiler).get();
|
!g_cfg.video.disable_asynchronous_shader_compiler, true).get();
|
||||||
|
|
||||||
if (m_prog_buffer.check_cache_missed())
|
if (m_prog_buffer.check_cache_missed())
|
||||||
{
|
{
|
||||||
if (m_prog_buffer.check_program_linked_flag())
|
|
||||||
{
|
|
||||||
// Program was linked or queued for linking
|
|
||||||
m_shaders_cache->store(pipeline_properties, current_vertex_program, current_fragment_program);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notify the user with HUD notification
|
// Notify the user with HUD notification
|
||||||
if (g_cfg.misc.show_shader_compilation_hint)
|
if (g_cfg.misc.show_shader_compilation_hint)
|
||||||
{
|
{
|
||||||
|
|
|
@ -86,21 +86,26 @@ struct GLTraits
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class GLProgramBuffer : public program_state_cache<GLTraits>
|
struct GLProgramBuffer : public program_state_cache<GLTraits>
|
||||||
{
|
{
|
||||||
public:
|
GLProgramBuffer() = default;
|
||||||
|
|
||||||
u64 get_hash(void*&)
|
void initialize(decompiler_callback_t callback)
|
||||||
|
{
|
||||||
|
notify_pipeline_compiled = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 get_hash(void* const&)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 get_hash(RSXVertexProgram &prog)
|
u64 get_hash(const RSXVertexProgram &prog)
|
||||||
{
|
{
|
||||||
return program_hash_util::vertex_program_utils::get_vertex_program_ucode_hash(prog);
|
return program_hash_util::vertex_program_utils::get_vertex_program_ucode_hash(prog);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 get_hash(RSXFragmentProgram &prog)
|
u64 get_hash(const RSXFragmentProgram &prog)
|
||||||
{
|
{
|
||||||
return program_hash_util::fragment_program_utils::get_fragment_program_ucode_hash(prog);
|
return program_hash_util::fragment_program_utils::get_fragment_program_ucode_hash(prog);
|
||||||
}
|
}
|
||||||
|
@ -109,7 +114,7 @@ public:
|
||||||
void add_pipeline_entry(RSXVertexProgram &vp, RSXFragmentProgram &fp, void* &props, Args&& ...args)
|
void add_pipeline_entry(RSXVertexProgram &vp, RSXFragmentProgram &fp, void* &props, Args&& ...args)
|
||||||
{
|
{
|
||||||
vp.skip_vertex_input_check = true;
|
vp.skip_vertex_input_check = true;
|
||||||
get_graphics_pipeline(vp, fp, props, false, std::forward<Args>(args)...);
|
get_graphics_pipeline(vp, fp, props, false, false, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
void preload_programs(RSXVertexProgram &vp, RSXFragmentProgram &fp)
|
void preload_programs(RSXVertexProgram &vp, RSXFragmentProgram &fp)
|
||||||
|
@ -122,9 +127,4 @@ public:
|
||||||
{
|
{
|
||||||
return m_cache_miss_flag;
|
return m_cache_miss_flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check_program_linked_flag() const
|
|
||||||
{
|
|
||||||
return m_program_compiled_flag;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -314,15 +314,8 @@ void GLVertexProgram::Delete()
|
||||||
shader.clear();
|
shader.clear();
|
||||||
|
|
||||||
if (id)
|
if (id)
|
||||||
{
|
|
||||||
if (Emu.IsStopped())
|
|
||||||
{
|
|
||||||
rsx_log.warning("GLVertexProgram::Delete(): glDeleteShader(%d) avoided", id);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
glDeleteShader(id);
|
glDeleteShader(id);
|
||||||
}
|
|
||||||
id = 0;
|
id = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -537,7 +537,14 @@ VKGSRender::VKGSRender() : GSRender()
|
||||||
m_video_output_pass = std::make_unique<vk::video_out_calibration_pass>();
|
m_video_output_pass = std::make_unique<vk::video_out_calibration_pass>();
|
||||||
m_video_output_pass->create(*m_device);
|
m_video_output_pass->create(*m_device);
|
||||||
|
|
||||||
m_prog_buffer = std::make_unique<VKProgramBuffer>();
|
m_prog_buffer = std::make_unique<VKProgramBuffer>
|
||||||
|
(
|
||||||
|
[this](const vk::pipeline_props& props, const RSXVertexProgram& vp, const RSXFragmentProgram& fp)
|
||||||
|
{
|
||||||
|
// Program was linked or queued for linking
|
||||||
|
m_shaders_cache->store(props, vp, fp);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
if (g_cfg.video.disable_vertex_cache || g_cfg.video.multithreaded_rsx)
|
if (g_cfg.video.disable_vertex_cache || g_cfg.video.multithreaded_rsx)
|
||||||
m_vertex_cache = std::make_unique<vk::null_vertex_cache>();
|
m_vertex_cache = std::make_unique<vk::null_vertex_cache>();
|
||||||
|
@ -2473,18 +2480,12 @@ bool VKGSRender::load_program()
|
||||||
vertex_program.skip_vertex_input_check = true;
|
vertex_program.skip_vertex_input_check = true;
|
||||||
fragment_program.unnormalized_coords = 0;
|
fragment_program.unnormalized_coords = 0;
|
||||||
m_program = m_prog_buffer->get_graphics_pipeline(vertex_program, fragment_program, properties,
|
m_program = m_prog_buffer->get_graphics_pipeline(vertex_program, fragment_program, properties,
|
||||||
!g_cfg.video.disable_asynchronous_shader_compiler, *m_device, pipeline_layout).get();
|
!g_cfg.video.disable_asynchronous_shader_compiler, true, *m_device, pipeline_layout).get();
|
||||||
|
|
||||||
vk::leave_uninterruptible();
|
vk::leave_uninterruptible();
|
||||||
|
|
||||||
if (m_prog_buffer->check_cache_missed())
|
if (m_prog_buffer->check_cache_missed())
|
||||||
{
|
{
|
||||||
if (m_prog_buffer->check_program_linked_flag())
|
|
||||||
{
|
|
||||||
// Program was linked or queued for linking
|
|
||||||
m_shaders_cache->store(properties, vertex_program, fragment_program);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notify the user with HUD notification
|
// Notify the user with HUD notification
|
||||||
if (g_cfg.misc.show_shader_compilation_hint)
|
if (g_cfg.misc.show_shader_compilation_hint)
|
||||||
{
|
{
|
||||||
|
|
|
@ -186,26 +186,22 @@ struct VKTraits
|
||||||
|
|
||||||
struct VKProgramBuffer : public program_state_cache<VKTraits>
|
struct VKProgramBuffer : public program_state_cache<VKTraits>
|
||||||
{
|
{
|
||||||
VKProgramBuffer() = default;
|
VKProgramBuffer(decompiler_callback_t callback)
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
{
|
||||||
program_state_cache<VKTraits>::clear();
|
notify_pipeline_compiled = callback;
|
||||||
m_vertex_shader_cache.clear();
|
|
||||||
m_fragment_shader_cache.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 get_hash(vk::pipeline_props &props)
|
u64 get_hash(const vk::pipeline_props &props)
|
||||||
{
|
{
|
||||||
return rpcs3::hash_struct<vk::pipeline_props>(props);
|
return rpcs3::hash_struct<vk::pipeline_props>(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 get_hash(RSXVertexProgram &prog)
|
u64 get_hash(const RSXVertexProgram &prog)
|
||||||
{
|
{
|
||||||
return program_hash_util::vertex_program_utils::get_vertex_program_ucode_hash(prog);
|
return program_hash_util::vertex_program_utils::get_vertex_program_ucode_hash(prog);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 get_hash(RSXFragmentProgram &prog)
|
u64 get_hash(const RSXFragmentProgram &prog)
|
||||||
{
|
{
|
||||||
return program_hash_util::fragment_program_utils::get_fragment_program_ucode_hash(prog);
|
return program_hash_util::fragment_program_utils::get_fragment_program_ucode_hash(prog);
|
||||||
}
|
}
|
||||||
|
@ -214,7 +210,7 @@ struct VKProgramBuffer : public program_state_cache<VKTraits>
|
||||||
void add_pipeline_entry(RSXVertexProgram &vp, RSXFragmentProgram &fp, vk::pipeline_props &props, Args&& ...args)
|
void add_pipeline_entry(RSXVertexProgram &vp, RSXFragmentProgram &fp, vk::pipeline_props &props, Args&& ...args)
|
||||||
{
|
{
|
||||||
vp.skip_vertex_input_check = true;
|
vp.skip_vertex_input_check = true;
|
||||||
get_graphics_pipeline(vp, fp, props, false, std::forward<Args>(args)...);
|
get_graphics_pipeline(vp, fp, props, false, false, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
void preload_programs(RSXVertexProgram &vp, RSXFragmentProgram &fp)
|
void preload_programs(RSXVertexProgram &vp, RSXFragmentProgram &fp)
|
||||||
|
@ -228,9 +224,4 @@ struct VKProgramBuffer : public program_state_cache<VKTraits>
|
||||||
{
|
{
|
||||||
return m_cache_miss_flag;
|
return m_cache_miss_flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check_program_linked_flag() const
|
|
||||||
{
|
|
||||||
return m_program_compiled_flag;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -616,7 +616,7 @@ namespace rsx
|
||||||
dlg->close();
|
dlg->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void store(pipeline_storage_type &pipeline, RSXVertexProgram &vp, RSXFragmentProgram &fp)
|
void store(const pipeline_storage_type &pipeline, const RSXVertexProgram &vp, const RSXFragmentProgram &fp)
|
||||||
{
|
{
|
||||||
if (g_cfg.video.disable_on_disk_shader_cache)
|
if (g_cfg.video.disable_on_disk_shader_cache)
|
||||||
{
|
{
|
||||||
|
@ -739,7 +739,7 @@ namespace rsx
|
||||||
return std::make_tuple(pipeline, vp, fp);
|
return std::make_tuple(pipeline, vp, fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
pipeline_data pack(pipeline_storage_type &pipeline, RSXVertexProgram &vp, RSXFragmentProgram &fp)
|
pipeline_data pack(const pipeline_storage_type &pipeline, const RSXVertexProgram &vp, const RSXFragmentProgram &fp)
|
||||||
{
|
{
|
||||||
pipeline_data data_block = {};
|
pipeline_data data_block = {};
|
||||||
data_block.pipeline_properties = pipeline;
|
data_block.pipeline_properties = pipeline;
|
||||||
|
|
|
@ -772,7 +772,7 @@ namespace rsx
|
||||||
}
|
}
|
||||||
|
|
||||||
template <int N>
|
template <int N>
|
||||||
void unpack_bitset(std::bitset<N>& block, u64* values)
|
void unpack_bitset(const std::bitset<N>& block, u64* values)
|
||||||
{
|
{
|
||||||
constexpr int count = N / 64;
|
constexpr int count = N / 64;
|
||||||
for (int n = 0; n < count; ++n)
|
for (int n = 0; n < count; ++n)
|
||||||
|
@ -893,7 +893,7 @@ namespace rsx
|
||||||
|
|
||||||
simple_array(const std::initializer_list<Ty>& args)
|
simple_array(const std::initializer_list<Ty>& args)
|
||||||
{
|
{
|
||||||
reserve(args.size());
|
reserve(::size32(args));
|
||||||
|
|
||||||
for (const auto& arg : args)
|
for (const auto& arg : args)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue