#include "stdafx.h" #include "GLPipelineCompiler.h" #include "Utilities/Thread.h" #include namespace gl { // Global list of worker threads std::unique_ptr> g_pipe_compilers; int g_num_pipe_compilers = 0; atomic_t g_compiler_index{}; pipe_compiler::pipe_compiler() { } pipe_compiler::~pipe_compiler() { if (m_context_destroy_func) { m_context_destroy_func(m_context); } } void pipe_compiler::initialize( std::function context_create_func, std::function context_bind_func, std::function context_destroy_func) { m_context_bind_func = context_bind_func; m_context_destroy_func = context_destroy_func; m_context = context_create_func(); } void pipe_compiler::operator()() { while (thread_ctrl::state() != thread_state::aborting) { for (auto&& job : m_work_queue.pop_all()) { if (m_context_ready.compare_and_swap_test(false, true)) { // Bind context on first use m_context_bind_func(m_context); } auto result = int_compile_graphics_pipe( job.vp_handle, job.fp_handle, job.post_create_func, job.post_link_func); job.completion_callback(result); } m_work_queue.wait(); } } std::unique_ptr 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) { if (flags == COMPILE_INLINE) { return int_compile_graphics_pipe(vp_handle, fp_handle, post_create_func, post_link_func); } m_work_queue.push(vp_handle, fp_handle, post_create_func, post_link_func, completion_callback_func); return {}; } std::unique_ptr pipe_compiler::int_compile_graphics_pipe( GLuint vp_handle, GLuint fp_handle, callback_t post_create_func, callback_t post_link_func) { auto result = std::make_unique(); result->create(); if (post_create_func) { post_create_func(result); } result->link(); if (post_link_func) { post_link_func(result); } return result; } void initialize_pipe_compiler( std::function context_create_func, std::function context_bind_func, std::function context_destroy_func, int num_worker_threads) { if (num_worker_threads == -1) { // Select optimal number of compiler threads const auto hw_threads = std::thread::hardware_concurrency(); if (hw_threads >= 12) { num_worker_threads = 4; } else if (hw_threads >= 8) { num_worker_threads = 2; } else { num_worker_threads = 1; } } verify(HERE), num_worker_threads >= 1; // Create the thread pool g_pipe_compilers = std::make_unique>("RSX.W", num_worker_threads); g_num_pipe_compilers = num_worker_threads; // Initialize the workers. At least one inline compiler shall exist (doesn't actually run) for (pipe_compiler& compiler : *g_pipe_compilers.get()) { compiler.initialize(context_create_func, context_bind_func, context_destroy_func); } } void destroy_pipe_compiler() { g_pipe_compilers.reset(); } pipe_compiler* get_pipe_compiler() { verify(HERE), g_pipe_compilers; int thread_index = g_compiler_index++; return g_pipe_compilers.get()->begin() + (thread_index % g_num_pipe_compilers); } }