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 * SPDX-License-Identifier: SGI-B-2.0
6 */
7
8 /**
9 * \file glxext.c
10 * GLX protocol interface boot-strap code.
11 *
12 * Direct rendering support added by Precision Insight, Inc.
13 *
14 * \author Kevin E. Martin <kevin@precisioninsight.com>
15 */
16
17 #include <assert.h>
18 #include <stdbool.h>
19 #include <stdarg.h>
20
21 #include "glxclient.h"
22 #include <X11/extensions/Xext.h>
23 #include <X11/extensions/extutil.h>
24 #ifdef GLX_USE_APPLEGL
25 #include "apple/apple_glx.h"
26 #include "apple/apple_visual.h"
27 #endif
28 #include "glxextensions.h"
29
30 #include "util/u_debug.h"
31 #if defined(GLX_DIRECT_RENDERING) && (!defined(GLX_USE_APPLEGL) || defined(GLX_USE_APPLE))
32 #include "dri_common.h"
33 #endif
34
35 #include "loader_x11.h"
36 #ifdef HAVE_LIBDRM
37 #include "loader_dri3_helper.h"
38 #endif
39
40 #include <X11/Xlib-xcb.h>
41 #include <xcb/xcb.h>
42 #include <xcb/glx.h>
43 #include "dri_util.h"
44 #include "pipe/p_screen.h"
45 #if defined(GLX_DIRECT_RENDERING) && (!defined(GLX_USE_APPLEGL) || defined(GLX_USE_APPLE))
46 #include <dlfcn.h>
47 #endif
48
49 #define __GLX_MIN_CONFIG_PROPS 18
50 #define __GLX_EXT_CONFIG_PROPS 32
51
52 /*
53 ** Since we send all non-core visual properties as token, value pairs,
54 ** we require 2 words across the wire. In order to maintain backwards
55 ** compatibility, we need to send the total number of words that the
56 ** VisualConfigs are sent back in so old libraries can simply "ignore"
57 ** the new properties.
58 */
59 #define __GLX_TOTAL_CONFIG \
60 (__GLX_MIN_CONFIG_PROPS + 2 * __GLX_EXT_CONFIG_PROPS)
61
62 _X_HIDDEN void
glx_message(int level,const char * f,...)63 glx_message(int level, const char *f, ...)
64 {
65 va_list args;
66 int threshold = _LOADER_WARNING;
67 const char *libgl_debug;
68
69 libgl_debug = getenv("LIBGL_DEBUG");
70 if (libgl_debug) {
71 if (strstr(libgl_debug, "quiet"))
72 threshold = _LOADER_FATAL;
73 else if (strstr(libgl_debug, "verbose"))
74 threshold = _LOADER_DEBUG;
75 }
76
77 /* Note that the _LOADER_* levels are lower numbers for more severe. */
78 if (level <= threshold) {
79 va_start(args, f);
80 vfprintf(stderr, f, args);
81 va_end(args);
82 }
83 }
84
85 /*
86 ** You can set this cell to 1 to force the gl drawing stuff to be
87 ** one command per packet
88 */
89 _X_HIDDEN int __glXDebug = 0;
90
91 /* Extension required boiler plate */
92
93 static const char __glXExtensionName[] = GLX_EXTENSION_NAME;
94 static struct glx_display *glx_displays;
95
96 static /* const */ char *error_list[] = {
97 "GLXBadContext",
98 "GLXBadContextState",
99 "GLXBadDrawable",
100 "GLXBadPixmap",
101 "GLXBadContextTag",
102 "GLXBadCurrentWindow",
103 "GLXBadRenderRequest",
104 "GLXBadLargeRequest",
105 "GLXUnsupportedPrivateRequest",
106 "GLXBadFBConfig",
107 "GLXBadPbuffer",
108 "GLXBadCurrentDrawable",
109 "GLXBadWindow",
110 "GLXBadProfileARB",
111 };
112
113 #ifdef GLX_USE_APPLEGL
114 static char *__glXErrorString(Display *dpy, int code, XExtCodes *codes,
115 char *buf, int n);
116 #endif
117
118 static
XEXT_GENERATE_ERROR_STRING(__glXErrorString,__glXExtensionName,__GLX_NUMBER_ERRORS,error_list)119 XEXT_GENERATE_ERROR_STRING(__glXErrorString, __glXExtensionName,
120 __GLX_NUMBER_ERRORS, error_list)
121
122 /*
123 * GLX events are a bit funky. We don't stuff the X event code into
124 * our user exposed (via XNextEvent) structure. Instead we use the GLX
125 * private event code namespace (and hope it doesn't conflict). Clients
126 * have to know that bit 15 in the event type field means they're getting
127 * a GLX event, and then handle the various sub-event types there, rather
128 * than simply checking the event code and handling it directly.
129 */
130
131 static Bool
132 __glXWireToEvent(Display *dpy, XEvent *event, xEvent *wire)
133 {
134 struct glx_display *glx_dpy = __glXInitialize(dpy);
135
136 if (glx_dpy == NULL)
137 return False;
138
139 switch ((wire->u.u.type & 0x7f) - glx_dpy->codes.first_event) {
140 case GLX_PbufferClobber:
141 {
142 GLXPbufferClobberEvent *aevent = (GLXPbufferClobberEvent *)event;
143 xGLXPbufferClobberEvent *awire = (xGLXPbufferClobberEvent *)wire;
144 aevent->event_type = awire->event_type;
145 aevent->serial = awire->sequenceNumber;
146 aevent->draw_type = awire->draw_type;
147 aevent->drawable = awire->drawable;
148 aevent->buffer_mask = awire->buffer_mask;
149 aevent->aux_buffer = awire->aux_buffer;
150 aevent->x = awire->x;
151 aevent->y = awire->y;
152 aevent->width = awire->width;
153 aevent->height = awire->height;
154 aevent->count = awire->count;
155 return True;
156 }
157 case GLX_BufferSwapComplete:
158 {
159 GLXBufferSwapComplete *aevent = (GLXBufferSwapComplete *)event;
160 xGLXBufferSwapComplete2 *awire = (xGLXBufferSwapComplete2 *)wire;
161 struct glx_drawable *glxDraw = GetGLXDrawable(dpy, awire->drawable);
162
163 if (!glxDraw)
164 return False;
165
166 aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
167 aevent->send_event = (awire->type & 0x80) != 0;
168 aevent->display = dpy;
169 aevent->event_type = awire->event_type;
170 aevent->drawable = glxDraw->xDrawable;
171 aevent->ust = ((CARD64)awire->ust_hi << 32) | awire->ust_lo;
172 aevent->msc = ((CARD64)awire->msc_hi << 32) | awire->msc_lo;
173
174 /* Handle 32-Bit wire sbc wraparound in both directions to cope with out
175 * of sequence 64-Bit sbc's
176 */
177 if ((int64_t) awire->sbc < ((int64_t) glxDraw->lastEventSbc - 0x40000000))
178 glxDraw->eventSbcWrap += 0x100000000;
179 if ((int64_t) awire->sbc > ((int64_t) glxDraw->lastEventSbc + 0x40000000))
180 glxDraw->eventSbcWrap -= 0x100000000;
181 glxDraw->lastEventSbc = awire->sbc;
182 aevent->sbc = awire->sbc + glxDraw->eventSbcWrap;
183 return True;
184 }
185 default:
186 /* client doesn't support server event */
187 break;
188 }
189
190 return False;
191 }
192
193 /* We don't actually support this. It doesn't make sense for clients to
194 * send each other GLX events.
195 */
196 static Status
__glXEventToWire(Display * dpy,XEvent * event,xEvent * wire)197 __glXEventToWire(Display *dpy, XEvent *event, xEvent *wire)
198 {
199 struct glx_display *glx_dpy = __glXInitialize(dpy);
200
201 if (glx_dpy == NULL)
202 return False;
203
204 switch (event->type) {
205 case GLX_DAMAGED:
206 break;
207 case GLX_SAVED:
208 break;
209 case GLX_EXCHANGE_COMPLETE_INTEL:
210 break;
211 case GLX_COPY_COMPLETE_INTEL:
212 break;
213 case GLX_FLIP_COMPLETE_INTEL:
214 break;
215 default:
216 /* client doesn't support server event */
217 break;
218 }
219
220 return Success;
221 }
222
223 /************************************************************************/
224 /*
225 ** Free the per screen configs data as well as the array of
226 ** __glXScreenConfigs.
227 */
228 static void
FreeScreenConfigs(struct glx_display * priv)229 FreeScreenConfigs(struct glx_display * priv)
230 {
231 struct glx_screen *psc;
232 GLint i, screens;
233
234 /* Free screen configuration information */
235 screens = ScreenCount(priv->dpy);
236 for (i = 0; i < screens; i++) {
237 psc = priv->screens[i];
238 if (!psc)
239 continue;
240 glx_screen_cleanup(psc);
241
242 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
243 if (psc->driScreen.deinitScreen)
244 psc->driScreen.deinitScreen(psc);
245 /* Free the direct rendering per screen data */
246 driDestroyScreen(psc->frontend_screen);
247 #endif
248 free(psc);
249 }
250 free((char *) priv->screens);
251 priv->screens = NULL;
252 }
253
254 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
255 static void
free_zombie_glx_drawable(struct set_entry * entry)256 free_zombie_glx_drawable(struct set_entry *entry)
257 {
258 __GLXDRIdrawable *pdraw = (__GLXDRIdrawable *)entry->key;
259
260 pdraw->destroyDrawable(pdraw);
261 }
262 #endif
263
264 static void
glx_display_free(struct glx_display * priv)265 glx_display_free(struct glx_display *priv)
266 {
267 struct glx_context *gc;
268
269 gc = __glXGetCurrentContext();
270 if (priv->dpy == gc->currentDpy) {
271 if (gc != &dummyContext)
272 gc->vtable->unbind(gc);
273
274 gc->vtable->destroy(gc);
275 __glXSetCurrentContextNull();
276 }
277
278 /* Needs to be done before free screen. */
279 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
280 _mesa_set_destroy(priv->zombieGLXDrawable, free_zombie_glx_drawable);
281 #endif
282
283 FreeScreenConfigs(priv);
284
285 __glxHashDestroy(priv->glXDrawHash);
286
287 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
288 __glxHashDestroy(priv->drawHash);
289 if (priv->dri2Hash)
290 __glxHashDestroy(priv->dri2Hash);
291
292 #endif /* GLX_DIRECT_RENDERING && !GLX_USE_APPLEGL */
293
294 free((char *) priv);
295 }
296
297 static int
__glXCloseDisplay(Display * dpy,XExtCodes * codes)298 __glXCloseDisplay(Display * dpy, XExtCodes * codes)
299 {
300 struct glx_display *priv, **prev;
301
302 _XLockMutex(_Xglobal_lock);
303 prev = &glx_displays;
304 for (priv = glx_displays; priv; prev = &priv->next, priv = priv->next) {
305 if (priv->dpy == dpy) {
306 *prev = priv->next;
307 break;
308 }
309 }
310 _XUnlockMutex(_Xglobal_lock);
311
312 if (priv != NULL)
313 glx_display_free(priv);
314
315 return 1;
316 }
317
318 /*
319 ** Query the version of the GLX extension. This procedure works even if
320 ** the client extension is not completely set up.
321 */
322 static Bool
QueryVersion(Display * dpy,int opcode,int * major,int * minor)323 QueryVersion(Display * dpy, int opcode, int *major, int *minor)
324 {
325 xcb_connection_t *c = XGetXCBConnection(dpy);
326 xcb_glx_query_version_reply_t *reply = xcb_glx_query_version_reply(c,
327 xcb_glx_query_version
328 (c,
329 GLX_MAJOR_VERSION,
330 GLX_MINOR_VERSION),
331 NULL);
332
333 if (!reply)
334 return GL_FALSE;
335
336 if (reply->major_version != GLX_MAJOR_VERSION) {
337 free(reply);
338 return GL_FALSE;
339 }
340 *major = reply->major_version;
341 *minor = min(reply->minor_version, GLX_MINOR_VERSION);
342 free(reply);
343 return GL_TRUE;
344 }
345
346 /*
347 * We don't want to enable this GLX_OML_swap_method in glxext.h,
348 * because we can't support it. The X server writes it out though,
349 * so we should handle it somehow, to avoid false warnings.
350 */
351 enum {
352 IGNORE_GLX_SWAP_METHOD_OML = 0x8060
353 };
354
355
356 static GLint
convert_from_x_visual_type(int visualType)357 convert_from_x_visual_type(int visualType)
358 {
359 static const int glx_visual_types[] = {
360 [StaticGray] = GLX_STATIC_GRAY,
361 [GrayScale] = GLX_GRAY_SCALE,
362 [StaticColor] = GLX_STATIC_COLOR,
363 [PseudoColor] = GLX_PSEUDO_COLOR,
364 [TrueColor] = GLX_TRUE_COLOR,
365 [DirectColor] = GLX_DIRECT_COLOR,
366 };
367
368 if (visualType < ARRAY_SIZE(glx_visual_types))
369 return glx_visual_types[visualType];
370
371 return GLX_NONE;
372 }
373
374 /*
375 * getVisualConfigs uses the !tagged_only path.
376 * getFBConfigs uses the tagged_only path.
377 */
378 _X_HIDDEN void
__glXInitializeVisualConfigFromTags(struct glx_config * config,int count,const INT32 * bp,Bool tagged_only,Bool fbconfig_style_tags)379 __glXInitializeVisualConfigFromTags(struct glx_config * config, int count,
380 const INT32 * bp, Bool tagged_only,
381 Bool fbconfig_style_tags)
382 {
383 int i;
384
385 if (!tagged_only) {
386 /* Copy in the first set of properties */
387 config->visualID = *bp++;
388
389 config->visualType = convert_from_x_visual_type(*bp++);
390
391 config->renderType = *bp++ ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT;
392
393 config->redBits = *bp++;
394 config->greenBits = *bp++;
395 config->blueBits = *bp++;
396 config->alphaBits = *bp++;
397 config->accumRedBits = *bp++;
398 config->accumGreenBits = *bp++;
399 config->accumBlueBits = *bp++;
400 config->accumAlphaBits = *bp++;
401
402 config->doubleBufferMode = *bp++;
403 config->stereoMode = *bp++;
404
405 config->rgbBits = *bp++;
406 config->depthBits = *bp++;
407 config->stencilBits = *bp++;
408 config->numAuxBuffers = *bp++;
409 config->level = *bp++;
410
411 #ifdef GLX_USE_APPLEGL
412 /* AppleSGLX supports pixmap and pbuffers with all config. */
413 config->drawableType = GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT;
414 /* Unfortunately this can create an ABI compatibility problem. */
415 count -= 18;
416 #else
417 count -= __GLX_MIN_CONFIG_PROPS;
418 #endif
419 }
420
421 /*
422 ** Additional properties may be in a list at the end
423 ** of the reply. They are in pairs of property type
424 ** and property value.
425 */
426
427 #define FETCH_OR_SET(tag) \
428 config-> tag = ( fbconfig_style_tags ) ? *bp++ : 1
429
430 for (i = 0; i < count; i += 2) {
431 long int tag = *bp++;
432
433 switch (tag) {
434 case GLX_RGBA:
435 if (fbconfig_style_tags)
436 config->renderType = *bp++ ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT;
437 else
438 config->renderType = GLX_RGBA_BIT;
439 break;
440 case GLX_BUFFER_SIZE:
441 config->rgbBits = *bp++;
442 break;
443 case GLX_LEVEL:
444 config->level = *bp++;
445 break;
446 case GLX_DOUBLEBUFFER:
447 FETCH_OR_SET(doubleBufferMode);
448 break;
449 case GLX_STEREO:
450 FETCH_OR_SET(stereoMode);
451 break;
452 case GLX_AUX_BUFFERS:
453 config->numAuxBuffers = *bp++;
454 break;
455 case GLX_RED_SIZE:
456 config->redBits = *bp++;
457 break;
458 case GLX_GREEN_SIZE:
459 config->greenBits = *bp++;
460 break;
461 case GLX_BLUE_SIZE:
462 config->blueBits = *bp++;
463 break;
464 case GLX_ALPHA_SIZE:
465 config->alphaBits = *bp++;
466 break;
467 case GLX_DEPTH_SIZE:
468 config->depthBits = *bp++;
469 break;
470 case GLX_STENCIL_SIZE:
471 config->stencilBits = *bp++;
472 break;
473 case GLX_ACCUM_RED_SIZE:
474 config->accumRedBits = *bp++;
475 break;
476 case GLX_ACCUM_GREEN_SIZE:
477 config->accumGreenBits = *bp++;
478 break;
479 case GLX_ACCUM_BLUE_SIZE:
480 config->accumBlueBits = *bp++;
481 break;
482 case GLX_ACCUM_ALPHA_SIZE:
483 config->accumAlphaBits = *bp++;
484 break;
485 case GLX_VISUAL_CAVEAT_EXT:
486 config->visualRating = *bp++;
487 break;
488 case GLX_X_VISUAL_TYPE:
489 config->visualType = *bp++;
490 break;
491 case GLX_TRANSPARENT_TYPE:
492 config->transparentPixel = *bp++;
493 break;
494 case GLX_TRANSPARENT_INDEX_VALUE:
495 config->transparentIndex = *bp++;
496 break;
497 case GLX_TRANSPARENT_RED_VALUE:
498 config->transparentRed = *bp++;
499 break;
500 case GLX_TRANSPARENT_GREEN_VALUE:
501 config->transparentGreen = *bp++;
502 break;
503 case GLX_TRANSPARENT_BLUE_VALUE:
504 config->transparentBlue = *bp++;
505 break;
506 case GLX_TRANSPARENT_ALPHA_VALUE:
507 config->transparentAlpha = *bp++;
508 break;
509 case GLX_VISUAL_ID:
510 config->visualID = *bp++;
511 break;
512 case GLX_DRAWABLE_TYPE:
513 config->drawableType = *bp++;
514 #ifdef GLX_USE_APPLEGL
515 /* AppleSGLX supports pixmap and pbuffers with all config. */
516 config->drawableType |= GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT;
517 #endif
518 break;
519 case GLX_RENDER_TYPE: /* fbconfig render type bits */
520 config->renderType = *bp++;
521 break;
522 case GLX_X_RENDERABLE:
523 config->xRenderable = *bp++;
524 break;
525 case GLX_FBCONFIG_ID:
526 config->fbconfigID = *bp++;
527 break;
528 case GLX_MAX_PBUFFER_WIDTH:
529 config->maxPbufferWidth = *bp++;
530 break;
531 case GLX_MAX_PBUFFER_HEIGHT:
532 config->maxPbufferHeight = *bp++;
533 break;
534 case GLX_MAX_PBUFFER_PIXELS:
535 config->maxPbufferPixels = *bp++;
536 break;
537 #ifndef GLX_USE_APPLEGL
538 case GLX_OPTIMAL_PBUFFER_WIDTH_SGIX:
539 config->optimalPbufferWidth = *bp++;
540 break;
541 case GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX:
542 config->optimalPbufferHeight = *bp++;
543 break;
544 case GLX_VISUAL_SELECT_GROUP_SGIX:
545 config->visualSelectGroup = *bp++;
546 break;
547 #endif
548 case GLX_SAMPLE_BUFFERS_SGIS:
549 config->sampleBuffers = *bp++;
550 break;
551 case GLX_SAMPLES_SGIS:
552 config->samples = *bp++;
553 break;
554 case IGNORE_GLX_SWAP_METHOD_OML:
555 /* We ignore this tag. See the comment above this function. */
556 ++bp;
557 break;
558 #ifndef GLX_USE_APPLEGL
559 case GLX_BIND_TO_TEXTURE_RGB_EXT:
560 config->bindToTextureRgb = *bp++;
561 break;
562 case GLX_BIND_TO_TEXTURE_RGBA_EXT:
563 config->bindToTextureRgba = *bp++;
564 break;
565 case GLX_BIND_TO_MIPMAP_TEXTURE_EXT:
566 config->bindToMipmapTexture = *bp++;
567 break;
568 case GLX_BIND_TO_TEXTURE_TARGETS_EXT:
569 config->bindToTextureTargets = *bp++;
570 break;
571 case GLX_Y_INVERTED_EXT:
572 config->yInverted = *bp++;
573 break;
574 #endif
575 case GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT:
576 config->sRGBCapable = *bp++;
577 break;
578
579 case GLX_USE_GL:
580 if (fbconfig_style_tags)
581 bp++;
582 break;
583 case GLX_FLOAT_COMPONENTS_NV:
584 config->floatComponentsNV = *bp++;
585 break;
586 case None:
587 i = count;
588 break;
589 default: {
590 long int tagvalue = *bp++;
591 DebugMessageF("WARNING: unknown fbconfig attribute from server: "
592 "tag 0x%lx value 0x%lx\n", tag, tagvalue);
593 break;
594 }
595 }
596 }
597 }
598
599 static struct glx_config *
createConfigsFromProperties(Display * dpy,int nvisuals,int nprops,int screen,GLboolean tagged_only)600 createConfigsFromProperties(Display * dpy, int nvisuals, int nprops,
601 int screen, GLboolean tagged_only)
602 {
603 INT32 buf[__GLX_TOTAL_CONFIG], *props;
604 unsigned prop_size;
605 struct glx_config *modes, *m;
606 int i;
607
608 if (nprops == 0)
609 return NULL;
610
611 /* Check number of properties */
612 if (nprops < __GLX_MIN_CONFIG_PROPS)
613 return NULL;
614
615 /* Allocate memory for our config structure */
616 modes = glx_config_create_list(nvisuals);
617 if (!modes)
618 return NULL;
619
620 prop_size = nprops * __GLX_SIZE_INT32;
621 if (prop_size <= sizeof(buf))
622 props = buf;
623 else
624 props = malloc(prop_size);
625
626 /* Read each config structure and convert it into our format */
627 m = modes;
628 for (i = 0; i < nvisuals; i++) {
629 _XRead(dpy, (char *) props, prop_size);
630 /* If this is GLXGetVisualConfigs then the reply will not include
631 * any drawable type info, but window support is implied because
632 * that's what a Visual describes, and pixmap support is implied
633 * because you almost certainly have a pixmap format corresponding
634 * to your visual format.
635 */
636 if (!tagged_only)
637 m->drawableType = GLX_WINDOW_BIT | GLX_PIXMAP_BIT;
638 __glXInitializeVisualConfigFromTags(m, nprops, props,
639 tagged_only, GL_TRUE);
640 m->screen = screen;
641 m = m->next;
642 }
643
644 if (props != buf)
645 free(props);
646
647 return modes;
648 }
649
650 static GLboolean
getVisualConfigs(struct glx_screen * psc,struct glx_display * priv,int screen)651 getVisualConfigs(struct glx_screen *psc,
652 struct glx_display *priv, int screen)
653 {
654 xGLXGetVisualConfigsReq *req;
655 xGLXGetVisualConfigsReply reply;
656 Display *dpy = priv->dpy;
657
658 LockDisplay(dpy);
659
660 psc->visuals = NULL;
661 GetReq(GLXGetVisualConfigs, req);
662 req->reqType = priv->codes.major_opcode;
663 req->glxCode = X_GLXGetVisualConfigs;
664 req->screen = screen;
665
666 if (!_XReply(dpy, (xReply *) & reply, 0, False))
667 goto out;
668
669 psc->visuals = createConfigsFromProperties(dpy,
670 reply.numVisuals,
671 reply.numProps,
672 screen, GL_FALSE);
673
674 out:
675 UnlockDisplay(dpy);
676 return psc->visuals != NULL;
677 }
678
679 static GLboolean
getFBConfigs(struct glx_screen * psc,struct glx_display * priv,int screen)680 getFBConfigs(struct glx_screen *psc, struct glx_display *priv, int screen)
681 {
682 xGLXGetFBConfigsReq *fb_req;
683 xGLXGetFBConfigsReply reply;
684 Display *dpy = priv->dpy;
685
686 psc->serverGLXexts = __glXQueryServerString(dpy, screen, GLX_EXTENSIONS);
687
688 if (psc->serverGLXexts == NULL) {
689 return GL_FALSE;
690 }
691
692 LockDisplay(dpy);
693
694 psc->configs = NULL;
695 GetReq(GLXGetFBConfigs, fb_req);
696 fb_req->reqType = priv->codes.major_opcode;
697 fb_req->glxCode = X_GLXGetFBConfigs;
698 fb_req->screen = screen;
699
700 if (!_XReply(dpy, (xReply *) & reply, 0, False))
701 goto out;
702
703 psc->configs = createConfigsFromProperties(dpy,
704 reply.numFBConfigs,
705 reply.numAttribs * 2,
706 screen, GL_TRUE);
707
708 out:
709 UnlockDisplay(dpy);
710 return psc->configs != NULL;
711 }
712
713 _X_HIDDEN Bool
glx_screen_init(struct glx_screen * psc,int screen,struct glx_display * priv)714 glx_screen_init(struct glx_screen *psc,
715 int screen, struct glx_display * priv)
716 {
717 /* Initialize per screen dynamic client GLX extensions */
718 psc->ext_list_first_time = GL_TRUE;
719 psc->scr = screen;
720 psc->dpy = priv->dpy;
721 psc->display = priv;
722
723 if (!getVisualConfigs(psc, priv, screen))
724 return GL_FALSE;
725
726 if (!getFBConfigs(psc, priv, screen))
727 return GL_FALSE;
728
729 return GL_TRUE;
730 }
731
732 _X_HIDDEN void
glx_screen_cleanup(struct glx_screen * psc)733 glx_screen_cleanup(struct glx_screen *psc)
734 {
735 if (psc->configs) {
736 glx_config_destroy_list(psc->configs);
737 free(psc->effectiveGLXexts);
738 psc->configs = NULL; /* NOTE: just for paranoia */
739 }
740 if (psc->visuals) {
741 glx_config_destroy_list(psc->visuals);
742 psc->visuals = NULL; /* NOTE: just for paranoia */
743 }
744 #if defined(GLX_DIRECT_RENDERING) && (!defined(GLX_USE_APPLEGL) || defined(GLX_USE_APPLE))
745 if (psc->driver_configs) {
746 driDestroyConfigs(psc->driver_configs);
747 psc->driver_configs = NULL;
748 }
749 #endif
750 free((char *) psc->serverGLXexts);
751 free((char *) psc->serverGLXvendor);
752 free((char *) psc->serverGLXversion);
753 free(psc->driverName);
754 }
755
756 static void
bind_extensions(struct glx_screen * psc,const char * driverName)757 bind_extensions(struct glx_screen *psc, const char *driverName)
758 {
759 unsigned mask;
760
761 if (psc->display->driver != GLX_DRIVER_SW) {
762 __glXEnableDirectExtension(psc, "GLX_EXT_buffer_age");
763 __glXEnableDirectExtension(psc, "GLX_EXT_swap_control");
764 __glXEnableDirectExtension(psc, "GLX_SGI_swap_control");
765 __glXEnableDirectExtension(psc, "GLX_MESA_swap_control");
766 __glXEnableDirectExtension(psc, "GLX_OML_sync_control");
767 __glXEnableDirectExtension(psc, "GLX_SGI_video_sync");
768 // for zink this needs to check whether RELAXED is available
769 if (psc->display->driver == GLX_DRIVER_DRI3)
770 __glXEnableDirectExtension(psc, "GLX_EXT_swap_control_tear");
771 }
772 if (psc->display->driver != GLX_DRIVER_ZINK_YES)
773 __glXEnableDirectExtension(psc, "GLX_MESA_copy_sub_buffer");
774 __glXEnableDirectExtension(psc, "GLX_SGI_make_current_read");
775
776 if (psc->can_EXT_texture_from_pixmap)
777 __glXEnableDirectExtension(psc, "GLX_EXT_texture_from_pixmap");
778
779 /*
780 * GLX_INTEL_swap_event is broken on the server side, where it's
781 * currently unconditionally enabled. This completely breaks
782 * systems running on drivers which don't support that extension.
783 * There's no way to test for its presence on this side, so instead
784 * of disabling it unconditionally, just disable it for drivers
785 * which are known to not support it.
786 *
787 * This was fixed in xserver 1.15.0 (190b03215), so now we only
788 * disable the broken driver.
789 */
790 if (!driverName || strcmp(driverName, "vmwgfx") != 0) {
791 __glXEnableDirectExtension(psc, "GLX_INTEL_swap_event");
792 }
793
794 #if defined(GLX_DIRECT_RENDERING) && (!defined(GLX_USE_APPLEGL) || defined(GLX_USE_APPLE))
795 mask = driGetAPIMask(psc->frontend_screen);
796
797 __glXEnableDirectExtension(psc, "GLX_ARB_create_context");
798 __glXEnableDirectExtension(psc, "GLX_ARB_create_context_profile");
799 __glXEnableDirectExtension(psc, "GLX_ARB_create_context_no_error");
800 __glXEnableDirectExtension(psc, "GLX_EXT_no_config_context");
801
802 if ((mask & ((1 << __DRI_API_GLES) |
803 (1 << __DRI_API_GLES2) |
804 (1 << __DRI_API_GLES3))) != 0) {
805 __glXEnableDirectExtension(psc,
806 "GLX_EXT_create_context_es_profile");
807 __glXEnableDirectExtension(psc,
808 "GLX_EXT_create_context_es2_profile");
809 }
810
811 if (dri_get_pipe_screen(psc->frontend_screen)->caps.device_reset_status_query)
812 __glXEnableDirectExtension(psc,
813 "GLX_ARB_create_context_robustness");
814
815 __glXEnableDirectExtension(psc, "GLX_ARB_context_flush_control");
816 __glXEnableDirectExtension(psc, "GLX_MESA_query_renderer");
817
818 __glXEnableDirectExtension(psc, "GLX_MESA_gl_interop");
819
820 char *tmp;
821 if (dri2GalliumConfigQuerys(psc->frontend_screen, "glx_extension_override",
822 &tmp) == 0)
823 __glXParseExtensionOverride(psc, tmp);
824
825 if (dri2GalliumConfigQuerys(psc->frontend_screen,
826 "indirect_gl_extension_override",
827 &tmp) == 0)
828 __IndirectGlParseExtensionOverride(psc, tmp);
829
830 {
831 uint8_t force = false;
832 if (dri2GalliumConfigQueryb(psc->frontend_screen, "force_direct_glx_context",
833 &force) == 0) {
834 psc->force_direct_context = force;
835 }
836
837 uint8_t invalid_glx_destroy_window = false;
838 if (dri2GalliumConfigQueryb(psc->frontend_screen,
839 "allow_invalid_glx_destroy_window",
840 &invalid_glx_destroy_window) == 0) {
841 psc->allow_invalid_glx_destroy_window = invalid_glx_destroy_window;
842 }
843
844 uint8_t keep_native_window_glx_drawable = false;
845 if (dri2GalliumConfigQueryb(psc->frontend_screen,
846 "keep_native_window_glx_drawable",
847 &keep_native_window_glx_drawable) == 0) {
848 psc->keep_native_window_glx_drawable = keep_native_window_glx_drawable;
849 }
850 }
851 #endif
852 }
853
854
855 /*
856 ** Allocate the memory for the per screen configs for each screen.
857 ** If that works then fetch the per screen configs data.
858 */
859 static Bool
AllocAndFetchScreenConfigs(Display * dpy,struct glx_display * priv,enum glx_driver glx_driver,Bool driver_name_is_inferred)860 AllocAndFetchScreenConfigs(Display * dpy, struct glx_display * priv, enum glx_driver glx_driver, Bool driver_name_is_inferred)
861 {
862 struct glx_screen *psc;
863 GLint i, screens;
864 unsigned screen_count = 0;
865 bool zink = (glx_driver & (GLX_DRIVER_ZINK_INFER | GLX_DRIVER_ZINK_YES)) > 0;
866
867 /*
868 ** First allocate memory for the array of per screen configs.
869 */
870 screens = ScreenCount(dpy);
871 priv->screens = calloc(screens, sizeof *priv->screens);
872 if (!priv->screens)
873 return GL_FALSE;
874
875 for (i = 0; i < screens; i++) {
876 psc = NULL;
877 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
878 #if defined(GLX_USE_DRM)
879 if (glx_driver & GLX_DRIVER_DRI3) {
880 bool use_zink;
881 psc = dri3_create_screen(i, priv, driver_name_is_inferred, &use_zink);
882 if (use_zink) {
883 glx_driver |= GLX_DRIVER_ZINK_YES;
884 zink = true;
885 driver_name_is_inferred = false;
886 }
887 }
888 #if defined(HAVE_X11_DRI2)
889 if (psc == NULL && glx_driver & GLX_DRIVER_DRI2 && dri2CheckSupport(dpy)) {
890 psc = dri2CreateScreen(i, priv, driver_name_is_inferred);
891 if (psc)
892 priv->dri2Hash = __glxHashCreate();
893 }
894 #endif
895 #endif /* GLX_USE_DRM */
896
897 #ifdef GLX_USE_WINDOWSGL
898 if (psc == NULL && glx_driver & GLX_DRIVER_WINDOWS) {
899 psc = driwindowsCreateScreen(i, priv, driver_name_is_inferred);
900 }
901 #endif
902
903 #endif /* GLX_DIRECT_RENDERING && !GLX_USE_APPLEGL */
904 #if defined(GLX_DIRECT_RENDERING) && (!defined(GLX_USE_APPLEGL) || defined(GLX_USE_APPLE))
905 if (psc == NULL &&
906 (glx_driver & GLX_DRIVER_SW || zink)) {
907 psc = driswCreateScreen(i, priv, glx_driver, driver_name_is_inferred);
908 }
909 #endif
910
911 bool indirect = false;
912
913 #if defined(GLX_USE_APPLEGL) && !defined(GLX_USE_APPLE)
914 if (psc == NULL)
915 psc = applegl_create_screen(i, priv);
916 #else
917 if (psc == NULL && !zink)
918 {
919 psc = indirect_create_screen(i, priv);
920 indirect = true;
921 }
922 #endif
923 priv->screens[i] = psc;
924 if (psc)
925 screen_count++;
926
927 if(indirect) /* Load extensions required only for indirect glx */
928 glxSendClientInfo(priv, i);
929 else if (psc && priv->driver != GLX_DRIVER_WINDOWS)
930 bind_extensions(psc, psc->driverName);
931 }
932 if (zink && !screen_count)
933 return GL_FALSE;
934 SyncHandle();
935 return GL_TRUE;
936 }
937
938 /*
939 ** Initialize the client side extension code.
940 */
941 _X_HIDDEN struct glx_display *
__glXInitialize(Display * dpy)942 __glXInitialize(Display * dpy)
943 {
944 XExtCodes *codes;
945 struct glx_display *dpyPriv, *d;
946 int i, majorVersion = 0;
947
948 _XLockMutex(_Xglobal_lock);
949
950 for (dpyPriv = glx_displays; dpyPriv; dpyPriv = dpyPriv->next) {
951 if (dpyPriv->dpy == dpy) {
952 _XUnlockMutex(_Xglobal_lock);
953 return dpyPriv;
954 }
955 }
956
957 /* Drop the lock while we create the display private. */
958 _XUnlockMutex(_Xglobal_lock);
959
960 dpyPriv = calloc(1, sizeof *dpyPriv);
961 if (!dpyPriv)
962 return NULL;
963
964 codes = XInitExtension(dpy, __glXExtensionName);
965 if (!codes) {
966 free(dpyPriv);
967 return NULL;
968 }
969
970 dpyPriv->codes = *codes;
971 dpyPriv->dpy = dpy;
972
973 /* This GLX implementation requires GLX 1.3 */
974 if (!QueryVersion(dpy, dpyPriv->codes.major_opcode,
975 &majorVersion, &dpyPriv->minorVersion)
976 || (majorVersion != 1)
977 || (majorVersion == 1 && dpyPriv->minorVersion < 3)) {
978 free(dpyPriv);
979 return NULL;
980 }
981
982 for (i = 0; i < __GLX_NUMBER_EVENTS; i++) {
983 XESetWireToEvent(dpy, dpyPriv->codes.first_event + i, __glXWireToEvent);
984 XESetEventToWire(dpy, dpyPriv->codes.first_event + i, __glXEventToWire);
985 }
986
987 XESetCloseDisplay(dpy, dpyPriv->codes.extension, __glXCloseDisplay);
988 XESetErrorString (dpy, dpyPriv->codes.extension, __glXErrorString);
989
990 dpyPriv->glXDrawHash = __glxHashCreate();
991
992 enum glx_driver glx_driver = 0;
993 const char *env = getenv("MESA_LOADER_DRIVER_OVERRIDE");
994
995 #if defined(GLX_DIRECT_RENDERING) && (!defined(GLX_USE_APPLEGL) || defined(GLX_USE_APPLE))
996 Bool glx_direct = !debug_get_bool_option("LIBGL_ALWAYS_INDIRECT", false);
997 Bool glx_accel = !debug_get_bool_option("LIBGL_ALWAYS_SOFTWARE", false);
998 Bool dri3 = !debug_get_bool_option("LIBGL_DRI3_DISABLE", false);
999 Bool kopper = !debug_get_bool_option("LIBGL_KOPPER_DISABLE", false);
1000
1001 if (env && !strcmp(env, "zink"))
1002 glx_driver |= GLX_DRIVER_ZINK_YES;
1003
1004 dpyPriv->drawHash = __glxHashCreate();
1005
1006 dpyPriv->zombieGLXDrawable = _mesa_pointer_set_create(NULL);
1007
1008 /* Set the logger before the *CreateDisplay functions. */
1009 loader_set_logger(glx_message);
1010
1011 /*
1012 ** Initialize the direct rendering per display data and functions.
1013 ** Note: This _must_ be done before calling any other DRI routines
1014 ** (e.g., those called in AllocAndFetchScreenConfigs).
1015 */
1016 #if defined(GLX_USE_DRM)
1017 bool dri3_err = false;
1018 if (glx_direct && glx_accel && dri3)
1019 dpyPriv->has_multibuffer = x11_dri3_check_multibuffer(XGetXCBConnection(dpy), &dri3_err, &dpyPriv->has_explicit_modifiers);
1020 if (glx_direct && glx_accel &&
1021 (!(glx_driver & GLX_DRIVER_ZINK_YES) || !kopper)) {
1022 if (dri3) {
1023 /* dri3 is tried as long as this doesn't error; whether modifiers work is not relevant */
1024 if (!dri3_err) {
1025 glx_driver |= GLX_DRIVER_DRI3;
1026 /* nouveau wants to fallback to zink so if we get a screen enable try_zink */
1027 if (!debug_get_bool_option("LIBGL_KOPPER_DISABLE", false))
1028 glx_driver |= GLX_DRIVER_ZINK_INFER;
1029 }
1030 }
1031 #if defined(HAVE_X11_DRI2)
1032 if (!debug_get_bool_option("LIBGL_DRI2_DISABLE", false))
1033 glx_driver |= GLX_DRIVER_DRI2;
1034 #endif
1035 #if defined(HAVE_ZINK)
1036 if (!(glx_driver & (GLX_DRIVER_DRI2 | GLX_DRIVER_DRI3)))
1037 if (kopper && !getenv("GALLIUM_DRIVER"))
1038 glx_driver |= GLX_DRIVER_ZINK_INFER;
1039 #endif /* HAVE_ZINK */
1040 }
1041 #endif /* GLX_USE_DRM */
1042 if (glx_direct)
1043 glx_driver |= GLX_DRIVER_SW;
1044
1045 #if !defined(GLX_USE_APPLE)
1046 if (!dpyPriv->has_explicit_modifiers && glx_accel && !debug_get_bool_option("LIBGL_KOPPER_DRI2", false)) {
1047 if (glx_driver & GLX_DRIVER_ZINK_YES) {
1048 /* only print error if zink was explicitly requested */
1049 CriticalErrorMessageF("DRI3 not available\n");
1050 free(dpyPriv);
1051 return NULL;
1052 }
1053 /* if no dri3 and not using dri2, disable zink */
1054 glx_driver &= ~GLX_DRIVER_ZINK_INFER;
1055 }
1056 #endif
1057
1058 #ifdef GLX_USE_WINDOWSGL
1059 if (glx_direct && glx_accel)
1060 glx_driver |= GLX_DRIVER_WINDOWS;
1061 #else
1062 #ifndef RTLD_NOW
1063 #define RTLD_NOW 0
1064 #endif
1065 #ifndef RTLD_GLOBAL
1066 #define RTLD_GLOBAL 0
1067 #endif
1068
1069 #ifndef GL_LIB_NAME
1070 #define GL_LIB_NAME "libGL.so.1"
1071 #endif
1072
1073 void *glhandle = dlopen(GL_LIB_NAME, RTLD_NOW | RTLD_GLOBAL);
1074 if (glhandle)
1075 dlclose(glhandle);
1076
1077 #endif
1078 #endif /* GLX_DIRECT_RENDERING && !GLX_USE_APPLEGL */
1079
1080 #if defined(GLX_USE_APPLEGL) && !defined(GLX_USE_APPLE)
1081 glx_driver |= GLX_DRIVER_SW;
1082 #endif
1083
1084 #if defined(GLX_USE_APPLEGL) && !defined(GLX_USE_APPLE)
1085 if (!applegl_create_display(dpyPriv)) {
1086 free(dpyPriv);
1087 return NULL;
1088 }
1089 #endif
1090
1091 if (!AllocAndFetchScreenConfigs(dpy, dpyPriv, glx_driver, !env)) {
1092 Bool fail = True;
1093 #if defined(GLX_DIRECT_RENDERING) && (!defined(GLX_USE_APPLEGL) || defined(GLX_USE_APPLE))
1094 if (glx_driver & GLX_DRIVER_ZINK_INFER) {
1095 fail = !AllocAndFetchScreenConfigs(dpy, dpyPriv, GLX_DRIVER_SW, true);
1096 }
1097 #endif
1098 if (fail) {
1099 free(dpyPriv);
1100 return NULL;
1101 }
1102 }
1103
1104 glxSendClientInfo(dpyPriv, -1);
1105
1106 /* Grab the lock again and add the display private, unless somebody
1107 * beat us to initializing on this display in the meantime. */
1108 _XLockMutex(_Xglobal_lock);
1109
1110 for (d = glx_displays; d; d = d->next) {
1111 if (d->dpy == dpy) {
1112 _XUnlockMutex(_Xglobal_lock);
1113 glx_display_free(dpyPriv);
1114 return d;
1115 }
1116 }
1117
1118 dpyPriv->next = glx_displays;
1119 glx_displays = dpyPriv;
1120
1121 _XUnlockMutex(_Xglobal_lock);
1122
1123 return dpyPriv;
1124 }
1125
1126 /*
1127 ** Setup for sending a GLX command on dpy. Make sure the extension is
1128 ** initialized. Try to avoid calling __glXInitialize as its kinda slow.
1129 */
1130 _X_HIDDEN CARD8
__glXSetupForCommand(Display * dpy)1131 __glXSetupForCommand(Display * dpy)
1132 {
1133 struct glx_context *gc;
1134 struct glx_display *priv;
1135
1136 /* If this thread has a current context, flush its rendering commands */
1137 gc = __glXGetCurrentContext();
1138 if (gc->currentDpy) {
1139 /* Flush rendering buffer of the current context, if any */
1140 (void) __glXFlushRenderBuffer(gc, gc->pc);
1141
1142 if (gc->currentDpy == dpy) {
1143 /* Use opcode from gc because its right */
1144 return gc->majorOpcode;
1145 }
1146 else {
1147 /*
1148 ** Have to get info about argument dpy because it might be to
1149 ** a different server
1150 */
1151 }
1152 }
1153
1154 /* Forced to lookup extension via the slow initialize route */
1155 priv = __glXInitialize(dpy);
1156 if (!priv) {
1157 return 0;
1158 }
1159 return priv->codes.major_opcode;
1160 }
1161
1162 /**
1163 * Flush the drawing command transport buffer.
1164 *
1165 * \param ctx Context whose transport buffer is to be flushed.
1166 * \param pc Pointer to first unused buffer location.
1167 *
1168 * \todo
1169 * Modify this function to use \c ctx->pc instead of the explicit
1170 * \c pc parameter.
1171 */
1172 _X_HIDDEN GLubyte *
__glXFlushRenderBuffer(struct glx_context * ctx,GLubyte * pc)1173 __glXFlushRenderBuffer(struct glx_context * ctx, GLubyte * pc)
1174 {
1175 Display *const dpy = ctx->currentDpy;
1176 xcb_connection_t *c = XGetXCBConnection(dpy);
1177 const GLint size = pc - ctx->buf;
1178
1179 if ((dpy != NULL) && (size > 0)) {
1180 xcb_glx_render(c, ctx->currentContextTag, size,
1181 (const uint8_t *) ctx->buf);
1182 }
1183
1184 /* Reset pointer and return it */
1185 ctx->pc = ctx->buf;
1186 return ctx->pc;
1187 }
1188
1189
1190 /**
1191 * Send a portion of a GLXRenderLarge command to the server. The advantage of
1192 * this function over \c __glXSendLargeCommand is that callers can use the
1193 * data buffer in the GLX context and may be able to avoid allocating an
1194 * extra buffer. The disadvantage is the clients will have to do more
1195 * GLX protocol work (i.e., calculating \c totalRequests, etc.).
1196 *
1197 * \sa __glXSendLargeCommand
1198 *
1199 * \param gc GLX context
1200 * \param requestNumber Which part of the whole command is this? The first
1201 * request is 1.
1202 * \param totalRequests How many requests will there be?
1203 * \param data Command data.
1204 * \param dataLen Size, in bytes, of the command data.
1205 */
1206 _X_HIDDEN void
__glXSendLargeChunk(struct glx_context * gc,GLint requestNumber,GLint totalRequests,const GLvoid * data,GLint dataLen)1207 __glXSendLargeChunk(struct glx_context * gc, GLint requestNumber,
1208 GLint totalRequests, const GLvoid * data, GLint dataLen)
1209 {
1210 Display *dpy = gc->currentDpy;
1211 xcb_connection_t *c = XGetXCBConnection(dpy);
1212 xcb_glx_render_large(c, gc->currentContextTag, requestNumber,
1213 totalRequests, dataLen, data);
1214 }
1215
1216
1217 /**
1218 * Send a command that is too large for the GLXRender protocol request.
1219 *
1220 * Send a large command, one that is too large for some reason to
1221 * send using the GLXRender protocol request. One reason to send
1222 * a large command is to avoid copying the data.
1223 *
1224 * \param ctx GLX context
1225 * \param header Header data.
1226 * \param headerLen Size, in bytes, of the header data. It is assumed that
1227 * the header data will always be small enough to fit in
1228 * a single X protocol packet.
1229 * \param data Command data.
1230 * \param dataLen Size, in bytes, of the command data.
1231 */
1232 _X_HIDDEN void
__glXSendLargeCommand(struct glx_context * ctx,const GLvoid * header,GLint headerLen,const GLvoid * data,GLint dataLen)1233 __glXSendLargeCommand(struct glx_context * ctx,
1234 const GLvoid * header, GLint headerLen,
1235 const GLvoid * data, GLint dataLen)
1236 {
1237 GLint maxSize;
1238 GLint totalRequests, requestNumber;
1239
1240 /*
1241 ** Calculate the maximum amount of data can be stuffed into a single
1242 ** packet. sz_xGLXRenderReq is added because bufSize is the maximum
1243 ** packet size minus sz_xGLXRenderReq.
1244 */
1245 maxSize = (ctx->bufSize + sz_xGLXRenderReq) - sz_xGLXRenderLargeReq;
1246 totalRequests = 1 + (dataLen / maxSize);
1247 if (dataLen % maxSize)
1248 totalRequests++;
1249
1250 /*
1251 ** Send all of the command, except the large array, as one request.
1252 */
1253 assert(headerLen <= maxSize);
1254 __glXSendLargeChunk(ctx, 1, totalRequests, header, headerLen);
1255
1256 /*
1257 ** Send enough requests until the whole array is sent.
1258 */
1259 for (requestNumber = 2; requestNumber <= (totalRequests - 1);
1260 requestNumber++) {
1261 __glXSendLargeChunk(ctx, requestNumber, totalRequests, data, maxSize);
1262 data = (const GLvoid *) (((const GLubyte *) data) + maxSize);
1263 dataLen -= maxSize;
1264 assert(dataLen > 0);
1265 }
1266
1267 assert(dataLen <= maxSize);
1268 __glXSendLargeChunk(ctx, requestNumber, totalRequests, data, dataLen);
1269 }
1270