s/GLchan/GLubyte/
[mesa.git] / src / mesa / main / context.c
index a50632615d0f370ea8cff2dffdbad3f67b256484..e0630c33d0b0c95439f41688b333df75a6a15743 100644 (file)
@@ -8,7 +8,7 @@
  * Mesa 3-D graphics library
  * Version:  6.5
  *
- * Copyright (C) 1999-2005  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2006  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"),
@@ -79,6 +79,7 @@
 #include "glheader.h"
 #include "imports.h"
 #include "accum.h"
+#include "arrayobj.h"
 #include "attrib.h"
 #include "blend.h"
 #include "buffers.h"
@@ -478,7 +479,7 @@ _mesa_create_visual( GLboolean rgbFlag,
                      GLint accumAlphaBits,
                      GLint numSamples )
 {
-   GLvisual *vis = (GLvisual *) CALLOC( sizeof(GLvisual) );
+   GLvisual *vis = (GLvisual *) _mesa_calloc(sizeof(GLvisual));
    if (vis) {
       if (!_mesa_initialize_visual(vis, rgbFlag, dbFlag, stereoFlag,
                                    redBits, greenBits, blueBits, alphaBits,
@@ -486,7 +487,7 @@ _mesa_create_visual( GLboolean rgbFlag,
                                    accumRedBits, accumGreenBits,
                                    accumBlueBits, accumAlphaBits,
                                    numSamples)) {
-         FREE(vis);
+         _mesa_free(vis);
          return NULL;
       }
    }
@@ -576,7 +577,7 @@ _mesa_initialize_visual( GLvisual *vis,
 void
 _mesa_destroy_visual( GLvisual *vis )
 {
-   FREE(vis);
+   _mesa_free(vis);
 }
 
 /*@}*/
@@ -605,7 +606,7 @@ _glthread_DECLARE_STATIC_MUTEX(OneTimeLock);
  * and sets the glapi callbacks if the \c MESA_DEBUG environment variable is
  * defined.
  *
- * \sa _mesa_init_lists(), _math_init().
+ * \sa _math_init().
  */
 static void
 one_time_init( GLcontext *ctx )
@@ -624,8 +625,6 @@ one_time_init( GLcontext *ctx )
       assert( sizeof(GLint) == 4 );
       assert( sizeof(GLuint) == 4 );
 
-      _mesa_init_lists();
-
 #if _HAVE_FULL_GL
       _math_init();
 
@@ -699,9 +698,15 @@ alloc_shared_state( GLcontext *ctx )
       goto cleanup;
 #endif
 
+#if FEATURE_ARB_vertex_buffer_object || FEATURE_ARB_pixel_buffer_object
    ss->BufferObjects = _mesa_NewHashTable();
+#endif
+
+   ss->ArrayObjects = _mesa_NewHashTable();
 
+#if FEATURE_ARB_shader_objects
    ss->GL2Objects = _mesa_NewHashTable ();
+#endif
 
    ss->Default1D = (*ctx->Driver.NewTextureObject)(ctx, 0, GL_TEXTURE_1D);
    if (!ss->Default1D)
@@ -764,13 +769,18 @@ alloc_shared_state( GLcontext *ctx )
    if (ss->DefaultFragmentShader)
       _mesa_delete_ati_fragment_shader(ctx, ss->DefaultFragmentShader);
 #endif
-#if FEATURE_ARB_vertex_buffer_object
+#if FEATURE_ARB_vertex_buffer_object || FEATURE_ARB_pixel_buffer_object
    if (ss->BufferObjects)
       _mesa_DeleteHashTable(ss->BufferObjects);
 #endif
 
+   if (ss->ArrayObjects)
+      _mesa_DeleteHashTable (ss->ArrayObjects);
+
+#if FEATURE_ARB_shader_objects
    if (ss->GL2Objects)
       _mesa_DeleteHashTable (ss->GL2Objects);
+#endif
 
 #if FEATURE_EXT_framebuffer_object
    if (ss->FrameBuffers)
@@ -794,8 +804,77 @@ alloc_shared_state( GLcontext *ctx )
    return GL_FALSE;
 }
 
+
+/**
+ * Callback for deleting a display list.  Called by _mesa_HashDeleteAll().
+ */
+static void
+delete_displaylist_cb(GLuint id, void *data, void *userData)
+{
+   struct mesa_display_list *list = (struct mesa_display_list *) data;
+   GLcontext *ctx = (GLcontext *) userData;
+   _mesa_delete_list(ctx, list);
+}
+
+/**
+ * Callback for deleting a texture object.  Called by _mesa_HashDeleteAll().
+ */
+static void
+delete_texture_cb(GLuint id, void *data, void *userData)
+{
+   struct gl_texture_object *texObj = (struct gl_texture_object *) data;
+   GLcontext *ctx = (GLcontext *) userData;
+   ctx->Driver.DeleteTexture(ctx, texObj);
+}
+
+/**
+ * Callback for deleting a program object.  Called by _mesa_HashDeleteAll().
+ */
+static void
+delete_program_cb(GLuint id, void *data, void *userData)
+{
+   struct gl_program *prog = (struct gl_program *) data;
+   GLcontext *ctx = (GLcontext *) userData;
+   ctx->Driver.DeleteProgram(ctx, prog);
+}
+
+/**
+ * Callback for deleting an ATI fragment shader object.
+ * Called by _mesa_HashDeleteAll().
+ */
+static void
+delete_fragshader_cb(GLuint id, void *data, void *userData)
+{
+   struct ati_fragment_shader *shader = (struct ati_fragment_shader *) data;
+   GLcontext *ctx = (GLcontext *) userData;
+   _mesa_delete_ati_fragment_shader(ctx, shader);
+}
+
+/**
+ * Callback for deleting a buffer object.  Called by _mesa_HashDeleteAll().
+ */
+static void
+delete_bufferobj_cb(GLuint id, void *data, void *userData)
+{
+   struct gl_buffer_object *bufObj = (struct gl_buffer_object *) data;
+   GLcontext *ctx = (GLcontext *) userData;
+   ctx->Driver.DeleteBuffer(ctx, bufObj);
+}
+
+/**
+ * Callback for deleting an array object.  Called by _mesa_HashDeleteAll().
+ */
+static void
+delete_arrayobj_cb(GLuint id, void *data, void *userData)
+{
+   struct gl_array_object *arrayObj = (struct gl_array_object *) data;
+   GLcontext *ctx = (GLcontext *) userData;
+   _mesa_delete_array_object(ctx, arrayObj);
+}
+
+
 /**
- * Deallocate a shared state context and all children structures.
+ * Deallocate a shared state object and all children structures.
  *
  * \param ctx GL context.
  * \param ss shared state pointer.
@@ -809,57 +888,28 @@ alloc_shared_state( GLcontext *ctx )
 static void
 free_shared_state( GLcontext *ctx, struct gl_shared_state *ss )
 {
-   /* Free display lists */
-   while (1) {
-      GLuint list = _mesa_HashFirstEntry(ss->DisplayList);
-      if (list) {
-         _mesa_destroy_list(ctx, list);
-      }
-      else {
-         break;
-      }
-   }
+   /*
+    * Free display lists
+    */
+   _mesa_HashDeleteAll(ss->DisplayList, delete_displaylist_cb, ctx);
    _mesa_DeleteHashTable(ss->DisplayList);
 
-   /* Free texture objects */
+   /*
+    * Free texture objects
+    */
    ASSERT(ctx->Driver.DeleteTexture);
    /* the default textures */
-   (*ctx->Driver.DeleteTexture)(ctx, ss->Default1D);
-   (*ctx->Driver.DeleteTexture)(ctx, ss->Default2D);
-   (*ctx->Driver.DeleteTexture)(ctx, ss->Default3D);
-   (*ctx->Driver.DeleteTexture)(ctx, ss->DefaultCubeMap);
-   (*ctx->Driver.DeleteTexture)(ctx, ss->DefaultRect);
+   ctx->Driver.DeleteTexture(ctx, ss->Default1D);
+   ctx->Driver.DeleteTexture(ctx, ss->Default2D);
+   ctx->Driver.DeleteTexture(ctx, ss->Default3D);
+   ctx->Driver.DeleteTexture(ctx, ss->DefaultCubeMap);
+   ctx->Driver.DeleteTexture(ctx, ss->DefaultRect);
    /* all other textures */
-   while (1) {
-      GLuint texName = _mesa_HashFirstEntry(ss->TexObjects);
-      if (texName) {
-         struct gl_texture_object *texObj = (struct gl_texture_object *)
-            _mesa_HashLookup(ss->TexObjects, texName);
-         ASSERT(texObj);
-         (*ctx->Driver.DeleteTexture)(ctx, texObj);
-         _mesa_HashRemove(ss->TexObjects, texName);
-      }
-      else {
-         break;
-      }
-   }
+   _mesa_HashDeleteAll(ss->TexObjects, delete_texture_cb, ctx);
    _mesa_DeleteHashTable(ss->TexObjects);
 
-#if FEATURE_NV_vertex_program
-   /* Free vertex programs */
-   while (1) {
-      GLuint prog = _mesa_HashFirstEntry(ss->Programs);
-      if (prog) {
-         struct program *p = (struct program *) _mesa_HashLookup(ss->Programs,
-                                                                 prog);
-         ASSERT(p);
-         ctx->Driver.DeleteProgram(ctx, p);
-         _mesa_HashRemove(ss->Programs, prog);
-      }
-      else {
-         break;
-      }
-   }
+#if defined(FEATURE_NV_vertex_program) || defined(FEATURE_NV_fragment_program)
+   _mesa_HashDeleteAll(ss->Programs, delete_program_cb, ctx);
    _mesa_DeleteHashTable(ss->Programs);
 #endif
 #if FEATURE_ARB_vertex_program
@@ -868,15 +918,24 @@ free_shared_state( GLcontext *ctx, struct gl_shared_state *ss )
 #if FEATURE_ARB_fragment_program
    _mesa_delete_program(ctx, ss->DefaultFragmentProgram);
 #endif
+
 #if FEATURE_ATI_fragment_shader
-   _mesa_free(ss->DefaultFragmentShader);
+   _mesa_HashDeleteAll(ss->ATIShaders, delete_fragshader_cb, ctx);
+   _mesa_DeleteHashTable(ss->ATIShaders);
+   _mesa_delete_ati_fragment_shader(ctx, ss->DefaultFragmentShader);
 #endif
 
-#if FEATURE_ARB_vertex_buffer_object
+#if FEATURE_ARB_vertex_buffer_object || FEATURE_ARB_pixel_buffer_object
+   _mesa_HashDeleteAll(ss->BufferObjects, delete_bufferobj_cb, ctx);
    _mesa_DeleteHashTable(ss->BufferObjects);
 #endif
 
-   _mesa_DeleteHashTable (ss->GL2Objects);
+   _mesa_HashDeleteAll(ss->ArrayObjects, delete_arrayobj_cb, ctx);
+   _mesa_DeleteHashTable(ss->ArrayObjects);
+
+#if FEATURE_ARB_shader_objects
+   _mesa_DeleteHashTable(ss->GL2Objects);
+#endif
 
 #if FEATURE_EXT_framebuffer_object
    _mesa_DeleteHashTable(ss->FrameBuffers);
@@ -885,7 +944,7 @@ free_shared_state( GLcontext *ctx, struct gl_shared_state *ss )
 
    _glthread_DESTROY_MUTEX(ss->Mutex);
 
-   FREE(ss);
+   _mesa_free(ss);
 }
 
 
@@ -897,18 +956,18 @@ _mesa_init_current( GLcontext *ctx )
 {
    GLuint i;
 
-   /* Current group */
+   /* Init all to (0,0,0,1) */
    for (i = 0; i < VERT_ATTRIB_MAX; i++) {
       ASSIGN_4V( ctx->Current.Attrib[i], 0.0, 0.0, 0.0, 1.0 );
    }
-   /* special cases: */
+
+   /* redo special cases: */
    ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_WEIGHT], 1.0, 0.0, 0.0, 1.0 );
    ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_NORMAL], 0.0, 0.0, 1.0, 1.0 );
    ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR0], 1.0, 1.0, 1.0, 1.0 );
    ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR1], 0.0, 0.0, 0.0, 1.0 );
    ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_FOG], 0.0, 0.0, 0.0, 0.0 );
