696bf9e2e15a2d5a4cbfae19c4c0aa23f8096a98
[mesa.git] / src / mesa / drivers / dri / fb / fb_dri.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.1
4 *
5 * Copyright (C) 1999-2004 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 /* Minimal swrast-based dri loadable driver.
26 *
27 * Todo:
28 * -- Use malloced (rather than framebuffer) memory for backbuffer
29 * -- 32bpp is hardwared -- fix
30 *
31 * NOTES:
32 * -- No mechanism for cliprects or resize notification --
33 * assumes this is a fullscreen device.
34 * -- No locking -- assumes this is the only driver accessing this
35 * device.
36 * -- Doesn't (yet) make use of any acceleration or other interfaces
37 * provided by fb. Would be entirely happy working against any
38 * fullscreen interface.
39 * -- HOWEVER: only a small number of pixelformats are supported, and
40 * the mechanism for choosing between them makes some assumptions
41 * that may not be valid everywhere.
42 */
43
44 #include "driver.h"
45 #include "drm.h"
46 #include "utils.h"
47
48 #include "buffers.h"
49 #include "extensions.h"
50 #include "array_cache/acache.h"
51 #include "swrast/swrast.h"
52 #include "swrast_setup/swrast_setup.h"
53 #include "tnl/tnl.h"
54 #include "tnl/t_context.h"
55 #include "tnl/t_pipeline.h"
56 #include "drivers/common/driverfuncs.h"
57
58
59 typedef struct {
60 GLcontext *glCtx; /* Mesa context */
61
62 struct {
63 __DRIcontextPrivate *context;
64 __DRIscreenPrivate *screen;
65 __DRIdrawablePrivate *drawable; /* drawable bound to this ctx */
66 } dri;
67
68 } fbContext, *fbContextPtr;
69
70 typedef struct {
71 GLframebuffer *mesa_framebuffer;
72 void *currentBuffer;
73 void *frontBuffer;
74 void *backBuffer;
75 int currentPitch;
76 } fbDrawable, *fbDrawablePtr;
77
78 typedef struct {
79 unsigned long hFrameBuffer;
80 int fbOrigin;
81 int fbSize;
82 int fbStride;
83 int fbWidth;
84 int fbHeight;
85 int bpp;
86 int drmFD;
87 drmAddress fbMap;
88 } fbDRI, *fbDRIPtr;
89
90 #define FB_CONTEXT(ctx) ((fbContextPtr)(ctx->DriverCtx))
91
92 #ifdef USE_NEW_INTERFACE
93 static PFNGLXCREATECONTEXTMODES create_context_modes = NULL;
94 #endif /* USE_NEW_INTERFACE */
95
96 static const GLubyte *
97 get_string(GLcontext *ctx, GLenum pname)
98 {
99 (void) ctx;
100 switch (pname) {
101 case GL_RENDERER:
102 return (const GLubyte *) "Mesa dumb framebuffer";
103 default:
104 return NULL;
105 }
106 }
107
108
109 static void
110 update_state( GLcontext *ctx, GLuint new_state )
111 {
112 /* not much to do here - pass it on */
113 _swrast_InvalidateState( ctx, new_state );
114 _swsetup_InvalidateState( ctx, new_state );
115 _ac_InvalidateState( ctx, new_state );
116 _tnl_InvalidateState( ctx, new_state );
117 }
118
119
120 /**
121 * Called by ctx->Driver.GetBufferSize from in core Mesa to query the
122 * current framebuffer size.
123 */
124 static void
125 get_buffer_size( GLframebuffer *buffer, GLuint *width, GLuint *height )
126 {
127 GET_CURRENT_CONTEXT(ctx);
128 fbContextPtr fbmesa = FB_CONTEXT(ctx);
129
130 *width = fbmesa->dri.drawable->w;
131 *height = fbmesa->dri.drawable->h;
132 }
133
134
135 static void
136 viewport(GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h)
137 {
138 _mesa_ResizeBuffersMESA();
139 }
140
141
142 /* specifies the buffer for swrast span rendering/reading */
143 static void
144 set_buffer( GLcontext *ctx, GLframebuffer *buffer, GLuint bufferBit )
145 {
146 fbContextPtr fbdevctx = FB_CONTEXT(ctx);
147 __DRIdrawablePrivate *dPriv = fbdevctx->dri.drawable;
148 fbDrawablePtr fbdrawable = (fbDrawablePtr)dPriv->driverPrivate;
149
150 /* What a twisted mess of private structs
151 */
152 assert(buffer == fbdrawable->mesa_framebuffer);
153
154
155 switch (bufferBit) {
156 case DD_FRONT_LEFT_BIT:
157 fbdrawable->currentBuffer = fbdrawable->frontBuffer;
158 break;
159 case DD_BACK_LEFT_BIT:
160 fbdrawable->currentBuffer = fbdrawable->backBuffer;
161 break;
162 default:
163 /* This happens a lot if the client renders to the frontbuffer */
164 if (0) _mesa_problem(ctx, "bad bufferBit in set_buffer()");
165 }
166 }
167
168
169 static void
170 init_core_functions( struct dd_function_table *functions )
171 {
172 functions->GetString = get_string;
173 functions->UpdateState = update_state;
174 functions->ResizeBuffers = _swrast_alloc_buffers;
175 functions->GetBufferSize = get_buffer_size;
176 functions->Viewport = viewport;
177
178 functions->Clear = _swrast_Clear; /* could accelerate with blits */
179 }
180
181
182 /*
183 * Generate code for span functions.
184 */
185
186 /* 24-bit BGR */
187 #define NAME(PREFIX) PREFIX##_B8G8R8
188 #define SPAN_VARS \
189 const fbContextPtr fbdevctx = FB_CONTEXT(ctx); \
190 __DRIdrawablePrivate *dPriv = fbdevctx->dri.drawable; \
191 const fbDrawablePtr fbdrawable = (fbDrawablePtr)dPriv->driverPrivate;
192 #define INIT_PIXEL_PTR(P, X, Y) \
193 GLubyte *P = (GLubyte *)fbdrawable->currentBuffer + (Y) * fbdrawable->currentPitch + (X) * 3
194 #define INC_PIXEL_PTR(P) P += 3
195 #define STORE_RGB_PIXEL(P, X, Y, R, G, B) \
196 P[0] = B; P[1] = G; P[2] = R
197 #define STORE_RGBA_PIXEL(P, X, Y, R, G, B, A) \
198 P[0] = B; P[1] = G; P[2] = R
199 #define FETCH_RGBA_PIXEL(R, G, B, A, P) \
200 R = P[2]; G = P[1]; B = P[0]; A = CHAN_MAX
201
202 #include "swrast/s_spantemp.h"
203
204
205 /* 32-bit BGRA */
206 #define NAME(PREFIX) PREFIX##_B8G8R8A8
207 #define SPAN_VARS \
208 const fbContextPtr fbdevctx = FB_CONTEXT(ctx); \
209 __DRIdrawablePrivate *dPriv = fbdevctx->dri.drawable; \
210 const fbDrawablePtr fbdrawable = (fbDrawablePtr)dPriv->driverPrivate;
211 #define INIT_PIXEL_PTR(P, X, Y) \
212 GLubyte *P = (GLubyte *)fbdrawable->currentBuffer + (Y) * fbdrawable->currentPitch + (X) * 4;
213 #define INC_PIXEL_PTR(P) P += 4
214 #define STORE_RGB_PIXEL(P, X, Y, R, G, B) \
215 P[0] = B; P[1] = G; P[2] = R; P[3] = 255
216 #define STORE_RGBA_PIXEL(P, X, Y, R, G, B, A) \
217 P[0] = B; P[1] = G; P[2] = R; P[3] = A
218 #define FETCH_RGBA_PIXEL(R, G, B, A, P) \
219 R = P[2]; G = P[1]; B = P[0]; A = P[3]
220
221 #include "swrast/s_spantemp.h"
222
223
224 /* 16-bit BGR (XXX implement dithering someday) */
225 #define NAME(PREFIX) PREFIX##_B5G6R5
226 #define SPAN_VARS \
227 const fbContextPtr fbdevctx = FB_CONTEXT(ctx); \
228 __DRIdrawablePrivate *dPriv = fbdevctx->dri.drawable; \
229 const fbDrawablePtr fbdrawable = (fbDrawablePtr)dPriv->driverPrivate;
230 #define INIT_PIXEL_PTR(P, X, Y) \
231 GLushort *P = (GLushort *) ((char *)fbdrawable->currentBuffer + (Y) * fbdrawable->currentPitch + (X) * 2)
232 #define INC_PIXEL_PTR(P) P += 1
233 #define STORE_RGB_PIXEL(P, X, Y, R, G, B) \
234 *P = ( (((R) & 0xf8) << 8) | (((G) & 0xfc) << 3) | ((B) >> 3) )
235 #define STORE_RGBA_PIXEL(P, X, Y, R, G, B, A) \
236 *P = ( (((R) & 0xf8) << 8) | (((G) & 0xfc) << 3) | ((B) >> 3) )
237 #define FETCH_RGBA_PIXEL(R, G, B, A, P) \
238 R = ( (((*P) >> 8) & 0xf8) | (((*P) >> 11) & 0x7) ); \
239 G = ( (((*P) >> 3) & 0xfc) | (((*P) >> 5) & 0x3) ); \
240 B = ( (((*P) << 3) & 0xf8) | (((*P) ) & 0x7) ); \
241 A = CHAN_MAX
242
243 #include "swrast/s_spantemp.h"
244
245
246 /* 15-bit BGR (XXX implement dithering someday) */
247 #define NAME(PREFIX) PREFIX##_B5G5R5
248 #define SPAN_VARS \
249 const fbContextPtr fbdevctx = FB_CONTEXT(ctx); \
250 __DRIdrawablePrivate *dPriv = fbdevctx->dri.drawable; \
251 const fbDrawablePtr fbdrawable = (fbDrawablePtr)dPriv->driverPrivate;
252 #define INIT_PIXEL_PTR(P, X, Y) \
253 GLushort *P = (GLushort *) ((char *)fbdrawable->currentBuffer + (Y) * fbdrawable->currentPitch + (X) * 2)
254 #define INC_PIXEL_PTR(P) P += 1
255 #define STORE_RGB_PIXEL(P, X, Y, R, G, B) \
256 *P = ( (((R) & 0xf8) << 7) | (((G) & 0xf8) << 2) | ((B) >> 3) )
257 #define STORE_RGBA_PIXEL(P, X, Y, R, G, B, A) \
258 *P = ( (((R) & 0xf8) << 7) | (((G) & 0xf8) << 2) | ((B) >> 3) )
259 #define FETCH_RGBA_PIXEL(R, G, B, A, P) \
260 R = ( (((*P) >> 7) & 0xf8) | (((*P) >> 10) & 0x7) ); \
261 G = ( (((*P) >> 2) & 0xf8) | (((*P) >> 5) & 0x7) ); \
262 B = ( (((*P) << 3) & 0xf8) | (((*P) ) & 0x7) ); \
263 A = CHAN_MAX
264
265 #include "swrast/s_spantemp.h"
266
267
268 /* 8-bit color index */
269 #define NAME(PREFIX) PREFIX##_CI8
270 #define SPAN_VARS \
271 const fbContextPtr fbdevctx = FB_CONTEXT(ctx); \
272 __DRIdrawablePrivate *dPriv = fbdevctx->dri.drawable; \
273 const fbDrawablePtr fbdrawable = (fbDrawablePtr)dPriv->driverPrivate;
274 #define INIT_PIXEL_PTR(P, X, Y) \
275 GLubyte *P = (GLubyte *)fbdrawable->currentBuffer + (Y) * fbdrawable->currentPitch + (X)
276 #define INC_PIXEL_PTR(P) P += 1
277 #define STORE_CI_PIXEL(P, CI) \
278 P[0] = CI
279 #define FETCH_CI_PIXEL(CI, P) \
280 CI = P[0]
281
282 #include "swrast/s_spantemp.h"
283
284
285 /* Initialize the driver specific screen private data.
286 */
287 static GLboolean
288 fbInitDriver( __DRIscreenPrivate *sPriv )
289 {
290 fbDRIPtr dri_priv = (fbDRIPtr)sPriv->pDevPriv;
291 fbDRIPtr priv;
292 int drmFD;
293
294 drmFD = drmOpen("radeon", NULL );
295 if (drmFD < 0) {
296 fprintf(stderr, "[drm] drmOpen failed\n");
297 return GL_FALSE;
298 }
299
300 priv = _mesa_malloc(sizeof(*priv));
301 if (!priv)
302 return GL_FALSE;
303
304 *priv = *dri_priv;
305
306 priv->drmFD = drmFD;
307 if (drmMap(drmFD, priv->hFrameBuffer, priv->fbSize, &priv->fbMap) < 0) {
308 fprintf(stderr, "[drm] drmMap framebuffer failed\n");
309 free(priv);
310 return GL_FALSE;
311 }
312
313 sPriv->private = priv;
314 return GL_TRUE;
315 }
316
317 static void
318 fbDestroyScreen( __DRIscreenPrivate *sPriv )
319 {
320 fbDRIPtr priv = (fbDRIPtr)sPriv->private;
321
322 drmUnmap(priv->fbMap, priv->fbSize);
323 drmClose(priv->drmFD);
324 _mesa_free(priv);
325 }
326
327 /* Create the device specific context.
328 */
329 static GLboolean
330 fbCreateContext( const __GLcontextModes *glVisual,
331 __DRIcontextPrivate *driContextPriv,
332 void *sharedContextPrivate)
333 {
334 fbContextPtr fbmesa;
335 GLcontext *ctx, *shareCtx;
336 struct dd_function_table functions;
337
338 assert(glVisual);
339 assert(driContextPriv);
340
341 /* Allocate the Fb context */
342 fbmesa = (fbContextPtr) _mesa_calloc( sizeof(*fbmesa) );
343 if ( !fbmesa )
344 return GL_FALSE;
345
346 /* Init default driver functions then plug in our FBdev-specific functions
347 */
348 _mesa_init_driver_functions(&functions);
349 init_core_functions(&functions);
350
351 /* Allocate the Mesa context */
352 if (sharedContextPrivate)
353 shareCtx = ((fbContextPtr) sharedContextPrivate)->glCtx;
354 else
355 shareCtx = NULL;
356
357 ctx = fbmesa->glCtx = _mesa_create_context(glVisual, shareCtx,
358 &functions, (void *) fbmesa);
359 if (!fbmesa->glCtx) {
360 _mesa_free(fbmesa);
361 return GL_FALSE;
362 }
363 driContextPriv->driverPrivate = fbmesa;
364
365 /* Create module contexts */
366 _swrast_CreateContext( ctx );
367 _ac_CreateContext( ctx );
368 _tnl_CreateContext( ctx );
369 _swsetup_CreateContext( ctx );
370 _swsetup_Wakeup( ctx );
371
372
373 /* swrast init -- need to verify these tests - I just plucked the
374 * numbers out of the air. (KW)
375 */
376 {
377 struct swrast_device_driver *swdd;
378 swdd = _swrast_GetDeviceDriverReference( ctx );
379 swdd->SetBuffer = set_buffer;
380 if (!glVisual->rgbMode) {
381 swdd->WriteCI32Span = write_index32_span_CI8;
382 swdd->WriteCI8Span = write_index8_span_CI8;
383 swdd->WriteMonoCISpan = write_monoindex_span_CI8;
384 swdd->WriteCI32Pixels = write_index_pixels_CI8;
385 swdd->WriteMonoCIPixels = write_monoindex_pixels_CI8;
386 swdd->ReadCI32Span = read_index_span_CI8;
387 swdd->ReadCI32Pixels = read_index_pixels_CI8;
388 }
389 else if (glVisual->rgbBits == 24 &&
390 glVisual->alphaBits == 0) {
391 swdd->WriteRGBASpan = write_rgba_span_B8G8R8;
392 swdd->WriteRGBSpan = write_rgb_span_B8G8R8;
393 swdd->WriteMonoRGBASpan = write_monorgba_span_B8G8R8;
394 swdd->WriteRGBAPixels = write_rgba_pixels_B8G8R8;
395 swdd->WriteMonoRGBAPixels = write_monorgba_pixels_B8G8R8;
396 swdd->ReadRGBASpan = read_rgba_span_B8G8R8;
397 swdd->ReadRGBAPixels = read_rgba_pixels_B8G8R8;
398 }
399 else if (glVisual->rgbBits == 32 &&
400 glVisual->alphaBits == 8) {
401 swdd->WriteRGBASpan = write_rgba_span_B8G8R8A8;
402 swdd->WriteRGBSpan = write_rgb_span_B8G8R8A8;
403 swdd->WriteMonoRGBASpan = write_monorgba_span_B8G8R8A8;
404 swdd->WriteRGBAPixels = write_rgba_pixels_B8G8R8A8;
405 swdd->WriteMonoRGBAPixels = write_monorgba_pixels_B8G8R8A8;
406 swdd->ReadRGBASpan = read_rgba_span_B8G8R8A8;
407 swdd->ReadRGBAPixels = read_rgba_pixels_B8G8R8A8;
408 }
409 else if (glVisual->rgbBits == 16 &&
410 glVisual->alphaBits == 0) {
411 swdd->WriteRGBASpan = write_rgba_span_B5G6R5;
412 swdd->WriteRGBSpan = write_rgb_span_B5G6R5;
413 swdd->WriteMonoRGBASpan = write_monorgba_span_B5G6R5;
414 swdd->WriteRGBAPixels = write_rgba_pixels_B5G6R5;
415 swdd->WriteMonoRGBAPixels = write_monorgba_pixels_B5G6R5;
416 swdd->ReadRGBASpan = read_rgba_span_B5G6R5;
417 swdd->ReadRGBAPixels = read_rgba_pixels_B5G6R5;
418 }
419 else if (glVisual->rgbBits == 15 &&
420 glVisual->alphaBits == 0) {
421 swdd->WriteRGBASpan = write_rgba_span_B5G5R5;
422 swdd->WriteRGBSpan = write_rgb_span_B5G5R5;
423 swdd->WriteMonoRGBASpan = write_monorgba_span_B5G5R5;
424 swdd->WriteRGBAPixels = write_rgba_pixels_B5G5R5;
425 swdd->WriteMonoRGBAPixels = write_monorgba_pixels_B5G5R5;
426 swdd->ReadRGBASpan = read_rgba_span_B5G5R5;
427 swdd->ReadRGBAPixels = read_rgba_pixels_B5G5R5;
428 }
429 else {
430 _mesa_printf("bad pixelformat rgb %d alpha %d\n",
431 glVisual->rgbBits,
432 glVisual->alphaBits );
433 }
434 }
435
436 /* use default TCL pipeline */
437 {
438 TNLcontext *tnl = TNL_CONTEXT(ctx);
439 tnl->Driver.RunPipeline = _tnl_run_pipeline;
440 }
441
442 _mesa_enable_sw_extensions(ctx);
443
444 return GL_TRUE;
445 }
446
447
448 static void
449 fbDestroyContext( __DRIcontextPrivate *driContextPriv )
450 {
451 GET_CURRENT_CONTEXT(ctx);
452 fbContextPtr fbmesa = (fbContextPtr) driContextPriv->driverPrivate;
453 fbContextPtr current = ctx ? FB_CONTEXT(ctx) : NULL;
454
455 /* check if we're deleting the currently bound context */
456 if (fbmesa == current) {
457 _mesa_make_current2(NULL, NULL, NULL);
458 }
459
460 /* Free fb context resources */
461 if ( fbmesa ) {
462 _swsetup_DestroyContext( fbmesa->glCtx );
463 _tnl_DestroyContext( fbmesa->glCtx );
464 _ac_DestroyContext( fbmesa->glCtx );
465 _swrast_DestroyContext( fbmesa->glCtx );
466
467 /* free the Mesa context */
468 fbmesa->glCtx->DriverCtx = NULL;
469 _mesa_destroy_context( fbmesa->glCtx );
470
471 _mesa_free( fbmesa );
472 }
473 }
474
475
476 /* Create and initialize the Mesa and driver specific pixmap buffer
477 * data.
478 */
479 static GLboolean
480 fbCreateBuffer( __DRIscreenPrivate *driScrnPriv,
481 __DRIdrawablePrivate *driDrawPriv,
482 const __GLcontextModes *mesaVis,
483 GLboolean isPixmap )
484 {
485 fbDRIPtr spriv = (fbDRIPtr)driScrnPriv->private;
486 fbDrawablePtr fbdrawable;
487
488 if (isPixmap) {
489 return GL_FALSE; /* not implemented */
490 }
491 else {
492 const GLboolean swDepth = mesaVis->depthBits > 0;
493 const GLboolean swAlpha = mesaVis->alphaBits > 0;
494 const GLboolean swAccum = mesaVis->accumRedBits > 0;
495 const GLboolean swStencil = mesaVis->stencilBits > 0;
496
497 fbdrawable = _mesa_calloc(sizeof(*fbdrawable));
498 if (!fbdrawable)
499 return 0;
500
501 fbdrawable->mesa_framebuffer = (void *)
502 _mesa_create_framebuffer( mesaVis,
503 swDepth,
504 swStencil,
505 swAccum,
506 swAlpha );
507
508 if (!fbdrawable->mesa_framebuffer) {
509 _mesa_free(fbdrawable);
510 return 0;
511 }
512 driDrawPriv->driverPrivate = fbdrawable;
513
514 fbdrawable->frontBuffer = fbdrawable->currentBuffer = spriv->fbMap;
515 fbdrawable->currentPitch = spriv->fbWidth;
516
517 /* Replace the framebuffer back buffer with a malloc'ed one --
518 * big speedup.
519 */
520 fbdrawable->backBuffer = _mesa_malloc(fbdrawable->currentPitch * driDrawPriv->h);
521
522 return 1;
523 }
524 }
525
526
527 static void
528 fbDestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
529 {
530 fbDrawablePtr fbdrawable = (fbDrawablePtr)driDrawPriv->driverPrivate;
531
532 _mesa_destroy_framebuffer(fbdrawable->mesa_framebuffer);
533 _mesa_free(fbdrawable->backBuffer);
534 _mesa_free(fbdrawable);
535 driDrawPriv->driverPrivate = NULL;
536 }
537
538
539
540 /* If the backbuffer is on a videocard, this is extraordinarily slow!
541 */
542 static void
543 fbSwapBuffers( __DRIdrawablePrivate *dPriv )
544 {
545 fbDrawablePtr fbdrawable = (fbDrawablePtr)dPriv->driverPrivate;
546
547 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
548 fbContextPtr fbmesa;
549 GLcontext *ctx;
550 fbmesa = (fbContextPtr) dPriv->driContextPriv->driverPrivate;
551 ctx = fbmesa->glCtx;
552 if (ctx->Visual.doubleBufferMode) {
553 int i;
554 int offset = 0;
555 char *tmp = _mesa_malloc(fbdrawable->currentPitch);
556
557 _mesa_notifySwapBuffers( ctx ); /* flush pending rendering comands */
558
559 ASSERT(fbdrawable->frontBuffer);
560 ASSERT(fbdrawable->backBuffer);
561
562 for (i = 0; i < dPriv->h; i++) {
563 _mesa_memcpy(tmp, (char *) fbdrawable->backBuffer + offset,
564 fbdrawable->currentPitch);
565 _mesa_memcpy((char *) fbdrawable->frontBuffer + offset, tmp,
566 fbdrawable->currentPitch);
567 offset += fbdrawable->currentPitch;
568 }
569
570 _mesa_free(tmp);
571 }
572 }
573 else {
574 /* XXX this shouldn't be an error but we can't handle it for now */
575 _mesa_problem(NULL, "fbSwapBuffers: drawable has no context!\n");
576 }
577 }
578
579
580 /* Force the context `c' to be the current context and associate with it
581 * buffer `b'.
582 */
583 static GLboolean
584 fbMakeCurrent( __DRIcontextPrivate *driContextPriv,
585 __DRIdrawablePrivate *driDrawPriv,
586 __DRIdrawablePrivate *driReadPriv )
587 {
588 if ( driContextPriv ) {
589 fbContextPtr newFbCtx =
590 (fbContextPtr) driContextPriv->driverPrivate;
591
592 newFbCtx->dri.drawable = driDrawPriv;
593
594 _mesa_make_current2( newFbCtx->glCtx,
595 ((fbDrawablePtr)driDrawPriv->driverPrivate)->mesa_framebuffer,
596 ((fbDrawablePtr)driReadPriv->driverPrivate)->mesa_framebuffer);
597 } else {
598 _mesa_make_current( 0, 0 );
599 }
600
601 return GL_TRUE;
602 }
603
604
605 /* Force the context `c' to be unbound from its buffer.
606 */
607 static GLboolean
608 fbUnbindContext( __DRIcontextPrivate *driContextPriv )
609 {
610 return GL_TRUE;
611 }
612
613 static struct __DriverAPIRec fbAPI = {
614 .InitDriver = fbInitDriver,
615 .DestroyScreen = fbDestroyScreen,
616 .CreateContext = fbCreateContext,
617 .DestroyContext = fbDestroyContext,
618 .CreateBuffer = fbCreateBuffer,
619 .DestroyBuffer = fbDestroyBuffer,
620 .SwapBuffers = fbSwapBuffers,
621 .MakeCurrent = fbMakeCurrent,
622 .UnbindContext = fbUnbindContext,
623 };
624
625
626
627 static int
628 __driValidateMode(const DRIDriverContext *ctx )
629 {
630 return 1;
631 }
632
633 static int
634 __driInitFBDev( struct DRIDriverContextRec *ctx )
635 {
636 fbDRIPtr pfbDRI;
637
638 /* Note that drmOpen will try to load the kernel module, if needed. */
639 /* we need a fbdev drm driver - it will only track maps */
640 ctx->drmFD = drmOpen("radeon", NULL );
641 if (ctx->drmFD < 0) {
642 fprintf(stderr, "[drm] drmOpen failed\n");
643 return 0;
644 }
645
646 ctx->shared.SAREASize = SAREA_MAX;
647
648 if (drmAddMap( ctx->drmFD,
649 0,
650 ctx->shared.SAREASize,
651 DRM_SHM,
652 DRM_CONTAINS_LOCK,
653 &ctx->shared.hSAREA) < 0)
654 {
655 fprintf(stderr, "[drm] drmAddMap failed\n");
656 return 0;
657 }
658 fprintf(stderr, "[drm] added %d byte SAREA at 0x%08lx\n",
659 ctx->shared.SAREASize, ctx->shared.hSAREA);
660
661 if (drmMap( ctx->drmFD,
662 ctx->shared.hSAREA,
663 ctx->shared.SAREASize,
664 (drmAddressPtr)(&ctx->pSAREA)) < 0)
665 {
666 fprintf(stderr, "[drm] drmMap failed\n");
667 return 0;
668 }
669 memset(ctx->pSAREA, 0, ctx->shared.SAREASize);
670 fprintf(stderr, "[drm] mapped SAREA 0x%08lx to %p, size %d\n",
671 ctx->shared.hSAREA, ctx->pSAREA, ctx->shared.SAREASize);
672
673 /* Need to AddMap the framebuffer and mmio regions here:
674 */
675 if (drmAddMap( ctx->drmFD,
676 (drm_handle_t)ctx->FBStart,
677 ctx->FBSize,
678 DRM_FRAME_BUFFER,
679 #ifndef _EMBEDDED
680 0,
681 #else
682 DRM_READ_ONLY,
683 #endif
684 &ctx->shared.hFrameBuffer) < 0)
685 {
686 fprintf(stderr, "[drm] drmAddMap framebuffer failed\n");
687 return 0;
688 }
689
690 fprintf(stderr, "[drm] framebuffer handle = 0x%08lx\n",
691 ctx->shared.hFrameBuffer);
692
693 pfbDRI = (fbDRIPtr)malloc(sizeof(*pfbDRI));
694 pfbDRI->hFrameBuffer = ctx->shared.hFrameBuffer;
695 pfbDRI->fbOrigin = ctx->shared.fbOrigin;
696 pfbDRI->fbSize = ctx->shared.fbSize;
697 pfbDRI->fbStride = ctx->shared.fbStride;
698 pfbDRI->fbWidth = ctx->shared.virtualWidth;
699 pfbDRI->fbHeight = ctx->shared.virtualHeight;
700 pfbDRI->bpp = ctx->bpp;
701
702 ctx->driverClientMsg = pfbDRI;
703 ctx->driverClientMsgSize = sizeof(*pfbDRI);
704
705 return 1;
706 }
707
708 static void
709 __driHaltFBDev( struct DRIDriverContextRec *ctx )
710 {
711 }
712
713 struct DRIDriverRec __driDriver = {
714 __driValidateMode,
715 __driValidateMode,
716 __driInitFBDev,
717 __driHaltFBDev
718 };
719
720 #ifdef USE_NEW_INTERFACE
721 static __GLcontextModes *
722 fbFillInModes( unsigned pixel_bits, unsigned depth_bits,
723 unsigned stencil_bits, GLboolean have_back_buffer )
724 {
725 __GLcontextModes * modes;
726 __GLcontextModes * m;
727 unsigned num_modes;
728 unsigned depth_buffer_factor;
729 unsigned back_buffer_factor;
730 GLenum fb_format;
731 GLenum fb_type;
732
733 /* Right now GLX_SWAP_COPY_OML isn't supported, but it would be easy
734 * enough to add support. Basically, if a context is created with an
735 * fbconfig where the swap method is GLX_SWAP_COPY_OML, pageflipping
736 * will never be used.
737 */
738 static const GLenum back_buffer_modes[] = {
739 GLX_NONE, GLX_SWAP_UNDEFINED_OML /*, GLX_SWAP_COPY_OML */
740 };
741
742 u_int8_t depth_bits_array[2];
743 u_int8_t stencil_bits_array[2];
744
745
746 depth_bits_array[0] = depth_bits;
747 depth_bits_array[1] = depth_bits;
748
749 /* Just like with the accumulation buffer, always provide some modes
750 * with a stencil buffer. It will be a sw fallback, but some apps won't
751 * care about that.
752 */
753 stencil_bits_array[0] = 0;
754 stencil_bits_array[1] = (stencil_bits == 0) ? 8 : stencil_bits;
755
756 depth_buffer_factor = ((depth_bits != 0) || (stencil_bits != 0)) ? 2 : 1;
757 back_buffer_factor = (have_back_buffer) ? 2 : 1;
758
759 num_modes = depth_buffer_factor * back_buffer_factor * 4;
760
761 if ( pixel_bits == 16 ) {
762 fb_format = GL_RGB;
763 fb_type = GL_UNSIGNED_SHORT_5_6_5;
764 }
765 else {
766 fb_format = GL_BGR;
767 fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
768 }
769
770 modes = (*create_context_modes)( num_modes, sizeof( __GLcontextModes ) );
771 m = modes;
772 if ( ! driFillInModes( & m, fb_format, fb_type,
773 depth_bits_array, stencil_bits_array, depth_buffer_factor,
774 back_buffer_modes, back_buffer_factor,
775 GLX_TRUE_COLOR ) ) {
776 fprintf( stderr, "[%s:%u] Error creating FBConfig!\n",
777 __func__, __LINE__ );
778 return NULL;
779 }
780
781 if ( ! driFillInModes( & m, fb_format, fb_type,
782 depth_bits_array, stencil_bits_array, depth_buffer_factor,
783 back_buffer_modes, back_buffer_factor,
784 GLX_DIRECT_COLOR ) ) {
785 fprintf( stderr, "[%s:%u] Error creating FBConfig!\n",
786 __func__, __LINE__ );
787 return NULL;
788 }
789
790 /* Mark the visual as slow if there are "fake" stencil bits.
791 */
792 for ( m = modes ; m != NULL ; m = m->next ) {
793 if ( (m->stencilBits != 0) && (m->stencilBits != stencil_bits) ) {
794 m->visualRating = GLX_SLOW_CONFIG;
795 }
796 }
797
798 return modes;
799 }
800
801
802 /**
803 * This is the bootstrap function for the driver. libGL supplies all of the
804 * requisite information about the system, and the driver initializes itself.
805 * This routine also fills in the linked list pointed to by \c driver_modes
806 * with the \c __GLcontextModes that the driver can support for windows or
807 * pbuffers.
808 *
809 * \return A pointer to a \c __DRIscreenPrivate on success, or \c NULL on
810 * failure.
811 */
812 PUBLIC
813 void * __driCreateNewScreen( __DRInativeDisplay *dpy, int scrn, __DRIscreen *psc,
814 const __GLcontextModes * modes,
815 const __DRIversion * ddx_version,
816 const __DRIversion * dri_version,
817 const __DRIversion * drm_version,
818 const __DRIframebuffer * frame_buffer,
819 drmAddress pSAREA, int fd,
820 int internal_api_version,
821 __GLcontextModes ** driver_modes )
822 {
823 __DRIscreenPrivate *psp;
824 static const __DRIversion ddx_expected = { 4, 0, 0 };
825 static const __DRIversion dri_expected = { 4, 0, 0 };
826 static const __DRIversion drm_expected = { 1, 5, 0 };
827
828
829 if ( ! driCheckDriDdxDrmVersions2( "fb",
830 dri_version, & dri_expected,
831 ddx_version, & ddx_expected,
832 drm_version, & drm_expected ) ) {
833 return NULL;
834 }
835
836 psp = __driUtilCreateNewScreen(dpy, scrn, psc, NULL,
837 ddx_version, dri_version, drm_version,
838 frame_buffer, pSAREA, fd,
839 internal_api_version, &fbAPI);
840 if ( psp != NULL ) {
841 create_context_modes = (PFNGLXCREATECONTEXTMODES)
842 glXGetProcAddress( (const GLubyte *) "__glXCreateContextModes" );
843 if ( create_context_modes != NULL ) {
844 #if 0
845 fbDRIPtr dri_priv = (fbDRIPtr) psp->pDevPriv;
846 *driver_modes = fbFillInModes( dri_priv->bpp,
847 (dri_priv->bpp == 16) ? 16 : 24,
848 (dri_priv->bpp == 16) ? 0 : 8,
849 (dri_priv->backOffset != dri_priv->depthOffset) );
850 #endif
851 *driver_modes = fbFillInModes( 24, 24, 8, 0);
852 }
853 }
854
855 return (void *) psp;
856 }
857 #endif /* USE_NEW_INTERFACE */