| /* |
| * Mesa 3-D graphics library |
| * Version: 6.3 |
| * |
| * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included |
| * in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
| * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| |
| /* Minimal swrast-based dri loadable driver. |
| * |
| * Todo: |
| * -- Use malloced (rather than framebuffer) memory for backbuffer |
| * -- 32bpp is hardwared -- fix |
| * |
| * NOTES: |
| * -- No mechanism for cliprects or resize notification -- |
| * assumes this is a fullscreen device. |
| * -- No locking -- assumes this is the only driver accessing this |
| * device. |
| * -- Doesn't (yet) make use of any acceleration or other interfaces |
| * provided by fb. Would be entirely happy working against any |
| * fullscreen interface. |
| * -- HOWEVER: only a small number of pixelformats are supported, and |
| * the mechanism for choosing between them makes some assumptions |
| * that may not be valid everywhere. |
| */ |
| |
| #include "driver.h" |
| #include "drm.h" |
| #include "utils.h" |
| #include "drirenderbuffer.h" |
| |
| #include "buffers.h" |
| #include "extensions.h" |
| #include "framebuffer.h" |
| #include "renderbuffer.h" |
| #include "vbo/vbo.h" |
| #include "swrast/swrast.h" |
| #include "swrast_setup/swrast_setup.h" |
| #include "tnl/tnl.h" |
| #include "tnl/t_context.h" |
| #include "tnl/t_pipeline.h" |
| #include "drivers/common/driverfuncs.h" |
| |
| void fbSetSpanFunctions(driRenderbuffer *drb, const GLvisual *vis); |
| |
| typedef struct { |
| GLcontext *glCtx; /* Mesa context */ |
| |
| struct { |
| __DRIcontextPrivate *context; |
| __DRIscreenPrivate *screen; |
| __DRIdrawablePrivate *drawable; /* drawable bound to this ctx */ |
| } dri; |
| |
| } fbContext, *fbContextPtr; |
| |
| #define FB_CONTEXT(ctx) ((fbContextPtr)(ctx->DriverCtx)) |
| |
| |
| static const GLubyte * |
| get_string(GLcontext *ctx, GLenum pname) |
| { |
| (void) ctx; |
| switch (pname) { |
| case GL_RENDERER: |
| return (const GLubyte *) "Mesa dumb framebuffer"; |
| default: |
| return NULL; |
| } |
| } |
| |
| |
| static void |
| update_state( GLcontext *ctx, GLuint new_state ) |
| { |
| /* not much to do here - pass it on */ |
| _swrast_InvalidateState( ctx, new_state ); |
| _swsetup_InvalidateState( ctx, new_state ); |
| _vbo_InvalidateState( ctx, new_state ); |
| _tnl_InvalidateState( ctx, new_state ); |
| } |
| |
| |
| /** |
| * Called by ctx->Driver.GetBufferSize from in core Mesa to query the |
| * current framebuffer size. |
| */ |
| static void |
| get_buffer_size( GLframebuffer *buffer, GLuint *width, GLuint *height ) |
| { |
| GET_CURRENT_CONTEXT(ctx); |
| fbContextPtr fbmesa = FB_CONTEXT(ctx); |
| |
| *width = fbmesa->dri.drawable->w; |
| *height = fbmesa->dri.drawable->h; |
| } |
| |
| |
| static void |
| updateFramebufferSize(GLcontext *ctx) |
| { |
| fbContextPtr fbmesa = FB_CONTEXT(ctx); |
| struct gl_framebuffer *fb = ctx->WinSysDrawBuffer; |
| if (fbmesa->dri.drawable->w != fb->Width || |
| fbmesa->dri.drawable->h != fb->Height) { |
| driUpdateFramebufferSize(ctx, fbmesa->dri.drawable); |
| } |
| } |
| |
| static void |
| viewport(GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h) |
| { |
| /* XXX this should be called after we acquire the DRI lock, not here */ |
| updateFramebufferSize(ctx); |
| } |
| |
| |
| static void |
| init_core_functions( struct dd_function_table *functions ) |
| { |
| functions->GetString = get_string; |
| functions->UpdateState = update_state; |
| functions->GetBufferSize = get_buffer_size; |
| functions->Viewport = viewport; |
| |
| functions->Clear = _swrast_Clear; /* could accelerate with blits */ |
| } |
| |
| |
| /* |
| * Generate code for span functions. |
| */ |
| |
| /* 24-bit BGR */ |
| #define NAME(PREFIX) PREFIX##_B8G8R8 |
| #define FORMAT GL_RGBA8 |
| #define SPAN_VARS \ |
| driRenderbuffer *drb = (driRenderbuffer *) rb; |
| #define INIT_PIXEL_PTR(P, X, Y) \ |
| GLubyte *P = (GLubyte *)drb->Base.Data + (drb->Base.Height - (Y)) * drb->pitch + (X) * 3; |
| #define INC_PIXEL_PTR(P) P += 3 |
| #define STORE_PIXEL(DST, X, Y, VALUE) \ |
| DST[0] = VALUE[BCOMP]; \ |
| DST[1] = VALUE[GCOMP]; \ |
| DST[2] = VALUE[RCOMP] |
| #define FETCH_PIXEL(DST, SRC) \ |
| DST[RCOMP] = SRC[2]; \ |
| DST[GCOMP] = SRC[1]; \ |
| DST[BCOMP] = SRC[0]; \ |
| DST[ACOMP] = 0xff |
| |
| #include "swrast/s_spantemp.h" |
| |
| |
| /* 32-bit BGRA */ |
| #define NAME(PREFIX) PREFIX##_B8G8R8A8 |
| #define FORMAT GL_RGBA8 |
| #define SPAN_VARS \ |
| driRenderbuffer *drb = (driRenderbuffer *) rb; |
| #define INIT_PIXEL_PTR(P, X, Y) \ |
| GLubyte *P = (GLubyte *)drb->Base.Data + (drb->Base.Height - (Y)) * drb->pitch + (X) * 4; |
| #define INC_PIXEL_PTR(P) P += 4 |
| #define STORE_PIXEL(DST, X, Y, VALUE) \ |
| DST[0] = VALUE[BCOMP]; \ |
| DST[1] = VALUE[GCOMP]; \ |
| DST[2] = VALUE[RCOMP]; \ |
| DST[3] = VALUE[ACOMP] |
| #define STORE_PIXEL_RGB(DST, X, Y, VALUE) \ |
| DST[0] = VALUE[BCOMP]; \ |
| DST[1] = VALUE[GCOMP]; \ |
| DST[2] = VALUE[RCOMP]; \ |
| DST[3] = 0xff |
| #define FETCH_PIXEL(DST, SRC) \ |
| DST[RCOMP] = SRC[2]; \ |
| DST[GCOMP] = SRC[1]; \ |
| DST[BCOMP] = SRC[0]; \ |
| DST[ACOMP] = SRC[3] |
| |
| #include "swrast/s_spantemp.h" |
| |
| |
| /* 16-bit BGR (XXX implement dithering someday) */ |
| #define NAME(PREFIX) PREFIX##_B5G6R5 |
| #define FORMAT GL_RGBA8 |
| #define SPAN_VARS \ |
| driRenderbuffer *drb = (driRenderbuffer *) rb; |
| #define INIT_PIXEL_PTR(P, X, Y) \ |
| GLushort *P = (GLushort *)drb->Base.Data + (drb->Base.Height - (Y)) * drb->pitch + (X) * 2; |
| #define INC_PIXEL_PTR(P) P += 1 |
| #define STORE_PIXEL(DST, X, Y, VALUE) \ |
| DST[0] = ( (((VALUE[RCOMP]) & 0xf8) << 8) | (((VALUE[GCOMP]) & 0xfc) << 3) | ((VALUE[BCOMP]) >> 3) ) |
| #define FETCH_PIXEL(DST, SRC) \ |
| DST[RCOMP] = ( (((SRC[0]) >> 8) & 0xf8) | (((SRC[0]) >> 11) & 0x7) ); \ |
| DST[GCOMP] = ( (((SRC[0]) >> 3) & 0xfc) | (((SRC[0]) >> 5) & 0x3) ); \ |
| DST[BCOMP] = ( (((SRC[0]) << 3) & 0xf8) | (((SRC[0]) ) & 0x7) ); \ |
| DST[ACOMP] = 0xff |
| |
| #include "swrast/s_spantemp.h" |
| |
| |
| /* 15-bit BGR (XXX implement dithering someday) */ |
| #define NAME(PREFIX) PREFIX##_B5G5R5 |
| #define FORMAT GL_RGBA8 |
| #define SPAN_VARS \ |
| driRenderbuffer *drb = (driRenderbuffer *) rb; |
| #define INIT_PIXEL_PTR(P, X, Y) \ |
| GLushort *P = (GLushort *)drb->Base.Data + (drb->Base.Height - (Y)) * drb->pitch + (X) * 2; |
| #define INC_PIXEL_PTR(P) P += 1 |
| #define STORE_PIXEL(DST, X, Y, VALUE) \ |
| DST[0] = ( (((VALUE[RCOMP]) & 0xf8) << 7) | (((VALUE[GCOMP]) & 0xf8) << 2) | ((VALUE[BCOMP]) >> 3) ) |
| #define FETCH_PIXEL(DST, SRC) \ |
| DST[RCOMP] = ( (((SRC[0]) >> 7) & 0xf8) | (((SRC[0]) >> 10) & 0x7) ); \ |
| DST[GCOMP] = ( (((SRC[0]) >> 2) & 0xf8) | (((SRC[0]) >> 5) & 0x7) ); \ |
| DST[BCOMP] = ( (((SRC[0]) << 3) & 0xf8) | (((SRC[0]) ) & 0x7) ); \ |
| DST[ACOMP] = 0xff |
| |
| #include "swrast/s_spantemp.h" |
| |
| |
| /* 8-bit color index */ |
| #define NAME(PREFIX) PREFIX##_CI8 |
| #define FORMAT GL_COLOR_INDEX8_EXT |
| #define SPAN_VARS \ |
| driRenderbuffer *drb = (driRenderbuffer *) rb; |
| #define INIT_PIXEL_PTR(P, X, Y) \ |
| GLubyte *P = (GLubyte *)drb->Base.Data + (drb->Base.Height - (Y)) * drb->pitch + (X); |
| #define INC_PIXEL_PTR(P) P += 1 |
| #define STORE_PIXEL(DST, X, Y, VALUE) \ |
| *DST = VALUE[0] |
| #define FETCH_PIXEL(DST, SRC) \ |
| DST = SRC[0] |
| |
| #include "swrast/s_spantemp.h" |
| |
| |
| |
| void |
| fbSetSpanFunctions(driRenderbuffer *drb, const GLvisual *vis) |
| { |
| ASSERT(drb->Base.InternalFormat == GL_RGBA); |
| if (drb->Base.InternalFormat == GL_RGBA) { |
| if (vis->redBits == 5 && vis->greenBits == 6 && vis->blueBits == 5) { |
| drb->Base.GetRow = get_row_B5G6R5; |
| drb->Base.GetValues = get_values_B5G6R5; |
| drb->Base.PutRow = put_row_B5G6R5; |
| drb->Base.PutMonoRow = put_mono_row_B5G6R5; |
| drb->Base.PutRowRGB = put_row_rgb_B5G6R5; |
| drb->Base.PutValues = put_values_B5G6R5; |
| drb->Base.PutMonoValues = put_mono_values_B5G6R5; |
| } |
| else if (vis->redBits == 5 && vis->greenBits == 5 && vis->blueBits == 5) { |
| drb->Base.GetRow = get_row_B5G5R5; |
| drb->Base.GetValues = get_values_B5G5R5; |
| drb->Base.PutRow = put_row_B5G5R5; |
| drb->Base.PutMonoRow = put_mono_row_B5G5R5; |
| drb->Base.PutRowRGB = put_row_rgb_B5G5R5; |
| drb->Base.PutValues = put_values_B5G5R5; |
| drb->Base.PutMonoValues = put_mono_values_B5G5R5; |
| } |
| else if (vis->redBits == 8 && vis->greenBits == 8 && vis->blueBits == 8 |
| && vis->alphaBits == 8) { |
| drb->Base.GetRow = get_row_B8G8R8A8; |
| drb->Base.GetValues = get_values_B8G8R8A8; |
| drb->Base.PutRow = put_row_B8G8R8A8; |
| drb->Base.PutMonoRow = put_mono_row_B8G8R8A8; |
| drb->Base.PutRowRGB = put_row_rgb_B8G8R8A8; |
| drb->Base.PutValues = put_values_B8G8R8A8; |
| drb->Base.PutMonoValues = put_mono_values_B8G8R8A8; |
| } |
| else if (vis->redBits == 8 && vis->greenBits == 8 && vis->blueBits == 8 |
| && vis->alphaBits == 0) { |
| drb->Base.GetRow = get_row_B8G8R8; |
| drb->Base.GetValues = get_values_B8G8R8; |
| drb->Base.PutRow = put_row_B8G8R8; |
| drb->Base.PutMonoRow = put_mono_row_B8G8R8; |
| drb->Base.PutRowRGB = put_row_rgb_B8G8R8; |
| drb->Base.PutValues = put_values_B8G8R8; |
| drb->Base.PutMonoValues = put_mono_values_B8G8R8; |
| } |
| else if (vis->indexBits == 8) { |
| drb->Base.GetRow = get_row_CI8; |
| drb->Base.GetValues = get_values_CI8; |
| drb->Base.PutRow = put_row_CI8; |
| drb->Base.PutMonoRow = put_mono_row_CI8; |
| drb->Base.PutValues = put_values_CI8; |
| drb->Base.PutMonoValues = put_mono_values_CI8; |
| } |
| } |
| else { |
| /* hardware z/stencil/etc someday */ |
| } |
| } |
| |
| |
| |
| /* Initialize the driver specific screen private data. |
| */ |
| static GLboolean |
| fbInitDriver( __DRIscreenPrivate *sPriv ) |
| { |
| sPriv->private = NULL; |
| return GL_TRUE; |
| } |
| |
| static void |
| fbDestroyScreen( __DRIscreenPrivate *sPriv ) |
| { |
| } |
| |
| |
| /* Create the device specific context. |
| */ |
| static GLboolean |
| fbCreateContext( const __GLcontextModes *glVisual, |
| __DRIcontextPrivate *driContextPriv, |
| void *sharedContextPrivate) |
| { |
| fbContextPtr fbmesa; |
| GLcontext *ctx, *shareCtx; |
| struct dd_function_table functions; |
| |
| assert(glVisual); |
| assert(driContextPriv); |
| |
| /* Allocate the Fb context */ |
| fbmesa = (fbContextPtr) _mesa_calloc( sizeof(*fbmesa) ); |
| if ( !fbmesa ) |
| return GL_FALSE; |
| |
| /* Init default driver functions then plug in our FBdev-specific functions |
| */ |
| _mesa_init_driver_functions(&functions); |
| init_core_functions(&functions); |
| |
| /* Allocate the Mesa context */ |
| if (sharedContextPrivate) |
| shareCtx = ((fbContextPtr) sharedContextPrivate)->glCtx; |
| else |
| shareCtx = NULL; |
| |
| ctx = fbmesa->glCtx = _mesa_create_context(glVisual, shareCtx, |
| &functions, (void *) fbmesa); |
| if (!fbmesa->glCtx) { |
| _mesa_free(fbmesa); |
| return GL_FALSE; |
| } |
| driContextPriv->driverPrivate = fbmesa; |
| |
| /* Create module contexts */ |
| _swrast_CreateContext( ctx ); |
| _vbo_CreateContext( ctx ); |
| _tnl_CreateContext( ctx ); |
| _swsetup_CreateContext( ctx ); |
| _swsetup_Wakeup( ctx ); |
| |
| |
| /* use default TCL pipeline */ |
| { |
| TNLcontext *tnl = TNL_CONTEXT(ctx); |
| tnl->Driver.RunPipeline = _tnl_run_pipeline; |
| } |
| |
| _mesa_enable_sw_extensions(ctx); |
| |
| return GL_TRUE; |
| } |
| |
| |
| static void |
| fbDestroyContext( __DRIcontextPrivate *driContextPriv ) |
| { |
| GET_CURRENT_CONTEXT(ctx); |
| fbContextPtr fbmesa = (fbContextPtr) driContextPriv->driverPrivate; |
| fbContextPtr current = ctx ? FB_CONTEXT(ctx) : NULL; |
| |
| /* check if we're deleting the currently bound context */ |
| if (fbmesa == current) { |
| _mesa_make_current(NULL, NULL, NULL); |
| } |
| |
| /* Free fb context resources */ |
| if ( fbmesa ) { |
| _swsetup_DestroyContext( fbmesa->glCtx ); |
| _tnl_DestroyContext( fbmesa->glCtx ); |
| _vbo_DestroyContext( fbmesa->glCtx ); |
| _swrast_DestroyContext( fbmesa->glCtx ); |
| |
| /* free the Mesa context */ |
| fbmesa->glCtx->DriverCtx = NULL; |
| _mesa_destroy_context( fbmesa->glCtx ); |
| |
| _mesa_free( fbmesa ); |
| } |
| } |
| |
| |
| /* Create and initialize the Mesa and driver specific pixmap buffer |
| * data. |
| */ |
| static GLboolean |
| fbCreateBuffer( __DRIscreenPrivate *driScrnPriv, |
| __DRIdrawablePrivate *driDrawPriv, |
| const __GLcontextModes *mesaVis, |
| GLboolean isPixmap ) |
| { |
| struct gl_framebuffer *mesa_framebuffer; |
| |
| if (isPixmap) { |
| return GL_FALSE; /* not implemented */ |
| } |
| else { |
| const GLboolean swDepth = mesaVis->depthBits > 0; |
| const GLboolean swAlpha = mesaVis->alphaBits > 0; |
| const GLboolean swAccum = mesaVis->accumRedBits > 0; |
| const GLboolean swStencil = mesaVis->stencilBits > 0; |
| |
| mesa_framebuffer = _mesa_create_framebuffer(mesaVis); |
| if (!mesa_framebuffer) |
| return 0; |
| |
| /* XXX double-check these parameters (bpp vs cpp, etc) */ |
| { |
| driRenderbuffer *drb = driNewRenderbuffer(GL_RGBA, |
| driScrnPriv->pFB, |
| driScrnPriv->fbBPP / 8, |
| driScrnPriv->fbOrigin, |
| driScrnPriv->fbStride, |
| driDrawPriv); |
| fbSetSpanFunctions(drb, mesaVis); |
| _mesa_add_renderbuffer(mesa_framebuffer, |
| BUFFER_FRONT_LEFT, &drb->Base); |
| } |
| if (mesaVis->doubleBufferMode) { |
| /* XXX what are the correct origin/stride values? */ |
| GLvoid *backBuf = _mesa_malloc(driScrnPriv->fbStride |
| * driScrnPriv->fbHeight); |
| driRenderbuffer *drb = driNewRenderbuffer(GL_RGBA, |
| backBuf, |
| driScrnPriv->fbBPP /8, |
| driScrnPriv->fbOrigin, |
| driScrnPriv->fbStride, |
| driDrawPriv); |
| fbSetSpanFunctions(drb, mesaVis); |
| _mesa_add_renderbuffer(mesa_framebuffer, |
| BUFFER_BACK_LEFT, &drb->Base); |
| } |
| |
| _mesa_add_soft_renderbuffers(mesa_framebuffer, |
| GL_FALSE, /* color */ |
| swDepth, |
| swStencil, |
| swAccum, |
| swAlpha, /* or always zero? */ |
| GL_FALSE /* aux */); |
| |
| driDrawPriv->driverPrivate = mesa_framebuffer; |
| |
| return 1; |
| } |
| } |
| |
| |
| static void |
| fbDestroyBuffer(__DRIdrawablePrivate *driDrawPriv) |
| { |
| _mesa_unreference_framebuffer((GLframebuffer **)(&(driDrawPriv->driverPrivate))); |
| } |
| |
| |
| |
| /* If the backbuffer is on a videocard, this is extraordinarily slow! |
| */ |
| static void |
| fbSwapBuffers( __DRIdrawablePrivate *dPriv ) |
| { |
| struct gl_framebuffer *mesa_framebuffer = (struct gl_framebuffer *)dPriv->driverPrivate; |
| struct gl_renderbuffer * front_renderbuffer = mesa_framebuffer->Attachment[BUFFER_FRONT_LEFT].Renderbuffer; |
| void *frontBuffer = front_renderbuffer->Data; |
| int currentPitch = ((driRenderbuffer *)front_renderbuffer)->pitch; |
| void *backBuffer = mesa_framebuffer->Attachment[BUFFER_BACK_LEFT].Renderbuffer->Data; |
| |
| if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) { |
| fbContextPtr fbmesa = (fbContextPtr) dPriv->driContextPriv->driverPrivate; |
| GLcontext *ctx = fbmesa->glCtx; |
| |
| if (ctx->Visual.doubleBufferMode) { |
| int i; |
| int offset = 0; |
| char *tmp = _mesa_malloc(currentPitch); |
| |
| _mesa_notifySwapBuffers( ctx ); /* flush pending rendering comands */ |
| |
| ASSERT(frontBuffer); |
| ASSERT(backBuffer); |
| |
| for (i = 0; i < dPriv->h; i++) { |
| _mesa_memcpy(tmp, (char *) backBuffer + offset, |
| currentPitch); |
| _mesa_memcpy((char *) frontBuffer + offset, tmp, |
| currentPitch); |
| offset += currentPitch; |
| } |
| |
| _mesa_free(tmp); |
| } |
| } |
| else { |
| /* XXX this shouldn't be an error but we can't handle it for now */ |
| _mesa_problem(NULL, "fbSwapBuffers: drawable has no context!\n"); |
| } |
| } |
| |
| |
| /* Force the context `c' to be the current context and associate with it |
| * buffer `b'. |
| */ |
| static GLboolean |
| fbMakeCurrent( __DRIcontextPrivate *driContextPriv, |
| __DRIdrawablePrivate *driDrawPriv, |
| __DRIdrawablePrivate *driReadPriv ) |
| { |
| if ( driContextPriv ) { |
| fbContextPtr newFbCtx = |
| (fbContextPtr) driContextPriv->driverPrivate; |
| |
| newFbCtx->dri.drawable = driDrawPriv; |
| |
| _mesa_make_current( newFbCtx->glCtx, |
| driDrawPriv->driverPrivate, |
| driReadPriv->driverPrivate); |
| } else { |
| _mesa_make_current( NULL, NULL, NULL ); |
| } |
| |
| return GL_TRUE; |
| } |
| |
| |
| /* Force the context `c' to be unbound from its buffer. |
| */ |
| static GLboolean |
| fbUnbindContext( __DRIcontextPrivate *driContextPriv ) |
| { |
| return GL_TRUE; |
| } |
| |
| static struct __DriverAPIRec fbAPI = { |
| .InitDriver = fbInitDriver, |
| .DestroyScreen = fbDestroyScreen, |
| .CreateContext = fbCreateContext, |
| .DestroyContext = fbDestroyContext, |
| .CreateBuffer = fbCreateBuffer, |
| .DestroyBuffer = fbDestroyBuffer, |
| .SwapBuffers = fbSwapBuffers, |
| .MakeCurrent = fbMakeCurrent, |
| .UnbindContext = fbUnbindContext, |
| }; |
| |
| |
| |
| static int |
| __driValidateMode(const DRIDriverContext *ctx ) |
| { |
| return 1; |
| } |
| |
| static int |
| __driInitFBDev( struct DRIDriverContextRec *ctx ) |
| { |
| /* Note that drmOpen will try to load the kernel module, if needed. */ |
| /* we need a fbdev drm driver - it will only track maps */ |
| ctx->drmFD = drmOpen("radeon", NULL ); |
| if (ctx->drmFD < 0) { |
| fprintf(stderr, "[drm] drmOpen failed\n"); |
| return 0; |
| } |
| |
| ctx->shared.SAREASize = SAREA_MAX; |
| |
| if (drmAddMap( ctx->drmFD, |
| 0, |
| ctx->shared.SAREASize, |
| DRM_SHM, |
| DRM_CONTAINS_LOCK, |
| &ctx->shared.hSAREA) < 0) |
| { |
| fprintf(stderr, "[drm] drmAddMap failed\n"); |
| return 0; |
| } |
| fprintf(stderr, "[drm] added %d byte SAREA at 0x%08lx\n", |
| ctx->shared.SAREASize, |
| (unsigned long) ctx->shared.hSAREA); |
| |
| if (drmMap( ctx->drmFD, |
| ctx->shared.hSAREA, |
| ctx->shared.SAREASize, |
| (drmAddressPtr)(&ctx->pSAREA)) < 0) |
| { |
| fprintf(stderr, "[drm] drmMap failed\n"); |
| return 0; |
| } |
| memset(ctx->pSAREA, 0, ctx->shared.SAREASize); |
| fprintf(stderr, "[drm] mapped SAREA 0x%08lx to %p, size %d\n", |
| (unsigned long) ctx->shared.hSAREA, ctx->pSAREA, |
| ctx->shared.SAREASize); |
| |
| /* Need to AddMap the framebuffer and mmio regions here: |
| */ |
| if (drmAddMap( ctx->drmFD, |
| (drm_handle_t)ctx->FBStart, |
| ctx->FBSize, |
| DRM_FRAME_BUFFER, |
| #ifndef _EMBEDDED |
| 0, |
| #else |
| DRM_READ_ONLY, |
| #endif |
| &ctx->shared.hFrameBuffer) < 0) |
| { |
| fprintf(stderr, "[drm] drmAddMap framebuffer failed\n"); |
| return 0; |
| } |
| |
| fprintf(stderr, "[drm] framebuffer handle = 0x%08lx\n", |
| (unsigned long) ctx->shared.hFrameBuffer); |
| |
| return 1; |
| } |
| |
| static void |
| __driHaltFBDev( struct DRIDriverContextRec *ctx ) |
| { |
| } |
| |
| struct DRIDriverRec __driDriver = { |
| __driValidateMode, |
| __driValidateMode, |
| __driInitFBDev, |
| __driHaltFBDev |
| }; |
| |
| static __GLcontextModes * |
| fbFillInModes( __DRIscreenPrivate *psp, |
| unsigned pixel_bits, unsigned depth_bits, |
| unsigned stencil_bits, GLboolean have_back_buffer ) |
| { |
| __GLcontextModes * modes; |
| __GLcontextModes * m; |
| unsigned num_modes; |
| unsigned depth_buffer_factor; |
| unsigned back_buffer_factor; |
| GLenum fb_format; |
| GLenum fb_type; |
| |
| /* Right now GLX_SWAP_COPY_OML isn't supported, but it would be easy |
| * enough to add support. Basically, if a context is created with an |
| * fbconfig where the swap method is GLX_SWAP_COPY_OML, pageflipping |
| * will never be used. |
| */ |
| static const GLenum back_buffer_modes[] = { |
| GLX_NONE, GLX_SWAP_UNDEFINED_OML /*, GLX_SWAP_COPY_OML */ |
| }; |
| |
| u_int8_t depth_bits_array[2]; |
| u_int8_t stencil_bits_array[2]; |
| |
| |
| depth_bits_array[0] = depth_bits; |
| depth_bits_array[1] = depth_bits; |
| |
| /* Just like with the accumulation buffer, always provide some modes |
| * with a stencil buffer. It will be a sw fallback, but some apps won't |
| * care about that. |
| */ |
| stencil_bits_array[0] = 0; |
| stencil_bits_array[1] = (stencil_bits == 0) ? 8 : stencil_bits; |
| |
| depth_buffer_factor = ((depth_bits != 0) || (stencil_bits != 0)) ? 2 : 1; |
| back_buffer_factor = (have_back_buffer) ? 2 : 1; |
| |
| num_modes = depth_buffer_factor * back_buffer_factor * 4; |
| |
| if ( pixel_bits == 16 ) { |
| fb_format = GL_RGB; |
| fb_type = GL_UNSIGNED_SHORT_5_6_5; |
| } |
| else { |
| fb_format = GL_RGBA; |
| fb_type = GL_UNSIGNED_INT_8_8_8_8_REV; |
| } |
| |
| modes = (*psp->contextModes->createContextModes)( num_modes, sizeof( __GLcontextModes ) ); |
| m = modes; |
| if ( ! driFillInModes( & m, fb_format, fb_type, |
| depth_bits_array, stencil_bits_array, depth_buffer_factor, |
| back_buffer_modes, back_buffer_factor, |
| GLX_TRUE_COLOR ) ) { |
| fprintf( stderr, "[%s:%u] Error creating FBConfig!\n", |
| __func__, __LINE__ ); |
| return NULL; |
| } |
| |
| if ( ! driFillInModes( & m, fb_format, fb_type, |
| depth_bits_array, stencil_bits_array, depth_buffer_factor, |
| back_buffer_modes, back_buffer_factor, |
| GLX_DIRECT_COLOR ) ) { |
| fprintf( stderr, "[%s:%u] Error creating FBConfig!\n", |
| __func__, __LINE__ ); |
| return NULL; |
| } |
| |
| /* Mark the visual as slow if there are "fake" stencil bits. |
| */ |
| for ( m = modes ; m != NULL ; m = m->next ) { |
| if ( (m->stencilBits != 0) && (m->stencilBits != stencil_bits) ) { |
| m->visualRating = GLX_SLOW_CONFIG; |
| } |
| } |
| |
| return modes; |
| } |
| |
| |
| /** |
| * This is the bootstrap function for the driver. libGL supplies all of the |
| * requisite information about the system, and the driver initializes itself. |
| * This routine also fills in the linked list pointed to by \c driver_modes |
| * with the \c __GLcontextModes that the driver can support for windows or |
| * pbuffers. |
| * |
| * \return A pointer to a \c __DRIscreenPrivate on success, or \c NULL on |
| * failure. |
| */ |
| PUBLIC |
| void * __driCreateNewScreen( __DRInativeDisplay *dpy, int scrn, __DRIscreen *psc, |
| const __GLcontextModes * modes, |
| const __DRIversion * ddx_version, |
| const __DRIversion * dri_version, |
| const __DRIversion * drm_version, |
| const __DRIframebuffer * frame_buffer, |
| drmAddress pSAREA, int fd, |
| int internal_api_version, |
| __GLcontextModes ** driver_modes ) |
| { |
| __DRIscreenPrivate *psp; |
| static const __DRIversion ddx_expected = { 4, 0, 0 }; |
| static const __DRIversion dri_expected = { 4, 0, 0 }; |
| static const __DRIversion drm_expected = { 1, 5, 0 }; |
| |
| |
| if ( ! driCheckDriDdxDrmVersions2( "fb", |
| dri_version, & dri_expected, |
| ddx_version, & ddx_expected, |
| drm_version, & drm_expected ) ) { |
| return NULL; |
| } |
| |
| psp = __driUtilCreateNewScreen(dpy, scrn, psc, NULL, |
| ddx_version, dri_version, drm_version, |
| frame_buffer, pSAREA, fd, |
| internal_api_version, &fbAPI); |
| if ( psp != NULL ) { |
| *driver_modes = fbFillInModes( psp, psp->fbBPP, |
| (psp->fbBPP == 16) ? 16 : 24, |
| (psp->fbBPP == 16) ? 0 : 8, |
| 1); |
| } |
| |
| return (void *) psp; |
| } |