mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-02-21 18:39:57 +00:00
gl: Thread shader source compilation dispatch
- glCompileShader is in itself much slower than anticipated
This commit is contained in:
parent
3ddfa288cf
commit
7553429130
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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(
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user