Fix/improve framebuffer object reference counting.
[mesa.git] / src / mesa / drivers / directfb / idirectfbgl_mesa.c
index fc1bb0058d2d77d657611cbee8ce6062378f91ef..88ac4bb31d50aec32951590edf9edf374c2010fc 100644 (file)
@@ -1,18 +1,19 @@
 /*
- * Copyright (C) 2004-2006 Claudio Ciccani <klan@users.sf.net>
+ * Copyright (C) 2004-2007 Claudio Ciccani <klan@directfb.org>
  *
- * 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,
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * 
+ * This library 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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; 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 <stdlib.h>
 #include <unistd.h>
 
+#include <pthread.h>
+
 #include <directfb.h>
+#include <directfb_version.h>
 
+#include <directfbgl.h>
+
+#include <direct/mem.h>
 #include <direct/messages.h>
 #include <direct/interface.h>
-#include <direct/mem.h>
 
-#ifdef CLAMP
-# undef CLAMP
-#endif 
-
-#include "GL/directfbgl.h"
+#undef CLAMP
 #include "glheader.h"
 #include "buffers.h"
 #include "context.h"
@@ -44,7 +46,7 @@
 #include "texformat.h"
 #include "teximage.h"
 #include "texstore.h"
-#include "array_cache/acache.h"
+#include "vbo/vbo.h"
 #include "swrast/swrast.h"
 #include "swrast_setup/swrast_setup.h"
 #include "tnl/tnl.h"
 #include "drivers/common/driverfuncs.h"
 
 
+#define VERSION_CODE( M, m, r )  (((M) * 1000) + ((m) * 100) + ((r)))
+#define DIRECTFB_VERSION_CODE    VERSION_CODE( DIRECTFB_MAJOR_VERSION, \
+                                               DIRECTFB_MINOR_VERSION, \
+                                               DIRECTFB_MICRO_VERSION )
+
+
 static DFBResult
 Probe( void *data );
 
@@ -78,8 +86,8 @@ typedef struct {
      int                     height;
      
      struct {
-          __u8              *start;
-          __u8              *end;
+          GLubyte           *start;
+          GLubyte           *end;
           int                pitch;
      } video;
 
@@ -89,6 +97,37 @@ typedef struct {
      struct gl_renderbuffer  render;
 } IDirectFBGL_data;
 
+/******************************************************************************/
+
+static pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER;
+static unsigned int    global_ref  = 0;
+
+static inline int directfbgl_init( void )
+{
+     pthread_mutexattr_t attr;
+     int                 ret;
+     
+     if (global_ref++)
+          return 0;
+
+     pthread_mutexattr_init( &attr );
+     pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_ERRORCHECK );
+     ret = pthread_mutex_init( &global_lock, &attr );
+     pthread_mutexattr_destroy( &attr );
+
+     return ret;
+}
+
+static inline void directfbgl_finish( void )
+{
+     if (--global_ref == 0)
+          pthread_mutex_destroy( &global_lock );
+}
+
+#define directfbgl_lock()    pthread_mutex_lock( &global_lock )
+#define directfbgl_unlock()  pthread_mutex_unlock( &global_lock )
+
+/******************************************************************************/
 
 static bool  directfbgl_init_visual    ( GLvisual              *visual,
                                          DFBSurfacePixelFormat  format );
