Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /* |
2 | * Copyright © 2008 George Sapountzis <gsap7@yahoo.gr> | |
3 | * Copyright © 2008 Red Hat, Inc | |
4 | * | |
5 | * Permission to use, copy, modify, distribute, and sell this software | |
6 | * and its documentation for any purpose is hereby granted without | |
7 | * fee, provided that the above copyright notice appear in all copies | |
8 | * and that both that copyright notice and this permission notice | |
9 | * appear in supporting documentation, and that the name of the | |
10 | * copyright holders not be used in advertising or publicity | |
11 | * pertaining to distribution of the software without specific, | |
12 | * written prior permission. The copyright holders make no | |
13 | * representations about the suitability of this software for any | |
14 | * purpose. It is provided "as is" without express or implied | |
15 | * warranty. | |
16 | * | |
17 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | |
18 | * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
19 | * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
20 | * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
21 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |
22 | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING | |
23 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
24 | * SOFTWARE. | |
25 | */ | |
26 | ||
27 | #ifdef HAVE_DIX_CONFIG_H | |
28 | #include <dix-config.h> | |
29 | #endif | |
30 | ||
31 | #include <stdint.h> | |
32 | #include <stdio.h> | |
33 | #include <string.h> | |
34 | #include <errno.h> | |
35 | #include <sys/time.h> | |
36 | #include <dlfcn.h> | |
37 | ||
38 | #include <GL/gl.h> | |
39 | #include <GL/internal/dri_interface.h> | |
40 | #include <GL/glxtokens.h> | |
41 | ||
42 | #include "scrnintstr.h" | |
43 | #include "pixmapstr.h" | |
44 | #include "gcstruct.h" | |
45 | #include "os.h" | |
46 | ||
47 | #include "glxserver.h" | |
48 | #include "glxutil.h" | |
49 | #include "glxdricommon.h" | |
50 | ||
51 | #include "extension_string.h" | |
52 | ||
53 | /* RTLD_LOCAL is not defined on Cygwin */ | |
54 | #ifdef __CYGWIN__ | |
55 | #ifndef RTLD_LOCAL | |
56 | #define RTLD_LOCAL 0 | |
57 | #endif | |
58 | #endif | |
59 | ||
60 | typedef struct __GLXDRIscreen __GLXDRIscreen; | |
61 | typedef struct __GLXDRIcontext __GLXDRIcontext; | |
62 | typedef struct __GLXDRIdrawable __GLXDRIdrawable; | |
63 | ||
64 | struct __GLXDRIscreen { | |
65 | __GLXscreen base; | |
66 | __DRIscreen *driScreen; | |
67 | void *driver; | |
68 | ||
69 | const __DRIcoreExtension *core; | |
70 | const __DRIswrastExtension *swrast; | |
71 | const __DRIcopySubBufferExtension *copySubBuffer; | |
72 | const __DRItexBufferExtension *texBuffer; | |
73 | const __DRIconfig **driConfigs; | |
74 | }; | |
75 | ||
76 | struct __GLXDRIcontext { | |
77 | __GLXcontext base; | |
78 | __DRIcontext *driContext; | |
79 | }; | |
80 | ||
81 | struct __GLXDRIdrawable { | |
82 | __GLXdrawable base; | |
83 | __DRIdrawable *driDrawable; | |
84 | __GLXDRIscreen *screen; | |
85 | ||
86 | GCPtr gc; /* scratch GC for span drawing */ | |
87 | GCPtr swapgc; /* GC for swapping the color buffers */ | |
88 | }; | |
89 | ||
90 | static void | |
91 | __glXDRIdrawableDestroy(__GLXdrawable * drawable) | |
92 | { | |
93 | __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; | |
94 | const __DRIcoreExtension *core = private->screen->core; | |
95 | ||
96 | (*core->destroyDrawable) (private->driDrawable); | |
97 | ||
98 | FreeGC(private->gc, (GContext) 0); | |
99 | FreeGC(private->swapgc, (GContext) 0); | |
100 | ||
101 | __glXDrawableRelease(drawable); | |
102 | ||
103 | free(private); | |
104 | } | |
105 | ||
106 | static GLboolean | |
107 | __glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable * drawable) | |
108 | { | |
109 | __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; | |
110 | const __DRIcoreExtension *core = private->screen->core; | |
111 | ||
112 | (*core->swapBuffers) (private->driDrawable); | |
113 | ||
114 | return TRUE; | |
115 | } | |
116 | ||
117 | static void | |
118 | __glXDRIdrawableCopySubBuffer(__GLXdrawable * basePrivate, | |
119 | int x, int y, int w, int h) | |
120 | { | |
121 | __GLXDRIdrawable *private = (__GLXDRIdrawable *) basePrivate; | |
122 | const __DRIcopySubBufferExtension *copySubBuffer = | |
123 | private->screen->copySubBuffer; | |
124 | ||
125 | if (copySubBuffer) | |
126 | (*copySubBuffer->copySubBuffer) (private->driDrawable, x, y, w, h); | |
127 | } | |
128 | ||
129 | static void | |
130 | __glXDRIcontextDestroy(__GLXcontext * baseContext) | |
131 | { | |
132 | __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; | |
133 | __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; | |
134 | ||
135 | (*screen->core->destroyContext) (context->driContext); | |
136 | __glXContextDestroy(&context->base); | |
137 | free(context); | |
138 | } | |
139 | ||
140 | static int | |
141 | __glXDRIcontextMakeCurrent(__GLXcontext * baseContext) | |
142 | { | |
143 | __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; | |
144 | __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv; | |
145 | __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv; | |
146 | __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; | |
147 | ||
148 | return (*screen->core->bindContext) (context->driContext, | |
149 | draw->driDrawable, read->driDrawable); | |
150 | } | |
151 | ||
152 | static int | |
153 | __glXDRIcontextLoseCurrent(__GLXcontext * baseContext) | |
154 | { | |
155 | __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; | |
156 | __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; | |
157 | ||
158 | return (*screen->core->unbindContext) (context->driContext); | |
159 | } | |
160 | ||
161 | static int | |
162 | __glXDRIcontextCopy(__GLXcontext * baseDst, __GLXcontext * baseSrc, | |
163 | unsigned long mask) | |
164 | { | |
165 | __GLXDRIcontext *dst = (__GLXDRIcontext *) baseDst; | |
166 | __GLXDRIcontext *src = (__GLXDRIcontext *) baseSrc; | |
167 | __GLXDRIscreen *screen = (__GLXDRIscreen *) dst->base.pGlxScreen; | |
168 | ||
169 | return (*screen->core->copyContext) (dst->driContext, | |
170 | src->driContext, mask); | |
171 | } | |
172 | ||
173 | #ifdef __DRI_TEX_BUFFER | |
174 | ||
175 | static int | |
176 | __glXDRIbindTexImage(__GLXcontext * baseContext, | |
177 | int buffer, __GLXdrawable * glxPixmap) | |
178 | { | |
179 | __GLXDRIdrawable *drawable = (__GLXDRIdrawable *) glxPixmap; | |
180 | const __DRItexBufferExtension *texBuffer = drawable->screen->texBuffer; | |
181 | __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; | |
182 | ||
183 | if (texBuffer == NULL) | |
184 | return Success; | |
185 | ||
186 | #if __DRI_TEX_BUFFER_VERSION >= 2 | |
187 | if (texBuffer->base.version >= 2 && texBuffer->setTexBuffer2 != NULL) { | |
188 | (*texBuffer->setTexBuffer2) (context->driContext, | |
189 | glxPixmap->target, | |
190 | glxPixmap->format, drawable->driDrawable); | |
191 | } | |
192 | else | |
193 | #endif | |
194 | texBuffer->setTexBuffer(context->driContext, | |
195 | glxPixmap->target, drawable->driDrawable); | |
196 | ||
197 | return Success; | |
198 | } | |
199 | ||
200 | static int | |
201 | __glXDRIreleaseTexImage(__GLXcontext * baseContext, | |
202 | int buffer, __GLXdrawable * pixmap) | |
203 | { | |
204 | /* FIXME: Just unbind the texture? */ | |
205 | return Success; | |
206 | } | |
207 | ||
208 | #else | |
209 | ||
210 | static int | |
211 | __glXDRIbindTexImage(__GLXcontext * baseContext, | |
212 | int buffer, __GLXdrawable * glxPixmap) | |
213 | { | |
214 | return Success; | |
215 | } | |
216 | ||
217 | static int | |
218 | __glXDRIreleaseTexImage(__GLXcontext * baseContext, | |
219 | int buffer, __GLXdrawable * pixmap) | |
220 | { | |
221 | return Success; | |
222 | } | |
223 | ||
224 | #endif | |
225 | ||
226 | static __GLXtextureFromPixmap __glXDRItextureFromPixmap = { | |
227 | __glXDRIbindTexImage, | |
228 | __glXDRIreleaseTexImage | |
229 | }; | |
230 | ||
231 | static void | |
232 | __glXDRIscreenDestroy(__GLXscreen * baseScreen) | |
233 | { | |
234 | int i; | |
235 | ||
236 | __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen; | |
237 | ||
238 | (*screen->core->destroyScreen) (screen->driScreen); | |
239 | ||
240 | dlclose(screen->driver); | |
241 | ||
242 | __glXScreenDestroy(baseScreen); | |
243 | ||
244 | if (screen->driConfigs) { | |
245 | for (i = 0; screen->driConfigs[i] != NULL; i++) | |
246 | free((__DRIconfig **) screen->driConfigs[i]); | |
247 | free(screen->driConfigs); | |
248 | } | |
249 | ||
250 | free(screen); | |
251 | } | |
252 | ||
253 | static __GLXcontext * | |
254 | __glXDRIscreenCreateContext(__GLXscreen * baseScreen, | |
255 | __GLXconfig * glxConfig, | |
256 | __GLXcontext * baseShareContext, | |
257 | unsigned num_attribs, | |
258 | const uint32_t *attribs, | |
259 | int *error) | |
260 | { | |
261 | __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen; | |
262 | __GLXDRIcontext *context, *shareContext; | |
263 | __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig; | |
264 | const __DRIcoreExtension *core = screen->core; | |
265 | __DRIcontext *driShare; | |
266 | ||
267 | /* DRISWRAST won't support createContextAttribs, so these parameters will | |
268 | * never be used. | |
269 | */ | |
270 | (void) num_attribs; | |
271 | (void) attribs; | |
272 | (void) error; | |
273 | ||
274 | shareContext = (__GLXDRIcontext *) baseShareContext; | |
275 | if (shareContext) | |
276 | driShare = shareContext->driContext; | |
277 | else | |
278 | driShare = NULL; | |
279 | ||
280 | context = calloc(1, sizeof *context); | |
281 | if (context == NULL) | |
282 | return NULL; | |
283 | ||
284 | context->base.destroy = __glXDRIcontextDestroy; | |
285 | context->base.makeCurrent = __glXDRIcontextMakeCurrent; | |
286 | context->base.loseCurrent = __glXDRIcontextLoseCurrent; | |
287 | context->base.copy = __glXDRIcontextCopy; | |
288 | context->base.textureFromPixmap = &__glXDRItextureFromPixmap; | |
289 | ||
290 | context->driContext = | |
291 | (*core->createNewContext) (screen->driScreen, | |
292 | config->driConfig, driShare, context); | |
293 | ||
294 | return &context->base; | |
295 | } | |
296 | ||
297 | static __GLXdrawable * | |
298 | __glXDRIscreenCreateDrawable(ClientPtr client, | |
299 | __GLXscreen * screen, | |
300 | DrawablePtr pDraw, | |
301 | XID drawId, | |
302 | int type, XID glxDrawId, __GLXconfig * glxConfig) | |
303 | { | |
304 | XID gcvals[2]; | |
305 | int status; | |
306 | __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen; | |
307 | __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig; | |
308 | __GLXDRIdrawable *private; | |
309 | ||
310 | private = calloc(1, sizeof *private); | |
311 | if (private == NULL) | |
312 | return NULL; | |
313 | ||
314 | private->screen = driScreen; | |
315 | if (!__glXDrawableInit(&private->base, screen, | |
316 | pDraw, type, glxDrawId, glxConfig)) { | |
317 | free(private); | |
318 | return NULL; | |
319 | } | |
320 | ||
321 | private->base.destroy = __glXDRIdrawableDestroy; | |
322 | private->base.swapBuffers = __glXDRIdrawableSwapBuffers; | |
323 | private->base.copySubBuffer = __glXDRIdrawableCopySubBuffer; | |
324 | ||
325 | gcvals[0] = GXcopy; | |
326 | private->gc = | |
327 | CreateGC(pDraw, GCFunction, gcvals, &status, (XID) 0, serverClient); | |
328 | gcvals[1] = FALSE; | |
329 | private->swapgc = | |
330 | CreateGC(pDraw, GCFunction | GCGraphicsExposures, gcvals, &status, | |
331 | (XID) 0, serverClient); | |
332 | ||
333 | private->driDrawable = | |
334 | (*driScreen->swrast->createNewDrawable) (driScreen->driScreen, | |
335 | config->driConfig, private); | |
336 | ||
337 | return &private->base; | |
338 | } | |
339 | ||
340 | static void | |
341 | swrastGetDrawableInfo(__DRIdrawable * draw, | |
342 | int *x, int *y, int *w, int *h, void *loaderPrivate) | |
343 | { | |
344 | __GLXDRIdrawable *drawable = loaderPrivate; | |
345 | DrawablePtr pDraw = drawable->base.pDraw; | |
346 | ||
347 | *x = pDraw->x; | |
348 | *y = pDraw->x; | |
349 | *w = pDraw->width; | |
350 | *h = pDraw->height; | |
351 | } | |
352 | ||
353 | static void | |
354 | swrastPutImage(__DRIdrawable * draw, int op, | |
355 | int x, int y, int w, int h, char *data, void *loaderPrivate) | |
356 | { | |
357 | __GLXDRIdrawable *drawable = loaderPrivate; | |
358 | DrawablePtr pDraw = drawable->base.pDraw; | |
359 | GCPtr gc; | |
360 | ||
361 | switch (op) { | |
362 | case __DRI_SWRAST_IMAGE_OP_DRAW: | |
363 | gc = drawable->gc; | |
364 | break; | |
365 | case __DRI_SWRAST_IMAGE_OP_SWAP: | |
366 | gc = drawable->swapgc; | |
367 | break; | |
368 | default: | |
369 | return; | |
370 | } | |
371 | ||
372 | ValidateGC(pDraw, gc); | |
373 | ||
374 | gc->ops->PutImage(pDraw, gc, pDraw->depth, x, y, w, h, 0, ZPixmap, data); | |
375 | } | |
376 | ||
377 | static void | |
378 | swrastGetImage(__DRIdrawable * draw, | |
379 | int x, int y, int w, int h, char *data, void *loaderPrivate) | |
380 | { | |
381 | __GLXDRIdrawable *drawable = loaderPrivate; | |
382 | DrawablePtr pDraw = drawable->base.pDraw; | |
383 | ScreenPtr pScreen = pDraw->pScreen; | |
384 | ||
385 | pScreen->GetImage(pDraw, x, y, w, h, ZPixmap, ~0L, data); | |
386 | } | |
387 | ||
388 | static const __DRIswrastLoaderExtension swrastLoaderExtension = { | |
389 | {__DRI_SWRAST_LOADER, 1}, | |
390 | swrastGetDrawableInfo, | |
391 | swrastPutImage, | |
392 | swrastGetImage | |
393 | }; | |
394 | ||
395 | static const __DRIextension *loader_extensions[] = { | |
396 | &systemTimeExtension.base, | |
397 | &swrastLoaderExtension.base, | |
398 | NULL | |
399 | }; | |
400 | ||
401 | static void | |
402 | initializeExtensions(__GLXDRIscreen * screen) | |
403 | { | |
404 | const __DRIextension **extensions; | |
405 | int i; | |
406 | ||
407 | extensions = screen->core->getExtensions(screen->driScreen); | |
408 | ||
409 | for (i = 0; extensions[i]; i++) { | |
410 | #ifdef __DRI_COPY_SUB_BUFFER | |
411 | if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) { | |
412 | screen->copySubBuffer = | |
413 | (const __DRIcopySubBufferExtension *) extensions[i]; | |
414 | /* GLX_MESA_copy_sub_buffer is always enabled. */ | |
415 | } | |
416 | #endif | |
417 | ||
418 | #ifdef __DRI_TEX_BUFFER | |
419 | if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0) { | |
420 | screen->texBuffer = (const __DRItexBufferExtension *) extensions[i]; | |
421 | /* GLX_EXT_texture_from_pixmap is always enabled. */ | |
422 | } | |
423 | #endif | |
424 | /* Ignore unknown extensions */ | |
425 | } | |
426 | } | |
427 | ||
428 | /* white lie */ | |
429 | extern glx_func_ptr glXGetProcAddressARB(const char *); | |
430 | ||
431 | static __GLXscreen * | |
432 | __glXDRIscreenProbe(ScreenPtr pScreen) | |
433 | { | |
434 | const char *driverName = "swrast"; | |
435 | __GLXDRIscreen *screen; | |
436 | ||
437 | screen = calloc(1, sizeof *screen); | |
438 | if (screen == NULL) | |
439 | return NULL; | |
440 | ||
441 | screen->base.destroy = __glXDRIscreenDestroy; | |
442 | screen->base.createContext = __glXDRIscreenCreateContext; | |
443 | screen->base.createDrawable = __glXDRIscreenCreateDrawable; | |
444 | screen->base.swapInterval = NULL; | |
445 | screen->base.pScreen = pScreen; | |
446 | ||
447 | screen->driver = glxProbeDriver(driverName, | |
448 | (void **) &screen->core, | |
449 | __DRI_CORE, 1, | |
450 | (void **) &screen->swrast, | |
451 | __DRI_SWRAST, 1); | |
452 | if (screen->driver == NULL) { | |
453 | goto handle_error; | |
454 | } | |
455 | ||
456 | screen->driScreen = | |
457 | (*screen->swrast->createNewScreen) (pScreen->myNum, | |
458 | loader_extensions, | |
459 | &screen->driConfigs, screen); | |
460 | ||
461 | if (screen->driScreen == NULL) { | |
462 | LogMessage(X_ERROR, "AIGLX error: Calling driver entry point failed\n"); | |
463 | goto handle_error; | |
464 | } | |
465 | ||
466 | initializeExtensions(screen); | |
467 | ||
468 | screen->base.fbconfigs = glxConvertConfigs(screen->core, screen->driConfigs, | |
469 | GLX_WINDOW_BIT | | |
470 | GLX_PIXMAP_BIT | | |
471 | GLX_PBUFFER_BIT); | |
472 | ||
473 | __glXScreenInit(&screen->base, pScreen); | |
474 | ||
475 | screen->base.GLXmajor = 1; | |
476 | screen->base.GLXminor = 4; | |
477 | ||
478 | __glXsetGetProcAddress(glXGetProcAddressARB); | |
479 | ||
480 | LogMessage(X_INFO, "AIGLX: Loaded and initialized %s\n", driverName); | |
481 | ||
482 | return &screen->base; | |
483 | ||
484 | handle_error: | |
485 | if (screen->driver) | |
486 | dlclose(screen->driver); | |
487 | ||
488 | free(screen); | |
489 | ||
490 | LogMessage(X_ERROR, "GLX: could not load software renderer\n"); | |
491 | ||
492 | return NULL; | |
493 | } | |
494 | ||
495 | _X_EXPORT __GLXprovider __glXDRISWRastProvider = { | |
496 | __glXDRIscreenProbe, | |
497 | "DRISWRAST", | |
498 | NULL | |
499 | }; |