Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Mesa 3-D graphics library
  3.  *
  4.  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
  5.  * (C) Copyright IBM Corporation 2006
  6.  * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
  7.  *
  8.  * Permission is hereby granted, free of charge, to any person obtaining a
  9.  * copy of this software and associated documentation files (the "Software"),
  10.  * to deal in the Software without restriction, including without limitation
  11.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  12.  * and/or sell copies of the Software, and to permit persons to whom the
  13.  * Software is furnished to do so, subject to the following conditions:
  14.  *
  15.  * The above copyright notice and this permission notice shall be included
  16.  * in all copies or substantial portions of the Software.
  17.  *
  18.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  19.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  21.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  22.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  23.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  24.  * OTHER DEALINGS IN THE SOFTWARE.
  25.  */
  26.  
  27.  
  28. /**
  29.  * \file arrayobj.c
  30.  * Functions for the GL_APPLE_vertex_array_object extension.
  31.  *
  32.  * \todo
  33.  * The code in this file borrows a lot from bufferobj.c.  There's a certain
  34.  * amount of cruft left over from that origin that may be unnecessary.
  35.  *
  36.  * \author Ian Romanick <idr@us.ibm.com>
  37.  * \author Brian Paul
  38.  */
  39.  
  40.  
  41. #include "glheader.h"
  42. #include "hash.h"
  43. #include "image.h"
  44. #include "imports.h"
  45. #include "context.h"
  46. #include "bufferobj.h"
  47. #include "arrayobj.h"
  48. #include "macros.h"
  49. #include "mtypes.h"
  50. #include "varray.h"
  51. #include "main/dispatch.h"
  52.  
  53.  
  54. /**
  55.  * Look up the array object for the given ID.
  56.  *
  57.  * \returns
  58.  * Either a pointer to the array object with the specified ID or \c NULL for
  59.  * a non-existent ID.  The spec defines ID 0 as being technically
  60.  * non-existent.
  61.  */
  62.  
  63. static inline struct gl_array_object *
  64. lookup_arrayobj(struct gl_context *ctx, GLuint id)
  65. {
  66.    if (id == 0)
  67.       return NULL;
  68.    else
  69.       return (struct gl_array_object *)
  70.          _mesa_HashLookup(ctx->Array.Objects, id);
  71. }
  72.  
  73.  
  74. /**
  75.  * For all the vertex arrays in the array object, unbind any pointers
  76.  * to any buffer objects (VBOs).
  77.  * This is done just prior to array object destruction.
  78.  */
  79. static void
  80. unbind_array_object_vbos(struct gl_context *ctx, struct gl_array_object *obj)
  81. {
  82.    GLuint i;
  83.  
  84.    for (i = 0; i < Elements(obj->VertexAttrib); i++)
  85.       _mesa_reference_buffer_object(ctx, &obj->VertexAttrib[i].BufferObj, NULL);
  86. }
  87.  
  88.  
  89. /**
  90.  * Allocate and initialize a new vertex array object.
  91.  *
  92.  * This function is intended to be called via
  93.  * \c dd_function_table::NewArrayObject.
  94.  */
  95. struct gl_array_object *
  96. _mesa_new_array_object( struct gl_context *ctx, GLuint name )
  97. {
  98.    struct gl_array_object *obj = CALLOC_STRUCT(gl_array_object);
  99.    if (obj)
  100.       _mesa_initialize_array_object(ctx, obj, name);
  101.    return obj;
  102. }
  103.  
  104.  
  105. /**
  106.  * Delete an array object.
  107.  *
  108.  * This function is intended to be called via
  109.  * \c dd_function_table::DeleteArrayObject.
  110.  */
  111. void
  112. _mesa_delete_array_object( struct gl_context *ctx, struct gl_array_object *obj )
  113. {
  114.    (void) ctx;
  115.    unbind_array_object_vbos(ctx, obj);
  116.    _mesa_reference_buffer_object(ctx, &obj->ElementArrayBufferObj, NULL);
  117.    _glthread_DESTROY_MUTEX(obj->Mutex);
  118.    free(obj);
  119. }
  120.  
  121.  
  122. /**
  123.  * Set ptr to arrayObj w/ reference counting.
  124.  * Note: this should only be called from the _mesa_reference_array_object()
  125.  * inline function.
  126.  */
  127. void
  128. _mesa_reference_array_object_(struct gl_context *ctx,
  129.                               struct gl_array_object **ptr,
  130.                               struct gl_array_object *arrayObj)
  131. {
  132.    assert(*ptr != arrayObj);
  133.  
  134.    if (*ptr) {
  135.       /* Unreference the old array object */
  136.       GLboolean deleteFlag = GL_FALSE;
  137.       struct gl_array_object *oldObj = *ptr;
  138.  
  139.       _glthread_LOCK_MUTEX(oldObj->Mutex);
  140.       ASSERT(oldObj->RefCount > 0);
  141.       oldObj->RefCount--;
  142. #if 0
  143.       printf("ArrayObj %p %d DECR to %d\n",
  144.              (void *) oldObj, oldObj->Name, oldObj->RefCount);
  145. #endif
  146.       deleteFlag = (oldObj->RefCount == 0);
  147.       _glthread_UNLOCK_MUTEX(oldObj->Mutex);
  148.  
  149.       if (deleteFlag) {
  150.          ASSERT(ctx->Driver.DeleteArrayObject);
  151.          ctx->Driver.DeleteArrayObject(ctx, oldObj);
  152.       }
  153.  
  154.       *ptr = NULL;
  155.    }
  156.    ASSERT(!*ptr);
  157.  
  158.    if (arrayObj) {
  159.       /* reference new array object */
  160.       _glthread_LOCK_MUTEX(arrayObj->Mutex);
  161.       if (arrayObj->RefCount == 0) {
  162.          /* this array's being deleted (look just above) */
  163.          /* Not sure this can every really happen.  Warn if it does. */
  164.          _mesa_problem(NULL, "referencing deleted array object");
  165.          *ptr = NULL;
  166.       }
  167.       else {
  168.          arrayObj->RefCount++;
  169. #if 0
  170.          printf("ArrayObj %p %d INCR to %d\n",
  171.                 (void *) arrayObj, arrayObj->Name, arrayObj->RefCount);
  172. #endif
  173.          *ptr = arrayObj;
  174.       }
  175.       _glthread_UNLOCK_MUTEX(arrayObj->Mutex);
  176.    }
  177. }
  178.  
  179.  
  180.  
  181. static void
  182. init_array(struct gl_context *ctx,
  183.            struct gl_client_array *array, GLint size, GLint type)
  184. {
  185.    array->Size = size;
  186.    array->Type = type;
  187.    array->Format = GL_RGBA; /* only significant for GL_EXT_vertex_array_bgra */
  188.    array->Stride = 0;
  189.    array->StrideB = 0;
  190.    array->Ptr = NULL;
  191.    array->Enabled = GL_FALSE;
  192.    array->Normalized = GL_FALSE;
  193.    array->Integer = GL_FALSE;
  194.    array->_ElementSize = size * _mesa_sizeof_type(type);
  195.    /* Vertex array buffers */
  196.    _mesa_reference_buffer_object(ctx, &array->BufferObj,
  197.                                  ctx->Shared->NullBufferObj);
  198. }
  199.  
  200.  
  201. /**
  202.  * Initialize a gl_array_object's arrays.
  203.  */
  204. void
  205. _mesa_initialize_array_object( struct gl_context *ctx,
  206.                                struct gl_array_object *obj,
  207.                                GLuint name )
  208. {
  209.    GLuint i;
  210.  
  211.    obj->Name = name;
  212.  
  213.    _glthread_INIT_MUTEX(obj->Mutex);
  214.    obj->RefCount = 1;
  215.  
  216.    /* Init the individual arrays */
  217.    for (i = 0; i < Elements(obj->VertexAttrib); i++) {
  218.       switch (i) {
  219.       case VERT_ATTRIB_WEIGHT:
  220.          init_array(ctx, &obj->VertexAttrib[VERT_ATTRIB_WEIGHT], 1, GL_FLOAT);
  221.          break;
  222.       case VERT_ATTRIB_NORMAL:
  223.          init_array(ctx, &obj->VertexAttrib[VERT_ATTRIB_NORMAL], 3, GL_FLOAT);
  224.          break;
  225.       case VERT_ATTRIB_COLOR1:
  226.          init_array(ctx, &obj->VertexAttrib[VERT_ATTRIB_COLOR1], 3, GL_FLOAT);
  227.          break;
  228.       case VERT_ATTRIB_FOG:
  229.          init_array(ctx, &obj->VertexAttrib[VERT_ATTRIB_FOG], 1, GL_FLOAT);
  230.          break;
  231.       case VERT_ATTRIB_COLOR_INDEX:
  232.          init_array(ctx, &obj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX], 1, GL_FLOAT);
  233.          break;
  234.       case VERT_ATTRIB_EDGEFLAG:
  235.          init_array(ctx, &obj->VertexAttrib[VERT_ATTRIB_EDGEFLAG], 1, GL_BOOL);
  236.          break;
  237.       case VERT_ATTRIB_POINT_SIZE:
  238.          init_array(ctx, &obj->VertexAttrib[VERT_ATTRIB_POINT_SIZE], 1, GL_FLOAT);
  239.          break;
  240.       default:
  241.          init_array(ctx, &obj->VertexAttrib[i], 4, GL_FLOAT);
  242.          break;
  243.       }
  244.    }
  245.  
  246.    _mesa_reference_buffer_object(ctx, &obj->ElementArrayBufferObj,
  247.                                  ctx->Shared->NullBufferObj);
  248. }
  249.  
  250.  
  251. /**
  252.  * Add the given array object to the array object pool.
  253.  */
  254. static void
  255. save_array_object( struct gl_context *ctx, struct gl_array_object *obj )
  256. {
  257.    if (obj->Name > 0) {
  258.       /* insert into hash table */
  259.       _mesa_HashInsert(ctx->Array.Objects, obj->Name, obj);
  260.    }
  261. }
  262.  
  263.  
  264. /**
  265.  * Remove the given array object from the array object pool.
  266.  * Do not deallocate the array object though.
  267.  */
  268. static void
  269. remove_array_object( struct gl_context *ctx, struct gl_array_object *obj )
  270. {
  271.    if (obj->Name > 0) {
  272.       /* remove from hash table */
  273.       _mesa_HashRemove(ctx->Array.Objects, obj->Name);
  274.    }
  275. }
  276.  
  277.  
  278.  
  279. /**
  280.  * Helper for _mesa_update_array_object_max_element().
  281.  * \return  min(arrayObj->VertexAttrib[*]._MaxElement).
  282.  */
  283. static GLuint
  284. compute_max_element(struct gl_array_object *arrayObj, GLbitfield64 enabled)
  285. {
  286.    GLuint min = ~((GLuint)0);
  287.    
  288.    while (enabled) {
  289.       struct gl_client_array *client_array;
  290.       GLint attrib = ffsll(enabled) - 1;
  291.       enabled ^= BITFIELD64_BIT(attrib);
  292.      
  293.       client_array = &arrayObj->VertexAttrib[attrib];
  294.       assert(client_array->Enabled);
  295.       _mesa_update_array_max_element(client_array);
  296.       min = MIN2(min, client_array->_MaxElement);
  297.    }
  298.    
  299.    return min;
  300. }
  301.  
  302.  
  303. /**
  304.  * Examine vertex arrays to update the gl_array_object::_MaxElement field.
  305.  */
  306. void
  307. _mesa_update_array_object_max_element(struct gl_context *ctx,
  308.                                       struct gl_array_object *arrayObj)
  309. {
  310.    GLbitfield64 enabled;
  311.  
  312.    if (!ctx->VertexProgram._Current ||
  313.        ctx->VertexProgram._Current == ctx->VertexProgram._TnlProgram) {
  314.       enabled = _mesa_array_object_get_enabled_ff(arrayObj);
  315.    } else {
  316.       enabled = _mesa_array_object_get_enabled_arb(arrayObj);
  317.    }
  318.  
  319.    /* _MaxElement is one past the last legal array element */
  320.    arrayObj->_MaxElement = compute_max_element(arrayObj, enabled);
  321. }
  322.  
  323.  
  324. /**********************************************************************/
  325. /* API Functions                                                      */
  326. /**********************************************************************/
  327.  
  328.  
  329. /**
  330.  * Helper for _mesa_BindVertexArray() and _mesa_BindVertexArrayAPPLE().
  331.  * \param genRequired  specifies behavour when id was not generated with
  332.  *                     glGenVertexArrays().
  333.  */
  334. static void
  335. bind_vertex_array(struct gl_context *ctx, GLuint id, GLboolean genRequired)
  336. {
  337.    struct gl_array_object * const oldObj = ctx->Array.ArrayObj;
  338.    struct gl_array_object *newObj = NULL;
  339.  
  340.    ASSERT(oldObj != NULL);
  341.  
  342.    if ( oldObj->Name == id )
  343.       return;   /* rebinding the same array object- no change */
  344.  
  345.    /*
  346.     * Get pointer to new array object (newObj)
  347.     */
  348.    if (id == 0) {
  349.       /* The spec says there is no array object named 0, but we use
  350.        * one internally because it simplifies things.
  351.        */
  352.       newObj = ctx->Array.DefaultArrayObj;
  353.    }
  354.    else {
  355.       /* non-default array object */
  356.       newObj = lookup_arrayobj(ctx, id);
  357.       if (!newObj) {
  358.          if (genRequired) {
  359.             _mesa_error(ctx, GL_INVALID_OPERATION, "glBindVertexArray(non-gen name)");
  360.             return;
  361.          }
  362.  
  363.          /* For APPLE version, generate a new array object now */
  364.          newObj = (*ctx->Driver.NewArrayObject)(ctx, id);
  365.          if (!newObj) {
  366.             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindVertexArrayAPPLE");
  367.             return;
  368.          }
  369.  
  370.          save_array_object(ctx, newObj);
  371.       }
  372.  
  373.       if (!newObj->EverBound) {
  374.          /* The "Interactions with APPLE_vertex_array_object" section of the
  375.           * GL_ARB_vertex_array_object spec says:
  376.           *
  377.           *     "The first bind call, either BindVertexArray or
  378.           *     BindVertexArrayAPPLE, determines the semantic of the object."
  379.           */
  380.          newObj->ARBsemantics = genRequired;
  381.          newObj->EverBound = GL_TRUE;
  382.       }
  383.    }
  384.  
  385.    ctx->NewState |= _NEW_ARRAY;
  386.    _mesa_reference_array_object(ctx, &ctx->Array.ArrayObj, newObj);
  387.  
  388.    /* Pass BindVertexArray call to device driver */
  389.    if (ctx->Driver.BindArrayObject && newObj)
  390.       ctx->Driver.BindArrayObject(ctx, newObj);
  391. }
  392.  
  393.  
  394. /**
  395.  * ARB version of glBindVertexArray()
  396.  * This function behaves differently from glBindVertexArrayAPPLE() in
  397.  * that this function requires all ids to have been previously generated
  398.  * by glGenVertexArrays[APPLE]().
  399.  */
  400. void GLAPIENTRY
  401. _mesa_BindVertexArray( GLuint id )
  402. {
  403.    GET_CURRENT_CONTEXT(ctx);
  404.    bind_vertex_array(ctx, id, GL_TRUE);
  405. }
  406.  
  407.  
  408. /**
  409.  * Bind a new array.
  410.  *
  411.  * \todo
  412.  * The binding could be done more efficiently by comparing the non-NULL
  413.  * pointers in the old and new objects.  The only arrays that are "dirty" are
  414.  * the ones that are non-NULL in either object.
  415.  */
  416. void GLAPIENTRY
  417. _mesa_BindVertexArrayAPPLE( GLuint id )
  418. {
  419.    GET_CURRENT_CONTEXT(ctx);
  420.    bind_vertex_array(ctx, id, GL_FALSE);
  421. }
  422.  
  423.  
  424. /**
  425.  * Delete a set of array objects.
  426.  *
  427.  * \param n      Number of array objects to delete.
  428.  * \param ids    Array of \c n array object IDs.
  429.  */
  430. void GLAPIENTRY
  431. _mesa_DeleteVertexArrays(GLsizei n, const GLuint *ids)
  432. {
  433.    GET_CURRENT_CONTEXT(ctx);
  434.    GLsizei i;
  435.  
  436.    if (n < 0) {
  437.       _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteVertexArrayAPPLE(n)");
  438.       return;
  439.    }
  440.  
  441.    for (i = 0; i < n; i++) {
  442.       struct gl_array_object *obj = lookup_arrayobj(ctx, ids[i]);
  443.  
  444.       if ( obj != NULL ) {
  445.          ASSERT( obj->Name == ids[i] );
  446.  
  447.          /* If the array object is currently bound, the spec says "the binding
  448.           * for that object reverts to zero and the default vertex array
  449.           * becomes current."
  450.           */
  451.          if ( obj == ctx->Array.ArrayObj ) {
  452.             _mesa_BindVertexArray(0);
  453.          }
  454.  
  455.          /* The ID is immediately freed for re-use */
  456.          remove_array_object(ctx, obj);
  457.  
  458.          /* Unreference the array object.
  459.           * If refcount hits zero, the object will be deleted.
  460.           */
  461.          _mesa_reference_array_object(ctx, &obj, NULL);
  462.       }
  463.    }
  464. }
  465.  
  466.  
  467. /**
  468.  * Generate a set of unique array object IDs and store them in \c arrays.
  469.  * Helper for _mesa_GenVertexArrays[APPLE]() functions below.
  470.  * \param n       Number of IDs to generate.
  471.  * \param arrays  Array of \c n locations to store the IDs.
  472.  * \param vboOnly Will arrays have to reside in VBOs?
  473.  */
  474. static void
  475. gen_vertex_arrays(struct gl_context *ctx, GLsizei n, GLuint *arrays)
  476. {
  477.    GLuint first;
  478.    GLint i;
  479.  
  480.    if (n < 0) {
  481.       _mesa_error(ctx, GL_INVALID_VALUE, "glGenVertexArraysAPPLE");
  482.       return;
  483.    }
  484.  
  485.    if (!arrays) {
  486.       return;
  487.    }
  488.  
  489.    first = _mesa_HashFindFreeKeyBlock(ctx->Array.Objects, n);
  490.  
  491.    /* Allocate new, empty array objects and return identifiers */
  492.    for (i = 0; i < n; i++) {
  493.       struct gl_array_object *obj;
  494.       GLuint name = first + i;
  495.  
  496.       obj = (*ctx->Driver.NewArrayObject)( ctx, name );
  497.       if (!obj) {
  498.          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenVertexArraysAPPLE");
  499.          return;
  500.       }
  501.       save_array_object(ctx, obj);
  502.       arrays[i] = first + i;
  503.    }
  504. }
  505.  
  506.  
  507. /**
  508.  * ARB version of glGenVertexArrays()
  509.  * All arrays will be required to live in VBOs.
  510.  */
  511. void GLAPIENTRY
  512. _mesa_GenVertexArrays(GLsizei n, GLuint *arrays)
  513. {
  514.    GET_CURRENT_CONTEXT(ctx);
  515.    gen_vertex_arrays(ctx, n, arrays);
  516. }
  517.  
  518.  
  519. /**
  520.  * APPLE version of glGenVertexArraysAPPLE()
  521.  * Arrays may live in VBOs or ordinary memory.
  522.  */
  523. void GLAPIENTRY
  524. _mesa_GenVertexArraysAPPLE(GLsizei n, GLuint *arrays)
  525. {
  526.    GET_CURRENT_CONTEXT(ctx);
  527.    gen_vertex_arrays(ctx, n, arrays);
  528. }
  529.  
  530.  
  531. /**
  532.  * Determine if ID is the name of an array object.
  533.  *
  534.  * \param id  ID of the potential array object.
  535.  * \return  \c GL_TRUE if \c id is the name of a array object,
  536.  *          \c GL_FALSE otherwise.
  537.  */
  538. GLboolean GLAPIENTRY
  539. _mesa_IsVertexArray( GLuint id )
  540. {
  541.    struct gl_array_object * obj;
  542.    GET_CURRENT_CONTEXT(ctx);
  543.    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
  544.  
  545.    if (id == 0)
  546.       return GL_FALSE;
  547.  
  548.    obj = lookup_arrayobj(ctx, id);
  549.    if (obj == NULL)
  550.       return GL_FALSE;
  551.  
  552.    return obj->EverBound;
  553. }
  554.