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