2 * Host-side implementation of GL/GLX API
4 * Copyright (c) 2006,2007 Even Rouault
6 * Gordon Williams <gordon.williams@collabora.co.uk>
7 * Ian Molton <ian.molton@collabora.co.uk>
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:
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
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
28 #define _XOPEN_SOURCE 600
34 #include "opengl_func.h"
35 #include "opengl_process.h"
36 #include "opengl_exec.h"
38 #include "tizen/src/debug_ch.h"
39 MULTI_DEBUG_CHANNEL(qemu, opengl);
44 #define DEBUGF(...) printf(__VA_ARGS__)
46 extern struct FILE *stderr; /* Standard error output stream. */
47 #define DEBUGF(...) fprintf(stderr, __VA_ARGS__)
51 /* do_decode_call_int()
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.
59 typedef unsigned long host_ptr;
61 static inline int do_decode_call_int(ProcessStruct *process, void *args_in, int args_len, char *r_buffer)
66 static void* args[50];
77 while((char*)argptr < (char*)args_in + args_len) {
78 func_number = *(short*)argptr;
81 if(func_number >= GL_N_CALLS) {
82 DEBUGF("Bad function number or corrupt command queue\n");
86 signature = (Signature *) tab_opengl_calls[func_number];
90 for (i = 0; i < signature->nb_args; i++) {
91 int args_size = *(int*)argptr;
93 switch (signature->args_type[i]) {
94 case TYPE_UNSIGNED_INT:
96 case TYPE_UNSIGNED_CHAR:
98 case TYPE_UNSIGNED_SHORT:
101 args[i] = *(int*)argptr;
104 case TYPE_NULL_TERMINATED_STRING:
105 CASE_IN_UNKNOWN_SIZE_POINTERS:
108 args[i] = (host_ptr)argptr+4;
110 args[i] = (host_ptr)NULL;
112 if ((args[i] == 0 && args_size == 0 &&
113 !IS_NULL_POINTER_OK_FOR_FUNC(func_number)) ||
114 (args[i] == 0 && args_size != 0))
121 CASE_IN_LENGTH_DEPENDING_ON_PREVIOUS_ARGS:
124 args[i] = (host_ptr)argptr+4;
126 args[i] = (host_ptr)NULL;
128 if (args[i] == 0 && args_size != 0)
137 /* NULL pointer is used as output pointer
138 since the argument size is zero. */
139 if (args_size == 0) {
143 /*On MAC OS, GL call glGetProgramInfoLog and glGetShaderInfoLog will crash if ouput pointer is NULL*/
148 } else if(*(int*)argptr) {
149 *(int*)r_buffer = args_size;
151 args[i] = (host_ptr)r_buffer;
152 r_buffer += args_size;
164 CASE_IN_KNOWN_SIZE_POINTERS:
167 args[i] = (host_ptr)argptr+4;
169 args[i] = (host_ptr)NULL;
171 if (args[i] == 0 && args_size != 0)
178 case TYPE_IN_IGNORED_POINTER:
183 DEBUGF( "Oops : call %s arg %d pid=%d\n",
184 tab_opengl_calls_name[func_number], i,
185 process->process_id);
191 if((char*)argptr > (char*)args_in + args_len) {
192 DEBUGF("Client bug: malformed command, killing process\n");
196 if (signature->ret_type == TYPE_CONST_CHAR)
197 r_buffer[0] = 0; // In case high bits are set.
199 ret = do_function_call(process, func_number, args, r_buffer);
200 switch(signature->ret_type) {
202 case TYPE_UNSIGNED_INT:
203 memcpy(r_buffer, &ret, sizeof(int));
206 case TYPE_UNSIGNED_CHAR:
207 *r_buffer = ret & 0xff;
209 case TYPE_CONST_CHAR:
213 DEBUGF("Unsupported GL API return type %i!\n", signature->ret_type);
218 switch(signature->ret_type) {
220 case TYPE_UNSIGNED_INT:
221 memcpy(r_buffer, &ret, sizeof(int));
224 case TYPE_UNSIGNED_CHAR:
225 *r_buffer = ret & 0xff;
227 case TYPE_CONST_CHAR:
231 DEBUGF("Unsupported GL API return type %i!\n", signature->ret_type);
237 #define GL_PASSINGTHROUGH_ABI 1
239 #define GLINIT_FAIL_ABI 3
240 #define GLINIT_QUEUE 2
241 #define GLINIT_NOQUEUE 1
243 int decode_call_int(ProcessStruct *process, char *in_args, int args_len, char *r_buffer)
245 static ProcessStruct *cur_process = NULL;
247 int first_func = *(short*)in_args;
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
254 if (cur_process != process) {
255 cur_process = process;
256 vmgl_context_switch(cur_process, (first_func == glXMakeCurrent_func)?0:1);
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;
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");
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");
274 *(int*)r_buffer = GLINIT_QUEUE; // Indicate that we can buffer commands
276 return 1; // Initialisation done
279 DEBUGF("Attempt to init twice. Continuing regardless.\n");
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");
290 ret = do_decode_call_int(cur_process, in_args, args_len, r_buffer);