-
-   ctx->Current.Index = 1;
+   ctx->Current.Attrib[VERT_ATTRIB_COLOR_INDEX][0] = 1.0;
    ctx->Current.EdgeFlag = GL_TRUE;
 }
 
@@ -943,14 +1002,18 @@ _mesa_init_constants( GLcontext *ctx )
    assert(MAX_TEXTURE_LEVELS >= MAX_3D_TEXTURE_LEVELS);
    assert(MAX_TEXTURE_LEVELS >= MAX_CUBE_TEXTURE_LEVELS);
 
+   assert(MAX_TEXTURE_UNITS >= MAX_TEXTURE_COORD_UNITS);
+   assert(MAX_TEXTURE_UNITS >= MAX_TEXTURE_IMAGE_UNITS);
+
    /* Constants, may be overriden (usually only reduced) by device drivers */
    ctx->Const.MaxTextureLevels = MAX_TEXTURE_LEVELS;
    ctx->Const.Max3DTextureLevels = MAX_3D_TEXTURE_LEVELS;
    ctx->Const.MaxCubeTextureLevels = MAX_CUBE_TEXTURE_LEVELS;
    ctx->Const.MaxTextureRectSize = MAX_TEXTURE_RECT_SIZE;
-   ctx->Const.MaxTextureUnits = MAX_TEXTURE_UNITS;
    ctx->Const.MaxTextureCoordUnits = MAX_TEXTURE_COORD_UNITS;
    ctx->Const.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
