/* * Copyright (C) 2004-2005 Claudio Ciccani * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * * Based on glfbdev.c, written by Brian Paul. * */ #include #include #include #include #include #include #include #ifdef CLAMP # undef CLAMP #endif #include "GL/directfbgl.h" #include "glheader.h" #include "buffers.h" #include "context.h" #include "extensions.h" #include "framebuffer.h" #include "renderbuffer.h" #include "imports.h" #include "texformat.h" #include "teximage.h" #include "texstore.h" #include "array_cache/acache.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" static DFBResult Probe( void *data ); static DFBResult Construct( IDirectFBGL *thiz, IDirectFBSurface *surface ); #include DIRECT_INTERFACE_IMPLEMENTATION( IDirectFBGL, Mesa ) /* * private data struct of IDirectFBGL */ typedef struct { int ref; /* reference counter */ bool locked; IDirectFBSurface *surface; DFBSurfacePixelFormat format; int width; int height; struct { __u8 *start; __u8 *end; int pitch; } video; GLvisual visual; GLframebuffer framebuffer; GLcontext context; struct gl_renderbuffer render; } IDirectFBGL_data; static bool dfb_mesa_setup_visual ( GLvisual *visual, DFBSurfacePixelFormat format ); static bool dfb_mesa_create_context ( GLcontext *context, GLframebuffer *framebuffer, GLvisual *visual, DFBSurfacePixelFormat format, IDirectFBGL_data *data ); static void dfb_mesa_destroy_context( GLcontext *context, GLframebuffer *framebuffer ); static void IDirectFBGL_Destruct( IDirectFBGL *thiz ) { IDirectFBGL_data *data = (IDirectFBGL_data*) thiz->priv; dfb_mesa_destroy_context( &data->context, &data->framebuffer ); data->surface->Release( data->surface ); DIRECT_DEALLOCATE_INTERFACE( thiz ); } static DFBResult IDirectFBGL_AddRef( IDirectFBGL *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBGL ); data->ref++; return DFB_OK; } static DFBResult IDirectFBGL_Release( IDirectFBGL *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBGL ) if (--data->ref == 0) { IDirectFBGL_Destruct( thiz ); } return DFB_OK; } static DFBResult IDirectFBGL_Lock( IDirectFBGL *thiz ) { IDirectFBSurface *surface; int width = 0; int height = 0; DFBResult err; DIRECT_INTERFACE_GET_DATA( IDirectFBGL ); if (data->locked) return DFB_LOCKED; surface = data->surface; surface->GetSize( surface, &width, &height ); err = surface->Lock( surface, DSLF_READ | DSLF_WRITE, (void**) &data->video.start, &data->video.pitch ); if (err != DFB_OK) { D_ERROR( "DirectFBGL/Mesa: couldn't lock surface.\n" ); return err; } data->video.end = data->video.start + (height-1) * data->video.pitch; data->render.Data = data->video.start; if (data->width != width || data->height != height) { data->width = width; data->height = height; _mesa_ResizeBuffersMESA(); } data->locked = true; return DFB_OK; } static DFBResult IDirectFBGL_Unlock( IDirectFBGL *thiz ) { DIRECT_INTERFACE_GET_DATA( IDirectFBGL ); if (!data->locked) return DFB_OK; data->surface->Unlock( data->surface ); data->video.start = NULL; data->video.end = NULL; data->locked = false; return DFB_OK; } static DFBResult IDirectFBGL_GetAttributes( IDirectFBGL *thiz, DFBGLAttributes *attributes ) { GLvisual *visual; DIRECT_INTERFACE_GET_DATA( IDirectFBGL ); if (!attributes) return DFB_INVARG; visual = &data->visual; attributes->buffer_size = visual->rgbBits ? : visual->indexBits; attributes->depth_size = visual->depthBits; attributes->stencil_size = visual->stencilBits; attributes->aux_buffers = visual->numAuxBuffers; attributes->red_size = visual->redBits; attributes->green_size = visual->greenBits; attributes->blue_size = visual->blueBits; attributes->alpha_size = visual->alphaBits; attributes->accum_red_size = visual->accumRedBits; attributes->accum_green_size = visual->accumGreenBits; attributes->accum_blue_size = visual->accumBlueBits; attributes->accum_alpha_size = visual->accumAlphaBits; attributes->double_buffer = (visual->doubleBufferMode != 0); attributes->stereo = (visual->stereoMode != 0); return DFB_OK; } /* exported symbols */ static DFBResult Probe( void *data ) { return DFB_OK; } static DFBResult Construct( IDirectFBGL *thiz, IDirectFBSurface *surface ) { /* Allocate interface data. */ DIRECT_ALLOCATE_INTERFACE_DATA( thiz, IDirectFBGL ); /* Initialize interface data. */ data->ref = 1; data->surface = surface; surface->AddRef( surface ); surface->GetPixelFormat( surface, &data->format ); surface->GetSize( surface, &data->width, &data->height ); /* Configure visual. */ if (!dfb_mesa_setup_visual( &data->visual, data->format )) { D_ERROR( "DirectFBGL/Mesa: failed to initialize visual.\n" ); surface->Release( surface ); return DFB_UNSUPPORTED; } /* Create context. */ if (!dfb_mesa_create_context( &data->context, &data->framebuffer, &data->visual, data->format, data )) { D_ERROR( "DirectFBGL/Mesa: failed to create context.\n" ); surface->Release( surface ); return DFB_UNSUPPORTED; } /* Assign interface pointers. */ thiz->AddRef = IDirectFBGL_AddRef; thiz->Release = IDirectFBGL_Release; thiz->Lock = IDirectFBGL_Lock; thiz->Unlock = IDirectFBGL_Unlock; thiz->GetAttributes = IDirectFBGL_GetAttributes; return DFB_OK; } /* internal functions */ static const GLubyte* get_string( GLcontext *ctx, GLenum pname ) { switch (pname) { case GL_VENDOR: return "Claudio Ciccani"; case GL_VERSION: return "1.0"; default: return NULL; } } static void update_state( GLcontext *ctx, GLuint new_state ) { _swrast_InvalidateState( ctx, new_state ); _swsetup_InvalidateState( ctx, new_state ); _ac_InvalidateState( ctx, new_state ); _tnl_InvalidateState( ctx, new_state ); } static void get_buffer_size( GLframebuffer *buffer, GLuint *width, GLuint *height ) { GLcontext *ctx = _mesa_get_current_context(); IDirectFBGL_data *data = (IDirectFBGL_data*) ctx->DriverCtx; *width = (GLuint) data->width; *height = (GLuint) data->height; } static void set_viewport( GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h ) { _mesa_ResizeBuffersMESA(); } /* required but not used */ static void set_buffer( GLcontext *ctx, GLframebuffer *buffer, GLuint bufferBit ) { return; } static void delete_renderbuffer( struct gl_renderbuffer *render ) { return; } static GLboolean renderbuffer_storage( GLcontext *ctx, struct gl_renderbuffer *render, GLenum internalFormat, GLuint width, GLuint height ) { return GL_TRUE; } /* RGB332 */ #define NAME(PREFIX) PREFIX##_RGB332 #define FORMAT GL_RGBA8 #define SPAN_VARS \ IDirectFBGL_data *data = (IDirectFBGL_data*) ctx->DriverCtx; #define INIT_PIXEL_PTR(P, X, Y) \ GLubyte *P = data->video.end - (Y) * data->video.pitch + (X); #define INC_PIXEL_PTR(P) P += 1 #define STORE_PIXEL(P, X, Y, S) \ *P = ( (((S[RCOMP]) & 0xe0)) | (((S[GCOMP]) & 0xe0) >> 3) | ((S[BCOMP]) >> 6) ) #define FETCH_PIXEL(D, P) \ D[RCOMP] = ((*P & 0xe0) ); \ D[GCOMP] = ((*P & 0x1c) << 3); \ D[BCOMP] = ((*P & 0x03) << 6); \ D[ACOMP] = 0xff #include "swrast/s_spantemp.h" /* ARGB1555 */ #define NAME(PREFIX) PREFIX##_ARGB1555 #define FORMAT GL_RGBA8 #define SPAN_VARS \ IDirectFBGL_data *data = (IDirectFBGL_data*) ctx->DriverCtx; #define INIT_PIXEL_PTR(P, X, Y) \ GLushort *P = (GLushort *) (data->video.end - (Y) * data->video.pitch + (X) * 2); #define INC_PIXEL_PTR(P) P += 1 #define STORE_PIXEL(P, X, Y, S) \ *P = ( (((S[RCOMP]) & 0xf8) << 7) | (((S[GCOMP]) & 0xf8) << 2) | ((S[BCOMP]) >> 3) ) #define FETCH_PIXEL(D, P) \ D[RCOMP] = ((*P & 0x7c00) >> 7); \ D[GCOMP] = ((*P & 0x03e0) >> 2); \ D[BCOMP] = ((*P & 0x001f) << 3); \ D[ACOMP] = ((*P & 0x8000) ? 0xff : 0) #include "swrast/s_spantemp.h" /* RGB16 */ #define NAME(PREFIX) PREFIX##_RGB16 #define FORMAT GL_RGBA8 #define SPAN_VARS \ IDirectFBGL_data *data = (IDirectFBGL_data*) ctx->DriverCtx; #define INIT_PIXEL_PTR(P, X, Y) \ GLushort *P = (GLushort *) (data->video.end - (Y) * data->video.pitch + (X) * 2); #define INC_PIXEL_PTR(P) P += 1 #define STORE_PIXEL(P, X, Y, S) \ *P = ( (((S[RCOMP]) & 0xf8) << 8) | (((S[GCOMP]) & 0xfc) << 3) | ((S[BCOMP]) >> 3) ) #define FETCH_PIXEL(D, P) \ D[RCOMP] = ((*P & 0xf800) >> 8); \ D[GCOMP] = ((*P & 0x07e0) >> 3); \ D[BCOMP] = ((*P & 0x001f) << 3); \ D[ACOMP] = 0xff #include "swrast/s_spantemp.h" /* RGB24 */ #define NAME(PREFIX) PREFIX##_RGB24 #define FORMAT GL_RGBA8 #define SPAN_VARS \ IDirectFBGL_data *data = ctx->DriverCtx; #define INIT_PIXEL_PTR(P, X, Y) \ GLubyte *P = data->video.end - (Y) * data->video.pitch + (X) * 3; #define INC_PIXEL_PTR(P) P += 3 #define STORE_PIXEL(P, X, Y, S) \ P[0] = S[BCOMP]; P[1] = S[GCOMP]; P[2] = S[BCOMP] #define FETCH_PIXEL(D, P) \ D[RCOMP] = P[2]; D[GCOMP] = P[1]; D[BCOMP] = P[0]; D[ACOMP] = 0xff #include "swrast/s_spantemp.h" /* RGB32 */ #define NAME(PREFIX) PREFIX##_RGB32 #define FORMAT GL_RGBA8 #define SPAN_VARS \ IDirectFBGL_data *data = (IDirectFBGL_data*) ctx->DriverCtx; #define INIT_PIXEL_PTR(P, X, Y) \ GLuint *P = (GLuint*) (data->video.end - (Y) * data->video.pitch + (X) * 4); #define INC_PIXEL_PTR(P) P += 1 #define STORE_PIXEL(P, X, Y, S) \ *P = ( ((S[RCOMP]) << 16) | ((S[GCOMP]) << 8) | (S[BCOMP]) ) #define FETCH_PIXEL(D, P) \ D[RCOMP] = ((*P & 0x00ff0000) >> 16); \ D[GCOMP] = ((*P & 0x0000ff00) >> 8); \ D[BCOMP] = ((*P & 0x000000ff) ); \ D[ACOMP] = 0xff #include "swrast/s_spantemp.h" /* ARGB */ #define NAME(PREFIX) PREFIX##_ARGB #define FORMAT GL_RGBA8 #define SPAN_VARS \ IDirectFBGL_data *data = (IDirectFBGL_data*) ctx->DriverCtx; #define INIT_PIXEL_PTR(P, X, Y) \ GLuint *P = (GLuint*) (data->video.end - (Y) * data->video.pitch + (X) * 4); #define INC_PIXEL_PTR(P) P += 1 #define STORE_PIXEL_RGB(P, X, Y, S) \ *P = ( 0xff000000 | ((S[RCOMP]) << 16) | ((S[GCOMP]) << 8) | (S[BCOMP]) ) #define STORE_PIXEL(P, X, Y, S) \ *P = ( ((S[ACOMP]) << 24) | ((S[RCOMP]) << 16) | ((S[GCOMP]) << 8) | (S[BCOMP]) ) #define FETCH_PIXEL(D, P) \ D[RCOMP] = ((*P & 0x00ff0000) >> 16); \ D[GCOMP] = ((*P & 0x0000ff00) >> 8); \ D[BCOMP] = ((*P & 0x000000ff) ); \ D[ACOMP] = ((*P & 0xff000000) >> 24) #include "swrast/s_spantemp.h" /* AiRGB */ #define NAME(PREFIX) PREFIX##_AiRGB #define FORMAT GL_RGBA8 #define SPAN_VARS \ IDirectFBGL_data *data = (IDirectFBGL_data*) ctx->DriverCtx; #define INIT_PIXEL_PTR(P, X, Y) \ GLuint *P = (GLuint*) (data->video.end - (Y) * data->video.pitch + (X) * 4); #define INC_PIXEL_PTR(P) P += 1 #define STORE_PIXEL_RGB(P, X, Y, S) \ *P = ( ((S[RCOMP]) << 16) | ((S[GCOMP]) << 8) | (S[BCOMP]) ) #define STORE_PIXEL(P, X, Y, S) \ *P = ( ((0xff - (S[ACOMP])) << 24) | ((S[RCOMP]) << 16) | ((S[GCOMP]) << 8) | (S[BCOMP]) ) #define FETCH_PIXEL(D, P) \ D[RCOMP] = ((*P & 0x00ff0000) >> 16); \ D[GCOMP] = ((*P & 0x0000ff00) >> 8); \ D[BCOMP] = ((*P & 0x000000ff) ); \ D[ACOMP] = (0xff - ((*P & 0xff000000) >> 24)) #include "swrast/s_spantemp.h" static bool dfb_mesa_setup_visual( GLvisual *visual, DFBSurfacePixelFormat format ) { GLboolean rgbFlag = GL_TRUE; GLboolean dbFlag = GL_FALSE; GLboolean stereoFlag = GL_FALSE; GLint redBits = 0; GLint blueBits = 0; GLint greenBits = 0; GLint alphaBits = 0; GLint indexBits = 0; GLint depthBits = 0; GLint stencilBits = 0; GLint accumRedBits = 0; GLint accumGreenBits = 0; GLint accumBlueBits = 0; GLint accumAlphaBits = 0; GLint numSamples = 0; /* FIXME: LUT8 support. */ switch (format) { case DSPF_RGB332: redBits = 3; greenBits = 3; blueBits = 2; break; case DSPF_ARGB1555: redBits = 5; greenBits = 5; blueBits = 5; alphaBits = 1; break; case DSPF_RGB16: redBits = 5; greenBits = 6; blueBits = 5; break; case DSPF_ARGB: case DSPF_AiRGB: alphaBits = 8; case DSPF_RGB24: case DSPF_RGB32: redBits = 8; greenBits = 8; blueBits = 8; break; default: D_WARN( "unsupported pixelformat" ); return false; } if (rgbFlag) { accumRedBits = redBits; accumGreenBits = greenBits; accumBlueBits = blueBits; accumAlphaBits = alphaBits; depthBits = redBits + greenBits + blueBits; stencilBits = alphaBits; } else depthBits = 8; return _mesa_initialize_visual( visual, rgbFlag, dbFlag, stereoFlag, redBits, greenBits, blueBits, alphaBits, indexBits, depthBits, stencilBits, accumRedBits, accumGreenBits, accumBlueBits, accumAlphaBits, numSamples ); } static bool dfb_mesa_create_context( GLcontext *context, GLframebuffer *framebuffer, GLvisual *visual, DFBSurfacePixelFormat format, IDirectFBGL_data *data ) { struct dd_function_table functions; struct swrast_device_driver *swdd; _mesa_initialize_framebuffer( framebuffer, visual ); _mesa_init_driver_functions( &functions ); functions.GetString = get_string; functions.UpdateState = update_state; functions.GetBufferSize = get_buffer_size; functions.Viewport = set_viewport; if (!_mesa_initialize_context( context, visual, NULL, &functions, (void*) data )) { D_DEBUG( "DirectFBGL/Mesa: _mesa_initialize_context() failed.\n" ); _mesa_free_framebuffer_data( framebuffer ); return false; } _swrast_CreateContext( context ); _ac_CreateContext( context ); _tnl_CreateContext( context ); _swsetup_CreateContext( context ); _swsetup_Wakeup( context ); swdd = _swrast_GetDeviceDriverReference( context ); swdd->SetBuffer = set_buffer; _mesa_init_renderbuffer( &data->render, 0 ); data->render.InternalFormat = GL_RGBA; data->render._BaseFormat = GL_RGBA; data->render.DataType = GL_UNSIGNED_BYTE; data->render.Data = data->video.start; data->render.Delete = delete_renderbuffer; data->render.AllocStorage = renderbuffer_storage; switch (format) { case DSPF_RGB332: data->render.GetRow = get_row_RGB332; data->render.GetValues = get_values_RGB332; data->render.PutRow = put_row_RGB332; data->render.PutMonoRow = put_mono_row_RGB332; data->render.PutValues = put_values_RGB332; data->render.PutMonoValues = put_mono_values_RGB332; break; case DSPF_ARGB1555: data->render.GetRow = get_row_ARGB1555; data->render.GetValues = get_values_ARGB1555; data->render.PutRow = put_row_ARGB1555; data->render.PutMonoRow = put_mono_row_ARGB1555; data->render.PutValues = put_values_ARGB1555; data->render.PutMonoValues = put_mono_values_ARGB1555; break; case DSPF_RGB16: data->render.GetRow = get_row_RGB16; data->render.GetValues = get_values_RGB16; data->render.PutRow = put_row_RGB16; data->render.PutMonoRow = put_mono_row_RGB16; data->render.PutValues = put_values_RGB16; data->render.PutMonoValues = put_mono_values_RGB16; break; case DSPF_RGB24: data->render.GetRow = get_row_RGB24; data->render.GetValues = get_values_RGB24; data->render.PutRow = put_row_RGB24; data->render.PutMonoRow = put_mono_row_RGB24; data->render.PutValues = put_values_RGB24; data->render.PutMonoValues = put_mono_values_RGB24; break; case DSPF_RGB32: data->render.GetRow = get_row_RGB32; data->render.GetValues = get_values_RGB32; data->render.PutRow = put_row_RGB32; data->render.PutMonoRow = put_mono_row_RGB32; data->render.PutValues = put_values_RGB32; data->render.PutMonoValues = put_mono_values_RGB32; break; case DSPF_ARGB: data->render.GetRow = get_row_ARGB; data->render.GetValues = get_values_ARGB; data->render.PutRow = put_row_ARGB; data->render.PutMonoRow = put_mono_row_ARGB; data->render.PutValues = put_values_ARGB; data->render.PutMonoValues = put_mono_values_ARGB; break; case DSPF_AiRGB: data->render.GetRow = get_row_AiRGB; data->render.GetValues = get_values_AiRGB; data->render.PutRow = put_row_AiRGB; data->render.PutMonoRow = put_mono_row_AiRGB; data->render.PutValues = put_values_AiRGB; data->render.PutMonoValues = put_mono_values_AiRGB; break; default: D_BUG( "unexpected pixelformat" ); return false; } _mesa_add_renderbuffer( framebuffer, BUFFER_FRONT_LEFT, &data->render ); _mesa_add_soft_renderbuffers( framebuffer, GL_FALSE, visual->haveDepthBuffer, visual->haveStencilBuffer, visual->haveAccumBuffer, GL_FALSE, GL_FALSE ); TNL_CONTEXT( context )->Driver.RunPipeline = _tnl_run_pipeline; _mesa_enable_sw_extensions( context ); _mesa_make_current( context, framebuffer, framebuffer ); return true; } static void dfb_mesa_destroy_context( GLcontext *context, GLframebuffer *framebuffer ) { _mesa_make_current( NULL, NULL, NULL ); _mesa_free_framebuffer_data( framebuffer ); _mesa_notifyDestroy( context ); _mesa_free_context_data( context ); }