Merge branch 'blender-v4.5-release'

This commit is contained in:
Miguel Pozo
2025-06-10 17:25:37 +02:00
5 changed files with 86 additions and 52 deletions

View File

@@ -274,10 +274,12 @@ const ActKeyColumn *ED_keylist_find_closest(const AnimKeylist *keylist, const fl
if (ED_keylist_is_empty(keylist)) {
return nullptr;
}
if (cfra <= keylist->runtime.key_columns.first().cfra) {
/* Need to check against BEZT_BINARYSEARCH_THRESH because `ED_keylist_find_prev` does so as well.
* Not doing that here could cause that function to return a nullptr. */
if (cfra - keylist->runtime.key_columns.first().cfra < BEZT_BINARYSEARCH_THRESH) {
return &keylist->runtime.key_columns.first();
}
if (cfra >= keylist->runtime.key_columns.last().cfra) {
if (cfra - keylist->runtime.key_columns.last().cfra > BEZT_BINARYSEARCH_THRESH) {
keylist->runtime.key_columns.last();
}
const ActKeyColumn *prev = ED_keylist_find_prev(keylist, cfra);

View File

@@ -23,8 +23,8 @@ class GPUWorker {
private:
Vector<std::unique_ptr<std::thread>> threads_;
std::condition_variable condition_var_;
std::mutex mutex_;
std::atomic<bool> terminate_ = false;
std::mutex &mutex_;
bool terminate_ = false;
public:
enum class ContextType {
@@ -37,9 +37,20 @@ class GPUWorker {
/**
* \param threads_count: Number of threads to span.
* \param context_type: The type of context each thread uses.
* \param run_cb: The callback function that will be called by a thread on `wake_up()`.
* \param mutex: Mutex used when trying to acquire the next work
* (and reused internally for termation).
* \param pop_work: The callback function that will be called to acquire the next work,
* should return a void pointer.
* NOTE: The mutex is locked when this function is called.
* \param do_work: The callback function that will be called for each acquired work
* (passed as a void pointer).
* NOTE: The mutex is unlocked when this function is called.
*/
GPUWorker(uint32_t threads_count, ContextType context_type, std::function<void()> run_cb);
GPUWorker(uint32_t threads_count,
ContextType context_type,
std::mutex &mutex,
std::function<void *()> pop_work,
std::function<void(void *)> do_work);
~GPUWorker();
/* Wake up a single thread. */
@@ -49,7 +60,9 @@ class GPUWorker {
}
private:
void run(std::shared_ptr<GPUSecondaryContext> context, std::function<void()> run_cb);
void run(std::shared_ptr<GPUSecondaryContext> context,
std::function<void *()> pop_work,
std::function<void(void *)> do_work);
};
} // namespace blender::gpu

View File

@@ -997,7 +997,11 @@ ShaderCompiler::ShaderCompiler(uint32_t threads_count,
if (!GPU_use_main_context_workaround()) {
compilation_worker_ = std::make_unique<GPUWorker>(
threads_count, context_type, [this]() { this->run_thread(); });
threads_count,
context_type,
mutex_,
[this]() -> void * { return this->pop_work(); },
[this](void *work) { this->do_work(work); });
}
}
@@ -1127,42 +1131,43 @@ bool ShaderCompiler::specialization_batch_is_ready(SpecializationBatchHandle &ha
return handle == 0;
}
void ShaderCompiler::run_thread()
void *ShaderCompiler::pop_work()
{
while (true) {
Batch *batch;
int shader_index;
{
std::lock_guard lock(mutex_);
/* NOTE: Already under mutex lock when GPUWorker calls this function. */
if (compilation_queue_.is_empty()) {
return;
}
ParallelWork work = compilation_queue_.pop();
batch = work.batch;
shader_index = work.shader_index;
}
/* Compile */
if (!batch->is_specialization_batch()) {
batch->shaders[shader_index] = compile_shader(*batch->infos[shader_index]);
}
else {
specialize_shader(batch->specializations[shader_index]);
}
{
std::lock_guard lock(mutex_);
batch->pending_compilations--;
if (batch->is_ready() && batch->is_cancelled) {
batch->free_shaders();
MEM_delete(batch);
}
}
compilation_finished_notification_.notify_all();
if (compilation_queue_.is_empty()) {
return nullptr;
}
ParallelWork work = compilation_queue_.pop();
return MEM_new<ParallelWork>(__func__, work);
}
void ShaderCompiler::do_work(void *work_payload)
{
ParallelWork *work = reinterpret_cast<ParallelWork *>(work_payload);
Batch *batch = work->batch;
int shader_index = work->shader_index;
MEM_delete(work);
/* Compile */
if (!batch->is_specialization_batch()) {
batch->shaders[shader_index] = compile_shader(*batch->infos[shader_index]);
}
else {
specialize_shader(batch->specializations[shader_index]);
}
{
std::lock_guard lock(mutex_);
batch->pending_compilations--;
if (batch->is_ready() && batch->is_cancelled) {
batch->free_shaders();
MEM_delete(batch);
}
}
compilation_finished_notification_.notify_all();
}
void ShaderCompiler::wait_for_all()

View File

@@ -265,7 +265,8 @@ class ShaderCompiler {
bool support_specializations_;
void run_thread();
void *pop_work();
void do_work(void *work_payload);
BatchHandle next_batch_handle_ = 1;

View File

@@ -8,43 +8,56 @@ namespace blender::gpu {
GPUWorker::GPUWorker(uint32_t threads_count,
ContextType context_type,
std::function<void()> run_cb)
std::mutex &mutex,
std::function<void *()> pop_work,
std::function<void(void *)> do_work)
: mutex_(mutex)
{
for (int i : IndexRange(threads_count)) {
UNUSED_VARS(i);
std::shared_ptr<GPUSecondaryContext> thread_context =
context_type == ContextType::PerThread ? std::make_shared<GPUSecondaryContext>() : nullptr;
threads_.append(std::make_unique<std::thread>([=]() { this->run(thread_context, run_cb); }));
threads_.append(
std::make_unique<std::thread>([=]() { this->run(thread_context, pop_work, do_work); }));
}
}
GPUWorker::~GPUWorker()
{
terminate_ = true;
{
std::unique_lock<std::mutex> lock(mutex_);
terminate_ = true;
}
condition_var_.notify_all();
for (std::unique_ptr<std::thread> &thread : threads_) {
thread->join();
}
}
void GPUWorker::run(std::shared_ptr<GPUSecondaryContext> context, std::function<void()> run_cb)
void GPUWorker::run(std::shared_ptr<GPUSecondaryContext> context,
std::function<void *()> pop_work,
std::function<void(void *)> do_work)
{
if (context) {
context->activate();
}
std::unique_lock<std::mutex> lock(mutex_);
/* Loop until we get the terminate signal. */
while (!terminate_) {
{
/* Wait until wake_up() */
std::unique_lock<std::mutex> lock(mutex_);
void *work = pop_work();
if (!work) {
condition_var_.wait(lock);
}
if (terminate_) {
if (terminate_) {
break;
}
continue;
}
run_cb();
lock.unlock();
do_work(work);
lock.lock();
}
}