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