Subversion Repositories Kolibri OS

Rev

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

  1. /*
  2.  * Mesa 3-D graphics library
  3.  * Version:  7.1
  4.  *
  5.  * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
  6.  *
  7.  * Permission is hereby granted, free of charge, to any person obtaining a
  8.  * copy of this software and associated documentation files (the "Software"),
  9.  * to deal in the Software without restriction, including without limitation
  10.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  11.  * and/or sell copies of the Software, and to permit persons to whom the
  12.  * Software is furnished to do so, subject to the following conditions:
  13.  *
  14.  * The above copyright notice and this permission notice shall be included
  15.  * in all copies or substantial portions of the Software.
  16.  *
  17.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  18.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  20.  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  21.  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  22.  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23.  */
  24.  
  25.  
  26. #include "glheader.h"
  27. #include "context.h"
  28. #include "hash.h"
  29. #include "imports.h"
  30. #include "queryobj.h"
  31. #include "mtypes.h"
  32. #include "main/dispatch.h"
  33.  
  34.  
  35. #if FEATURE_queryobj
  36.  
  37.  
  38. /**
  39.  * Allocate a new query object.  This is a fallback routine called via
  40.  * ctx->Driver.NewQueryObject().
  41.  * \param ctx - rendering context
  42.  * \param id - the new object's ID
  43.  * \return pointer to new query_object object or NULL if out of memory.
  44.  */
  45. static struct gl_query_object *
  46. _mesa_new_query_object(struct gl_context *ctx, GLuint id)
  47. {
  48.    struct gl_query_object *q = MALLOC_STRUCT(gl_query_object);
  49.    (void) ctx;
  50.    if (q) {
  51.       q->Id = id;
  52.       q->Result = 0;
  53.       q->Active = GL_FALSE;
  54.       q->Ready = GL_TRUE;   /* correct, see spec */
  55.    }
  56.    return q;
  57. }
  58.  
  59.  
  60. /**
  61.  * Begin a query.  Software driver fallback.
  62.  * Called via ctx->Driver.BeginQuery().
  63.  */
  64. static void
  65. _mesa_begin_query(struct gl_context *ctx, struct gl_query_object *q)
  66. {
  67.    /* no-op */
  68. }
  69.  
  70.  
  71. /**
  72.  * End a query.  Software driver fallback.
  73.  * Called via ctx->Driver.EndQuery().
  74.  */
  75. static void
  76. _mesa_end_query(struct gl_context *ctx, struct gl_query_object *q)
  77. {
  78.    q->Ready = GL_TRUE;
  79. }
  80.  
  81.  
  82. /**
  83.  * Wait for query to complete.  Software driver fallback.
  84.  * Called via ctx->Driver.WaitQuery().
  85.  */
  86. static void
  87. _mesa_wait_query(struct gl_context *ctx, struct gl_query_object *q)
  88. {
  89.    /* For software drivers, _mesa_end_query() should have completed the query.
  90.     * For real hardware, implement a proper WaitQuery() driver function,
  91.     * which may require issuing a flush.
  92.     */
  93.    assert(q->Ready);
  94. }
  95.  
  96.  
  97. /**
  98.  * Check if a query results are ready.  Software driver fallback.
  99.  * Called via ctx->Driver.CheckQuery().
  100.  */
  101. static void
  102. _mesa_check_query(struct gl_context *ctx, struct gl_query_object *q)
  103. {
  104.    /* No-op for sw rendering.
  105.     * HW drivers may need to flush at this time.
  106.     */
  107. }
  108.  
  109.  
  110. /**
  111.  * Delete a query object.  Called via ctx->Driver.DeleteQuery().
  112.  * Not removed from hash table here.
  113.  */
  114. static void
  115. _mesa_delete_query(struct gl_context *ctx, struct gl_query_object *q)
  116. {
  117.    free(q);
  118. }
  119.  
  120.  
  121. void
  122. _mesa_init_query_object_functions(struct dd_function_table *driver)
  123. {
  124.    driver->NewQueryObject = _mesa_new_query_object;
  125.    driver->DeleteQuery = _mesa_delete_query;
  126.    driver->BeginQuery = _mesa_begin_query;
  127.    driver->EndQuery = _mesa_end_query;
  128.    driver->WaitQuery = _mesa_wait_query;
  129.    driver->CheckQuery = _mesa_check_query;
  130. }
  131.  
  132.  
  133. /**
  134.  * Return pointer to the query object binding point for the given target.
  135.  * \return NULL if invalid target, else the address of binding point
  136.  */
  137. static struct gl_query_object **
  138. get_query_binding_point(struct gl_context *ctx, GLenum target)
  139. {
  140.    switch (target) {
  141.    case GL_SAMPLES_PASSED_ARB:
  142.       if (ctx->Extensions.ARB_occlusion_query)
  143.          return &ctx->Query.CurrentOcclusionObject;
  144.       else
  145.          return NULL;
  146.    case GL_TIME_ELAPSED_EXT:
  147.       if (ctx->Extensions.EXT_timer_query)
  148.          return &ctx->Query.CurrentTimerObject;
  149.       else
  150.          return NULL;
  151. #if FEATURE_EXT_transform_feedback
  152.    case GL_PRIMITIVES_GENERATED:
  153.       if (ctx->Extensions.EXT_transform_feedback)
  154.          return &ctx->Query.PrimitivesGenerated;
  155.       else
  156.          return NULL;
  157.    case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
  158.       if (ctx->Extensions.EXT_transform_feedback)
  159.          return &ctx->Query.PrimitivesWritten;
  160.       else
  161.          return NULL;
  162. #endif
  163.    default:
  164.       return NULL;
  165.    }
  166. }
  167.  
  168.  
  169. void GLAPIENTRY
  170. _mesa_GenQueriesARB(GLsizei n, GLuint *ids)
  171. {
  172.    GLuint first;
  173.    GET_CURRENT_CONTEXT(ctx);
  174.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  175.  
  176.    if (n < 0) {
  177.       _mesa_error(ctx, GL_INVALID_VALUE, "glGenQueriesARB(n < 0)");
  178.       return;
  179.    }
  180.  
  181.    /* No query objects can be active at this time! */
  182.    if (ctx->Query.CurrentOcclusionObject ||
  183.        ctx->Query.CurrentTimerObject) {
  184.       _mesa_error(ctx, GL_INVALID_OPERATION, "glGenQueriesARB");
  185.       return;
  186.    }
  187.  
  188.    first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n);
  189.    if (first) {
  190.       GLsizei i;
  191.       for (i = 0; i < n; i++) {
  192.          struct gl_query_object *q
  193.             = ctx->Driver.NewQueryObject(ctx, first + i);
  194.          if (!q) {
  195.             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenQueriesARB");
  196.             return;
  197.          }
  198.          ids[i] = first + i;
  199.          _mesa_HashInsert(ctx->Query.QueryObjects, first + i, q);
  200.       }
  201.    }
  202. }
  203.  
  204.  
  205. void GLAPIENTRY
  206. _mesa_DeleteQueriesARB(GLsizei n, const GLuint *ids)
  207. {
  208.    GLint i;
  209.    GET_CURRENT_CONTEXT(ctx);
  210.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  211.  
  212.    if (n < 0) {
  213.       _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)");
  214.       return;
  215.    }
  216.  
  217.    /* No query objects can be active at this time! */
  218.    if (ctx->Query.CurrentOcclusionObject ||
  219.        ctx->Query.CurrentTimerObject) {
  220.       _mesa_error(ctx, GL_INVALID_OPERATION, "glDeleteQueriesARB");
  221.       return;
  222.    }
  223.  
  224.    for (i = 0; i < n; i++) {
  225.       if (ids[i] > 0) {
  226.          struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]);
  227.          if (q) {
  228.             ASSERT(!q->Active); /* should be caught earlier */
  229.             _mesa_HashRemove(ctx->Query.QueryObjects, ids[i]);
  230.             ctx->Driver.DeleteQuery(ctx, q);
  231.          }
  232.       }
  233.    }
  234. }
  235.  
  236.  
  237. GLboolean GLAPIENTRY
  238. _mesa_IsQueryARB(GLuint id)
  239. {
  240.    GET_CURRENT_CONTEXT(ctx);
  241.    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
  242.  
  243.    if (id && _mesa_lookup_query_object(ctx, id))
  244.       return GL_TRUE;
  245.    else
  246.       return GL_FALSE;
  247. }
  248.  
  249.  
  250. static void GLAPIENTRY
  251. _mesa_BeginQueryARB(GLenum target, GLuint id)
  252. {
  253.    struct gl_query_object *q, **bindpt;
  254.    GET_CURRENT_CONTEXT(ctx);
  255.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  256.  
  257.    FLUSH_VERTICES(ctx, _NEW_DEPTH);
  258.  
  259.    bindpt = get_query_binding_point(ctx, target);
  260.    if (!bindpt) {
  261.       _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)");
  262.       return;
  263.    }
  264.  
  265.    if (id == 0) {
  266.       _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB(id==0)");
  267.       return;
  268.    }
  269.  
  270.    q = _mesa_lookup_query_object(ctx, id);
  271.    if (!q) {
  272.       /* create new object */
  273.       q = ctx->Driver.NewQueryObject(ctx, id);
  274.       if (!q) {
  275.          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQueryARB");
  276.          return;
  277.       }
  278.       _mesa_HashInsert(ctx->Query.QueryObjects, id, q);
  279.    }
  280.    else {
  281.       /* pre-existing object */
  282.       if (q->Active) {
  283.          _mesa_error(ctx, GL_INVALID_OPERATION,
  284.                      "glBeginQueryARB(query already active)");
  285.          return;
  286.       }
  287.    }
  288.  
  289.    q->Target = target;
  290.    q->Active = GL_TRUE;
  291.    q->Result = 0;
  292.    q->Ready = GL_FALSE;
  293.  
  294.    /* XXX should probably refcount query objects */
  295.    *bindpt = q;
  296.  
  297.    ctx->Driver.BeginQuery(ctx, q);
  298. }
  299.  
  300.  
  301. static void GLAPIENTRY
  302. _mesa_EndQueryARB(GLenum target)
  303. {
  304.    struct gl_query_object *q, **bindpt;
  305.    GET_CURRENT_CONTEXT(ctx);
  306.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  307.  
  308.    FLUSH_VERTICES(ctx, _NEW_DEPTH);
  309.  
  310.    bindpt = get_query_binding_point(ctx, target);
  311.    if (!bindpt) {
  312.       _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)");
  313.       return;
  314.    }
  315.  
  316.    /* XXX should probably refcount query objects */
  317.    q = *bindpt;
  318.    *bindpt = NULL;
  319.  
  320.    if (!q || !q->Active) {
  321.       _mesa_error(ctx, GL_INVALID_OPERATION,
  322.                   "glEndQueryARB(no matching glBeginQueryARB)");
  323.       return;
  324.    }
  325.  
  326.    q->Active = GL_FALSE;
  327.    ctx->Driver.EndQuery(ctx, q);
  328. }
  329.  
  330.  
  331. void GLAPIENTRY
  332. _mesa_GetQueryivARB(GLenum target, GLenum pname, GLint *params)
  333. {
  334.    struct gl_query_object *q, **bindpt;
  335.    GET_CURRENT_CONTEXT(ctx);
  336.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  337.  
  338.    bindpt = get_query_binding_point(ctx, target);
  339.    if (!bindpt) {
  340.       _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)");
  341.       return;
  342.    }
  343.  
  344.    q = *bindpt;
  345.  
  346.    switch (pname) {
  347.       case GL_QUERY_COUNTER_BITS_ARB:
  348.          *params = 8 * sizeof(q->Result);
  349.          break;
  350.       case GL_CURRENT_QUERY_ARB:
  351.          *params = q ? q->Id : 0;
  352.          break;
  353.       default:
  354.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryivARB(pname)");
  355.          return;
  356.    }
  357. }
  358.  
  359.  
  360. void GLAPIENTRY
  361. _mesa_GetQueryObjectivARB(GLuint id, GLenum pname, GLint *params)
  362. {
  363.    struct gl_query_object *q = NULL;
  364.    GET_CURRENT_CONTEXT(ctx);
  365.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  366.  
  367.    if (id)
  368.       q = _mesa_lookup_query_object(ctx, id);
  369.  
  370.    if (!q || q->Active) {
  371.       _mesa_error(ctx, GL_INVALID_OPERATION,
  372.                   "glGetQueryObjectivARB(id=%d is invalid or active)", id);
  373.       return;
  374.    }
  375.  
  376.    switch (pname) {
  377.       case GL_QUERY_RESULT_ARB:
  378.          if (!q->Ready)
  379.             ctx->Driver.WaitQuery(ctx, q);
  380.          /* if result is too large for returned type, clamp to max value */
  381.          if (q->Result > 0x7fffffff) {
  382.             *params = 0x7fffffff;
  383.          }
  384.          else {
  385.             *params = (GLint)q->Result;
  386.          }
  387.          break;
  388.       case GL_QUERY_RESULT_AVAILABLE_ARB:
  389.          if (!q->Ready)
  390.             ctx->Driver.CheckQuery( ctx, q );
  391.          *params = q->Ready;
  392.          break;
  393.       default:
  394.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectivARB(pname)");
  395.          return;
  396.    }
  397. }
  398.  
  399.  
  400. void GLAPIENTRY
  401. _mesa_GetQueryObjectuivARB(GLuint id, GLenum pname, GLuint *params)
  402. {
  403.    struct gl_query_object *q = NULL;
  404.    GET_CURRENT_CONTEXT(ctx);
  405.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  406.  
  407.    if (id)
  408.       q = _mesa_lookup_query_object(ctx, id);
  409.  
  410.    if (!q || q->Active) {
  411.       _mesa_error(ctx, GL_INVALID_OPERATION,
  412.                   "glGetQueryObjectuivARB(id=%d is invalid or active)", id);
  413.       return;
  414.    }
  415.  
  416.    switch (pname) {
  417.       case GL_QUERY_RESULT_ARB:
  418.          if (!q->Ready)
  419.             ctx->Driver.WaitQuery(ctx, q);
  420.          /* if result is too large for returned type, clamp to max value */
  421.          if (q->Result > 0xffffffff) {
  422.             *params = 0xffffffff;
  423.          }
  424.          else {
  425.             *params = (GLuint)q->Result;
  426.          }
  427.          break;
  428.       case GL_QUERY_RESULT_AVAILABLE_ARB:
  429.          if (!q->Ready)
  430.             ctx->Driver.CheckQuery( ctx, q );
  431.          *params = q->Ready;
  432.          break;
  433.       default:
  434.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectuivARB(pname)");
  435.          return;
  436.    }
  437. }
  438.  
  439.  
  440. /**
  441.  * New with GL_EXT_timer_query
  442.  */
  443. static void GLAPIENTRY
  444. _mesa_GetQueryObjecti64vEXT(GLuint id, GLenum pname, GLint64EXT *params)
  445. {
  446.    struct gl_query_object *q = NULL;
  447.    GET_CURRENT_CONTEXT(ctx);
  448.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  449.  
  450.    if (id)
  451.       q = _mesa_lookup_query_object(ctx, id);
  452.  
  453.    if (!q || q->Active) {
  454.       _mesa_error(ctx, GL_INVALID_OPERATION,
  455.                   "glGetQueryObjectui64vARB(id=%d is invalid or active)", id);
  456.       return;
  457.    }
  458.  
  459.    switch (pname) {
  460.       case GL_QUERY_RESULT_ARB:
  461.          if (!q->Ready)
  462.             ctx->Driver.WaitQuery(ctx, q);
  463.          *params = q->Result;
  464.          break;
  465.       case GL_QUERY_RESULT_AVAILABLE_ARB:
  466.          if (!q->Ready)
  467.             ctx->Driver.CheckQuery( ctx, q );
  468.          *params = q->Ready;
  469.          break;
  470.       default:
  471.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjecti64vARB(pname)");
  472.          return;
  473.    }
  474. }
  475.  
  476.  
  477. /**
  478.  * New with GL_EXT_timer_query
  479.  */
  480. static void GLAPIENTRY
  481. _mesa_GetQueryObjectui64vEXT(GLuint id, GLenum pname, GLuint64EXT *params)
  482. {
  483.    struct gl_query_object *q = NULL;
  484.    GET_CURRENT_CONTEXT(ctx);
  485.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  486.  
  487.    if (id)
  488.       q = _mesa_lookup_query_object(ctx, id);
  489.  
  490.    if (!q || q->Active) {
  491.       _mesa_error(ctx, GL_INVALID_OPERATION,
  492.                   "glGetQueryObjectuui64vARB(id=%d is invalid or active)", id);
  493.       return;
  494.    }
  495.  
  496.    switch (pname) {
  497.       case GL_QUERY_RESULT_ARB:
  498.          if (!q->Ready)
  499.             ctx->Driver.WaitQuery(ctx, q);
  500.          *params = q->Result;
  501.          break;
  502.       case GL_QUERY_RESULT_AVAILABLE_ARB:
  503.          if (!q->Ready)
  504.             ctx->Driver.CheckQuery( ctx, q );
  505.          *params = q->Ready;
  506.          break;
  507.       default:
  508.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectui64vARB(pname)");
  509.          return;
  510.    }
  511. }
  512.  
  513.  
  514. void
  515. _mesa_init_queryobj_dispatch(struct _glapi_table *disp)
  516. {
  517.    SET_GenQueriesARB(disp, _mesa_GenQueriesARB);
  518.    SET_DeleteQueriesARB(disp, _mesa_DeleteQueriesARB);
  519.    SET_IsQueryARB(disp, _mesa_IsQueryARB);
  520.    SET_BeginQueryARB(disp, _mesa_BeginQueryARB);
  521.    SET_EndQueryARB(disp, _mesa_EndQueryARB);
  522.    SET_GetQueryivARB(disp, _mesa_GetQueryivARB);
  523.    SET_GetQueryObjectivARB(disp, _mesa_GetQueryObjectivARB);
  524.    SET_GetQueryObjectuivARB(disp, _mesa_GetQueryObjectuivARB);
  525.  
  526.    SET_GetQueryObjecti64vEXT(disp, _mesa_GetQueryObjecti64vEXT);
  527.    SET_GetQueryObjectui64vEXT(disp, _mesa_GetQueryObjectui64vEXT);
  528. }
  529.  
  530.  
  531. #endif /* FEATURE_queryobj */
  532.  
  533.  
  534. /**
  535.  * Allocate/init the context state related to query objects.
  536.  */
  537. void
  538. _mesa_init_queryobj(struct gl_context *ctx)
  539. {
  540.    ctx->Query.QueryObjects = _mesa_NewHashTable();
  541.    ctx->Query.CurrentOcclusionObject = NULL;
  542. }
  543.  
  544.  
  545. /**
  546.  * Callback for deleting a query object.  Called by _mesa_HashDeleteAll().
  547.  */
  548. static void
  549. delete_queryobj_cb(GLuint id, void *data, void *userData)
  550. {
  551.    struct gl_query_object *q= (struct gl_query_object *) data;
  552.    struct gl_context *ctx = (struct gl_context *)userData;
  553.    ctx->Driver.DeleteQuery(ctx, q);
  554. }
  555.  
  556.  
  557. /**
  558.  * Free the context state related to query objects.
  559.  */
  560. void
  561. _mesa_free_queryobj_data(struct gl_context *ctx)
  562. {
  563.    _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx);
  564.    _mesa_DeleteHashTable(ctx->Query.QueryObjects);
  565. }
  566.