diff options
author | Campbell Barton <ideasman42@gmail.com> | 2017-03-09 08:33:20 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2017-03-09 08:41:33 +0300 |
commit | a68c631cf86ebc878ac5b96ef5fb69db15be9161 (patch) | |
tree | 80508a8291502a07ad999a9f385bdc854be0f22d /source | |
parent | 8d98362710798fe9e40e6a24c32306e4d4edfef0 (diff) | |
parent | 817e975dee27640947bf7d083db39d1d70120385 (diff) |
Merge branch 'master' into blender2.8
Diffstat (limited to 'source')
24 files changed, 333 insertions, 244 deletions
diff --git a/source/blender/blenlib/BLI_rect.h b/source/blender/blenlib/BLI_rect.h index 484a679f76a..041679ef876 100644 --- a/source/blender/blenlib/BLI_rect.h +++ b/source/blender/blenlib/BLI_rect.h @@ -47,8 +47,8 @@ bool BLI_rcti_is_empty(const struct rcti *rect); bool BLI_rctf_is_empty(const struct rctf *rect); void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax); void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax); -void BLI_rctf_init_pt_size(struct rctf *rect, const float xy[2], float size); -void BLI_rcti_init_pt_size(struct rcti *rect, const int xy[2], int size); +void BLI_rctf_init_pt_radius(struct rctf *rect, const float xy[2], float size); +void BLI_rcti_init_pt_radius(struct rcti *rect, const int xy[2], int size); void BLI_rcti_init_minmax(struct rcti *rect); void BLI_rctf_init_minmax(struct rctf *rect); void BLI_rcti_do_minmax_v(struct rcti *rect, const int xy[2]); diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h index d27bf4dad20..c3c587275e1 100644 --- a/source/blender/blenlib/BLI_task.h +++ b/source/blender/blenlib/BLI_task.h @@ -81,6 +81,7 @@ typedef void (*TaskFreeFunction)(TaskPool *__restrict pool, void *taskdata, int TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata); TaskPool *BLI_task_pool_create_background(TaskScheduler *scheduler, void *userdata); +TaskPool *BLI_task_pool_create_suspended(TaskScheduler *scheduler, void *userdata); void BLI_task_pool_free(TaskPool *pool); void BLI_task_pool_push_ex( @@ -96,9 +97,6 @@ void BLI_task_pool_work_and_wait(TaskPool *pool); /* cancel all tasks, keep worker threads running */ void BLI_task_pool_cancel(TaskPool *pool); -/* set number of threads allowed to be used by this pool */ -void BLI_pool_set_num_threads(TaskPool *pool, int num_threads); - /* for worker threads, test if canceled */ bool BLI_task_pool_canceled(TaskPool *pool); diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c index e01a4714131..fd24a00156d 100644 --- a/source/blender/blenlib/intern/rct.c +++ b/source/blender/blenlib/intern/rct.c @@ -351,7 +351,7 @@ void BLI_rcti_init(rcti *rect, int xmin, int xmax, int ymin, int ymax) } } -void BLI_rctf_init_pt_size(rctf *rect, const float xy[2], float size) +void BLI_rctf_init_pt_radius(rctf *rect, const float xy[2], float size) { rect->xmin = xy[0] - size; rect->xmax = xy[0] + size; @@ -359,7 +359,7 @@ void BLI_rctf_init_pt_size(rctf *rect, const float xy[2], float size) rect->ymax = xy[1] + size; } -void BLI_rcti_init_pt_size(rcti *rect, const int xy[2], int size) +void BLI_rcti_init_pt_radius(rcti *rect, const int xy[2], int size) { rect->xmin = xy[0] - size; rect->xmax = xy[0] + size; diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c index 5d16fd9229c..49d2ee83a66 100644 --- a/source/blender/blenlib/intern/task.c +++ b/source/blender/blenlib/intern/task.c @@ -48,6 +48,32 @@ */ #define MEMPOOL_SIZE 256 +/* Number of tasks which are pushed directly to local thread queue. + * + * This allows thread to fetch next task without locking the whole queue. + */ +#define LOCALQUEUE_SIZE 1 + +#ifndef NDEBUG +# define ASSERT_THREAD_ID(scheduler, thread_id) \ + do { \ + if (!BLI_thread_is_main()) { \ + TaskThread *thread = pthread_getspecific(scheduler->tls_id_key); \ + if (thread == NULL) { \ + BLI_assert(thread_id == 0); \ + } \ + else { \ + BLI_assert(thread_id == thread->id); \ + } \ + } \ + else { \ + BLI_assert(thread_id == 0); \ + } \ + } while (false) +#else +# define ASSERT_THREAD_ID(scheduler, thread_id) +#endif + typedef struct Task { struct Task *next, *prev; @@ -102,12 +128,16 @@ typedef struct TaskMemPoolStats { } TaskMemPoolStats; #endif +typedef struct TaskThreadLocalStorage { + TaskMemPool task_mempool; + int num_local_queue; + Task *local_queue[LOCALQUEUE_SIZE]; +} TaskThreadLocalStorage; + struct TaskPool { TaskScheduler *scheduler; volatile size_t num; - size_t num_threads; - size_t currently_running_tasks; ThreadMutex num_mutex; ThreadCondition num_cond; @@ -115,6 +145,11 @@ struct TaskPool { ThreadMutex user_mutex; volatile bool do_cancel; + volatile bool do_work; + + volatile bool is_suspended; + ListBase suspended_queue; + size_t num_suspended; /* If set, this pool may never be work_and_wait'ed, which means TaskScheduler * has to use its special background fallback thread in case we are in @@ -122,16 +157,10 @@ struct TaskPool { */ bool run_in_background; - /* This pool is used for caching task pointers for thread id 0. - * This could either point to a global scheduler's task_mempool[0] if the - * pool is handled form the main thread or point to task_mempool_local - * otherwise. - * - * This way we solve possible threading conflicts accessing same global - * memory pool from multiple threads from which wait_work() is called. + /* This is a task scheduler's ID of a thread at which pool was constructed. + * It will be used to access task TLS. */ - TaskMemPool *task_mempool; - TaskMemPool task_mempool_local; + int thread_id; #ifdef DEBUG_STATS TaskMemPoolStats *mempool_stats; @@ -141,7 +170,6 @@ struct TaskPool { struct TaskScheduler { pthread_t *threads; struct TaskThread *task_threads; - TaskMemPool *task_mempool; int num_threads; bool background_thread_only; @@ -150,15 +178,19 @@ struct TaskScheduler { ThreadCondition queue_cond; volatile bool do_exit; + + /* NOTE: In pthread's TLS we store the whole TaskThread structure. */ + pthread_key_t tls_id_key; }; typedef struct TaskThread { TaskScheduler *scheduler; int id; + TaskThreadLocalStorage tls; } TaskThread; /* Helper */ -static void task_data_free(Task *task, const int thread_id) +BLI_INLINE void task_data_free(Task *task, const int thread_id) { if (task->free_taskdata) { if (task->freedata) { @@ -170,12 +202,24 @@ static void task_data_free(Task *task, const int thread_id) } } -BLI_INLINE TaskMemPool *get_task_mempool(TaskPool *pool, const int thread_id) +BLI_INLINE TaskThreadLocalStorage *get_task_tls(TaskPool *pool, + const int thread_id) { + TaskScheduler *scheduler = pool->scheduler; + BLI_assert(thread_id >= 0); + BLI_assert(thread_id <= scheduler->num_threads); if (thread_id == 0) { - return pool->task_mempool; + return &scheduler->task_threads[pool->thread_id].tls; + } + return &scheduler->task_threads[thread_id].tls; +} + +BLI_INLINE void free_task_tls(TaskThreadLocalStorage *tls) +{ + TaskMemPool *task_mempool = &tls->task_mempool; + for (int i = 0; i < task_mempool->num_tasks; ++i) { + MEM_freeN(task_mempool->tasks[i]); } - return &pool->scheduler->task_mempool[thread_id]; } static Task *task_alloc(TaskPool *pool, const int thread_id) @@ -183,15 +227,17 @@ static Task *task_alloc(TaskPool *pool, const int thread_id) BLI_assert(thread_id <= pool->scheduler->num_threads); if (thread_id != -1) { BLI_assert(thread_id >= 0); - TaskMemPool *mem_pool = get_task_mempool(pool, thread_id); + BLI_assert(thread_id <= pool->scheduler->num_threads); + TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id); + TaskMemPool *task_mempool = &tls->task_mempool; /* Try to re-use task memory from a thread local storage. */ - if (mem_pool->num_tasks > 0) { - --mem_pool->num_tasks; + if (task_mempool->num_tasks > 0) { + --task_mempool->num_tasks; /* Success! We've just avoided task allocation. */ #ifdef DEBUG_STATS pool->mempool_stats[thread_id].num_reuse++; #endif - return mem_pool->tasks[mem_pool->num_tasks]; + return task_mempool->tasks[task_mempool->num_tasks]; } /* We are doomed to allocate new task data. */ #ifdef DEBUG_STATS @@ -206,11 +252,12 @@ static void task_free(TaskPool *pool, Task *task, const int thread_id) task_data_free(task, thread_id); BLI_assert(thread_id >= 0); BLI_assert(thread_id <= pool->scheduler->num_threads); - TaskMemPool *mem_pool = get_task_mempool(pool, thread_id); - if (mem_pool->num_tasks < MEMPOOL_SIZE - 1) { + TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id); + TaskMemPool *task_mempool = &tls->task_mempool; + if (task_mempool->num_tasks < MEMPOOL_SIZE - 1) { /* Successfully allowed the task to be re-used later. */ - mem_pool->tasks[mem_pool->num_tasks] = task; - ++mem_pool->num_tasks; + task_mempool->tasks[task_mempool->num_tasks] = task; + ++task_mempool->num_tasks; } else { /* Local storage saturated, no other way than just discard @@ -236,7 +283,6 @@ static void task_pool_num_decrease(TaskPool *pool, size_t done) BLI_assert(pool->num >= done); pool->num -= done; - atomic_sub_and_fetch_z(&pool->currently_running_tasks, done); if (pool->num == 0) BLI_condition_notify_all(&pool->num_cond); @@ -244,11 +290,11 @@ static void task_pool_num_decrease(TaskPool *pool, size_t done) BLI_mutex_unlock(&pool->num_mutex); } -static void task_pool_num_increase(TaskPool *pool) +static void task_pool_num_increase(TaskPool *pool, size_t new) { BLI_mutex_lock(&pool->num_mutex); - pool->num++; + pool->num += new; BLI_condition_notify_all(&pool->num_cond); BLI_mutex_unlock(&pool->num_mutex); @@ -290,17 +336,10 @@ static bool task_scheduler_thread_wait_pop(TaskScheduler *scheduler, Task **task continue; } - if (atomic_add_and_fetch_z(&pool->currently_running_tasks, 1) <= pool->num_threads || - pool->num_threads == 0) - { - *task = current_task; - found_task = true; - BLI_remlink(&scheduler->queue, *task); - break; - } - else { - atomic_sub_and_fetch_z(&pool->currently_running_tasks, 1); - } + *task = current_task; + found_task = true; + BLI_remlink(&scheduler->queue, *task); + break; } if (!found_task) BLI_condition_wait(&scheduler->queue_cond, &scheduler->queue_mutex); @@ -311,13 +350,34 @@ static bool task_scheduler_thread_wait_pop(TaskScheduler *scheduler, Task **task return true; } +BLI_INLINE void handle_local_queue(TaskThreadLocalStorage *tls, + const int thread_id) +{ + while (tls->num_local_queue > 0) { + /* We pop task from queue before handling it so handler of the task can + * push next job to the local queue. + */ + tls->num_local_queue--; + Task *local_task = tls->local_queue[tls->num_local_queue]; + /* TODO(sergey): Double-check work_and_wait() doesn't handle other's + * pool tasks. + */ + TaskPool *local_pool = local_task->pool; + local_task->run(local_pool, local_task->taskdata, thread_id); + task_free(local_pool, local_task, thread_id); + } +} + static void *task_scheduler_thread_run(void *thread_p) { TaskThread *thread = (TaskThread *) thread_p; + TaskThreadLocalStorage *tls = &thread->tls; TaskScheduler *scheduler = thread->scheduler; int thread_id = thread->id; Task *task; + pthread_setspecific(scheduler->tls_id_key, thread); + /* keep popping off tasks */ while (task_scheduler_thread_wait_pop(scheduler, &task)) { TaskPool *pool = task->pool; @@ -328,6 +388,9 @@ static void *task_scheduler_thread_run(void *thread_p) /* delete task */ task_free(pool, task, thread_id); + /* Handle all tasks from local queue. */ + handle_local_queue(tls, thread_id); + /* notify pool task was done */ task_pool_num_decrease(pool, 1); } @@ -361,16 +424,20 @@ TaskScheduler *BLI_task_scheduler_create(int num_threads) num_threads = 1; } + scheduler->task_threads = MEM_callocN(sizeof(TaskThread) * (num_threads + 1), + "TaskScheduler task threads"); + + pthread_key_create(&scheduler->tls_id_key, NULL); + /* launch threads that will be waiting for work */ if (num_threads > 0) { int i; scheduler->num_threads = num_threads; scheduler->threads = MEM_callocN(sizeof(pthread_t) * num_threads, "TaskScheduler threads"); - scheduler->task_threads = MEM_callocN(sizeof(TaskThread) * num_threads, "TaskScheduler task threads"); for (i = 0; i < num_threads; i++) { - TaskThread *thread = &scheduler->task_threads[i]; + TaskThread *thread = &scheduler->task_threads[i + 1]; thread->scheduler = scheduler; thread->id = i + 1; @@ -378,9 +445,6 @@ TaskScheduler *BLI_task_scheduler_create(int num_threads) fprintf(stderr, "TaskScheduler failed to launch thread %d/%d\n", i, num_threads); } } - - scheduler->task_mempool = MEM_callocN(sizeof(*scheduler->task_mempool) * (num_threads + 1), - "TaskScheduler task_mempool"); } return scheduler; @@ -396,6 +460,8 @@ void BLI_task_scheduler_free(TaskScheduler *scheduler) BLI_condition_notify_all(&scheduler->queue_cond); BLI_mutex_unlock(&scheduler->queue_mutex); + pthread_key_delete(scheduler->tls_id_key); + /* delete threads */ if (scheduler->threads) { int i; @@ -410,17 +476,12 @@ void BLI_task_scheduler_free(TaskScheduler *scheduler) /* Delete task thread data */ if (scheduler->task_threads) { - MEM_freeN(scheduler->task_threads); - } - - /* Delete task memory pool */ - if (scheduler->task_mempool) { - for (int i = 0; i <= scheduler->num_threads; ++i) { - for (int j = 0; j < scheduler->task_mempool[i].num_tasks; ++j) { - MEM_freeN(scheduler->task_mempool[i].tasks[j]); - } + for (int i = 0; i < scheduler->num_threads + 1; ++i) { + TaskThreadLocalStorage *tls = &scheduler->task_threads[i].tls; + free_task_tls(tls); } - MEM_freeN(scheduler->task_mempool); + + MEM_freeN(scheduler->task_threads); } /* delete leftover tasks */ @@ -443,7 +504,7 @@ int BLI_task_scheduler_num_threads(TaskScheduler *scheduler) static void task_scheduler_push(TaskScheduler *scheduler, Task *task, TaskPriority priority) { - task_pool_num_increase(task->pool); + task_pool_num_increase(task->pool, 1); /* add task to queue */ BLI_mutex_lock(&scheduler->queue_mutex); @@ -469,7 +530,7 @@ static void task_scheduler_clear(TaskScheduler *scheduler, TaskPool *pool) nexttask = task->next; if (task->pool == pool) { - task_data_free(task, 0); + task_data_free(task, pool->thread_id); BLI_freelinkN(&scheduler->queue, task); done++; @@ -484,7 +545,10 @@ static void task_scheduler_clear(TaskScheduler *scheduler, TaskPool *pool) /* Task Pool */ -static TaskPool *task_pool_create_ex(TaskScheduler *scheduler, void *userdata, const bool is_background) +static TaskPool *task_pool_create_ex(TaskScheduler *scheduler, + void *userdata, + const bool is_background, + const bool is_suspended) { TaskPool *pool = MEM_mallocN(sizeof(TaskPool), "TaskPool"); @@ -502,9 +566,11 @@ static TaskPool *task_pool_create_ex(TaskScheduler *scheduler, void *userdata, c pool->scheduler = scheduler; pool->num = 0; - pool->num_threads = 0; - pool->currently_running_tasks = 0; pool->do_cancel = false; + pool->do_work = false; + pool->is_suspended = is_suspended; + pool->num_suspended = 0; + pool->suspended_queue.first = pool->suspended_queue.last = NULL; pool->run_in_background = is_background; BLI_mutex_init(&pool->num_mutex); @@ -514,11 +580,21 @@ static TaskPool *task_pool_create_ex(TaskScheduler *scheduler, void *userdata, c BLI_mutex_init(&pool->user_mutex); if (BLI_thread_is_main()) { - pool->task_mempool = scheduler->task_mempool; + pool->thread_id = 0; } else { - pool->task_mempool = &pool->task_mempool_local; - pool->task_mempool_local.num_tasks = 0; + TaskThread *thread = pthread_getspecific(scheduler->tls_id_key); + /* NOTE: It is possible that pool is created from non-main thread + * which isn't a scheduler thread. In this case pthread's TLS will + * be NULL and we can safely consider thread id 0 for the main + * thread of this pool (the one which does wort_and_wait()). + */ + if (thread == NULL) { + pool->thread_id = 0; + } + else { + pool->thread_id = thread->id; + } } #ifdef DEBUG_STATS @@ -545,7 +621,7 @@ static TaskPool *task_pool_create_ex(TaskScheduler *scheduler, void *userdata, c */ TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata) { - return task_pool_create_ex(scheduler, userdata, false); + return task_pool_create_ex(scheduler, userdata, false, false); } /** @@ -560,7 +636,17 @@ TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata) */ TaskPool *BLI_task_pool_create_background(TaskScheduler *scheduler, void *userdata) { - return task_pool_create_ex(scheduler, userdata, true); + return task_pool_create_ex(scheduler, userdata, true, false); +} + +/** + * Similar to BLI_task_pool_create() but does not schedule any tasks for execution + * for until BLI_task_pool_work_and_wait() is called. This helps reducing therading + * overhead when pushing huge amount of small initial tasks from the main thread. + */ +TaskPool *BLI_task_pool_create_suspended(TaskScheduler *scheduler, void *userdata) +{ + return task_pool_create_ex(scheduler, userdata, false, true); } void BLI_task_pool_free(TaskPool *pool) @@ -572,13 +658,6 @@ void BLI_task_pool_free(TaskPool *pool) BLI_mutex_end(&pool->user_mutex); - /* Free local memory pool, those pointers are lost forever. */ - if (pool->task_mempool == &pool->task_mempool_local) { - for (int i = 0; i < pool->task_mempool_local.num_tasks; i++) { - MEM_freeN(pool->task_mempool_local.tasks[i]); - } - } - #ifdef DEBUG_STATS printf("Thread ID Allocated Reused Discarded\n"); for (int i = 0; i < pool->scheduler->num_threads + 1; ++i) { @@ -609,6 +688,25 @@ static void task_pool_push( task->freedata = freedata; task->pool = pool; + if (pool->is_suspended) { + BLI_addhead(&pool->suspended_queue, task); + atomic_fetch_and_add_z(&pool->num_suspended, 1); + return; + } + + if (thread_id != -1 && + (thread_id != pool->thread_id || pool->do_work)) + { + ASSERT_THREAD_ID(pool->scheduler, thread_id); + + TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id); + if (tls->num_local_queue < LOCALQUEUE_SIZE) { + tls->local_queue[tls->num_local_queue] = task; + tls->num_local_queue++; + return; + } + } + task_scheduler_push(pool->scheduler, task, priority); } @@ -633,8 +731,27 @@ void BLI_task_pool_push_from_thread(TaskPool *pool, TaskRunFunction run, void BLI_task_pool_work_and_wait(TaskPool *pool) { + TaskThreadLocalStorage *tls = get_task_tls(pool, pool->thread_id); TaskScheduler *scheduler = pool->scheduler; + if (atomic_fetch_and_and_uint8((uint8_t*)&pool->is_suspended, 0)) { + if (pool->num_suspended) { + task_pool_num_increase(pool, pool->num_suspended); + BLI_mutex_lock(&scheduler->queue_mutex); + + BLI_movelisttolist(&scheduler->queue, &pool->suspended_queue); + + BLI_condition_notify_all(&scheduler->queue_cond); + BLI_mutex_unlock(&scheduler->queue_mutex); + + } + pool->is_suspended = false; + } + + pool->do_work = true; + + ASSERT_THREAD_ID(pool->scheduler, pool->thread_id); + BLI_mutex_lock(&pool->num_mutex); while (pool->num != 0) { @@ -648,16 +765,12 @@ void BLI_task_pool_work_and_wait(TaskPool *pool) /* find task from this pool. if we get a task from another pool, * we can get into deadlock */ - if (pool->num_threads == 0 || - pool->currently_running_tasks < pool->num_threads) - { - for (task = scheduler->queue.first; task; task = task->next) { - if (task->pool == pool) { - work_task = task; - found_task = true; - BLI_remlink(&scheduler->queue, task); - break; - } + for (task = scheduler->queue.first; task; task = task->next) { + if (task->pool == pool) { + work_task = task; + found_task = true; + BLI_remlink(&scheduler->queue, task); + break; } } @@ -666,11 +779,13 @@ void BLI_task_pool_work_and_wait(TaskPool *pool) /* if found task, do it, otherwise wait until other tasks are done */ if (found_task) { /* run task */ - atomic_add_and_fetch_z(&pool->currently_running_tasks, 1); - work_task->run(pool, work_task->taskdata, 0); + work_task->run(pool, work_task->taskdata, pool->thread_id); /* delete task */ - task_free(pool, task, 0); + task_free(pool, task, pool->thread_id); + + /* Handle all tasks from local queue. */ + handle_local_queue(tls, pool->thread_id); /* notify pool task was done */ task_pool_num_decrease(pool, 1); @@ -685,12 +800,8 @@ void BLI_task_pool_work_and_wait(TaskPool *pool) } BLI_mutex_unlock(&pool->num_mutex); -} -void BLI_pool_set_num_threads(TaskPool *pool, int num_threads) -{ - /* NOTE: Don't try to modify threads while tasks are running! */ - pool->num_threads = num_threads; + handle_local_queue(tls, pool->thread_id); } void BLI_task_pool_cancel(TaskPool *pool) @@ -893,7 +1004,8 @@ static void task_parallel_range_ex( BLI_task_pool_push_from_thread(task_pool, parallel_range_func, userdata_chunk_local, false, - TASK_PRIORITY_HIGH, 0); + TASK_PRIORITY_HIGH, + task_pool->thread_id); } BLI_task_pool_work_and_wait(task_pool); @@ -1099,7 +1211,8 @@ void BLI_task_parallel_listbase( BLI_task_pool_push_from_thread(task_pool, parallel_listbase_func, NULL, false, - TASK_PRIORITY_HIGH, 0); + TASK_PRIORITY_HIGH, + task_pool->thread_id); } BLI_task_pool_work_and_wait(task_pool); diff --git a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp index e1ada9a8c39..5f78067220a 100644 --- a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp +++ b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp @@ -94,4 +94,10 @@ void ConvolutionEdgeFilterOperation::executePixel(float output[4], int x, int y, output[2] = output[2] * value[0] + in2[2] * mval; output[3] = in2[3]; + + /* Make sure we don't return negative color. */ + output[0] = max(output[0], 0.0f); + output[1] = max(output[1], 0.0f); + output[2] = max(output[2], 0.0f); + output[3] = max(output[3], 0.0f); } diff --git a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp index 68ec2be5ebd..6ac1ff9a1eb 100644 --- a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp +++ b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp @@ -107,6 +107,12 @@ void ConvolutionFilterOperation::executePixel(float output[4], int x, int y, voi output[1] = output[1] * value[0] + in2[1] * mval; output[2] = output[2] * value[0] + in2[2] * mval; output[3] = output[3] * value[0] + in2[3] * mval; + + /* Make sure we don't return negative color. */ + output[0] = max(output[0], 0.0f); + output[1] = max(output[1], 0.0f); + output[2] = max(output[2], 0.0f); + output[3] = max(output[3], 0.0f); } bool ConvolutionFilterOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index 3a042535d26..e739bc9dbb5 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -95,105 +95,38 @@ static void deg_task_run_func(TaskPool *pool, /* Should only be the case for NOOPs, which never get to this point. */ BLI_assert(node->evaluate); - while (true) { - /* Get context. */ - /* TODO: Who initialises this? "Init" operations aren't able to - * initialise it!!! - */ - /* TODO(sergey): We don't use component contexts at this moment. */ - /* ComponentDepsNode *comp = node->owner; */ - BLI_assert(node->owner != NULL); - - /* Since we're not leaving the thread for until the graph branches it is - * possible to have NO-OP on the way. for which evaluate() will be NULL. - * but that's all fine, we'll just scheduler it's children. - */ - if (node->evaluate) { + /* Get context. */ + /* TODO: Who initialises this? "Init" operations aren't able to + * initialise it!!! + */ + /* TODO(sergey): We don't use component contexts at this moment. */ + /* ComponentDepsNode *comp = node->owner; */ + BLI_assert(node->owner != NULL); + + /* Since we're not leaving the thread for until the graph branches it is + * possible to have NO-OP on the way. for which evaluate() will be NULL. + * but that's all fine, we'll just scheduler it's children. + */ + if (node->evaluate) { /* Take note of current time. */ #ifdef USE_DEBUGGER - double start_time = PIL_check_seconds_timer(); - DepsgraphDebug::task_started(state->graph, node); + double start_time = PIL_check_seconds_timer(); + DepsgraphDebug::task_started(state->graph, node); #endif - /* Perform operation. */ - node->evaluate(state->eval_ctx); + /* Perform operation. */ + node->evaluate(state->eval_ctx); /* Note how long this took. */ #ifdef USE_DEBUGGER - double end_time = PIL_check_seconds_timer(); - DepsgraphDebug::task_completed(state->graph, - node, - end_time - start_time); + double end_time = PIL_check_seconds_timer(); + DepsgraphDebug::task_completed(state->graph, + node, + end_time - start_time); #endif - } - - /* If there's only one outgoing link we try to immediately switch to - * that node evaluation, without leaving the thread. - * - * It's only doable if the child don't have extra relations or all they - * are satisfied. - * - * TODO(sergey): Checks here can be de-duplicated with the ones from - * schedule_node(), however, how to do it nicely? - */ - if (node->outlinks.size() == 1) { - DepsRelation *rel = node->outlinks[0]; - OperationDepsNode *child = (OperationDepsNode *)rel->to; - BLI_assert(child->type == DEPSNODE_TYPE_OPERATION); - if (!child->scheduled) { - unsigned int id_layers = child->owner->owner->layers; - if (!((child->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 && - (id_layers & state->layers) != 0)) - { - /* Node does not need an update, so can;t continue with the - * chain and need to switch to another one by leaving the - * thread. - */ - break; - } - if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) { - BLI_assert(child->num_links_pending > 0); - atomic_sub_and_fetch_uint32(&child->num_links_pending, 1); - } - if (child->num_links_pending == 0) { - bool is_scheduled = atomic_fetch_and_or_uint8( - (uint8_t *)&child->scheduled, (uint8_t)true); - if (!is_scheduled) { - /* Node was not scheduled, switch to it! */ - node = child; - } - else { - /* Someone else scheduled the node, leaving us - * unemployed in this thread, we're leaving. - */ - break; - } - } - else { - /* There are other dependencies on the child, can't do - * anything in the current thread. - */ - break; - } - } - else { - /* Happens when having cyclic dependencies. - * - * Nothing to do here, single child was already scheduled, we - * can leave the thread now. - */ - break; - } - } - else { - /* TODO(sergey): It's possible to use one of the outgoing relations - * as a chain which we'll try to keep alive, but it's a bit more - * involved change. - */ - schedule_children(pool, state->graph, node, state->layers, thread_id); - break; - } } + + schedule_children(pool, state->graph, node, state->layers, thread_id); } typedef struct CalculatePengindData { @@ -378,12 +311,19 @@ void deg_evaluate_on_refresh(EvaluationContext *eval_ctx, state.graph = graph; state.layers = layers; - TaskScheduler *task_scheduler = BLI_task_scheduler_get(); - TaskPool *task_pool = BLI_task_pool_create(task_scheduler, &state); + TaskScheduler *task_scheduler; + bool need_free_scheduler; if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) { - BLI_pool_set_num_threads(task_pool, 1); + task_scheduler = BLI_task_scheduler_create(1); + need_free_scheduler = true; } + else { + task_scheduler = BLI_task_scheduler_get(); + need_free_scheduler = false; + } + + TaskPool *task_pool = BLI_task_pool_create_suspended(task_scheduler, &state); calculate_pending_parents(graph, layers); @@ -410,6 +350,10 @@ void deg_evaluate_on_refresh(EvaluationContext *eval_ctx, /* Clear any uncleared tags - just in case. */ deg_graph_clear_tags(graph); + + if (need_free_scheduler) { + BLI_task_scheduler_free(task_scheduler); + } } } // namespace DEG diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index 7c6c25bef0d..e10f86f6e95 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -180,6 +180,11 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph) comp_node->done = 1; /* Flush to nodes along links... */ + /* TODO(sergey): This is mainly giving speedup due ot less queue pushes, which + * reduces number of memory allocations. + * + * We should try solve the allocation issue instead of doing crazy things here. + */ if (node->outlinks.size() == 1) { OperationDepsNode *to_node = (OperationDepsNode *)node->outlinks[0]->to; if (to_node->scheduled == false) { diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index a9acb41fcf6..a6f2fa40f46 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -303,11 +303,11 @@ static EditBone *get_nearest_editbonepoint( ebone_next_act = NULL; } - BLI_rcti_init_pt_size(&rect, mval, 5); + BLI_rcti_init_pt_radius(&rect, mval, 5); hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, true); if (hits == 0) { - BLI_rcti_init_pt_size(&rect, mval, 12); + BLI_rcti_init_pt_radius(&rect, mval, 12); hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, true); } /* See if there are any selected bones in this group */ diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index c2813d8c5a7..c3b918ef64f 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -1929,7 +1929,7 @@ static bool sk_selectStroke(bContext *C, SK_Sketch *sketch, const int mval[2], c view3d_set_viewcontext(C, &vc); - BLI_rcti_init_pt_size(&rect, mval, 5); + BLI_rcti_init_pt_radius(&rect, mval, 5); hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index ad5f6279606..ce1153911da 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -2681,13 +2681,14 @@ static void ui_litem_layout_absolute(uiLayout *litem) static void ui_litem_estimate_split(uiLayout *litem) { ui_litem_estimate_row(litem); + litem->item.flag &= ~UI_ITEM_MIN; } static void ui_litem_layout_split(uiLayout *litem) { uiLayoutItemSplit *split = (uiLayoutItemSplit *)litem; uiItem *item; - float percentage; + float percentage, extra_pixel = 0.0f; const int tot = BLI_listbase_count(&litem->items); int itemh, x, y, w, colw = 0; @@ -2710,7 +2711,9 @@ static void ui_litem_layout_split(uiLayout *litem) x += colw; if (item->next) { - colw = (w - (int)(w * percentage)) / (tot - 1); + const float width = extra_pixel + (w - (int)(w * percentage)) / ((float)tot - 1); + extra_pixel = width - (int)width; + colw = (int)width; colw = MAX2(colw, 0); x += litem->space; diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c index 9c42d3eb08f..fff53d6885e 100644 --- a/source/blender/editors/metaball/mball_edit.c +++ b/source/blender/editors/metaball/mball_edit.c @@ -592,7 +592,7 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese view3d_set_viewcontext(C, &vc); - BLI_rcti_init_pt_size(&rect, mval, 12); + BLI_rcti_init_pt_radius(&rect, mval, 12); hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true); diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index 21a7ec0d06c..1d870b89026 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -718,7 +718,6 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) oglrender->task_scheduler = task_scheduler; oglrender->task_pool = BLI_task_pool_create_background(task_scheduler, oglrender); - BLI_pool_set_num_threads(oglrender->task_pool, 1); } else { oglrender->task_scheduler = NULL; @@ -750,6 +749,23 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender) int i; if (oglrender->is_animation) { + /* Trickery part for movie output: + * + * We MUST write frames in an exact order, so we only let background + * thread to work on that, and main thread is simply waits for that + * thread to do all the dirty work. + * + * After this loop is done work_and_wait() will have nothing to do, + * so we don't run into wrong order of frames written to the stream. + */ + if (BKE_imtype_is_movie(scene->r.im_format.imtype)) { + BLI_mutex_lock(&oglrender->task_mutex); + while (oglrender->num_scheduled_frames > 0) { + BLI_condition_wait(&oglrender->task_condition, + &oglrender->task_mutex); + } + BLI_mutex_unlock(&oglrender->task_mutex); + } BLI_task_pool_work_and_wait(oglrender->task_pool); BLI_task_pool_free(oglrender->task_pool); /* Depending on various things we might or might not use global scheduler. */ diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 54ddd9aed46..fdfe316f5ed 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -1070,7 +1070,7 @@ int node_find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **so /* check if we click in a socket */ for (node = snode->edittree->nodes.first; node; node = node->next) { - BLI_rctf_init_pt_size(&rect, cursor, NODE_SOCKSIZE + 4); + BLI_rctf_init_pt_radius(&rect, cursor, NODE_SOCKSIZE + 4); if (!(node->flag & NODE_HIDDEN)) { /* extra padding inside and out - allow dragging on the text areas too */ diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 7920631b100..37d300ca0a7 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -882,6 +882,7 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w case ND_CONSTRAINT: case ND_KEYS: case ND_PARTICLE: + case ND_POINTCACHE: case ND_LOD: ED_region_tag_redraw(ar); break; diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 131095c8c47..b65e8e01768 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -4872,7 +4872,7 @@ static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int marg rect.ymax = mval[1] + 1; } else { - BLI_rcti_init_pt_size(&rect, mval, margin); + BLI_rcti_init_pt_radius(&rect, mval, margin); } view3d_update_depths_rect(ar, &depth_temp, &rect); diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 911bea78461..eb961c786af 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -258,7 +258,7 @@ void ED_view3d_smooth_view_force_finish( struct bContext *C, struct View3D *v3d, struct ARegion *ar); -void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rctf *rect); +void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rcti *rect); void view3d_viewmatrix_set(Scene *scene, const View3D *v3d, RegionView3D *rv3d); void fly_modal_keymap(struct wmKeyConfig *keyconf); diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 921ac136dad..3f6afb2634d 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -1059,9 +1059,11 @@ static void deselectall_except(SceneLayer *sl, Base *b) /* deselect all except } } -static Base *object_mouse_select_menu(bContext *C, ViewContext *vc, unsigned int *buffer, int hits, const int mval[2], short toggle) +static Base *object_mouse_select_menu( + bContext *C, ViewContext *vc, unsigned int *buffer, int hits, + const int mval[2], bool toggle) { - short baseCount = 0; + int baseCount = 0; bool ok; LinkNode *linklist = NULL; @@ -1151,19 +1153,19 @@ static bool selectbuffer_has_bones(const unsigned int *buffer, const unsigned in } /* utility function for mixed_bones_object_selectbuffer */ -static short selectbuffer_ret_hits_15(unsigned int *UNUSED(buffer), const short hits15) +static int selectbuffer_ret_hits_15(unsigned int *UNUSED(buffer), const int hits15) { return hits15; } -static short selectbuffer_ret_hits_9(unsigned int *buffer, const short hits15, const short hits9) +static int selectbuffer_ret_hits_9(unsigned int *buffer, const int hits15, const int hits9) { const int offs = 4 * hits15; memcpy(buffer, buffer + offs, 4 * hits9 * sizeof(unsigned int)); return hits9; } -static short selectbuffer_ret_hits_5(unsigned int *buffer, const short hits15, const short hits9, const short hits5) +static int selectbuffer_ret_hits_5(unsigned int *buffer, const int hits15, const int hits9, const int hits5) { const int offs = 4 * hits15 + 4 * hits9; memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(unsigned int)); @@ -1172,14 +1174,14 @@ static short selectbuffer_ret_hits_5(unsigned int *buffer, const short hits15, c /* we want a select buffer with bones, if there are... */ /* so check three selection levels and compare */ -static short mixed_bones_object_selectbuffer( +static int mixed_bones_object_selectbuffer( ViewContext *vc, unsigned int *buffer, const int mval[2], bool use_cycle, bool enumerate, bool *r_do_nearest) { rcti rect; int offs; - short hits15, hits9 = 0, hits5 = 0; + int hits15, hits9 = 0, hits5 = 0; bool has_bones15 = false, has_bones9 = false, has_bones5 = false; static int last_mval[2] = {-100, -100}; bool do_nearest = false; @@ -1207,7 +1209,7 @@ static short mixed_bones_object_selectbuffer( do_nearest = do_nearest && !enumerate; - BLI_rcti_init(&rect, mval[0] - 14, mval[0] + 14, mval[1] - 14, mval[1] + 14); + BLI_rcti_init_pt_radius(&rect, mval, 14); hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, do_nearest); if (hits15 == 1) { return selectbuffer_ret_hits_15(buffer, hits15); @@ -1216,7 +1218,7 @@ static short mixed_bones_object_selectbuffer( has_bones15 = selectbuffer_has_bones(buffer, hits15); offs = 4 * hits15; - BLI_rcti_init(&rect, mval[0] - 9, mval[0] + 9, mval[1] - 9, mval[1] + 9); + BLI_rcti_init_pt_radius(&rect, mval, 9); hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, do_nearest); if (hits9 == 1) { return selectbuffer_ret_hits_9(buffer, hits15, hits9); @@ -1225,7 +1227,7 @@ static short mixed_bones_object_selectbuffer( has_bones9 = selectbuffer_has_bones(buffer + offs, hits9); offs += 4 * hits9; - BLI_rcti_init(&rect, mval[0] - 5, mval[0] + 5, mval[1] - 5, mval[1] + 5); + BLI_rcti_init_pt_radius(&rect, mval, 5); hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, do_nearest); if (hits5 == 1) { return selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5); @@ -1384,7 +1386,7 @@ static bool ed_object_select_pick( bool is_obedit; float dist = ED_view3d_select_dist_px() * 1.3333f; bool retval = false; - short hits; + int hits; const float mval_fl[2] = {(float)mval[0], (float)mval[1]}; @@ -1876,7 +1878,7 @@ static int do_meta_box_select(ViewContext *vc, rcti *rect, bool select, bool ext int a; unsigned int buffer[MAXPICKBUF]; - short hits; + int hits; hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, false); @@ -1910,7 +1912,7 @@ static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool int a; unsigned int buffer[MAXPICKBUF]; - short hits; + int hits; hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, false); @@ -1985,7 +1987,7 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b int bone_only; int bone_selected = 0; int totobj = MAXPICKBUF; /* XXX solve later */ - short hits; + int hits; if ((ob) && (ob->mode & OB_MODE_POSE)) bone_only = 1; @@ -2549,7 +2551,7 @@ static void lattice_circle_select(ViewContext *vc, const bool select, const int /* NOTE: pose-bone case is copied from editbone case... */ -static short pchan_circle_doSelectJoint(void *userData, bPoseChannel *pchan, const float screen_co[2]) +static bool pchan_circle_doSelectJoint(void *userData, bPoseChannel *pchan, const float screen_co[2]) { CircleSelectUserData *data = userData; @@ -2627,7 +2629,7 @@ static void pose_circle_select(ViewContext *vc, const bool select, const int mva } } -static short armature_circle_doSelectJoint(void *userData, EditBone *ebone, const float screen_co[2], short head) +static bool armature_circle_doSelectJoint(void *userData, EditBone *ebone, const float screen_co[2], bool head) { CircleSelectUserData *data = userData; diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 687a9a398d9..637479f9ee3 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -903,7 +903,7 @@ void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist) /** * \param rect optional for picking (can be NULL). */ -void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rctf *rect) +void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rcti *rect) { RegionView3D *rv3d = ar->regiondata; rctf viewplane; @@ -1170,7 +1170,7 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b SceneLayer *sl = vc->sl; View3D *v3d = vc->v3d; ARegion *ar = vc->ar; - rctf rect; + rcti rect; short hits; const bool use_obedit_skip = (scene->obedit != NULL) && (vc->obedit == NULL); const bool do_passes = do_nearest && GPU_select_query_check_active(); @@ -1180,10 +1180,10 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b /* case not a border select */ if (input->xmin == input->xmax) { /* seems to be default value for bones only now */ - BLI_rctf_init_pt_size(&rect, (const float[2]){input->xmin, input->ymin}, 12); + BLI_rcti_init_pt_radius(&rect, (const int[2]){input->xmin, input->ymin}, 12); } else { - BLI_rctf_rcti_copy(&rect, input); + rect = *input; } view3d_winmatrix_set(ar, v3d, &rect); diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index 489badf594b..a78bf1551bc 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -1768,14 +1768,14 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl { View3D *v3d = sa->spacedata.first; RegionView3D *rv3d = ar->regiondata; - rctf rect, selrect; + rcti rect; GLuint buffer[64]; // max 4 items per select, so large enuf short hits; const bool is_picksel = true; const bool do_passes = GPU_select_query_check_active(); /* XXX check a bit later on this... (ton) */ - extern void view3d_winmatrix_set(ARegion *ar, View3D *v3d, rctf *rect); + extern void view3d_winmatrix_set(ARegion *ar, View3D *v3d, const rcti *rect); /* when looking through a selected camera, the manipulator can be at the * exact same position as the view, skip so we don't break selection */ @@ -1787,15 +1787,13 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl rect.ymin = mval[1] - hotspot; rect.ymax = mval[1] + hotspot; - selrect = rect; - view3d_winmatrix_set(ar, v3d, &rect); mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); if (do_passes) - GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_NEAREST_FIRST_PASS, 0); + GPU_select_begin(buffer, 64, &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0); else - GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_ALL, 0); + GPU_select_begin(buffer, 64, &rect, GPU_SELECT_ALL, 0); /* do the drawing */ if (v3d->twtype & V3D_MANIP_ROTATE) { @@ -1810,7 +1808,7 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl hits = GPU_select_end(); if (do_passes) { - GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_NEAREST_SECOND_PASS, hits); + GPU_select_begin(buffer, 64, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits); /* do the drawing */ if (v3d->twtype & V3D_MANIP_ROTATE) { @@ -1916,10 +1914,8 @@ int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op) drawflags = manipulator_selectbuf(sa, ar, event->mval, 0.2f * (float)U.tw_hotspot); if (drawflags == 0) drawflags = val; - /* We are not doing translation but were requested to do planar constraints. - * This wouldn't work, so we give other keymaps a chance. - */ - if ((drawflags & MAN_TRANS_C) == 0 && use_planar) { + /* Planar constraint doesn't make sense for rotation, give other keymaps a chance */ + if ((drawflags & MAN_ROT_C) && use_planar) { return 0; } diff --git a/source/blender/gpu/GPU_select.h b/source/blender/gpu/GPU_select.h index d3cb914976e..93f5ce13bbd 100644 --- a/source/blender/gpu/GPU_select.h +++ b/source/blender/gpu/GPU_select.h @@ -32,7 +32,7 @@ #include "BLI_sys_types.h" -struct rctf; +struct rcti; /* flags for mode of operation */ enum { @@ -41,7 +41,7 @@ enum { GPU_SELECT_NEAREST_SECOND_PASS = 3, }; -void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, const struct rctf *input, char mode, int oldhits); +void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, const struct rcti *input, char mode, int oldhits); bool GPU_select_load_id(unsigned int id); unsigned int GPU_select_end(void); bool GPU_select_query_check_active(void); diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c index f78191a6f6d..35944c455a5 100644 --- a/source/blender/gpu/intern/gpu_select.c +++ b/source/blender/gpu/intern/gpu_select.c @@ -37,6 +37,8 @@ #include "DNA_userdef_types.h" +#include "BLI_rect.h" + #include "BLI_utildefines.h" /* Ad hoc number of queries to allocate to skip doing many glGenQueries */ @@ -72,7 +74,7 @@ static GPUQueryState g_query_state = {0}; /** * initialize and provide buffer for results */ -void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, const rctf *input, char mode, int oldhits) +void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, const rcti *input, char mode, int oldhits) { g_query_state.select_is_active = true; g_query_state.query_issued = false; @@ -109,7 +111,7 @@ void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, const rctf *in * get rejected before the depth test. Should probably cull rect against * scissor for viewport but this is a rare case I think */ glGetFloatv(GL_SCISSOR_BOX, viewport); - glViewport(viewport[0], viewport[1], (int)(input->xmax - input->xmin), (int)(input->ymax - input->ymin)); + glViewport(viewport[0], viewport[1], BLI_rcti_size_x(input), BLI_rcti_size_y(input)); /* occlusion queries operates on fragments that pass tests and since we are interested on all * objects in the view frustum independently of their order, we need to disable the depth test */ diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulatormap.c b/source/blender/windowmanager/manipulators/intern/wm_manipulatormap.c index 500092f5f2d..2dd02450dcf 100644 --- a/source/blender/windowmanager/manipulators/intern/wm_manipulatormap.c +++ b/source/blender/windowmanager/manipulators/intern/wm_manipulatormap.c @@ -279,35 +279,32 @@ static int manipulator_find_intersected_3D_intern( ARegion *ar = CTX_wm_region(C); View3D *v3d = sa->spacedata.first; RegionView3D *rv3d = ar->regiondata; - rctf rect, selrect; + rcti rect; GLuint buffer[64]; // max 4 items per select, so large enuf short hits; const bool do_passes = GPU_select_query_check_active(); - extern void view3d_winmatrix_set(ARegion *ar, View3D *v3d, rctf *rect); - + extern void view3d_winmatrix_set(ARegion *ar, View3D *v3d, const rcti *rect); rect.xmin = co[0] - hotspot; rect.xmax = co[0] + hotspot; rect.ymin = co[1] - hotspot; rect.ymax = co[1] + hotspot; - selrect = rect; - view3d_winmatrix_set(ar, v3d, &rect); mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); if (do_passes) - GPU_select_begin(buffer, ARRAY_SIZE(buffer), &selrect, GPU_SELECT_NEAREST_FIRST_PASS, 0); + GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0); else - GPU_select_begin(buffer, ARRAY_SIZE(buffer), &selrect, GPU_SELECT_ALL, 0); + GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_ALL, 0); /* do the drawing */ manipulator_find_active_3D_loop(C, visible_manipulators); hits = GPU_select_end(); if (do_passes) { - GPU_select_begin(buffer, ARRAY_SIZE(buffer), &selrect, GPU_SELECT_NEAREST_SECOND_PASS, hits); + GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits); manipulator_find_active_3D_loop(C, visible_manipulators); GPU_select_end(); } diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index 5ee69aebd5d..f05dc59875f 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -943,7 +943,7 @@ static int arg_handle_native_pixels_set(int UNUSED(argc), const char **UNUSED(ar } static const char arg_handle_with_borders_doc[] = -"\n\tForce opening without borders" +"\n\tForce opening with borders" ; static int arg_handle_with_borders(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) { |