+   ctx->Const.MaxTextureUnits = MIN2(ctx->Const.MaxTextureCoordUnits,
+                                     ctx->Const.MaxTextureImageUnits);
    ctx->Const.MaxTextureMaxAnisotropy = MAX_TEXTURE_MAX_ANISOTROPY;
    ctx->Const.MaxTextureLodBias = MAX_TEXTURE_LOD_BIAS;
    ctx->Const.MaxArrayLockSize = MAX_ARRAY_LOCK_SIZE;
@@ -1025,12 +1088,42 @@ _mesa_init_constants( GLcontext *ctx )
 #endif
 
    /* sanity checks */
-   ASSERT(ctx->Const.MaxTextureUnits == MAX2(ctx->Const.MaxTextureImageUnits, ctx->Const.MaxTextureCoordUnits));
+   ASSERT(ctx->Const.MaxTextureUnits == MIN2(ctx->Const.MaxTextureImageUnits,
+                                             ctx->Const.MaxTextureCoordUnits));
    ASSERT(ctx->Const.FragmentProgram.MaxLocalParams <= MAX_PROGRAM_LOCAL_PARAMS);
    ASSERT(ctx->Const.VertexProgram.MaxLocalParams <= MAX_PROGRAM_LOCAL_PARAMS);
 }
 
 
