Small optimization for big-endian (e.g., PowerPC) systems.
[mesa.git] / src / mesa / drivers / dri / x11 / x11_dri.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 0.1
4 *
5 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * 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 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 /* Minimal swrast-based DRI-loadable driver.
27 *
28 * Derived from fb_dri.c, the difference being that one works for
29 * framebuffers without X, whereas this points Mesa at an X surface
30 * to draw on.
31 *
32 * This is basically just a wrapper around src/mesa/drivers/x11 to make it
33 * look like a DRI driver.
34 */
35
36 #define GLX_DIRECT_RENDERING
37
38 #include <assert.h>
39 #include <errno.h>
40 #include <signal.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <dlfcn.h>
45 #include <fcntl.h>
46 #include <unistd.h>
47 #include <sys/ioctl.h>
48 #include <sys/mman.h>
49 #include <sys/types.h>
50 #include <sys/shm.h>
51 #include <sys/stat.h>
52 #include <linux/kd.h>
53 #include <linux/vt.h>
54
55 #include "dri_util.h"
56
57 #include "GL/xmesa.h"
58 #include "xmesaP.h"
59
60 #include "mtypes.h"
61 #include "context.h"
62 #include "extensions.h"
63 #include "imports.h"
64 #include "matrix.h"
65 #include "texformat.h"
66 #include "texstore.h"
67 #include "teximage.h"
68 #include "array_cache/acache.h"
69 #include "swrast/swrast.h"
70 #include "swrast_setup/swrast_setup.h"
71 #include "tnl/tnl.h"
72 #include "tnl/t_context.h"
73 #include "tnl/t_pipeline.h"
74 #include "drivers/common/driverfuncs.h"
75
76 #include "x11_dri.h"
77
78 typedef struct {
79 GLcontext *glCtx; /* Mesa context */
80
81 struct {
82 __DRIcontextPrivate *context;
83 __DRIscreenPrivate *screen;
84 __DRIdrawablePrivate *drawable; /* drawable bound to this ctx */
85 } dri;
86 } x11Context, *x11ContextPtr;
87
88 #define X11_CONTEXT(ctx) ((x11ContextPtr)(ctx->DriverCtx))
89
90 static const GLubyte *
91 get_string(GLcontext *ctx, GLenum pname)
92 {
93 (void) ctx;
94 switch (pname) {
95 case GL_RENDERER:
96 return (const GLubyte *) "Mesa X11 hack";
97 default:
98 return NULL;
99 }
100 }
101
102 static void
103 update_state(GLcontext *ctx, GLuint new_state)
104 {
105 /* not much to do here - pass it on */
106 _swrast_InvalidateState(ctx, new_state);
107 _swsetup_InvalidateState(ctx, new_state);
108 _ac_InvalidateState(ctx, new_state);
109 _tnl_InvalidateState(ctx, new_state);
110 }
111
112 /**
113 * Called by ctx->Driver.GetBufferSize from in core Mesa to query the
114 * current framebuffer size.
115 */
116 static void
117 get_buffer_size(GLframebuffer *buffer, GLuint *width, GLuint *height)
118 {
119 GET_CURRENT_CONTEXT(ctx);
120 x11ContextPtr x11mesa = X11_CONTEXT(ctx);
121
122 *width = x11mesa->dri.drawable->w;
123 *height = x11mesa->dri.drawable->h;
124 }
125
126 static void
127 init_core_functions(struct dd_function_table *functions)
128 {
129 functions->GetString = get_string;
130 functions->UpdateState = update_state;
131 functions->ResizeBuffers = _swrast_alloc_buffers;
132 functions->GetBufferSize = get_buffer_size;
133
134 functions->Clear = _swrast_Clear; /* could accelerate with blits */
135 }
136
137 /* Initialize the driver specific screen private data.
138 */
139 static GLboolean
140 x11InitDriver(__DRIscreenPrivate *sPriv)
141 {
142 sPriv->private = NULL;
143 return GL_TRUE;
144 }
145
146 static void
147 x11DestroyScreen(__DRIscreenPrivate *sPriv)
148 {
149 }
150
151 /* placeholders, disables rendering */
152 static void
153 nullwrite(void *a, int b, int c, int d, void *e, void *f)
154 {
155 }
156
157 static void
158 set_buffer( GLcontext *ctx, GLframebuffer *buffer, GLuint bufferBit )
159 {
160 }
161
162 /* Create the device specific context. */
163 static GLboolean
164 x11CreateContext(const __GLcontextModes *glVisual,
165 __DRIcontextPrivate *driContextPriv,
166 void *sharedContextPrivate)
167 {
168 x11ContextPtr x11mesa;
169 GLcontext *ctx, *shareCtx;
170 struct dd_function_table functions;
171
172 assert(glVisual);
173 assert(driContextPriv);
174
175 /* Allocate the Fb context */
176 x11mesa = (x11ContextPtr) CALLOC(sizeof(*x11mesa));
177 if (!x11mesa)
178 return GL_FALSE;
179
180 /* Init default driver functions then plug in our own functions */
181 _mesa_init_driver_functions(&functions);
182 init_core_functions(&functions);
183
184 /* Allocate the Mesa context */
185 if (sharedContextPrivate)
186 shareCtx = ((x11ContextPtr) sharedContextPrivate)->glCtx;
187 else
188 shareCtx = NULL;
189
190 ctx = x11mesa->glCtx = _mesa_create_context(glVisual, shareCtx,
191 &functions, (void *) x11mesa);
192 if (!x11mesa->glCtx) {
193 FREE(x11mesa);
194 return GL_FALSE;
195 }
196 driContextPriv->driverPrivate = x11mesa;
197
198 /* Create module contexts */
199 _swrast_CreateContext(ctx);
200 _ac_CreateContext(ctx);
201 _tnl_CreateContext(ctx);
202 _swsetup_CreateContext(ctx);
203 _swsetup_Wakeup(ctx);
204
205 /* swrast init */
206 {
207 struct swrast_device_driver *swdd;
208 swdd = _swrast_GetDeviceDriverReference(ctx);
209 swdd->SetBuffer = set_buffer;
210 if (!glVisual->rgbMode) {
211 swdd->WriteCI32Span =
212 swdd->WriteCI32Span =
213 swdd->WriteCI8Span =
214 swdd->WriteMonoCISpan =
215 swdd->WriteCI32Pixels =
216 swdd->WriteMonoCIPixels =
217 swdd->ReadCI32Span =
218 swdd->ReadCI32Pixels = nullwrite;
219 }
220 else if (glVisual->rgbBits == 24 &&
221 glVisual->alphaBits == 0) {
222 swdd->WriteRGBASpan =
223 swdd->WriteRGBSpan =
224 swdd->WriteMonoRGBASpan =
225 swdd->WriteRGBAPixels =
226 swdd->WriteMonoRGBAPixels =
227 swdd->ReadRGBASpan =
228 swdd->ReadRGBAPixels = nullwrite;
229 }
230 else if (glVisual->rgbBits == 32 &&
231 glVisual->alphaBits == 8) {
232 swdd->WriteRGBASpan =
233 swdd->WriteRGBSpan =
234 swdd->WriteMonoRGBASpan =
235 swdd->WriteRGBAPixels =
236 swdd->WriteMonoRGBAPixels =
237 swdd->ReadRGBASpan =
238 swdd->ReadRGBAPixels = nullwrite;
239 }
240 else if (glVisual->rgbBits == 16 &&
241 glVisual->alphaBits == 0) {
242 swdd->WriteRGBASpan =
243 swdd->WriteRGBSpan =
244 swdd->WriteMonoRGBASpan =
245 swdd->WriteRGBAPixels =
246 swdd->WriteMonoRGBAPixels =
247 swdd->ReadRGBASpan =
248 swdd->ReadRGBAPixels = nullwrite;
249 }
250 else if (glVisual->rgbBits == 15 &&
251 glVisual->alphaBits == 0) {
252 swdd->WriteRGBASpan =
253 swdd->WriteRGBSpan =
254 swdd->WriteMonoRGBASpan =
255 swdd->WriteRGBAPixels =
256 swdd->WriteMonoRGBAPixels =
257 swdd->ReadRGBASpan =
258 swdd->ReadRGBAPixels = nullwrite;
259 }
260 else {
261 _mesa_printf("bad pixelformat rgb %d alpha %d\n",
262 glVisual->rgbBits,
263 glVisual->alphaBits );
264 }
265 }
266
267 /* use default TCL pipeline */
268 {
269 TNLcontext *tnl = TNL_CONTEXT(ctx);
270 tnl->Driver.RunPipeline = _tnl_run_pipeline;
271 }
272
273 _mesa_enable_sw_extensions(ctx);
274
275 return GL_TRUE;
276 }
277
278
279 static void
280 x11DestroyContext(__DRIcontextPrivate *driContextPriv)
281 {
282 GET_CURRENT_CONTEXT(ctx);
283 x11ContextPtr x11mesa = (x11ContextPtr) driContextPriv->driverPrivate;
284 x11ContextPtr current = ctx ? X11_CONTEXT(ctx) : NULL;
285
286 /* check if we're deleting the currently bound context */
287 if (x11mesa == current) {
288 _mesa_make_current2(NULL, NULL, NULL);
289 }
290
291 /* Free x11 context resources */
292 if (x11mesa) {
293 _swsetup_DestroyContext(x11mesa->glCtx);
294 _tnl_DestroyContext(x11mesa->glCtx);
295 _ac_DestroyContext(x11mesa->glCtx);
296 _swrast_DestroyContext(x11mesa->glCtx);
297
298 /* free the Mesa context */
299 x11mesa->glCtx->DriverCtx = NULL;
300 _mesa_destroy_context(x11mesa->glCtx);
301
302 FREE(x11mesa);
303 }
304 }
305
306
307 /* Create and initialize the Mesa and driver specific pixmap buffer
308 * data.
309 */
310 static GLboolean
311 x11CreateBuffer(__DRIscreenPrivate *driScrnPriv,
312 __DRIdrawablePrivate *driDrawPriv,
313 const __GLcontextModes *mesaVis,
314 GLboolean isPixmap)
315 {
316 if (isPixmap) {
317 return GL_FALSE; /* not implemented */
318 }
319 else {
320 const GLboolean swDepth = mesaVis->depthBits > 0;
321 const GLboolean swAlpha = mesaVis->alphaBits > 0;
322 const GLboolean swAccum = mesaVis->accumRedBits > 0;
323 const GLboolean swStencil = mesaVis->stencilBits > 0;
324 driDrawPriv->driverPrivate = (void *)
325 _mesa_create_framebuffer(mesaVis,
326 swDepth,
327 swStencil,
328 swAccum,
329 swAlpha);
330
331 if (!driDrawPriv->driverPrivate)
332 return 0;
333
334 /* Replace the framebuffer back buffer with a malloc'ed one --
335 * big speedup.
336 */
337 /*
338 if (driDrawPriv->backBuffer)
339 driDrawPriv->backBuffer = malloc(driDrawPriv->currentPitch * driDrawPriv->h);
340 */
341
342 return 1;
343 }
344 }
345
346
347 static void
348 x11DestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
349 {
350 _mesa_destroy_framebuffer((GLframebuffer *) (driDrawPriv->driverPrivate));
351 /* free(driDrawPriv->backBuffer); */
352 }
353
354
355
356 /* If the backbuffer is on a videocard, this is extraordinarily slow!
357 */
358 static void
359 x11SwapBuffers(__DRIdrawablePrivate *dPriv)
360 {
361
362 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
363 x11ContextPtr x11mesa;
364 GLcontext *ctx;
365 x11mesa = (x11ContextPtr) dPriv->driContextPriv->driverPrivate;
366 ctx = x11mesa->glCtx;
367 if (ctx->Visual.doubleBufferMode) {
368 int i;
369 int offset = 0;
370 char *tmp /*= malloc(dPriv->currentPitch) */ ;
371
372 _mesa_notifySwapBuffers(ctx); /* flush pending rendering comands */
373
374 /*
375 ASSERT(dPriv->frontBuffer);
376 ASSERT(dPriv->backBuffer);
377
378 for (i = 0 ; i < dPriv->h ; i++ ) {
379 memcpy(tmp, (char *)dPriv->frontBuffer + offset, dPriv->currentPitch);
380 memcpy((char *)dPriv->backBuffer + offset, tmp, dPriv->currentPitch);
381 offset += dPriv->currentPitch;
382 }
383
384 free(tmp);
385 */
386 }
387 }
388 else {
389 /* XXX this shouldn't be an error but we can't handle it for now */
390 _mesa_problem(NULL, "x11SwapBuffers: drawable has no context!\n");
391 }
392 }
393
394
395 /* Force the context `c' to be the current context and associate with it
396 * buffer `b'.
397 */
398 static GLboolean
399 x11MakeCurrent(__DRIcontextPrivate *driContextPriv,
400 __DRIdrawablePrivate *driDrawPriv,
401 __DRIdrawablePrivate *driReadPriv)
402 {
403 if (driContextPriv) {
404 x11ContextPtr newFbCtx =
405 (x11ContextPtr) driContextPriv->driverPrivate;
406
407 newFbCtx->dri.drawable = driDrawPriv;
408
409 _mesa_make_current2(newFbCtx->glCtx,
410 (GLframebuffer *) driDrawPriv->driverPrivate,
411 (GLframebuffer *) driReadPriv->driverPrivate);
412
413 if (!newFbCtx->glCtx->Viewport.Width) {
414 _mesa_set_viewport(newFbCtx->glCtx, 0, 0,
415 driDrawPriv->w, driDrawPriv->h);
416 }
417 } else {
418 _mesa_make_current(0, 0);
419 }
420
421 return GL_TRUE;
422 }
423
424
425 /* Force the context `c' to be unbound from its buffer.
426 */
427 static GLboolean
428 x11UnbindContext(__DRIcontextPrivate *driContextPriv)
429 {
430 return GL_TRUE;
431 }
432
433 static struct __DriverAPIRec x11API = {
434 x11InitDriver,
435 x11DestroyScreen,
436 x11CreateContext,
437 x11DestroyContext,
438 x11CreateBuffer,
439 x11DestroyBuffer,
440 x11SwapBuffers,
441 x11MakeCurrent,
442 x11UnbindContext
443 };
444
445 /*
446 * This is the bootstrap function for the driver.
447 * The __driCreateScreen name is the symbol that libGL.so fetches.
448 * Return: pointer to a __DRIscreenPrivate.
449 */
450 void *
451 __driCreateScreen(Display *dpy, int scrn, __DRIscreen *psc,
452 int numConfigs, __GLXvisualConfig *config)
453 {
454 __DRIscreenPrivate *psp;
455 psp = __driUtilCreateScreen(dpy, scrn, psc, numConfigs, config, &x11API);
456 return (void *) psp;
457 }
458
459 /**
460 * \brief Establish the set of modes available for the display.
461 *
462 * \param ctx display handle.
463 * \param numModes will receive the number of supported modes.
464 * \param modes will point to the list of supported modes.
465 *
466 * \return one on success, or zero on failure.
467 *
468 * Allocates a single visual and fills it with information according to the
469 * display bit depth. Supports only 16 and 32 bpp bit depths, aborting
470 * otherwise.
471 */
472 const __GLcontextModes __glModes[] = {
473 /* 32 bit, RGBA Depth=24 Stencil=8 */
474 {.rgbMode = GL_TRUE, .colorIndexMode = GL_FALSE, .doubleBufferMode = GL_TRUE, .stereoMode = GL_FALSE,
475 .haveAccumBuffer = GL_FALSE, .haveDepthBuffer = GL_TRUE, .haveStencilBuffer = GL_TRUE,
476 .redBits = 8, .greenBits = 8, .blueBits = 8, .alphaBits = 8,
477 .redMask = 0xff0000, .greenMask = 0xff00, .blueMask = 0xff, .alphaMask = 0xff000000,
478 .rgbBits = 32, .indexBits = 0,
479 .accumRedBits = 0, .accumGreenBits = 0, .accumBlueBits = 0, .accumAlphaBits = 0,
480 .depthBits = 24, .stencilBits = 8,
481 .numAuxBuffers= 0, .level = 0, .pixmapMode = GL_FALSE, },
482
483 /* 16 bit, RGB Depth=16 */
484 {.rgbMode = GL_TRUE, .colorIndexMode = GL_FALSE, .doubleBufferMode = GL_TRUE, .stereoMode = GL_FALSE,
485 .haveAccumBuffer = GL_FALSE, .haveDepthBuffer = GL_TRUE, .haveStencilBuffer = GL_FALSE,
486 .redBits = 5, .greenBits = 6, .blueBits = 5, .alphaBits = 0,
487 .redMask = 0xf800, .greenMask = 0x07e0, .blueMask = 0x001f, .alphaMask = 0x0,
488 .rgbBits = 16, .indexBits = 0,
489 .accumRedBits = 0, .accumGreenBits = 0, .accumBlueBits = 0, .accumAlphaBits = 0,
490 .depthBits = 16, .stencilBits = 0,
491 .numAuxBuffers= 0, .level = 0, .pixmapMode = GL_FALSE, },
492 };