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