sync with tizen_2.2
[sdk/emulator/qemu.git] / hw / gles2_kernel_calls.c
1 /* Copyright (c) 2009-2010 Nokia Corporation
2  *
3  * This program is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU General Public License as
5  * published by the Free Software Foundation; either version 2 or
6  * (at your option) any later version of the License.
7  *
8  * You should have received a copy of the GNU General Public License along
9  * with this program; if not, see <http://www.gnu.org/licenses/>.
10  */
11
12 #include "gles2_calls.h"
13
14 void* gles2_client_worker(void *opaque);
15
16 #undef GLES2_CB
17 #define GLES2_CB(func) \
18     CB(func, kernel)
19
20 // Called by kernel module when a new client connects.
21 GLES2_CB(init)
22 {
23     unsigned i;
24     gles2_Client *client;
25     pthread_attr_t attr;
26     uint32_t abi = gles2_arg_dword(s, d);
27
28     for (i = 0; i < GLES2_NCLIENTS; ++i) {
29         if (!s->clients[i]) {
30             break;
31         }
32     }
33
34     if (i == GLES2_NCLIENTS) {
35         GLES2_PRINT("ERROR: No free slots!\n");
36         gles2_ret_dword(s, 0);
37         return;
38     }
39
40     GLES2_PRINT("Client Initialization!\n");
41
42     if (!abi || abi >= gles2_abi_last) {
43         GLES2_PRINT("ERROR: unknown ABI %d!\n", abi);
44         /* support legacy clients that do not provide ABI id */
45         abi = gles2_abi_arm_softfp;
46     }
47     s->abi = abi;
48     GLES2_PRINT("Selected ABI %d\n", s->abi);
49
50     client = malloc(sizeof(*client));
51     memset(client, 0, sizeof(*client));
52     client->s = s;
53     client->nr = i + 1;
54     client->rendering_api = EGL_OPENGL_ES_API;
55     pthread_mutex_init(&client->mutex_wait, NULL);
56     pthread_mutex_init(&client->mutex_run, NULL);
57     pthread_mutex_init(&client->mutex_xcode, NULL);
58     pthread_cond_init(&client->cond_start, NULL);
59     pthread_cond_init(&client->cond_state, NULL);
60     pthread_cond_init(&client->cond_xcode, NULL);
61     pthread_cond_init(&client->cond_return, NULL);
62     client->state = gles2_ClientState_init;
63     pthread_attr_init(&attr);
64     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
65
66     pthread_mutex_lock(&client->mutex_wait);
67
68     GLES2_PRINT("Creating worker...\n");
69     pthread_create(&client->thread, &attr, gles2_client_worker, client);
70
71     do {
72         pthread_cond_wait(&client->cond_state, &client->mutex_wait);
73     } while(client->state != gles2_ClientState_ready);
74     pthread_mutex_unlock(&client->mutex_wait);
75
76     GLES2_PRINT("Worker initialized\n");
77
78     s->clients[i] = client;
79     gles2_ret_dword(s, client->nr);
80 }
81
82 // Called by kernel module when an existing client disconnects.
83  GLES2_CB(exit)
84 {
85     uint32_t nr = gles2_arg_dword(s, d);
86     gles2_Client *client;
87
88     GLES2_PRINT("Exit called for client %d!\n", nr);
89
90     if ((nr > GLES2_NCLIENTS + 1) ||
91     (nr < 1)) {
92         GLES2_PRINT("Client number (%d) out of range!\n",nr);
93     return;
94     }  else {
95         client = s->clients[nr - 1];
96     }
97
98     if (!client) {
99         GLES2_PRINT("Can't exit NULL client!\n");
100         return;
101     }
102
103     GLES2_PRINT("\tRequesting worker to exit.\n");
104
105     // Make sure nothing is running.
106     GLES2_PRINT("Syncing with worker...\n");
107     pthread_mutex_lock(&client->mutex_wait);
108     while (client->state != gles2_ClientState_ready) {
109         pthread_cond_wait(&client->cond_state, &client->mutex_wait);
110     }
111     pthread_mutex_lock(&client->mutex_run);
112     client->call = NULL;
113     client->state = gles2_ClientState_pending;
114     GLES2_PRINT("Requesting exit...\n");
115     pthread_cond_signal(&client->cond_start);
116     pthread_mutex_unlock(&client->mutex_wait);
117
118     GLES2_PRINT("Waiting worker to exit...\n");
119     do {
120         pthread_cond_wait(&client->cond_state, &client->mutex_run);
121     } while (client->state != gles2_ClientState_exit);
122     pthread_mutex_unlock(&client->mutex_run);
123
124     GLES2_PRINT("\tJoining...\n");
125     pthread_join(client->thread, NULL);
126     pthread_mutex_destroy(&client->mutex_wait);
127     pthread_mutex_destroy(&client->mutex_run);
128     pthread_cond_destroy(&client->cond_start);
129     pthread_cond_destroy(&client->cond_state);
130
131     free(client);
132     s->clients[nr - 1] = NULL;
133
134     GLES2_PRINT("\tDone!\n");
135 }
136
137 /**
138 * Worker thread function for clients .
139 * Each worker thread is linked to a %gles2_Client struct and to
140 * one guest thread in the guest system.
141 */
142 void* gles2_client_worker(void *opaque)
143 {
144     gles2_Client *client = opaque;
145     int run = 1;
146
147     GLES2_PRINT("WORKER(%d): Starting!\n", client->nr);
148
149     pthread_mutex_lock(&client->mutex_xcode);
150     do
151     {
152         gles2_decode_t d = 0;
153         GLES2_PRINT("WORKER(%d): Waiting for call...\n", client->nr);
154         pthread_mutex_lock(&client->mutex_wait);
155
156         client->state = gles2_ClientState_ready;
157         pthread_cond_signal(&client->cond_state);
158         client->phase_xcode = 4;
159         pthread_cond_signal(&client->cond_xcode);
160         pthread_mutex_unlock(&client->mutex_xcode);
161         while (client->state != gles2_ClientState_pending) {
162             pthread_cond_wait(&client->cond_start, &client->mutex_wait);
163         }
164
165         GLES2_PRINT("WORKER(%d): Got call, waiting permission to run...\n", client->nr);
166
167         pthread_mutex_lock(&client->mutex_run);
168         GLES2_PRINT("WORKER(%d): Running!\n", client->nr);
169         client->state = gles2_ClientState_running;
170         pthread_mutex_unlock(&client->mutex_wait);
171
172         if (client->call) {
173             GLES2_TRACE("WORKER(%d): Calling function %s (%p)...\n",
174                         client->nr, client->call->name, client->call);
175             client->call->callback(client->s, &d, client);
176 #ifdef CONFIG_DEBUG_GLES
177             /*if (client->call->name[0] == 'g') {
178                 unsigned int error = gles20_glGetError();
179                 if (error) {
180                     fprintf(stderr, "GL error 0x%04x from function %s\n",
181                             error, client->call->name);
182                 }
183             }*/
184 #endif // CONFIG_DEBUG_GLES == 1
185             GLES2_PRINT("\tWORKER(%d): Done.\n", client->nr);
186             client->prev_call = client->call;
187             client->state = gles2_ClientState_done;
188         } else {
189             GLES2_PRINT("WORKER(%d): Exit requested!\n", client->nr);
190             run = 0;
191             client->state = gles2_ClientState_exit;
192             pthread_cond_signal(&client->cond_state);
193         }
194         pthread_mutex_unlock(&client->mutex_run);
195     } while (run);
196
197     GLES2_PRINT("WORKER(%d): Exiting!\n", client->nr);
198     return opaque;
199 }