1/* 2 * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) 3 * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice including the dates of first publication and 13 * either this permission notice or a reference to 14 * http://oss.sgi.com/projects/FreeB/ 15 * shall be included in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 22 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. 24 * 25 * Except as contained in this notice, the name of Silicon Graphics, Inc. 26 * shall not be used in advertising or otherwise to promote the sale, use or 27 * other dealings in this Software without prior written authorization from 28 * Silicon Graphics, Inc. 29 */ 30 31#ifdef HAVE_DIX_CONFIG_H 32#include <dix-config.h> 33#endif 34 35#include <string.h> 36#include <stdio.h> 37#include <stdlib.h> 38 39#include "glxserver.h" 40#include "glxutil.h" 41#include "glxext.h" 42#include "indirect_dispatch.h" 43#include "unpack.h" 44#include "glapitable.h" 45#include "glapi.h" 46#include "glthread.h" 47#include "dispatch.h" 48 49int __glXDisp_FeedbackBuffer(__GLXclientState *cl, GLbyte *pc) 50{ 51 ClientPtr client = cl->client; 52 GLsizei size; 53 GLenum type; 54 __GLXcontext *cx; 55 int error; 56 57 REQUEST_FIXED_SIZE(xGLXSingleReq, 8); 58 59 cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); 60 if (!cx) { 61 return error; 62 } 63 64 pc += __GLX_SINGLE_HDR_SIZE; 65 size = *(GLsizei *)(pc+0); 66 type = *(GLenum *)(pc+4); 67 if (cx->feedbackBufSize < size) { 68 cx->feedbackBuf = (GLfloat *) realloc(cx->feedbackBuf, 69 (size_t)size 70 * __GLX_SIZE_FLOAT32); 71 if (!cx->feedbackBuf) { 72 cl->client->errorValue = size; 73 return BadAlloc; 74 } 75 cx->feedbackBufSize = size; 76 } 77 CALL_FeedbackBuffer( GET_DISPATCH(), (size, type, cx->feedbackBuf) ); 78 __GLX_NOTE_UNFLUSHED_CMDS(cx); 79 return Success; 80} 81 82int __glXDisp_SelectBuffer(__GLXclientState *cl, GLbyte *pc) 83{ 84 ClientPtr client = cl->client; 85 __GLXcontext *cx; 86 GLsizei size; 87 int error; 88 89 REQUEST_FIXED_SIZE(xGLXSingleReq, 4); 90 91 cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); 92 if (!cx) { 93 return error; 94 } 95 96 pc += __GLX_SINGLE_HDR_SIZE; 97 size = *(GLsizei *)(pc+0); 98 if (cx->selectBufSize < size) { 99 cx->selectBuf = (GLuint *) realloc(cx->selectBuf, 100 (size_t) size 101 * __GLX_SIZE_CARD32); 102 if (!cx->selectBuf) { 103 cl->client->errorValue = size; 104 return BadAlloc; 105 } 106 cx->selectBufSize = size; 107 } 108 CALL_SelectBuffer( GET_DISPATCH(), (size, cx->selectBuf) ); 109 __GLX_NOTE_UNFLUSHED_CMDS(cx); 110 return Success; 111} 112 113int __glXDisp_RenderMode(__GLXclientState *cl, GLbyte *pc) 114{ 115 ClientPtr client = cl->client; 116 xGLXRenderModeReply reply; 117 __GLXcontext *cx; 118 GLint nitems=0, retBytes=0, retval, newModeCheck; 119 GLubyte *retBuffer = NULL; 120 GLenum newMode; 121 int error; 122 123 REQUEST_FIXED_SIZE(xGLXSingleReq, 4); 124 125 cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); 126 if (!cx) { 127 return error; 128 } 129 130 pc += __GLX_SINGLE_HDR_SIZE; 131 newMode = *(GLenum*) pc; 132 retval = CALL_RenderMode( GET_DISPATCH(), (newMode) ); 133 134 /* Check that render mode worked */ 135 CALL_GetIntegerv( GET_DISPATCH(), (GL_RENDER_MODE, &newModeCheck) ); 136 if (newModeCheck != newMode) { 137 /* Render mode change failed. Bail */ 138 newMode = newModeCheck; 139 goto noChangeAllowed; 140 } 141 142 /* 143 ** Render mode might have still failed if we get here. But in this 144 ** case we can't really tell, nor does it matter. If it did fail, it 145 ** will return 0, and thus we won't send any data across the wire. 146 */ 147 148 switch (cx->renderMode) { 149 case GL_RENDER: 150 cx->renderMode = newMode; 151 break; 152 case GL_FEEDBACK: 153 if (retval < 0) { 154 /* Overflow happened. Copy the entire buffer */ 155 nitems = cx->feedbackBufSize; 156 } else { 157 nitems = retval; 158 } 159 retBytes = nitems * __GLX_SIZE_FLOAT32; 160 retBuffer = (GLubyte*) cx->feedbackBuf; 161 cx->renderMode = newMode; 162 break; 163 case GL_SELECT: 164 if (retval < 0) { 165 /* Overflow happened. Copy the entire buffer */ 166 nitems = cx->selectBufSize; 167 } else { 168 GLuint *bp = cx->selectBuf; 169 GLint i; 170 171 /* 172 ** Figure out how many bytes of data need to be sent. Parse 173 ** the selection buffer to determine this fact as the 174 ** return value is the number of hits, not the number of 175 ** items in the buffer. 176 */ 177 nitems = 0; 178 i = retval; 179 while (--i >= 0) { 180 GLuint n; 181 182 /* Parse select data for this hit */ 183 n = *bp; 184 bp += 3 + n; 185 } 186 nitems = bp - cx->selectBuf; 187 } 188 retBytes = nitems * __GLX_SIZE_CARD32; 189 retBuffer = (GLubyte*) cx->selectBuf; 190 cx->renderMode = newMode; 191 break; 192 } 193 194 /* 195 ** First reply is the number of elements returned in the feedback or 196 ** selection array, as per the API for glRenderMode itself. 197 */ 198 noChangeAllowed:; 199 reply.length = nitems; 200 reply.type = X_Reply; 201 reply.sequenceNumber = client->sequence; 202 reply.retval = retval; 203 reply.size = nitems; 204 reply.newMode = newMode; 205 WriteToClient(client, sz_xGLXRenderModeReply, (char *)&reply); 206 if (retBytes) { 207 WriteToClient(client, retBytes, (char *)retBuffer); 208 } 209 return Success; 210} 211 212int __glXDisp_Flush(__GLXclientState *cl, GLbyte *pc) 213{ 214 ClientPtr client = cl->client; 215 __GLXcontext *cx; 216 int error; 217 218 REQUEST_SIZE_MATCH(xGLXSingleReq); 219 220 cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); 221 if (!cx) { 222 return error; 223 } 224 225 CALL_Flush( GET_DISPATCH(), () ); 226 __GLX_NOTE_FLUSHED_CMDS(cx); 227 return Success; 228} 229 230int __glXDisp_Finish(__GLXclientState *cl, GLbyte *pc) 231{ 232 ClientPtr client = cl->client; 233 __GLXcontext *cx; 234 int error; 235 236 REQUEST_SIZE_MATCH(xGLXSingleReq); 237 238 cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); 239 if (!cx) { 240 return error; 241 } 242 243 /* Do a local glFinish */ 244 CALL_Finish( GET_DISPATCH(), () ); 245 __GLX_NOTE_FLUSHED_CMDS(cx); 246 247 /* Send empty reply packet to indicate finish is finished */ 248 client = cl->client; 249 __GLX_BEGIN_REPLY(0); 250 __GLX_SEND_HEADER(); 251 return Success; 252} 253 254#define SEPARATOR " " 255 256char *__glXcombine_strings(const char *cext_string, const char *sext_string) 257{ 258 size_t clen, slen; 259 char *combo_string, *token, *s1; 260 const char *s2, *end; 261 262 /* safeguard to prevent potentially fatal errors in the string functions */ 263 if (!cext_string) 264 cext_string = ""; 265 if (!sext_string) 266 sext_string = ""; 267 268 /* 269 ** String can't be longer than min(cstring, sstring) 270 ** pull tokens out of shortest string 271 ** include space in combo_string for final separator and null terminator 272 */ 273 clen = strlen(cext_string); 274 slen = strlen(sext_string); 275 if (clen > slen) { 276 combo_string = (char *) malloc(slen + 2); 277 s1 = (char *) malloc(slen + 2); 278 if (s1) strcpy(s1, sext_string); 279 s2 = cext_string; 280 } else { 281 combo_string = (char *) malloc(clen + 2); 282 s1 = (char *) malloc(clen + 2); 283 if (s1) strcpy(s1, cext_string); 284 s2 = sext_string; 285 } 286 if (!combo_string || !s1) { 287 free(combo_string); 288 free(s1); 289 return NULL; 290 } 291 combo_string[0] = '\0'; 292 293 /* Get first extension token */ 294 token = strtok( s1, SEPARATOR); 295 while ( token != NULL ) { 296 297 /* 298 ** if token in second string then save it 299 ** beware of extension names which are prefixes of other extension names 300 */ 301 const char *p = s2; 302 end = p + strlen(p); 303 while (p < end) { 304 size_t n = strcspn(p, SEPARATOR); 305 if ((strlen(token) == n) && (strncmp(token, p, n) == 0)) { 306 combo_string = strcat(combo_string, token); 307 combo_string = strcat(combo_string, SEPARATOR); 308 } 309 p += (n + 1); 310 } 311 312 /* Get next extension token */ 313 token = strtok( NULL, SEPARATOR); 314 } 315 free(s1); 316 return combo_string; 317} 318 319int DoGetString(__GLXclientState *cl, GLbyte *pc, GLboolean need_swap) 320{ 321 ClientPtr client = cl->client; 322 __GLXcontext *cx; 323 GLenum name; 324 const char *string; 325 __GLX_DECLARE_SWAP_VARIABLES; 326 int error; 327 char *buf = NULL, *buf1 = NULL; 328 GLint length = 0; 329 330 REQUEST_FIXED_SIZE(xGLXSingleReq, 4); 331 332 /* If the client has the opposite byte order, swap the contextTag and 333 * the name. 334 */ 335 if ( need_swap ) { 336 __GLX_SWAP_INT(pc + 4); 337 __GLX_SWAP_INT(pc + __GLX_SINGLE_HDR_SIZE); 338 } 339 340 cx = __glXForceCurrent(cl, __GLX_GET_SINGLE_CONTEXT_TAG(pc), &error); 341 if (!cx) { 342 return error; 343 } 344 345 pc += __GLX_SINGLE_HDR_SIZE; 346 name = *(GLenum *)(pc + 0); 347 string = (const char *) CALL_GetString( GET_DISPATCH(), (name) ); 348 349 if (string == NULL) 350 string = ""; 351 352 /* 353 ** Restrict extensions to those that are supported by both the 354 ** implementation and the connection. That is, return the 355 ** intersection of client, server, and core extension strings. 356 */ 357 if (name == GL_EXTENSIONS) { 358 buf1 = __glXcombine_strings(string, 359 cl->GLClientextensions); 360 buf = __glXcombine_strings(buf1, 361 cx->pGlxScreen->GLextensions); 362 free(buf1); 363 string = buf; 364 } 365 else if ( name == GL_VERSION ) { 366 if ( atof( string ) > atof( GLServerVersion ) ) { 367 buf = malloc( strlen( string ) + strlen( GLServerVersion ) + 4 ); 368 if ( buf == NULL ) { 369 string = GLServerVersion; 370 } 371 else { 372 sprintf( buf, "%s (%s)", GLServerVersion, string ); 373 string = buf; 374 } 375 } 376 } 377 if (string) { 378 length = strlen((const char *) string) + 1; 379 } 380 381 __GLX_BEGIN_REPLY(length); 382 __GLX_PUT_SIZE(length); 383 384 if ( need_swap ) { 385 __GLX_SWAP_REPLY_SIZE(); 386 __GLX_SWAP_REPLY_HEADER(); 387 } 388 389 __GLX_SEND_HEADER(); 390 WriteToClient(client, length, (char *) string); 391 free(buf); 392 393 return Success; 394} 395 396int __glXDisp_GetString(__GLXclientState *cl, GLbyte *pc) 397{ 398 return DoGetString(cl, pc, GL_FALSE); 399} 400