+/**
+ * Do some sanity checks on the limits/constants for the given context.
+ * Only called the first time a context is bound.
+ */
+static void
+check_context_limits(GLcontext *ctx)
+{
+   /* Many context limits/constants are limited by the size of
+    * internal arrays.
+    */
+   assert(ctx->Const.MaxTextureImageUnits <= MAX_TEXTURE_IMAGE_UNITS);
+   assert(ctx->Const.MaxTextureCoordUnits <= MAX_TEXTURE_COORD_UNITS);
+   assert(ctx->Const.MaxTextureUnits <= MAX_TEXTURE_IMAGE_UNITS);
+   assert(ctx->Const.MaxTextureUnits <= MAX_TEXTURE_COORD_UNITS);
+
+   assert(ctx->Const.MaxViewportWidth <= MAX_WIDTH);
+   assert(ctx->Const.MaxViewportHeight <= MAX_WIDTH);
+
+   /* make sure largest texture image is <= MAX_WIDTH in size */
+   assert((1 << (ctx->Const.MaxTextureLevels -1 )) <= MAX_WIDTH);
+   assert((1 << (ctx->Const.MaxCubeTextureLevels -1 )) <= MAX_WIDTH);
+   assert((1 << (ctx->Const.Max3DTextureLevels -1 )) <= MAX_WIDTH);
+
+   assert(ctx->Const.MaxDrawBuffers <= MAX_DRAW_BUFFERS);
+
+   /* XXX probably add more tests */
+}
+
+
 /**
  * Initialize the attribute groups in a GL context.
  *
@@ -1317,6 +1410,7 @@ _mesa_free_context_data( GLcontext *ctx )
 #if FEATURE_ARB_vertex_buffer_object
    _mesa_delete_buffer_object(ctx, ctx->Array.NullBufferObj);
 #endif
+   _mesa_delete_array_object(ctx, ctx->Array.DefaultArrayObj);
 
    /* free dispatch tables */
    _mesa_free(ctx->Exec);
