Tizen 2.1 base
[sdk/emulator/qemu.git] / tizen / src / hw / helper_opengl.c
1 /*
2  *  Host-side implementation of GL/GLX API
3  *
4  *  Copyright (c) 2006,2007 Even Rouault
5  *  Modified by: 
6  *    Gordon Williams <gordon.williams@collabora.co.uk>
7  *    Ian Molton <ian.molton@collabora.co.uk>
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a copy
10  * of this software and associated documentation files (the "Software"), to deal
11  * in the Software without restriction, including without limitation the rights
12  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13  * copies of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included in
17  * all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25  * THE SOFTWARE.
26  */
27
28 #define _XOPEN_SOURCE 600
29
30 #include <string.h>
31 #include <stdlib.h>
32 #include <assert.h>
33 #include "osdep.h"
34 #include "opengl_func.h"
35 #include "opengl_process.h"
36 #include "opengl_exec.h"
37
38 #include "tizen/src/debug_ch.h"
39 MULTI_DEBUG_CHANNEL(qemu, opengl);
40 #define DEBUGF          TRACE
41
42 #if 0
43 #ifdef _WIN32
44 #define DEBUGF(...) printf(__VA_ARGS__)
45 #else
46 extern struct FILE *stderr;             /* Standard error output stream.  */
47 #define DEBUGF(...) fprintf(stderr, __VA_ARGS__)
48 #endif
49 #endif
50
51 /* do_decode_call_int()
52  *
53  * Loop through the buffered command stream executing each OpenGL call in
54  * sequence. due to the way calls are buffered, only the last call in the
55  * buffer may have 'out' parameters or a non-void return code. This allows
56  * for efficient buffering whilst avoiding un-necessary buffer flushes.
57  */
58
59 typedef unsigned long host_ptr;
60
61 static inline int do_decode_call_int(ProcessStruct *process, void *args_in, int args_len, char *r_buffer)
62 {
63     Signature *signature;
64     int i, ret;
65     char *argptr, *tmp;
66     static void* args[50];
67     int func_number;
68 #ifdef __APPLE__
69     char temp4mac[256];
70 #endif
71
72     if(!args_len)
73         return 0;
74
75     argptr = args_in;
76
77     while((char*)argptr < (char*)args_in + args_len) {
78         func_number = *(short*)argptr;
79         argptr += 2;
80
81         if(func_number >= GL_N_CALLS) {
82             DEBUGF("Bad function number or corrupt command queue\n");
83             return 0;
84         }
85
86         signature = (Signature *) tab_opengl_calls[func_number];
87
88         tmp = argptr;
89
90         for (i = 0; i < signature->nb_args; i++) {
91             int args_size = *(int*)argptr;
92             argptr+=4;
93             switch (signature->args_type[i]) {
94                 case TYPE_UNSIGNED_INT:
95                 case TYPE_INT:
96                 case TYPE_UNSIGNED_CHAR:
97                 case TYPE_CHAR:
98                 case TYPE_UNSIGNED_SHORT:
99                 case TYPE_SHORT:
100                 case TYPE_FLOAT:
101                     args[i] = *(int*)argptr;
102                 break;
103
104                 case TYPE_NULL_TERMINATED_STRING:
105                 CASE_IN_UNKNOWN_SIZE_POINTERS:
106                 {
107                     if(*(int*)argptr)
108                         args[i] = (host_ptr)argptr+4;
109                     else
110                         args[i] = (host_ptr)NULL;
111
112                     if ((args[i] == 0 && args_size == 0 &&
113                         !IS_NULL_POINTER_OK_FOR_FUNC(func_number)) ||
114                         (args[i] == 0 && args_size != 0))
115                             return 0;
116
117                     argptr += 4;
118                     break;
119                 }
120
121                 CASE_IN_LENGTH_DEPENDING_ON_PREVIOUS_ARGS:
122                 {
123                     if(*(int*)argptr)
124                         args[i] = (host_ptr)argptr+4;
125                     else
126                         args[i] = (host_ptr)NULL;
127
128                     if (args[i] == 0 && args_size != 0)
129                         return 0;
130
131                     argptr += 4;
132                     break;
133                 }
134
135                 CASE_OUT_POINTERS:
136                 {
137                                         /* NULL pointer is used as output pointer
138                                            since the argument size is zero. */
139                                         if (args_size == 0) {
140                                                 *(int*)r_buffer = 0;
141                                                 r_buffer += 4;
142 #ifdef __APPLE__
143 /*On MAC OS, GL call glGetProgramInfoLog and glGetShaderInfoLog will crash if ouput pointer is NULL*/
144                                                 args[i] = temp4mac;
145 #else
146                                                 args[i] = NULL;
147 #endif
148                                         } else if(*(int*)argptr) {
149                         *(int*)r_buffer = args_size;
150                         r_buffer+=4;
151                         args[i] = (host_ptr)r_buffer;
152                         r_buffer += args_size;
153                     }
154                     else {
155                         args[i] = 0;
156                     }
157
158                     argptr += 4;
159                     args_size = 0;
160                     break;
161                 } 
162
163                 case TYPE_DOUBLE:
164                 CASE_IN_KNOWN_SIZE_POINTERS:
165                 {
166                     if(*(int*)argptr)
167                         args[i] = (host_ptr)argptr+4;
168                     else
169                         args[i] = (host_ptr)NULL;
170
171                     if (args[i] == 0 && args_size != 0)
172                         return 0;
173
174                     argptr += 4;
175                     break;
176                 }
177
178                 case TYPE_IN_IGNORED_POINTER:
179                     args[i] = 0;
180                     break;
181
182                 default:
183                     DEBUGF( "Oops : call %s arg %d pid=%d\n",
184                             tab_opengl_calls_name[func_number], i,
185                             process->process_id);
186                     return 0;
187             }
188             argptr += args_size;
189         }
190
191         if((char*)argptr > (char*)args_in + args_len) {
192             DEBUGF("Client bug: malformed command, killing process\n");
193             return 0;
194         }
195
196         if (signature->ret_type == TYPE_CONST_CHAR)
197             r_buffer[0] = 0; // In case high bits are set.
198
199         ret = do_function_call(process, func_number, args, r_buffer);
200         switch(signature->ret_type) {
201         case TYPE_INT:
202         case TYPE_UNSIGNED_INT:
203             memcpy(r_buffer, &ret, sizeof(int));
204             break;
205         case TYPE_CHAR:
206         case TYPE_UNSIGNED_CHAR:
207             *r_buffer = ret & 0xff;
208             break;
209         case TYPE_CONST_CHAR:
210         case TYPE_NONE:
211             break;
212         default:
213            DEBUGF("Unsupported GL API return type %i!\n", signature->ret_type);
214            exit (-1);
215         }
216     }  // endwhile
217 /*
218     switch(signature->ret_type) {
219         case TYPE_INT:
220         case TYPE_UNSIGNED_INT:
221             memcpy(r_buffer, &ret, sizeof(int));
222             break;
223         case TYPE_CHAR:
224         case TYPE_UNSIGNED_CHAR:
225             *r_buffer = ret & 0xff;
226             break;
227         case TYPE_CONST_CHAR:
228         case TYPE_NONE:
229             break;
230         default:
231            DEBUGF("Unsupported GL API return type %i!\n", signature->ret_type);
232            exit (-1);
233     }
234 */
235     return 1;
236 }
237 #define GL_PASSINGTHROUGH_ABI 1
238
239 #define GLINIT_FAIL_ABI 3
240 #define GLINIT_QUEUE 2
241 #define GLINIT_NOQUEUE 1
242
243 int decode_call_int(ProcessStruct *process, char *in_args, int args_len, char *r_buffer)
244 {
245         static ProcessStruct *cur_process = NULL;
246         int ret;
247         int first_func = *(short*)in_args;
248
249         /* Select the appropriate context for this pid if it isnt already active
250          * Note: if we're about to execute glXMakeCurrent() then we tell the
251          * renderer not to waste its time switching contexts
252          */
253
254         if (cur_process != process) {
255                 cur_process = process;
256                 vmgl_context_switch(cur_process, (first_func == glXMakeCurrent_func)?0:1);
257         }
258
259         if(unlikely(first_func == _init32_func || first_func == _init64_func)) {
260                 if(!cur_process->wordsize) {
261                         int *version = (int*)(in_args+2);
262                         cur_process->wordsize = first_func == _init32_func?4:8;
263
264                         if((version[0] != 1) || (version[1] < GL_PASSINGTHROUGH_ABI)) {
265                                 *(int*)r_buffer = GLINIT_FAIL_ABI; // ABI check FAIL
266                                 TRACE("Error! The GL passing through package in the image does not match the version of QEMUGL. Please update the image!\n");
267                                 exit (1);
268                         } else if(version[1] > GL_PASSINGTHROUGH_ABI) {
269                                 *(int*)r_buffer = GLINIT_FAIL_ABI; // ABI check FAIL
270                                 TRACE("Error! The GL passing through package in the image does not match the version of QEMUGL. Please update the QEMUGL!\n");
271                                 exit (1);
272                         }
273                         else
274                                 *(int*)r_buffer = GLINIT_QUEUE; // Indicate that we can buffer commands
275
276                         return 1; // Initialisation done
277                 }
278                 else {
279                         DEBUGF("Attempt to init twice. Continuing regardless.\n");
280                         return 1;
281                 }
282         }
283
284         if(unlikely(first_func == -1 || !cur_process->wordsize)) {
285                 if(!cur_process->wordsize && first_func != -1)
286                         DEBUGF("commands submitted before process init.\n");
287                 ret = 0;
288         }
289         else {
290                 ret = do_decode_call_int(cur_process, in_args, args_len, r_buffer);
291         }
292
293         if(!ret)
294                 cur_process = NULL;
295
296         return ret;
297 }