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