gl: Thread shader source compilation dispatch

- glCompileShader is in itself much slower than anticipated
This commit is contained in:
kd-11 2020-11-09 21:43:07 +03:00 committed by kd-11
parent 3ddfa288cf
commit 7553429130
10 changed files with 89 additions and 100 deletions

View File

@ -375,11 +375,6 @@ void GLFragmentProgram::Decompile(const RSXFragmentProgram& prog)
} }
shader.create(::glsl::program_domain::glsl_fragment_program, source); shader.create(::glsl::program_domain::glsl_fragment_program, source);
}
void GLFragmentProgram::Compile()
{
shader.compile();
id = shader.id(); id = shader.id();
} }

View File

@ -68,9 +68,6 @@ public:
*/ */
void Decompile(const RSXFragmentProgram& prog); void Decompile(const RSXFragmentProgram& prog);
/** Compile the decompiled fragment shader into a format we can use with OpenGL. */
void Compile();
private: private:
/** Deletes the shader and any stored information */ /** Deletes the shader and any stored information */
void Delete(); void Delete();

View File

@ -358,6 +358,9 @@ void GLGSRender::on_init_thread()
void GLGSRender::on_exit() void GLGSRender::on_exit()
{ {
// Destroy internal RSX state, may call upon this->do_local_task
GSRender::on_exit();
// Globals // Globals
// TODO: Move these // TODO: Move these
gl::destroy_compute_tasks(); gl::destroy_compute_tasks();
@ -491,10 +494,6 @@ void GLGSRender::on_exit()
query.driver_handle = 0; query.driver_handle = 0;
} }
glFlush();
glFinish();
GSRender::on_exit();
zcull_ctrl.release(); zcull_ctrl.release();
gl::set_primary_context_thread(false); gl::set_primary_context_thread(false);

View File

@ -25,14 +25,7 @@ namespace gl
void flush_command_queue(fence& fence_obj) void flush_command_queue(fence& fence_obj)
{ {
if (is_primary_context_thread()) fence_obj.check_signaled();
{
fence_obj.check_signaled();
}
else
{
glFlush();
}
} }
GLenum draw_mode(rsx::primitive_type in) GLenum draw_mode(rsx::primitive_type in)

View File

@ -13,6 +13,7 @@
#include "../Common/GLSLTypes.h" #include "../Common/GLSLTypes.h"
#include "Emu/system_config.h" #include "Emu/system_config.h"
#include "Utilities/mutex.h"
#include "Utilities/geometry.h" #include "Utilities/geometry.h"
#include "util/logs.hpp" #include "util/logs.hpp"
@ -2226,6 +2227,40 @@ public:
GLuint m_id = GL_NONE; GLuint m_id = GL_NONE;
fence m_compiled_fence; fence m_compiled_fence;
fence m_init_fence;
shared_mutex m_compile_lock;
atomic_t<bool> m_is_compiled{};
void precompile()
{
const char* str = source.c_str();
const GLint length = ::narrow<GLint>(source.length());
if (g_cfg.video.log_programs)
{
std::string base_name;
switch (type)
{
case ::glsl::program_domain::glsl_vertex_program:
base_name = "shaderlog/VertexProgram";
break;
case ::glsl::program_domain::glsl_fragment_program:
base_name = "shaderlog/FragmentProgram";
break;
case ::glsl::program_domain::glsl_compute_program:
base_name = "shaderlog/ComputeProgram";
break;
}
fs::file(fs::get_cache_dir() + base_name + std::to_string(m_id) + ".glsl", fs::rewrite).write(str);
}
glShaderSource(m_id, 1, &str, &length);
m_init_fence.create();
flush_command_queue(m_init_fence);
}
public: public:
shader() = default; shader() = default;
@ -2268,33 +2303,21 @@ public:
} }
m_id = glCreateShader(shader_type); m_id = glCreateShader(shader_type);
precompile();
} }
shader& compile() shader& compile()
{ {
const char* str = source.c_str(); std::lock_guard lock(m_compile_lock);
const GLint length = ::narrow<GLint>(source.length()); if (m_is_compiled)
if (g_cfg.video.log_programs)
{ {
std::string base_name; // Another thread compiled this already
switch (type) return *this;
{
case ::glsl::program_domain::glsl_vertex_program:
base_name = "shaderlog/VertexProgram";
break;
case ::glsl::program_domain::glsl_fragment_program:
base_name = "shaderlog/FragmentProgram";
break;
case ::glsl::program_domain::glsl_compute_program:
base_name = "shaderlog/ComputeProgram";
break;
}
fs::file(fs::get_cache_dir() + base_name + std::to_string(m_id) + ".glsl", fs::rewrite).write(str);
} }
glShaderSource(m_id, 1, &str, &length); verify(HERE), !m_init_fence.is_empty(); // Do not attempt to compile a shader_view!!
m_init_fence.server_wait_sync();
glCompileShader(m_id); glCompileShader(m_id);
GLint status = GL_FALSE; GLint status = GL_FALSE;
@ -2318,6 +2341,8 @@ public:
m_compiled_fence.create(); m_compiled_fence.create();
flush_command_queue(m_compiled_fence); flush_command_queue(m_compiled_fence);
m_is_compiled = true;
return *this; return *this;
} }
@ -2355,6 +2380,11 @@ public:
return m_id != GL_NONE; return m_id != GL_NONE;
} }
bool compiled() const
{
return m_is_compiled;
}
explicit operator bool() const explicit operator bool() const
{ {
return created(); return created();

View File

@ -47,7 +47,6 @@ namespace gl
} }
auto result = int_compile_graphics_pipe( auto result = int_compile_graphics_pipe(
job.vp_handle, job.fp_handle,
job.post_create_func, job.post_create_func,
job.post_link_func); job.post_link_func);
@ -59,41 +58,33 @@ namespace gl
} }
std::unique_ptr<glsl::program> pipe_compiler::compile( std::unique_ptr<glsl::program> pipe_compiler::compile(
GLuint vp_handle, GLuint fp_handle,
op_flags flags, op_flags flags,
callback_t post_create_func, build_callback_t post_create_func,
callback_t post_link_func, build_callback_t post_link_func,
callback_t completion_callback_func) storage_callback_t completion_callback_func)
{ {
if (flags == COMPILE_INLINE) if (flags == COMPILE_INLINE)
{ {
return int_compile_graphics_pipe(vp_handle, fp_handle, post_create_func, post_link_func); return int_compile_graphics_pipe(post_create_func, post_link_func);
} }
m_work_queue.push(vp_handle, fp_handle, post_create_func, post_link_func, completion_callback_func); m_work_queue.push(post_create_func, post_link_func, completion_callback_func);
return {}; return {};
} }
std::unique_ptr<glsl::program> pipe_compiler::int_compile_graphics_pipe( std::unique_ptr<glsl::program> pipe_compiler::int_compile_graphics_pipe(
GLuint vp_handle, GLuint fp_handle, build_callback_t post_create_func,
callback_t post_create_func, build_callback_t post_link_func)
callback_t post_link_func)
{ {
auto result = std::make_unique<glsl::program>(); auto result = std::make_unique<glsl::program>();
result->create(); result->create();
if (post_create_func) if (post_create_func)
{ {
post_create_func(result); post_create_func(result.get());
}
result->link();
if (post_link_func)
{
post_link_func(result);
} }
result->link(post_link_func);
return result; return result;
} }

