1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2012 Intel Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#include "swapchain9.h"
25bf215546Sopenharmony_ci#include "surface9.h"
26bf215546Sopenharmony_ci#include "device9.h"
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include "nine_helpers.h"
29bf215546Sopenharmony_ci#include "nine_pipe.h"
30bf215546Sopenharmony_ci#include "nine_dump.h"
31bf215546Sopenharmony_ci
32bf215546Sopenharmony_ci#include "util/u_inlines.h"
33bf215546Sopenharmony_ci#include "util/u_surface.h"
34bf215546Sopenharmony_ci#include "hud/hud_context.h"
35bf215546Sopenharmony_ci#include "frontend/drm_driver.h"
36bf215546Sopenharmony_ci
37bf215546Sopenharmony_ci#include "os/os_thread.h"
38bf215546Sopenharmony_ci#include "threadpool.h"
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_ci/* POSIX thread function */
41bf215546Sopenharmony_cistatic void *
42bf215546Sopenharmony_cithreadpool_worker(void *data)
43bf215546Sopenharmony_ci{
44bf215546Sopenharmony_ci    struct threadpool *pool = data;
45bf215546Sopenharmony_ci
46bf215546Sopenharmony_ci    pthread_mutex_lock(&pool->m);
47bf215546Sopenharmony_ci
48bf215546Sopenharmony_ci    while (!pool->shutdown) {
49bf215546Sopenharmony_ci        struct threadpool_task *task;
50bf215546Sopenharmony_ci
51bf215546Sopenharmony_ci        /* Block (dropping the lock) until new work arrives for us. */
52bf215546Sopenharmony_ci        while (!pool->workqueue && !pool->shutdown)
53bf215546Sopenharmony_ci            pthread_cond_wait(&pool->new_work, &pool->m);
54bf215546Sopenharmony_ci
55bf215546Sopenharmony_ci        if (pool->shutdown)
56bf215546Sopenharmony_ci            break;
57bf215546Sopenharmony_ci
58bf215546Sopenharmony_ci        /* Pull the first task from the list.  We don't free it -- it now lacks
59bf215546Sopenharmony_ci         * a reference other than the worker creator's, whose responsibility it
60bf215546Sopenharmony_ci         * is to call threadpool_wait_for_work() to free it.
61bf215546Sopenharmony_ci         */
62bf215546Sopenharmony_ci        task = pool->workqueue;
63bf215546Sopenharmony_ci        pool->workqueue = task->next;
64bf215546Sopenharmony_ci
65bf215546Sopenharmony_ci        /* Call the task's work func. */
66bf215546Sopenharmony_ci        pthread_mutex_unlock(&pool->m);
67bf215546Sopenharmony_ci        task->work(task->data);
68bf215546Sopenharmony_ci        pthread_mutex_lock(&pool->m);
69bf215546Sopenharmony_ci        task->finished = TRUE;
70bf215546Sopenharmony_ci        pthread_cond_broadcast(&task->finish);
71bf215546Sopenharmony_ci    }
72bf215546Sopenharmony_ci
73bf215546Sopenharmony_ci    pthread_mutex_unlock(&pool->m);
74bf215546Sopenharmony_ci
75bf215546Sopenharmony_ci    return NULL;
76bf215546Sopenharmony_ci}
77bf215546Sopenharmony_ci
78bf215546Sopenharmony_ci/* Windows thread function */
79bf215546Sopenharmony_cistatic DWORD NINE_WINAPI
80bf215546Sopenharmony_ciwthreadpool_worker(void *data)
81bf215546Sopenharmony_ci{
82bf215546Sopenharmony_ci    threadpool_worker(data);
83bf215546Sopenharmony_ci
84bf215546Sopenharmony_ci    return 0;
85bf215546Sopenharmony_ci}
86bf215546Sopenharmony_ci
87bf215546Sopenharmony_cistruct threadpool *
88bf215546Sopenharmony_ci_mesa_threadpool_create(struct NineSwapChain9 *swapchain)
89bf215546Sopenharmony_ci{
90bf215546Sopenharmony_ci    struct threadpool *pool = calloc(1, sizeof(*pool));
91bf215546Sopenharmony_ci
92bf215546Sopenharmony_ci    if (!pool)
93bf215546Sopenharmony_ci        return NULL;
94bf215546Sopenharmony_ci
95bf215546Sopenharmony_ci    pthread_mutex_init(&pool->m, NULL);
96bf215546Sopenharmony_ci    pthread_cond_init(&pool->new_work, NULL);
97bf215546Sopenharmony_ci
98bf215546Sopenharmony_ci    /* This uses WINE's CreateThread, so the thread function needs to use
99bf215546Sopenharmony_ci     * the Windows ABI */
100bf215546Sopenharmony_ci    pool->wthread = NineSwapChain9_CreateThread(swapchain, wthreadpool_worker, pool);
101bf215546Sopenharmony_ci    if (!pool->wthread) {
102bf215546Sopenharmony_ci        /* using pthread as fallback */
103bf215546Sopenharmony_ci        pthread_create(&pool->pthread, NULL, threadpool_worker, pool);
104bf215546Sopenharmony_ci    }
105bf215546Sopenharmony_ci    return pool;
106bf215546Sopenharmony_ci}
107bf215546Sopenharmony_ci
108bf215546Sopenharmony_civoid
109bf215546Sopenharmony_ci_mesa_threadpool_destroy(struct NineSwapChain9 *swapchain, struct threadpool *pool)
110bf215546Sopenharmony_ci{
111bf215546Sopenharmony_ci    if (!pool)
112bf215546Sopenharmony_ci        return;
113bf215546Sopenharmony_ci
114bf215546Sopenharmony_ci    pthread_mutex_lock(&pool->m);
115bf215546Sopenharmony_ci    pool->shutdown = TRUE;
116bf215546Sopenharmony_ci    pthread_cond_broadcast(&pool->new_work);
117bf215546Sopenharmony_ci    pthread_mutex_unlock(&pool->m);
118bf215546Sopenharmony_ci
119bf215546Sopenharmony_ci    if (pool->wthread) {
120bf215546Sopenharmony_ci        NineSwapChain9_WaitForThread(swapchain, pool->wthread);
121bf215546Sopenharmony_ci    } else {
122bf215546Sopenharmony_ci        pthread_join(pool->pthread, NULL);
123bf215546Sopenharmony_ci    }
124bf215546Sopenharmony_ci
125bf215546Sopenharmony_ci    pthread_cond_destroy(&pool->new_work);
126bf215546Sopenharmony_ci    pthread_mutex_destroy(&pool->m);
127bf215546Sopenharmony_ci    free(pool);
128bf215546Sopenharmony_ci}
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_ci/**
131bf215546Sopenharmony_ci * Queues a request for the work function to be asynchronously executed by the
132bf215546Sopenharmony_ci * thread pool.
133bf215546Sopenharmony_ci *
134bf215546Sopenharmony_ci * The work func will get the "data" argument as its parameter -- any
135bf215546Sopenharmony_ci * communication between the caller and the work function will occur through
136bf215546Sopenharmony_ci * that.
137bf215546Sopenharmony_ci *
138bf215546Sopenharmony_ci * If there is an error, the work function is called immediately and NULL is
139bf215546Sopenharmony_ci * returned.
140bf215546Sopenharmony_ci */
141bf215546Sopenharmony_cistruct threadpool_task *
142bf215546Sopenharmony_ci_mesa_threadpool_queue_task(struct threadpool *pool,
143bf215546Sopenharmony_ci                            threadpool_task_func work, void *data)
144bf215546Sopenharmony_ci{
145bf215546Sopenharmony_ci    struct threadpool_task *task, *previous;
146bf215546Sopenharmony_ci
147bf215546Sopenharmony_ci    if (!pool) {
148bf215546Sopenharmony_ci        work(data);
149bf215546Sopenharmony_ci        return NULL;
150bf215546Sopenharmony_ci    }
151bf215546Sopenharmony_ci
152bf215546Sopenharmony_ci    task = calloc(1, sizeof(*task));
153bf215546Sopenharmony_ci    if (!task) {
154bf215546Sopenharmony_ci        work(data);
155bf215546Sopenharmony_ci        return NULL;
156bf215546Sopenharmony_ci    }
157bf215546Sopenharmony_ci
158bf215546Sopenharmony_ci    task->work = work;
159bf215546Sopenharmony_ci    task->data = data;
160bf215546Sopenharmony_ci    task->next = NULL;
161bf215546Sopenharmony_ci    pthread_cond_init(&task->finish, NULL);
162bf215546Sopenharmony_ci
163bf215546Sopenharmony_ci    pthread_mutex_lock(&pool->m);
164bf215546Sopenharmony_ci
165bf215546Sopenharmony_ci    if (!pool->workqueue) {
166bf215546Sopenharmony_ci        pool->workqueue = task;
167bf215546Sopenharmony_ci    } else {
168bf215546Sopenharmony_ci        previous = pool->workqueue;
169bf215546Sopenharmony_ci        while (previous && previous->next)
170bf215546Sopenharmony_ci            previous = previous->next;
171bf215546Sopenharmony_ci
172bf215546Sopenharmony_ci        previous->next = task;
173bf215546Sopenharmony_ci    }
174bf215546Sopenharmony_ci    pthread_cond_signal(&pool->new_work);
175bf215546Sopenharmony_ci    pthread_mutex_unlock(&pool->m);
176bf215546Sopenharmony_ci
177bf215546Sopenharmony_ci    return task;
178bf215546Sopenharmony_ci}
179bf215546Sopenharmony_ci
180bf215546Sopenharmony_ci/**
181bf215546Sopenharmony_ci * Blocks on the completion of the given task and frees the task.
182bf215546Sopenharmony_ci */
183bf215546Sopenharmony_civoid
184bf215546Sopenharmony_ci_mesa_threadpool_wait_for_task(struct threadpool *pool,
185bf215546Sopenharmony_ci                               struct threadpool_task **task_handle)
186bf215546Sopenharmony_ci{
187bf215546Sopenharmony_ci    struct threadpool_task *task = *task_handle;
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_ci    if (!pool || !task)
190bf215546Sopenharmony_ci        return;
191bf215546Sopenharmony_ci
192bf215546Sopenharmony_ci    pthread_mutex_lock(&pool->m);
193bf215546Sopenharmony_ci    while (!task->finished)
194bf215546Sopenharmony_ci        pthread_cond_wait(&task->finish, &pool->m);
195bf215546Sopenharmony_ci    pthread_mutex_unlock(&pool->m);
196bf215546Sopenharmony_ci
197bf215546Sopenharmony_ci    pthread_cond_destroy(&task->finish);
198bf215546Sopenharmony_ci    free(task);
199bf215546Sopenharmony_ci    *task_handle = NULL;
200bf215546Sopenharmony_ci}
201