@@ -1333,7 +1427,7 @@ _mesa_free_context_data( GLcontext *ctx )
    }
 
    if (ctx->Extensions.String)
-      FREE((void *) ctx->Extensions.String);
+      _mesa_free((void *) ctx->Extensions.String);
 }
 
 
@@ -1349,7 +1443,7 @@ _mesa_destroy_context( GLcontext *ctx )
 {
    if (ctx) {
       _mesa_free_context_data(ctx);
-      FREE( (void *) ctx );
+      _mesa_free( (void *) ctx );
    }
 }
 
@@ -1404,7 +1498,7 @@ _mesa_copy_context( const GLcontext *src, GLcontext *dst, GLuint mask )
    if (mask & GL_LIGHTING_BIT) {
       GLuint i;
       /* begin with memcpy */
-      MEMCPY( &dst->Light, &src->Light, sizeof(struct gl_light) );
+      dst->Light = src->Light;
       /* fixup linked lists to prevent pointer insanity */
       make_empty_list( &(dst->Light.EnabledList) );
       for (i = 0; i < MAX_LIGHTS; i++) {
@@ -1479,6 +1573,11 @@ _mesa_copy_context( const GLcontext *src, GLcontext *dst, GLuint mask )
 /**
  * Check if the given context can render into the given framebuffer
  * by checking visual attributes.
+ *
+ * XXX this may go away someday because we're moving toward more freedom
+ * in binding contexts to drawables with different visual attributes.
+ * The GL_EXT_f_b_o extension is prompting some of that.
+ *
  * \return GL_TRUE if compatible, GL_FALSE otherwise.
  */
 static GLboolean 
@@ -1492,8 +1591,11 @@ check_compatible(const GLcontext *ctx, const GLframebuffer *buffer)
 
    if (ctxvis->rgbMode != bufvis->rgbMode)
       return GL_FALSE;
+#if 0
+   /* disabling this fixes the fgl_glxgears pbuffer demo */
    if (ctxvis->doubleBufferMode && !bufvis->doubleBufferMode)
       return GL_FALSE;
+#endif
    if (ctxvis->stereoMode && !bufvis->stereoMode)
       return GL_FALSE;
    if (ctxvis->haveAccumBuffer && !bufvis->haveAccumBuffer)
@@ -1527,11 +1629,12 @@ static void
 initialize_framebuffer_size(GLcontext *ctx, GLframebuffer *fb)
 {
    GLuint width, height;
-   ASSERT(ctx->Driver.GetBufferSize);
-   ctx->Driver.GetBufferSize(fb, &width, &height);
-   if (ctx->Driver.ResizeBuffers)
-      ctx->Driver.ResizeBuffers(ctx, fb, width, height);
-   fb->Initialized = GL_TRUE;
+   if (ctx->Driver.GetBufferSize) {
+      ctx->Driver.GetBufferSize(fb, &width, &height);
+      if (ctx->Driver.ResizeBuffers)
+         ctx->Driver.ResizeBuffers(ctx, fb, width, height);
+      fb->Initialized = GL_TRUE;
+   }
 }
 
 
@@ -1558,23 +1661,22 @@ _mesa_make_current( GLcontext *newCtx, GLframebuffer *drawBuffer,
 
    /* Check that the context's and framebuffer's visuals are compatible.
     */
-   if (newCtx && drawBuffer && newCtx->DrawBuffer != drawBuffer) {
-      if (!check_compatible(newCtx, drawBuffer))
+   if (newCtx && drawBuffer && newCtx->WinSysDrawBuffer != drawBuffer) {
+      if (!check_compatible(newCtx, drawBuffer)) {
+         _mesa_warning(newCtx,
+              "MakeCurrent: incompatible visuals for context and drawbuffer");
          return;
+      }
    }
-   if (newCtx && readBuffer && newCtx->ReadBuffer != readBuffer) {
-      if (!check_compatible(newCtx, readBuffer))
+   if (newCtx && readBuffer && newCtx->WinSysReadBuffer != readBuffer) {
+      if (!check_compatible(newCtx, readBuffer)) {
+         _mesa_warning(newCtx,
+              "MakeCurrent: incompatible visuals for context and readbuffer");
          return;
+      }
    }
 
-#if !defined(IN_DRI_DRIVER)
-   /* We call this function periodically (just here for now) in
-    * order to detect when multithreading has begun.  In a DRI driver, this
-    * step is done by the driver loader (e.g., libGL).
-    */
-   _glapi_check_multithread();
-#endif /* !defined(IN_DRI_DRIVER) */
-
+   /* We used to call _glapi_check_multithread() here.  Now do it in drivers */
    _glapi_set_context((void *) newCtx);
    ASSERT(_mesa_get_current_context() == newCtx);
 
@@ -1591,14 +1693,23 @@ _mesa_make_current( GLcontext *newCtx, GLframebuffer *drawBuffer,
          ASSERT(readBuffer->Name == 0);
          newCtx->WinSysDrawBuffer = drawBuffer;
          newCtx->WinSysReadBuffer = readBuffer;
-         /* don't replace user-buffer bindings with window system buffer */
+
+         /*
+          * Only set the context's Draw/ReadBuffer fields if they're NULL
+          * or not bound to a user-created FBO.
+          */
          if (!newCtx->DrawBuffer || newCtx->DrawBuffer->Name == 0) {
             newCtx->DrawBuffer = drawBuffer;
+         }
+         if (!newCtx->ReadBuffer || newCtx->ReadBuffer->Name == 0) {
             newCtx->ReadBuffer = readBuffer;
          }
 
         newCtx->NewState |= _NEW_BUFFERS;
 
+#if 1
+         /* We want to get rid of these lines: */
+
 #if _HAVE_FULL_GL
          if (!drawBuffer->Initialized) {
             initialize_framebuffer_size(newCtx, drawBuffer);
@@ -1606,13 +1717,33 @@ _mesa_make_current( GLcontext *newCtx, GLframebuffer *drawBuffer,
          if (readBuffer != drawBuffer && !readBuffer->Initialized) {
             initialize_framebuffer_size(newCtx, readBuffer);
          }
+
+        _mesa_resizebuffers(newCtx);
+#endif
+
+#else
+         /* We want the drawBuffer and readBuffer to be initialized by
+          * the driver.
+          * This generally means the Width and Height match the actual
+          * window size and the renderbuffers (both hardware and software
+          * based) are allocated to match.  The later can generally be
+          * done with a call to _mesa_resize_framebuffer().
+          *
+          * It's theoretically possible for a buffer to have zero width
+          * or height, but for now, assert check that the driver did what's
+          * expected of it.
+          */
+         ASSERT(drawBuffer->Width > 0);
+         ASSERT(drawBuffer->Height > 0);
 #endif
+
          if (newCtx->FirstTimeCurrent) {
             /* set initial viewport and scissor size now */
             _mesa_set_viewport(newCtx, 0, 0,
                                drawBuffer->Width, drawBuffer->Height);
-            newCtx->Scissor.Width = drawBuffer->Width;
-            newCtx->Scissor.Height = drawBuffer->Height;
+           _mesa_set_scissor(newCtx, 0, 0,
+                             drawBuffer->Width, drawBuffer->Height );
+            check_context_limits(newCtx);
          }
       }