GPU: Add GPU_shader_batch_cancel

Fix the recently implemented ShaderCompiler::batch_cancel.
Expose it with GPU_shader_batch_cancel and
GPU_shader_specialization_batch_cancel.
Use them in the EEVEE ShaderModule destructor, to prevent blocking on
destruction when there are in-flight compilations.

Pull Request: https://projects.blender.org/blender/blender/pulls/138774
This commit is contained in:
Miguel Pozo
2025-05-12 19:54:03 +02:00
parent ee5185b287
commit c16aba915f
6 changed files with 51 additions and 12 deletions

View File

@@ -72,19 +72,19 @@ ShaderModule::ShaderModule()
ShaderModule::~ShaderModule()
{
/* Finish compilation to avoid asserts on exit at GLShaderCompiler destructor. */
if (compilation_handle_) {
static_shaders_are_ready(true);
}
/* Cancel compilation to avoid asserts on exit at ShaderCompiler destructor. */
/* Specializations first, to avoid releasing the base shader while the specialization compilation
* is still in flight. */
for (SpecializationBatchHandle &handle : specialization_handles_.values()) {
if (handle) {
while (!GPU_shader_batch_specializations_is_ready(handle)) {
/* Block until ready. */
}
GPU_shader_batch_specializations_cancel(handle);
}
}
if (compilation_handle_) {
GPU_shader_batch_cancel(compilation_handle_);
}
}
/** \} */

View File

@@ -100,6 +100,11 @@ bool GPU_shader_batch_is_ready(BatchHandle handle);
* WARNING: The handle will be invalidated by this call, you can't request the same batch twice.
*/
blender::Vector<GPUShader *> GPU_shader_batch_finalize(BatchHandle &handle);
/**
* Cancel the compilation of the batch.
* WARNING: The handle will be invalidated by this call.
*/
void GPU_shader_batch_cancel(BatchHandle &handle);
/** \} */
@@ -267,6 +272,12 @@ SpecializationBatchHandle GPU_shader_batch_specializations(
*/
bool GPU_shader_batch_specializations_is_ready(SpecializationBatchHandle &handle);
/**
* Cancel the specialization batch.
* WARNING: The handle will be invalidated by this call.
*/
void GPU_shader_batch_specializations_cancel(SpecializationBatchHandle &handle);
/** \} */
/* -------------------------------------------------------------------- */

View File

@@ -45,11 +45,11 @@ void GPU_exit()
gpu_codegen_exit();
gpu_backend_delete_resources();
gpu_shader_dependency_exit();
gpu_shader_create_info_exit();
gpu_backend_delete_resources();
initialized = false;
}

View File

@@ -380,6 +380,11 @@ Vector<GPUShader *> GPU_shader_batch_finalize(BatchHandle &handle)
return reinterpret_cast<Vector<GPUShader *> &>(result);
}
void GPU_shader_batch_cancel(BatchHandle &handle)
{
GPUBackend::get()->get_compiler()->batch_cancel(handle);
}
void GPU_shader_compile_static()
{
printf("Compiling all static GPU shaders. This process takes a while.\n");
@@ -552,6 +557,11 @@ bool GPU_shader_batch_specializations_is_ready(SpecializationBatchHandle &handle
return GPUBackend::get()->get_compiler()->specialization_batch_is_ready(handle);
}
void GPU_shader_batch_specializations_cancel(SpecializationBatchHandle &handle)
{
GPUBackend::get()->get_compiler()->batch_cancel(handle);
}
/** \} */
/* -------------------------------------------------------------------- */
@@ -1002,7 +1012,7 @@ BatchHandle ShaderCompiler::batch_compile(Span<const shader::ShaderCreateInfo *>
void ShaderCompiler::batch_cancel(BatchHandle &handle)
{
std::lock_guard lock(mutex_);
std::unique_lock lock(mutex_);
Batch *batch = batches_.pop(handle);
@@ -1015,7 +1025,14 @@ void ShaderCompiler::batch_cancel(BatchHandle &handle)
compilation_queue_.erase(std::remove_if(compilation_queue_.begin(),
compilation_queue_.end(),
[](const ParallelWork &work) { return !work.batch; }));
[](const ParallelWork &work) { return !work.batch; }),
compilation_queue_.end());
if (batch->is_specialization_batch()) {
/* For specialization batches, we block until ready, since base shader compilation may be
* cancelled afterwards, leaving the specialization with a deleted base shader. */
compilation_finished_notification_.wait(lock, [&]() { return batch->is_ready(); });
}
if (batch->is_ready()) {
batch->free_shaders();

View File

@@ -211,6 +211,14 @@ class ShaderCompiler {
BatchHandle next_batch_handle_ = 1;
protected:
/* Must be called earlier from the destructor of the subclass if the compilation process relies
* on subclass resources. */
void destruct_compilation_worker()
{
compilation_worker_.reset();
}
public:
ShaderCompiler(uint32_t threads_count = 1,
GPUWorker::ContextType context_type = GPUWorker::ContextType::PerThread,

View File

@@ -1740,6 +1740,9 @@ void GLCompilerWorker::release()
GLShaderCompiler::~GLShaderCompiler()
{
/* Must be called before we destruct the GLCompilerWorkers. */
destruct_compilation_worker();
for (GLCompilerWorker *worker : workers_) {
delete worker;
}