@@ -100,21 +139,26 @@ static bool  directfbgl_create_context ( GLcontext             *context,
 static void  directfbgl_destroy_context( GLcontext             *context,
                                          GLframebuffer         *framebuffer );
 
+/******************************************************************************/
+
 
 static void
-IDirectFBGL_Destruct( IDirectFBGL *thiz )
+IDirectFBGL_Mesa_Destruct( IDirectFBGL *thiz )
 {
      IDirectFBGL_data *data = (IDirectFBGL_data*) thiz->priv;
 
      directfbgl_destroy_context( &data->context, &data->framebuffer );
      
-     data->surface->Release( data->surface );
+     if (data->surface)
+          data->surface->Release( data->surface );
 
      DIRECT_DEALLOCATE_INTERFACE( thiz );
+
+     directfbgl_finish();
 }
 
 static DFBResult
-IDirectFBGL_AddRef( IDirectFBGL *thiz )
+IDirectFBGL_Mesa_AddRef( IDirectFBGL *thiz )
 {
      DIRECT_INTERFACE_GET_DATA( IDirectFBGL );
 
@@ -124,38 +168,43 @@ IDirectFBGL_AddRef( IDirectFBGL *thiz )
 }
 
 static DFBResult
-IDirectFBGL_Release( IDirectFBGL *thiz )
+IDirectFBGL_Mesa_Release( IDirectFBGL *thiz )
 {
      DIRECT_INTERFACE_GET_DATA( IDirectFBGL )
 
-     if (--data->ref == 0) {
-          IDirectFBGL_Destruct( thiz );
-     }
+     if (--data->ref == 0) 
+          IDirectFBGL_Mesa_Destruct( thiz );
 
      return DFB_OK;
 }
 
 static DFBResult
-IDirectFBGL_Lock( IDirectFBGL *thiz )
+IDirectFBGL_Mesa_Lock( IDirectFBGL *thiz )
 {
      IDirectFBSurface *surface;
      int               width   = 0;
      int               height  = 0;
-     DFBResult         err;
+     DFBResult         ret;
      
      DIRECT_INTERFACE_GET_DATA( IDirectFBGL );
 
-     if (data->locked++)
+     if (data->locked) {
+          data->locked++;
           return DFB_OK;
+     }
+
+     if (directfbgl_lock())
+          return DFB_LOCKED;
 
      surface = data->surface;
      surface->GetSize( surface, &width, &height );
      
-     err = surface->Lock( surface, DSLF_READ | DSLF_WRITE, 
+     ret = surface->Lock( surface, DSLF_READ | DSLF_WRITE, 
                           (void*)&data->video.start, &data->video.pitch );
-     if (err != DFB_OK) {
+     if (ret) {
           D_ERROR( "DirectFBGL/Mesa: couldn't lock surface.\n" );
-          return err;
+          directfbgl_unlock();
+          return ret;
      }
      data->video.end = data->video.start + (height-1) * data->video.pitch;
 
@@ -165,33 +214,39 @@ IDirectFBGL_Lock( IDirectFBGL *thiz )
                          &data->framebuffer, &data->framebuffer );
      
      if (data->width != width || data->height != height) {
+          _mesa_resize_framebuffer( &data->context, 
+                                    &data->framebuffer, width, height );
           data->width  = width;
-          data->height = height;
-          _mesa_ResizeBuffersMESA();
+          data->height = height;                        
      }
+
+     data->locked++;
      
      return DFB_OK;
 }
 
 static DFBResult
-IDirectFBGL_Unlock( IDirectFBGL *thiz )
+IDirectFBGL_Mesa_Unlock( IDirectFBGL *thiz )
 {     
      DIRECT_INTERFACE_GET_DATA( IDirectFBGL );
 
      if (!data->locked)
           return DFB_OK;
-
+          
      if (--data->locked == 0) {
           _mesa_make_current( NULL, NULL, NULL );
+     
           data->surface->Unlock( data->surface );
-     }
 
+          directfbgl_unlock();
+     }
+     
      return DFB_OK;
 }
 
 static DFBResult
-IDirectFBGL_GetAttributes( IDirectFBGL     *thiz,
-                           DFBGLAttributes *attributes )
+IDirectFBGL_Mesa_GetAttributes( IDirectFBGL     *thiz,
+                                DFBGLAttributes *attributes )
 {
      DFBSurfaceCapabilities   caps;
      GLvisual                *visual;
@@ -217,12 +272,32 @@ IDirectFBGL_GetAttributes( IDirectFBGL     *thiz,
      attributes->accum_green_size = visual->accumGreenBits;
      attributes->accum_blue_size  = visual->accumBlueBits;
      attributes->accum_alpha_size = visual->accumAlphaBits;
-     attributes->double_buffer    = (caps & DSCAPS_FLIPPING) ? 1 : 0;
+     attributes->double_buffer    = ((caps & DSCAPS_FLIPPING) != 0);
      attributes->stereo           = (visual->stereoMode != 0);
 
      return DFB_OK;
 }
 
+#if DIRECTFBGL_INTERFACE_VERSION >= 1
+static DFBResult
+IDirectFBGL_Mesa_GetProcAddress( IDirectFBGL  *thiz,
+                                 const char   *name,
+                                 void        **ret_address )
+{
+     DIRECT_INTERFACE_GET_DATA( IDirectFBGL );
+
+     if (!name)
+          return DFB_INVARG;
+          
+     if (!ret_address)
+          return DFB_INVARG;
+          
+     *ret_address = _glapi_get_proc_address( name );
+          
+     return (*ret_address) ? DFB_OK : DFB_UNSUPPORTED;
+}
+#endif
+
 
 /* exported symbols */
 
@@ -233,24 +308,34 @@ Probe( void *data )
 }
 
 static DFBResult
-Construct( IDirectFBGL      *thiz,
-           IDirectFBSurface *surface )
-{ 
+Construct( IDirectFBGL *thiz, IDirectFBSurface *surface )
+{
+     DFBResult ret;
+     
+     /* Initialize global resources. */
+     if (directfbgl_init())
+          return DFB_INIT;
+     
      /* Allocate interface data. */
      DIRECT_ALLOCATE_INTERFACE_DATA( thiz, IDirectFBGL );
-
      /* Initialize interface data. */
-     data->ref     = 1;
-     data->surface = surface;
+     data->ref = 1;
+
+     /* Duplicate destination surface. */
+     ret = surface->GetSubSurface( surface, NULL, &data->surface );
+     if (ret) {
+          IDirectFBGL_Mesa_Destruct( thiz );
+          return ret;
+     }
 
-     surface->AddRef( surface );
-     surface->GetPixelFormat( surface, &data->format );
-     surface->GetSize( surface, &data->width, &data->height );
+     data->surface->GetPixelFormat( data->surface, &data->format );
+     data->surface->GetSize( data->surface, &data->width, &data->height );
 
      /* Configure visual. */
      if (!directfbgl_init_visual( &data->visual, data->format )) {
           D_ERROR( "DirectFBGL/Mesa: failed to initialize visual.\n" );
-          surface->Release( surface );
+          IDirectFBGL_Mesa_Destruct( thiz );
           return DFB_UNSUPPORTED;
      }
      
@@ -258,16 +343,19 @@ Construct( IDirectFBGL      *thiz,
      if (!directfbgl_create_context( &data->context, &data->framebuffer,
                                      &data->visual, data->format, data )) {
           D_ERROR( "DirectFBGL/Mesa: failed to create context.\n" );
-          surface->Release( surface );
+          IDirectFBGL_Mesa_Destruct( thiz );
           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;
+     thiz->AddRef         = IDirectFBGL_Mesa_AddRef;
+     thiz->Release        = IDirectFBGL_Mesa_Release;
+     thiz->Lock           = IDirectFBGL_Mesa_Lock;
+     thiz->Unlock         = IDirectFBGL_Mesa_Unlock;
+     thiz->GetAttributes  = IDirectFBGL_Mesa_GetAttributes;
+#if DIRECTFBGL_INTERFACE_VERSION >= 1
+     thiz->GetProcAddress = IDirectFBGL_Mesa_GetProcAddress;
+#endif 
 
      return DFB_OK;
 }
@@ -278,12 +366,7 @@ Construct( IDirectFBGL      *thiz,
 static const GLubyte*
 dfbGetString( GLcontext *ctx, GLenum pname )
 {
-     switch (pname) {
-          case GL_VENDOR:
-               return "Claudio Ciccani";
-          default:
-               return NULL;
-     }
+     return NULL;
 }
 
 static void
@@ -291,7 +374,7 @@ dfbUpdateState( GLcontext *ctx, GLuint new_state )
 {
      _swrast_InvalidateState( ctx, new_state );
      _swsetup_InvalidateState( ctx, new_state );
-     _ac_InvalidateState( ctx, new_state );
+     _vbo_InvalidateState( ctx, new_state );
      _tnl_InvalidateState( ctx, new_state );
 }
 
@@ -305,55 +388,61 @@ dfbGetBufferSize( GLframebuffer *buffer, GLuint *width, GLuint *height )
      *height = (GLuint) data->height;
 }
 
+/**
+ * We only implement this function as a mechanism to check if the
+ * framebuffer size has changed (and update corresponding state).
+ */
 static void
 dfbSetViewport( GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h )
 {
-     _mesa_ResizeBuffersMESA();
+     /* Nothing to do (the surface can't be resized while it's locked). */
+     return;
 }
 
 static void
-dfbClear( GLcontext *ctx, GLbitfield mask, GLboolean all,
-          GLint x, GLint y, GLint width, GLint height )
+dfbClear( GLcontext *ctx, GLbitfield mask )
 {
      IDirectFBGL_data *data = (IDirectFBGL_data*) ctx->DriverCtx;
-     
-     if (mask & BUFFER_BIT_FRONT_LEFT &&
-         ctx->Color.ColorMask[0]      &&
-         ctx->Color.ColorMask[1]      &&
-         ctx->Color.ColorMask[2]      &&
+#define BUFFER_BIT_MASK (BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_FRONT_RIGHT | \
+                         BUFFER_BIT_BACK_LEFT  | BUFFER_BIT_BACK_RIGHT  )
+     if (mask & BUFFER_BIT_MASK  &&
+         ctx->Color.ColorMask[0] &&
+         ctx->Color.ColorMask[1] &&
+         ctx->Color.ColorMask[2] &&
          ctx->Color.ColorMask[3])
      {
-          __u8 a, r, g, b;
+          DFBRegion clip;
+          GLubyte   a, r, g, b;
           
           UNCLAMPED_FLOAT_TO_UBYTE( a, ctx->Color.ClearColor[ACOMP] );
           UNCLAMPED_FLOAT_TO_UBYTE( r, ctx->Color.ClearColor[RCOMP] );
           UNCLAMPED_FLOAT_TO_UBYTE( g, ctx->Color.ClearColor[GCOMP] );
           UNCLAMPED_FLOAT_TO_UBYTE( b, ctx->Color.ClearColor[BCOMP] );
 
+          clip.x1 = ctx->DrawBuffer->_Xmin;
+          clip.y1 = ctx->DrawBuffer->_Ymin;
+          clip.x2 = ctx->DrawBuffer->_Xmax - 1;
+          clip.y2 = ctx->DrawBuffer->_Ymax - 1;
+          data->surface->SetClip( data->surface, &clip );
+          
           data->surface->Unlock( data->surface );
           
-          if (all) {
-               data->surface->SetClip( data->surface, NULL );
-               data->surface->Clear( data->surface, r, g, b, a );
-          }
-          else {
-               DFBRegion reg = { x1:x, y1:y, x2:x+width-1, y2:y+height-1 };
-               data->surface->SetClip( data->surface, &reg );
-               data->surface->Clear( data->surface, r, g, b, a );
-               data->surface->SetClip( data->surface, NULL );
-          }
+          data->surface->Clear( data->surface, r, g, b, a );
           
           data->surface->Lock( data->surface, DSLF_READ | DSLF_WRITE,
                                (void*)&data->video.start, &data->video.pitch );
+          data->video.end = data->video.start + (data->height-1) * data->video.pitch;
+          data->render.Data = data->video.start;
           
-          mask &= ~BUFFER_BIT_FRONT_LEFT;
+          mask &= ~BUFFER_BIT_MASK;
      }
+#undef BUFFER_BIT_MASK
      
      if (mask)
-          _swrast_Clear( ctx, mask, all, x, y, width, height );
-}        
-          
-     
+          _swrast_Clear( ctx, mask );
+}
+
 
 /************************ RenderBuffer functions *****************************/
 
@@ -698,7 +787,7 @@ directfbgl_create_context( GLcontext             *context,
      }
 
      _swrast_CreateContext( context );
-     _ac_CreateContext( context );
+     _vbo_CreateContext( context );
      _tnl_CreateContext( context );
      _swsetup_CreateContext( context );
      _swsetup_Wakeup( context );
@@ -716,6 +805,7 @@ directfbgl_create_context( GLcontext             *context,
                data->render.GetRow        = get_row_RGB332;
                data->render.GetValues     = get_values_RGB332;
                data->render.PutRow        = put_row_RGB332;
+               data->render.PutRowRGB     = put_row_rgb_RGB332;
                data->render.PutMonoRow    = put_mono_row_RGB332;
                data->render.PutValues     = put_values_RGB332;
                data->render.PutMonoValues = put_mono_values_RGB332;
@@ -724,6 +814,7 @@ directfbgl_create_context( GLcontext             *context,
                data->render.GetRow        = get_row_ARGB4444;
                data->render.GetValues     = get_values_ARGB4444;
                data->render.PutRow        = put_row_ARGB4444;
+               data->render.PutRowRGB     = put_row_rgb_ARGB4444;
                data->render.PutMonoRow    = put_mono_row_ARGB4444;
                data->render.PutValues     = put_values_ARGB4444;
                data->render.PutMonoValues = put_mono_values_ARGB4444;
@@ -732,6 +823,7 @@ directfbgl_create_context( GLcontext             *context,
                data->render.GetRow        = get_row_ARGB2554;
                data->render.GetValues     = get_values_ARGB2554;
                data->render.PutRow        = put_row_ARGB2554;
+               data->render.PutRowRGB     = put_row_rgb_ARGB2554;
                data->render.PutMonoRow    = put_mono_row_ARGB2554;
                data->render.PutValues     = put_values_ARGB2554;
                data->render.PutMonoValues = put_mono_values_ARGB2554;
@@ -740,6 +832,7 @@ directfbgl_create_context( GLcontext             *context,
                data->render.GetRow        = get_row_ARGB1555;
                data->render.GetValues     = get_values_ARGB1555;
                data->render.PutRow        = put_row_ARGB1555;
+               data->render.PutRowRGB     = put_row_rgb_ARGB1555;
                data->render.PutMonoRow    = put_mono_row_ARGB1555;
                data->render.PutValues     = put_values_ARGB1555;
                data->render.PutMonoValues = put_mono_values_ARGB1555;
@@ -748,6 +841,7 @@ directfbgl_create_context( GLcontext             *context,
                data->render.GetRow        = get_row_RGB16;
                data->render.GetValues     = get_values_RGB16;
                data->render.PutRow        = put_row_RGB16;
+               data->render.PutRowRGB     = put_row_rgb_RGB16;
                data->render.PutMonoRow    = put_mono_row_RGB16;
                data->render.PutValues     = put_values_RGB16;
                data->render.PutMonoValues = put_mono_values_RGB16;
@@ -756,6 +850,7 @@ directfbgl_create_context( GLcontext             *context,
                data->render.GetRow        = get_row_RGB24;
                data->render.GetValues     = get_values_RGB24;
                data->render.PutRow        = put_row_RGB24;
+               data->render.PutRowRGB     = put_row_rgb_RGB24;
                data->render.PutMonoRow    = put_mono_row_RGB24;
                data->render.PutValues     = put_values_RGB24;
                data->render.PutMonoValues = put_mono_values_RGB24;
@@ -764,6 +859,7 @@ directfbgl_create_context( GLcontext             *context,
                data->render.GetRow        = get_row_RGB32;
                data->render.GetValues     = get_values_RGB32;
                data->render.PutRow        = put_row_RGB32;
+               data->render.PutRowRGB     = put_row_rgb_RGB32;
                data->render.PutMonoRow    = put_mono_row_RGB32;
                data->render.PutValues     = put_values_RGB32;
                data->render.PutMonoValues = put_mono_values_RGB32;
@@ -772,6 +868,7 @@ directfbgl_create_context( GLcontext             *context,
                data->render.GetRow        = get_row_ARGB;
                data->render.GetValues     = get_values_ARGB;
                data->render.PutRow        = put_row_ARGB;
+               data->render.PutRowRGB     = put_row_rgb_ARGB;
                data->render.PutMonoRow    = put_mono_row_ARGB;
                data->render.PutValues     = put_values_ARGB;
                data->render.PutMonoValues = put_mono_values_ARGB;
@@ -780,6 +877,7 @@ directfbgl_create_context( GLcontext             *context,
                data->render.GetRow        = get_row_AiRGB;
                data->render.GetValues     = get_values_AiRGB;
                data->render.PutRow        = put_row_AiRGB;
+               data->render.PutRowRGB     = put_row_rgb_AiRGB;
                data->render.PutMonoRow    = put_mono_row_AiRGB;
                data->render.PutValues     = put_values_AiRGB;
                data->render.PutMonoValues = put_mono_values_AiRGB;