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);
}
void GLFragmentProgram::Compile()
{
shader.compile();
id = shader.id();
}

View File

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

View File

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

View File

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

View File

@ -13,6 +13,7 @@
#include "../Common/GLSLTypes.h"
#include "Emu/system_config.h"
#include "Utilities/mutex.h"
#include "Utilities/geometry.h"
#include "util/logs.hpp"
@ -2226,6 +2227,40 @@ public:
GLuint m_id = GL_NONE;
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:
shader() = default;
@ -2268,33 +2303,21 @@ public:
}
m_id = glCreateShader(shader_type);
precompile();
}
shader& compile()
{
const char* str = source.c_str();
const GLint length = ::narrow<GLint>(source.length());
if (g_cfg.video.log_programs)
std::lock_guard lock(m_compile_lock);
if (m_is_compiled)
{
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);
// Another thread compiled this already
return *this;
}
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);
GLint status = GL_FALSE;
@ -2318,6 +2341,8 @@ public:
m_compiled_fence.create();
flush_command_queue(m_compiled_fence);
m_is_compiled = true;
return *this;
}
@ -2355,6 +2380,11 @@ public:
return m_id != GL_NONE;
}
bool compiled() const
{
return m_is_compiled;
}
explicit operator bool() const
{
return created();

View File

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

View File

@ -15,7 +15,8 @@ namespace gl
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();
@ -26,11 +27,10 @@ namespace gl
std::function<void(draw_context_t)> context_destroy_func);
std::unique_ptr<glsl::program> compile(
GLuint vp_handle, GLuint fp_handle,
op_flags flags,
callback_t post_create_func = {},
callback_t post_link_func = {},
callback_t completion_callback = {});
build_callback_t post_create_func = {},
build_callback_t post_link_func = {},
storage_callback_t completion_callback = {});
void operator()();
@ -38,14 +38,12 @@ namespace gl
struct pipe_compiler_job
{
GLuint vp_handle;
GLuint fp_handle;
callback_t post_create_func;
callback_t post_link_func;
callback_t completion_callback;
build_callback_t post_create_func;
build_callback_t post_link_func;
storage_callback_t completion_callback;
pipe_compiler_job(GLuint vp, GLuint fp, callback_t post_create, callback_t post_link, callback_t completion)
: vp_handle(vp), fp_handle(fp), post_create_func(post_create), post_link_func(post_link), completion_callback(completion)
pipe_compiler_job(build_callback_t post_create, build_callback_t post_link, storage_callback_t 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::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(

View File

@ -18,14 +18,12 @@ struct GLTraits
void recompile_fragment_program(const RSXFragmentProgram &RSXFP, fragment_program_type& fragmentProgramData, size_t /*ID*/)
{
fragmentProgramData.Decompile(RSXFP);
fragmentProgramData.Compile();
}
static
void recompile_vertex_program(const RSXVertexProgram &RSXVP, vertex_program_type& vertexProgramData, size_t /*ID*/)
{
vertexProgramData.Decompile(RSXVP);
vertexProgramData.Compile();
}
static
@ -44,25 +42,21 @@ struct GLTraits
auto compiler = gl::get_pipe_compiler();
auto flags = (compile_async) ? gl::pipe_compiler::COMPILE_DEFERRED : gl::pipe_compiler::COMPILE_INLINE;
gl::fence vp_fence, fp_fence;
if (compile_async)
auto post_create_func = [vp = &vertexProgramData.shader, fp = &fragmentProgramData.shader]
(gl::glsl::program* program)
{
vp_fence = vertexProgramData.shader.get_compile_fence_sync();
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())
if (!vp->compiled())
{
// Force server threads to wait for the compilation to finish
vp_fence.server_wait_sync();
fp_fence.server_wait_sync();
const_cast<gl::glsl::shader*>(vp)->compile();
}
program->attach(gl::glsl::shader_view(vp_id))
.attach(gl::glsl::shader_view(fp_id))
if (!fp->compiled())
{
const_cast<gl::glsl::shader*>(fp)->compile();
}
program->attach(*vp)
.attach(*fp)
.bind_fragment_data_location("ocol0", 0)
.bind_fragment_data_location("ocol1", 1)
.bind_fragment_data_location("ocol2", 2)
@ -71,12 +65,12 @@ struct GLTraits
if (g_cfg.video.log_programs)
{
rsx_log.notice("*** prog id = %d", program->id());
rsx_log.notice("*** vp id = %d", vp_id);
rsx_log.notice("*** fp id = %d", fp_id);
rsx_log.notice("*** vp id = %d", vp->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
// 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;
};
auto pipeline = compiler->compile(vertexProgramData.id, fragmentProgramData.id,
flags, post_create_func, post_link_func, callback);
auto pipeline = compiler->compile(flags, post_create_func, post_link_func, callback);
return callback(pipeline);
}
};

View File

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

View File

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