View File

@ -15,7 +15,8 @@ namespace gl
COMPILE_DEFERRED = 2 COMPILE_DEFERRED = 2
}; };
using callback_t = std::function<void(std::unique_ptr<glsl::program>&)>; using storage_callback_t = std::function<void(std::unique_ptr<glsl::program>&)>;
using build_callback_t = std::function<void(glsl::program*)>;
pipe_compiler(); pipe_compiler();
~pipe_compiler(); ~pipe_compiler();
@ -26,11 +27,10 @@ namespace gl
std::function<void(draw_context_t)> context_destroy_func); std::function<void(draw_context_t)> context_destroy_func);
std::unique_ptr<glsl::program> compile( std::unique_ptr<glsl::program> compile(
GLuint vp_handle, GLuint fp_handle,
op_flags flags, op_flags flags,
callback_t post_create_func = {}, build_callback_t post_create_func = {},
callback_t post_link_func = {}, build_callback_t post_link_func = {},
callback_t completion_callback = {}); storage_callback_t completion_callback = {});
void operator()(); void operator()();
@ -38,14 +38,12 @@ namespace gl
struct pipe_compiler_job struct pipe_compiler_job
{ {
GLuint vp_handle; build_callback_t post_create_func;
GLuint fp_handle; build_callback_t post_link_func;
callback_t post_create_func; storage_callback_t completion_callback;
callback_t post_link_func;
callback_t completion_callback;
pipe_compiler_job(GLuint vp, GLuint fp, callback_t post_create, callback_t post_link, callback_t completion) pipe_compiler_job(build_callback_t post_create, build_callback_t post_link, storage_callback_t completion)
: vp_handle(vp), fp_handle(fp), post_create_func(post_create), post_link_func(post_link), completion_callback(completion) : post_create_func(post_create), post_link_func(post_link), completion_callback(completion)
{} {}
}; };
@ -58,7 +56,7 @@ namespace gl
std::function<void(draw_context_t context)> m_context_destroy_func; std::function<void(draw_context_t context)> m_context_destroy_func;
std::unique_ptr<glsl::program> int_compile_graphics_pipe( std::unique_ptr<glsl::program> int_compile_graphics_pipe(
GLuint vp_handle, GLuint fp_handle, callback_t post_create_func, callback_t post_link_func); build_callback_t post_create_func, build_callback_t post_link_func);
}; };
void initialize_pipe_compiler( void initialize_pipe_compiler(

View File

@ -18,14 +18,12 @@ struct GLTraits
void recompile_fragment_program(const RSXFragmentProgram &RSXFP, fragment_program_type& fragmentProgramData, size_t /*ID*/) void recompile_fragment_program(const RSXFragmentProgram &RSXFP, fragment_program_type& fragmentProgramData, size_t /*ID*/)
{ {
fragmentProgramData.Decompile(RSXFP); fragmentProgramData.Decompile(RSXFP);
fragmentProgramData.Compile();
} }
static static
void recompile_vertex_program(const RSXVertexProgram &RSXVP, vertex_program_type& vertexProgramData, size_t /*ID*/) void recompile_vertex_program(const RSXVertexProgram &RSXVP, vertex_program_type& vertexProgramData, size_t /*ID*/)
{ {
vertexProgramData.Decompile(RSXVP); vertexProgramData.Decompile(RSXVP);
vertexProgramData.Compile();
} }
static static
@ -44,25 +42,21 @@ struct GLTraits
auto compiler = gl::get_pipe_compiler(); auto compiler = gl::get_pipe_compiler();
auto flags = (compile_async) ? gl::pipe_compiler::COMPILE_DEFERRED : gl::pipe_compiler::COMPILE_INLINE; auto flags = (compile_async) ? gl::pipe_compiler::COMPILE_DEFERRED : gl::pipe_compiler::COMPILE_INLINE;
gl::fence vp_fence, fp_fence; auto post_create_func = [vp = &vertexProgramData.shader, fp = &fragmentProgramData.shader]
if (compile_async) (gl::glsl::program* program)
{ {
vp_fence = vertexProgramData.shader.get_compile_fence_sync(); if (!vp->compiled())
fp_fence = fragmentProgramData.shader.get_compile_fence_sync();
}
auto post_create_func = [vp_id = vertexProgramData.id, fp_id = fragmentProgramData.id, vp_fence, fp_fence]
(std::unique_ptr<gl::glsl::program>& program)
{
if (!vp_fence.is_empty())
{ {
// Force server threads to wait for the compilation to finish const_cast<gl::glsl::shader*>(vp)->compile();
vp_fence.server_wait_sync();
fp_fence.server_wait_sync();
} }
program->attach(gl::glsl::shader_view(vp_id)) if (!fp->compiled())
.attach(gl::glsl::shader_view(fp_id)) {
const_cast<gl::glsl::shader*>(fp)->compile();
}
program->attach(*vp)
.attach(*fp)
.bind_fragment_data_location("ocol0", 0) .bind_fragment_data_location("ocol0", 0)
.bind_fragment_data_location("ocol1", 1) .bind_fragment_data_location("ocol1", 1)
.bind_fragment_data_location("ocol2", 2) .bind_fragment_data_location("ocol2", 2)
@ -71,12 +65,12 @@ struct GLTraits
if (g_cfg.video.log_programs) if (g_cfg.video.log_programs)
{ {
rsx_log.notice("*** prog id = %d", program->id()); rsx_log.notice("*** prog id = %d", program->id());
rsx_log.notice("*** vp id = %d", vp_id); rsx_log.notice("*** vp id = %d", vp->id());
rsx_log.notice("*** fp id = %d", fp_id); rsx_log.notice("*** fp id = %d", fp->id());
} }
}; };
auto post_link_func = [](std::unique_ptr<gl::glsl::program>& program) auto post_link_func = [](gl::glsl::program* program)
{ {
// Program locations are guaranteed to not change after linking // Program locations are guaranteed to not change after linking
// Texture locations are simply bound to the TIUs so this can be done once // Texture locations are simply bound to the TIUs so this can be done once
@ -110,9 +104,7 @@ struct GLTraits
program->uniforms[1] = GL_STREAM_BUFFER_START + 1; program->uniforms[1] = GL_STREAM_BUFFER_START + 1;
}; };
auto pipeline = compiler->compile(vertexProgramData.id, fragmentProgramData.id, auto pipeline = compiler->compile(flags, post_create_func, post_link_func, callback);
flags, post_create_func, post_link_func, callback);
return callback(pipeline); return callback(pipeline);
} }
}; };

View File

@ -273,11 +273,6 @@ void GLVertexProgram::Decompile(const RSXVertexProgram& prog)
decompiler.Task(); decompiler.Task();
shader.create(::glsl::program_domain::glsl_vertex_program, source); shader.create(::glsl::program_domain::glsl_vertex_program, source);
}
void GLVertexProgram::Compile()
{
shader.compile();
id = shader.id(); id = shader.id();
} }

View File

@ -59,7 +59,6 @@ public:
gl::glsl::shader shader; gl::glsl::shader shader;
void Decompile(const RSXVertexProgram& prog); void Decompile(const RSXVertexProgram& prog);
void Compile();
private: private:
void Delete(); void Delete();