Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright © 2012 Intel Corporation
  3.  *
  4.  * Permission is hereby granted, free of charge, to any person obtaining a
  5.  * copy of this software and associated documentation files (the "Software"),
  6.  * to deal in the Software without restriction, including without limitation
  7.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8.  * and/or sell copies of the Software, and to permit persons to whom the
  9.  * Software is furnished to do so, subject to the following conditions:
  10.  *
  11.  * The above copyright notice and this permission notice (including the next
  12.  * paragraph) shall be included in all copies or substantial portions of the
  13.  * Software.
  14.  *
  15.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  18.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20.  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  21.  * DEALINGS IN THE SOFTWARE.
  22.  */
  23.  
  24. /**
  25.  * \file performance_monitor.c
  26.  * Core Mesa support for the AMD_performance_monitor extension.
  27.  *
  28.  * In order to implement this extension, start by defining two enums:
  29.  * one for Groups, and one for Counters.  These will be used as indexes into
  30.  * arrays, so they should start at 0 and increment from there.
  31.  *
  32.  * Counter IDs need to be globally unique.  That is, you can't have counter 7
  33.  * in group A and counter 7 in group B.  A global enum of all available
  34.  * counters is a convenient way to guarantee this.
  35.  */
  36.  
  37. #include <stdbool.h>
  38. #include "glheader.h"
  39. #include "context.h"
  40. #include "enums.h"
  41. #include "hash.h"
  42. #include "macros.h"
  43. #include "mtypes.h"
  44. #include "performance_monitor.h"
  45. #include "util/bitset.h"
  46. #include "util/ralloc.h"
  47.  
  48. void
  49. _mesa_init_performance_monitors(struct gl_context *ctx)
  50. {
  51.    ctx->PerfMonitor.Monitors = _mesa_NewHashTable();
  52.    ctx->PerfMonitor.NumGroups = 0;
  53.    ctx->PerfMonitor.Groups = NULL;
  54. }
  55.  
  56. static struct gl_perf_monitor_object *
  57. new_performance_monitor(struct gl_context *ctx, GLuint index)
  58. {
  59.    unsigned i;
  60.    struct gl_perf_monitor_object *m = ctx->Driver.NewPerfMonitor(ctx);
  61.  
  62.    if (m == NULL)
  63.       return NULL;
  64.  
  65.    m->Name = index;
  66.  
  67.    m->Active = false;
  68.  
  69.    m->ActiveGroups =
  70.       rzalloc_array(NULL, unsigned, ctx->PerfMonitor.NumGroups);
  71.  
  72.    m->ActiveCounters =
  73.       ralloc_array(NULL, BITSET_WORD *, ctx->PerfMonitor.NumGroups);
  74.  
  75.    if (m->ActiveGroups == NULL || m->ActiveCounters == NULL)
  76.       goto fail;
  77.  
  78.    for (i = 0; i < ctx->PerfMonitor.NumGroups; i++) {
  79.       const struct gl_perf_monitor_group *g = &ctx->PerfMonitor.Groups[i];
  80.  
  81.       m->ActiveCounters[i] = rzalloc_array(m->ActiveCounters, BITSET_WORD,
  82.                                            BITSET_WORDS(g->NumCounters));
  83.       if (m->ActiveCounters[i] == NULL)
  84.          goto fail;
  85.    }
  86.  
  87.    return m;
  88.  
  89. fail:
  90.    ralloc_free(m->ActiveGroups);
  91.    ralloc_free(m->ActiveCounters);
  92.    ctx->Driver.DeletePerfMonitor(ctx, m);
  93.    return NULL;
  94. }
  95.  
  96. static void
  97. free_performance_monitor(GLuint key, void *data, void *user)
  98. {
  99.    struct gl_perf_monitor_object *m = data;
  100.    struct gl_context *ctx = user;
  101.  
  102.    ralloc_free(m->ActiveGroups);
  103.    ralloc_free(m->ActiveCounters);
  104.    ctx->Driver.DeletePerfMonitor(ctx, m);
  105. }
  106.  
  107. void
  108. _mesa_free_performance_monitors(struct gl_context *ctx)
  109. {
  110.    _mesa_HashDeleteAll(ctx->PerfMonitor.Monitors,
  111.                        free_performance_monitor, ctx);
  112.    _mesa_DeleteHashTable(ctx->PerfMonitor.Monitors);
  113. }
  114.  
  115. static inline struct gl_perf_monitor_object *
  116. lookup_monitor(struct gl_context *ctx, GLuint id)
  117. {
  118.    return (struct gl_perf_monitor_object *)
  119.       _mesa_HashLookup(ctx->PerfMonitor.Monitors, id);
  120. }
  121.  
  122. static inline const struct gl_perf_monitor_group *
  123. get_group(const struct gl_context *ctx, GLuint id)
  124. {
  125.    if (id >= ctx->PerfMonitor.NumGroups)
  126.       return NULL;
  127.  
  128.    return &ctx->PerfMonitor.Groups[id];
  129. }
  130.  
  131. static inline const struct gl_perf_monitor_counter *
  132. get_counter(const struct gl_perf_monitor_group *group_obj, GLuint id)
  133. {
  134.    if (id >= group_obj->NumCounters)
  135.       return NULL;
  136.  
  137.    return &group_obj->Counters[id];
  138. }
  139.  
  140. /* For INTEL_performance_query, query id 0 is reserved to be invalid. We use
  141.  * index to Groups array + 1 as the query id. Same applies to counter id.
  142.  */
  143. static inline GLuint
  144. queryid_to_index(GLuint queryid)
  145. {
  146.    return queryid - 1;
  147. }
  148.  
  149. static inline GLuint
  150. index_to_queryid(GLuint index)
  151. {
  152.    return index + 1;
  153. }
  154.  
  155. static inline bool
  156. queryid_valid(const struct gl_context *ctx, GLuint queryid)
  157. {
  158.    return get_group(ctx, queryid_to_index(queryid)) != NULL;
  159. }
  160.  
  161. static inline GLuint
  162. counterid_to_index(GLuint counterid)
  163. {
  164.    return counterid - 1;
  165. }
  166.  
  167. /*****************************************************************************/
  168.  
  169. void GLAPIENTRY
  170. _mesa_GetPerfMonitorGroupsAMD(GLint *numGroups, GLsizei groupsSize,
  171.                               GLuint *groups)
  172. {
  173.    GET_CURRENT_CONTEXT(ctx);
  174.  
  175.    if (numGroups != NULL)
  176.       *numGroups = ctx->PerfMonitor.NumGroups;
  177.  
  178.    if (groupsSize > 0 && groups != NULL) {
  179.       unsigned i;
  180.       unsigned n = MIN2((GLuint) groupsSize, ctx->PerfMonitor.NumGroups);
  181.  
  182.       /* We just use the index in the Groups array as the ID. */
  183.       for (i = 0; i < n; i++)
  184.          groups[i] = i;
  185.    }
  186. }
  187.  
  188. void GLAPIENTRY
  189. _mesa_GetPerfMonitorCountersAMD(GLuint group, GLint *numCounters,
  190.                                 GLint *maxActiveCounters,
  191.                                 GLsizei countersSize, GLuint *counters)
  192. {
  193.    GET_CURRENT_CONTEXT(ctx);
  194.    const struct gl_perf_monitor_group *group_obj = get_group(ctx, group);
  195.    if (group_obj == NULL) {
  196.       _mesa_error(ctx, GL_INVALID_VALUE,
  197.                   "glGetPerfMonitorCountersAMD(invalid group)");
  198.       return;
  199.    }
  200.  
  201.    if (maxActiveCounters != NULL)
  202.       *maxActiveCounters = group_obj->MaxActiveCounters;
  203.  
  204.    if (numCounters != NULL)
  205.       *numCounters = group_obj->NumCounters;
  206.  
  207.    if (counters != NULL) {
  208.       unsigned i;
  209.       unsigned n = MIN2(group_obj->NumCounters, (GLuint) countersSize);
  210.       for (i = 0; i < n; i++) {
  211.          /* We just use the index in the Counters array as the ID. */
  212.          counters[i] = i;
  213.       }
  214.    }
  215. }
  216.  
  217. void GLAPIENTRY
  218. _mesa_GetPerfMonitorGroupStringAMD(GLuint group, GLsizei bufSize,
  219.                                    GLsizei *length, GLchar *groupString)
  220. {
  221.    GET_CURRENT_CONTEXT(ctx);
  222.  
  223.    const struct gl_perf_monitor_group *group_obj = get_group(ctx, group);
  224.  
  225.    if (group_obj == NULL) {
  226.       _mesa_error(ctx, GL_INVALID_VALUE, "glGetPerfMonitorGroupStringAMD");
  227.       return;
  228.    }
  229.  
  230.    if (bufSize == 0) {
  231.       /* Return the number of characters that would be required to hold the
  232.        * group string, excluding the null terminator.
  233.        */
  234.       if (length != NULL)
  235.          *length = strlen(group_obj->Name);
  236.    } else {
  237.       if (length != NULL)
  238.          *length = MIN2(strlen(group_obj->Name), bufSize);
  239.       if (groupString != NULL)
  240.          strncpy(groupString, group_obj->Name, bufSize);
  241.    }
  242. }
  243.  
  244. void GLAPIENTRY
  245. _mesa_GetPerfMonitorCounterStringAMD(GLuint group, GLuint counter,
  246.                                      GLsizei bufSize, GLsizei *length,
  247.                                      GLchar *counterString)
  248. {
  249.    GET_CURRENT_CONTEXT(ctx);
  250.  
  251.    const struct gl_perf_monitor_group *group_obj;
  252.    const struct gl_perf_monitor_counter *counter_obj;
  253.  
  254.    group_obj = get_group(ctx, group);
  255.  
  256.    if (group_obj == NULL) {
  257.       _mesa_error(ctx, GL_INVALID_VALUE,
  258.                   "glGetPerfMonitorCounterStringAMD(invalid group)");
  259.       return;
  260.    }
  261.  
  262.    counter_obj = get_counter(group_obj, counter);
  263.  
  264.    if (counter_obj == NULL) {
  265.       _mesa_error(ctx, GL_INVALID_VALUE,
  266.                   "glGetPerfMonitorCounterStringAMD(invalid counter)");
  267.       return;
  268.    }
  269.  
  270.    if (bufSize == 0) {
  271.       /* Return the number of characters that would be required to hold the
  272.        * counter string, excluding the null terminator.
  273.        */
  274.       if (length != NULL)
  275.          *length = strlen(counter_obj->Name);
  276.    } else {
  277.       if (length != NULL)
  278.          *length = MIN2(strlen(counter_obj->Name), bufSize);
  279.       if (counterString != NULL)
  280.          strncpy(counterString, counter_obj->Name, bufSize);
  281.    }
  282. }
  283.  
  284. void GLAPIENTRY
  285. _mesa_GetPerfMonitorCounterInfoAMD(GLuint group, GLuint counter, GLenum pname,
  286.                                    GLvoid *data)
  287. {
  288.    GET_CURRENT_CONTEXT(ctx);
  289.  
  290.    const struct gl_perf_monitor_group *group_obj;
  291.    const struct gl_perf_monitor_counter *counter_obj;
  292.  
  293.    group_obj = get_group(ctx, group);
  294.  
  295.    if (group_obj == NULL) {
  296.       _mesa_error(ctx, GL_INVALID_VALUE,
  297.                   "glGetPerfMonitorCounterInfoAMD(invalid group)");
  298.       return;
  299.    }
  300.  
  301.    counter_obj = get_counter(group_obj, counter);
  302.  
  303.    if (counter_obj == NULL) {
  304.       _mesa_error(ctx, GL_INVALID_VALUE,
  305.                   "glGetPerfMonitorCounterInfoAMD(invalid counter)");
  306.       return;
  307.    }
  308.  
  309.    switch (pname) {
  310.    case GL_COUNTER_TYPE_AMD:
  311.       *((GLenum *) data) = counter_obj->Type;
  312.       break;
  313.  
  314.    case GL_COUNTER_RANGE_AMD:
  315.       switch (counter_obj->Type) {
  316.       case GL_FLOAT:
  317.       case GL_PERCENTAGE_AMD: {
  318.          float *f_data = data;
  319.          f_data[0] = counter_obj->Minimum.f;
  320.          f_data[1] = counter_obj->Maximum.f;
  321.          break;
  322.       }
  323.       case GL_UNSIGNED_INT: {
  324.          uint32_t *u32_data = data;
  325.          u32_data[0] = counter_obj->Minimum.u32;
  326.          u32_data[1] = counter_obj->Maximum.u32;
  327.          break;
  328.       }
  329.       case GL_UNSIGNED_INT64_AMD: {
  330.          uint64_t *u64_data = data;
  331.          u64_data[0] = counter_obj->Minimum.u64;
  332.          u64_data[1] = counter_obj->Maximum.u64;
  333.          break;
  334.       }
  335.       default:
  336.          assert(!"Should not get here: invalid counter type");
  337.       }
  338.       break;
  339.  
  340.    default:
  341.       _mesa_error(ctx, GL_INVALID_ENUM,
  342.                   "glGetPerfMonitorCounterInfoAMD(pname)");
  343.       return;
  344.    }
  345. }
  346.  
  347. void GLAPIENTRY
  348. _mesa_GenPerfMonitorsAMD(GLsizei n, GLuint *monitors)
  349. {
  350.    GLuint first;
  351.    GET_CURRENT_CONTEXT(ctx);
  352.  
  353.    if (MESA_VERBOSE & VERBOSE_API)
  354.       _mesa_debug(ctx, "glGenPerfMonitorsAMD(%d)\n", n);
  355.  
  356.    if (n < 0) {
  357.       _mesa_error(ctx, GL_INVALID_VALUE, "glGenPerfMonitorsAMD(n < 0)");
  358.       return;
  359.    }
  360.  
  361.    if (monitors == NULL)
  362.       return;
  363.  
  364.    /* We don't actually need them to be contiguous, but this is what
  365.     * the rest of Mesa does, so we may as well.
  366.     */
  367.    first = _mesa_HashFindFreeKeyBlock(ctx->PerfMonitor.Monitors, n);
  368.    if (first) {
  369.       GLsizei i;
  370.       for (i = 0; i < n; i++) {
  371.          struct gl_perf_monitor_object *m =
  372.             new_performance_monitor(ctx, first + i);
  373.          if (!m) {
  374.             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenPerfMonitorsAMD");
  375.             return;
  376.          }
  377.          monitors[i] = first + i;
  378.          _mesa_HashInsert(ctx->PerfMonitor.Monitors, first + i, m);
  379.       }
  380.    } else {
  381.       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenPerfMonitorsAMD");
  382.       return;
  383.    }
  384. }
  385.  
  386. void GLAPIENTRY
  387. _mesa_DeletePerfMonitorsAMD(GLsizei n, GLuint *monitors)
  388. {
  389.    GLint i;
  390.    GET_CURRENT_CONTEXT(ctx);
  391.  
  392.    if (MESA_VERBOSE & VERBOSE_API)
  393.       _mesa_debug(ctx, "glDeletePerfMonitorsAMD(%d)\n", n);
  394.  
  395.    if (n < 0) {
  396.       _mesa_error(ctx, GL_INVALID_VALUE, "glDeletePerfMonitorsAMD(n < 0)");
  397.       return;
  398.    }
  399.  
  400.    if (monitors == NULL)
  401.       return;
  402.  
  403.    for (i = 0; i < n; i++) {
  404.       struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitors[i]);
  405.  
  406.       if (m) {
  407.          /* Give the driver a chance to stop the monitor if it's active. */
  408.          if (m->Active) {
  409.             ctx->Driver.ResetPerfMonitor(ctx, m);
  410.             m->Ended = false;
  411.          }
  412.  
  413.          _mesa_HashRemove(ctx->PerfMonitor.Monitors, monitors[i]);
  414.          ralloc_free(m->ActiveGroups);
  415.          ralloc_free(m->ActiveCounters);
  416.          ctx->Driver.DeletePerfMonitor(ctx, m);
  417.       } else {
  418.          /* "INVALID_VALUE error will be generated if any of the monitor IDs
  419.           *  in the <monitors> parameter to DeletePerfMonitorsAMD do not
  420.           *  reference a valid generated monitor ID."
  421.           */
  422.          _mesa_error(ctx, GL_INVALID_VALUE,
  423.                      "glDeletePerfMonitorsAMD(invalid monitor)");
  424.       }
  425.    }
  426. }
  427.  
  428. void GLAPIENTRY
  429. _mesa_SelectPerfMonitorCountersAMD(GLuint monitor, GLboolean enable,
  430.                                    GLuint group, GLint numCounters,
  431.                                    GLuint *counterList)
  432. {
  433.    GET_CURRENT_CONTEXT(ctx);
  434.    int i;
  435.    struct gl_perf_monitor_object *m;
  436.    const struct gl_perf_monitor_group *group_obj;
  437.  
  438.    m = lookup_monitor(ctx, monitor);
  439.  
  440.    /* "INVALID_VALUE error will be generated if the <monitor> parameter to
  441.     *  SelectPerfMonitorCountersAMD does not reference a monitor created by
  442.     *  GenPerfMonitorsAMD."
  443.     */
  444.    if (m == NULL) {
  445.       _mesa_error(ctx, GL_INVALID_VALUE,
  446.                   "glSelectPerfMonitorCountersAMD(invalid monitor)");
  447.       return;
  448.    }
  449.  
  450.    group_obj = get_group(ctx, group);
  451.  
  452.    /* "INVALID_VALUE error will be generated if the <group> parameter to
  453.     *  GetPerfMonitorCountersAMD, GetPerfMonitorCounterStringAMD,
  454.     *  GetPerfMonitorCounterStringAMD, GetPerfMonitorCounterInfoAMD, or
  455.     *  SelectPerfMonitorCountersAMD does not reference a valid group ID."
  456.     */
  457.    if (group_obj == NULL) {
  458.       _mesa_error(ctx, GL_INVALID_VALUE,
  459.                   "glSelectPerfMonitorCountersAMD(invalid group)");
  460.       return;
  461.    }
  462.  
  463.    /* "INVALID_VALUE error will be generated if the <numCounters> parameter to
  464.     *  SelectPerfMonitorCountersAMD is less than 0."
  465.     */
  466.    if (numCounters < 0) {
  467.       _mesa_error(ctx, GL_INVALID_VALUE,
  468.                   "glSelectPerfMonitorCountersAMD(numCounters < 0)");
  469.       return;
  470.    }
  471.  
  472.    /* "When SelectPerfMonitorCountersAMD is called on a monitor, any outstanding
  473.     *  results for that monitor become invalidated and the result queries
  474.     *  PERFMON_RESULT_SIZE_AMD and PERFMON_RESULT_AVAILABLE_AMD are reset to 0."
  475.     */
  476.    ctx->Driver.ResetPerfMonitor(ctx, m);
  477.  
  478.    /* Sanity check the counter ID list. */
  479.    for (i = 0; i < numCounters; i++) {
  480.       if (counterList[i] >= group_obj->NumCounters) {
  481.          _mesa_error(ctx, GL_INVALID_VALUE,
  482.                      "glSelectPerfMonitorCountersAMD(invalid counter ID)");
  483.          return;
  484.       }
  485.    }
  486.  
  487.    if (enable) {
  488.       /* Enable the counters */
  489.       for (i = 0; i < numCounters; i++) {
  490.          ++m->ActiveGroups[group];
  491.          BITSET_SET(m->ActiveCounters[group], counterList[i]);
  492.       }
  493.    } else {
  494.       /* Disable the counters */
  495.       for (i = 0; i < numCounters; i++) {
  496.          --m->ActiveGroups[group];
  497.          BITSET_CLEAR(m->ActiveCounters[group], counterList[i]);
  498.       }
  499.    }
  500. }
  501.  
  502. void GLAPIENTRY
  503. _mesa_BeginPerfMonitorAMD(GLuint monitor)
  504. {
  505.    GET_CURRENT_CONTEXT(ctx);
  506.  
  507.    struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitor);
  508.  
  509.    if (m == NULL) {
  510.       _mesa_error(ctx, GL_INVALID_VALUE,
  511.                   "glBeginPerfMonitorAMD(invalid monitor)");
  512.       return;
  513.    }
  514.  
  515.    /* "INVALID_OPERATION error will be generated if BeginPerfMonitorAMD is
  516.     *  called when a performance monitor is already active."
  517.     */
  518.    if (m->Active) {
  519.       _mesa_error(ctx, GL_INVALID_OPERATION,
  520.                   "glBeginPerfMonitor(already active)");
  521.       return;
  522.    }
  523.  
  524.    /* The driver is free to return false if it can't begin monitoring for
  525.     * any reason.  This translates into an INVALID_OPERATION error.
  526.     */
  527.    if (ctx->Driver.BeginPerfMonitor(ctx, m)) {
  528.       m->Active = true;
  529.       m->Ended = false;
  530.    } else {
  531.       _mesa_error(ctx, GL_INVALID_OPERATION,
  532.                   "glBeginPerfMonitor(driver unable to begin monitoring)");
  533.    }
  534. }
  535.  
  536. void GLAPIENTRY
  537. _mesa_EndPerfMonitorAMD(GLuint monitor)
  538. {
  539.    GET_CURRENT_CONTEXT(ctx);
  540.  
  541.    struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitor);
  542.  
  543.    if (m == NULL) {
  544.       _mesa_error(ctx, GL_INVALID_VALUE, "glEndPerfMonitorAMD(invalid monitor)");
  545.       return;
  546.    }
  547.  
  548.    /* "INVALID_OPERATION error will be generated if EndPerfMonitorAMD is called
  549.     *  when a performance monitor is not currently started."
  550.     */
  551.    if (!m->Active) {
  552.       _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginPerfMonitor(not active)");
  553.       return;
  554.    }
  555.  
  556.    ctx->Driver.EndPerfMonitor(ctx, m);
  557.  
  558.    m->Active = false;
  559.    m->Ended = true;
  560. }
  561.  
  562. /**
  563.  * Return the number of bytes needed to store a monitor's result.
  564.  */
  565. static unsigned
  566. perf_monitor_result_size(const struct gl_context *ctx,
  567.                          const struct gl_perf_monitor_object *m)
  568. {
  569.    unsigned group, counter;
  570.    unsigned size = 0;
  571.  
  572.    for (group = 0; group < ctx->PerfMonitor.NumGroups; group++) {
  573.       const struct gl_perf_monitor_group *g = &ctx->PerfMonitor.Groups[group];
  574.       for (counter = 0; counter < g->NumCounters; counter++) {
  575.          const struct gl_perf_monitor_counter *c = &g->Counters[counter];
  576.  
  577.          if (!BITSET_TEST(m->ActiveCounters[group], counter))
  578.             continue;
  579.  
  580.          size += sizeof(uint32_t); /* Group ID */
  581.          size += sizeof(uint32_t); /* Counter ID */
  582.          size += _mesa_perf_monitor_counter_size(c);
  583.       }
  584.    }
  585.    return size;
  586. }
  587.  
  588. void GLAPIENTRY
  589. _mesa_GetPerfMonitorCounterDataAMD(GLuint monitor, GLenum pname,
  590.                                    GLsizei dataSize, GLuint *data,
  591.                                    GLint *bytesWritten)
  592. {
  593.    GET_CURRENT_CONTEXT(ctx);
  594.  
  595.    struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitor);
  596.    bool result_available;
  597.  
  598.    if (m == NULL) {
  599.       _mesa_error(ctx, GL_INVALID_VALUE,
  600.                   "glGetPerfMonitorCounterDataAMD(invalid monitor)");
  601.       return;
  602.    }
  603.  
  604.    /* "It is an INVALID_OPERATION error for <data> to be NULL." */
  605.    if (data == NULL) {
  606.       _mesa_error(ctx, GL_INVALID_OPERATION,
  607.                   "glGetPerfMonitorCounterDataAMD(data == NULL)");
  608.       return;
  609.    }
  610.  
  611.    /* We need at least enough room for a single value. */
  612.    if (dataSize < sizeof(GLuint)) {
  613.       if (bytesWritten != NULL)
  614.          *bytesWritten = 0;
  615.       return;
  616.    }
  617.  
  618.    /* If the monitor has never ended, there is no result. */
  619.    result_available = m->Ended &&
  620.       ctx->Driver.IsPerfMonitorResultAvailable(ctx, m);
  621.  
  622.    /* AMD appears to return 0 for all queries unless a result is available. */
  623.    if (!result_available) {
  624.       *data = 0;
  625.       if (bytesWritten != NULL)
  626.          *bytesWritten = sizeof(GLuint);
  627.       return;
  628.    }
  629.  
  630.    switch (pname) {
  631.    case GL_PERFMON_RESULT_AVAILABLE_AMD:
  632.       *data = 1;
  633.       if (bytesWritten != NULL)
  634.          *bytesWritten = sizeof(GLuint);
  635.       break;
  636.    case GL_PERFMON_RESULT_SIZE_AMD:
  637.       *data = perf_monitor_result_size(ctx, m);
  638.       if (bytesWritten != NULL)
  639.          *bytesWritten = sizeof(GLuint);
  640.       break;
  641.    case GL_PERFMON_RESULT_AMD:
  642.       ctx->Driver.GetPerfMonitorResult(ctx, m, dataSize, data, bytesWritten);
  643.       break;
  644.    default:
  645.       _mesa_error(ctx, GL_INVALID_ENUM,
  646.                   "glGetPerfMonitorCounterDataAMD(pname)");
  647.    }
  648. }
  649.  
  650. /**
  651.  * Returns how many bytes a counter's value takes up.
  652.  */
  653. unsigned
  654. _mesa_perf_monitor_counter_size(const struct gl_perf_monitor_counter *c)
  655. {
  656.    switch (c->Type) {
  657.    case GL_FLOAT:
  658.    case GL_PERCENTAGE_AMD:
  659.       return sizeof(GLfloat);
  660.    case GL_UNSIGNED_INT:
  661.       return sizeof(GLuint);
  662.    case GL_UNSIGNED_INT64_AMD:
  663.       return sizeof(uint64_t);
  664.    default:
  665.       assert(!"Should not get here: invalid counter type");
  666.       return 0;
  667.    }
  668. }
  669.  
  670. extern void GLAPIENTRY
  671. _mesa_GetFirstPerfQueryIdINTEL(GLuint *queryId)
  672. {
  673.    GET_CURRENT_CONTEXT(ctx);
  674.    unsigned numGroups;
  675.  
  676.    /* The GL_INTEL_performance_query spec says:
  677.     *
  678.     *    "If queryId pointer is equal to 0, INVALID_VALUE error is generated."
  679.     */
  680.    if (!queryId) {
  681.       _mesa_error(ctx, GL_INVALID_VALUE,
  682.                   "glGetFirstPerfQueryIdINTEL(queryId == NULL)");
  683.       return;
  684.    }
  685.  
  686.    numGroups = ctx->PerfMonitor.NumGroups;
  687.  
  688.    /* The GL_INTEL_performance_query spec says:
  689.     *
  690.     *    "If the given hardware platform doesn't support any performance
  691.     *    queries, then the value of 0 is returned and INVALID_OPERATION error
  692.     *    is raised."
  693.     */
  694.    if (numGroups == 0) {
  695.       *queryId = 0;
  696.       _mesa_error(ctx, GL_INVALID_OPERATION,
  697.                   "glGetFirstPerfQueryIdINTEL(no queries supported)");
  698.       return;
  699.    }
  700.  
  701.    *queryId = index_to_queryid(0);
  702. }
  703.  
  704. extern void GLAPIENTRY
  705. _mesa_GetNextPerfQueryIdINTEL(GLuint queryId, GLuint *nextQueryId)
  706. {
  707.    GET_CURRENT_CONTEXT(ctx);
  708.  
  709.    /* The GL_INTEL_performance_query spec says:
  710.     *
  711.     *    "The result is passed in location pointed by nextQueryId. If query
  712.     *    identified by queryId is the last query available the value of 0 is
  713.     *    returned. If the specified performance query identifier is invalid
  714.     *    then INVALID_VALUE error is generated. If nextQueryId pointer is
  715.     *    equal to 0, an INVALID_VALUE error is generated.  Whenever error is
  716.     *    generated, the value of 0 is returned."
  717.     */
  718.  
  719.    if (!nextQueryId) {
  720.       _mesa_error(ctx, GL_INVALID_VALUE,
  721.                   "glGetNextPerfQueryIdINTEL(nextQueryId == NULL)");
  722.       return;
  723.    }
  724.  
  725.    if (!queryid_valid(ctx, queryId)) {
  726.       *nextQueryId = 0;
  727.       _mesa_error(ctx, GL_INVALID_VALUE,
  728.                   "glGetNextPerfQueryIdINTEL(invalid query)");
  729.       return;
  730.    }
  731.  
  732.    ++queryId;
  733.  
  734.    if (!queryid_valid(ctx, queryId)) {
  735.       *nextQueryId = 0;
  736.    } else {
  737.       *nextQueryId = queryId;
  738.    }
  739. }
  740.  
  741. extern void GLAPIENTRY
  742. _mesa_GetPerfQueryIdByNameINTEL(char *queryName, GLuint *queryId)
  743. {
  744.    GET_CURRENT_CONTEXT(ctx);
  745.    unsigned i;
  746.  
  747.    /* The GL_INTEL_performance_query spec says:
  748.     *
  749.     *    "If queryName does not reference a valid query name, an INVALID_VALUE
  750.     *    error is generated."
  751.     */
  752.    if (!queryName) {
  753.       _mesa_error(ctx, GL_INVALID_VALUE,
  754.                   "glGetPerfQueryIdByNameINTEL(queryName == NULL)");
  755.       return;
  756.    }
  757.  
  758.    /* The specification does not state that this produces an error. */
  759.    if (!queryId) {
  760.       _mesa_warning(ctx, "glGetPerfQueryIdByNameINTEL(queryId == NULL)");
  761.       return;
  762.    }
  763.  
  764.    for (i = 0; i < ctx->PerfMonitor.NumGroups; ++i) {
  765.       const struct gl_perf_monitor_group *group_obj = get_group(ctx, i);
  766.       if (strcmp(group_obj->Name, queryName) == 0) {
  767.          *queryId = index_to_queryid(i);
  768.          return;
  769.       }
  770.    }
  771.  
  772.    _mesa_error(ctx, GL_INVALID_VALUE,
  773.                "glGetPerfQueryIdByNameINTEL(invalid query name)");
  774. }
  775.  
  776. extern void GLAPIENTRY
  777. _mesa_GetPerfQueryInfoINTEL(GLuint queryId,
  778.                             GLuint queryNameLength, char *queryName,
  779.                             GLuint *dataSize, GLuint *noCounters,
  780.                             GLuint *noActiveInstances,
  781.                             GLuint *capsMask)
  782. {
  783.    GET_CURRENT_CONTEXT(ctx);
  784.    unsigned i;
  785.  
  786.    const struct gl_perf_monitor_group *group_obj =
  787.       get_group(ctx, queryid_to_index(queryId));
  788.  
  789.    if (group_obj == NULL) {
  790.       /* The GL_INTEL_performance_query spec says:
  791.        *
  792.        *    "If queryId does not reference a valid query type, an
  793.        *    INVALID_VALUE error is generated."
  794.        */
  795.       _mesa_error(ctx, GL_INVALID_VALUE,
  796.                   "glGetPerfQueryInfoINTEL(invalid query)");
  797.       return;
  798.    }
  799.  
  800.    if (queryName) {
  801.       strncpy(queryName, group_obj->Name, queryNameLength);
  802.  
  803.       /* No specification given about whether the string needs to be
  804.        * zero-terminated. Zero-terminate the string always as we don't
  805.        * otherwise communicate the length of the returned string.
  806.        */
  807.       if (queryNameLength > 0) {
  808.          queryName[queryNameLength - 1] = '\0';
  809.       }
  810.    }
  811.  
  812.    if (dataSize) {
  813.       unsigned size = 0;
  814.       for (i = 0; i < group_obj->NumCounters; ++i) {
  815.          /* What we get from the driver is group id (uint32_t) + counter id
  816.           * (uint32_t) + value.
  817.           */
  818.          size += 2 * sizeof(uint32_t) + _mesa_perf_monitor_counter_size(&group_obj->Counters[i]);
  819.       }
  820.       *dataSize = size;
  821.    }
  822.  
  823.    if (noCounters) {
  824.       *noCounters = group_obj->NumCounters;
  825.    }
  826.  
  827.    /* The GL_INTEL_performance_query spec says:
  828.     *
  829.     *    "-- the actual number of already created query instances in
  830.     *    maxInstances location"
  831.     *
  832.     * 1) Typo in the specification, should be noActiveInstances.
  833.     * 2) Another typo in the specification, maxInstances parameter is not listed
  834.     *    in the declaration of this function in the list of new functions.
  835.     */
  836.    if (noActiveInstances) {
  837.       *noActiveInstances = _mesa_HashNumEntries(ctx->PerfMonitor.Monitors);
  838.    }
  839.  
  840.    if (capsMask) {
  841.       /* TODO: This information not yet available in the monitor structs. For
  842.        * now, we hardcode SINGLE_CONTEXT, since that's what the implementation
  843.        * currently tries very hard to do.
  844.        */
  845.       *capsMask = GL_PERFQUERY_SINGLE_CONTEXT_INTEL;
  846.    }
  847. }
  848.  
  849. extern void GLAPIENTRY
  850. _mesa_GetPerfCounterInfoINTEL(GLuint queryId, GLuint counterId,
  851.                               GLuint counterNameLength, char *counterName,
  852.                               GLuint counterDescLength, char *counterDesc,
  853.                               GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum,
  854.                               GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue)
  855. {
  856.    GET_CURRENT_CONTEXT(ctx);
  857.  
  858.    const struct gl_perf_monitor_group *group_obj;
  859.    const struct gl_perf_monitor_counter *counter_obj;
  860.    unsigned counterIndex;
  861.    unsigned i;
  862.  
  863.    group_obj = get_group(ctx, queryid_to_index(queryId));
  864.  
  865.    /* The GL_INTEL_performance_query spec says:
  866.     *
  867.     *    "If the pair of queryId and counterId does not reference a valid
  868.     *    counter, an INVALID_VALUE error is generated."
  869.     */
  870.    if (group_obj == NULL) {
  871.       _mesa_error(ctx, GL_INVALID_VALUE,
  872.                   "glGetPerfCounterInfoINTEL(invalid queryId)");
  873.       return;
  874.    }
  875.  
  876.    counterIndex = counterid_to_index(counterId);
  877.    counter_obj = get_counter(group_obj, counterIndex);
  878.  
  879.    if (counter_obj == NULL) {
  880.       _mesa_error(ctx, GL_INVALID_VALUE,
  881.                   "glGetPerfCounterInfoINTEL(invalid counterId)");
  882.       return;
  883.    }
  884.  
  885.    if (counterName) {
  886.       strncpy(counterName, counter_obj->Name, counterNameLength);
  887.  
  888.       /* No specification given about whether the string needs to be
  889.        * zero-terminated. Zero-terminate the string always as we don't
  890.        * otherwise communicate the length of the returned string.
  891.        */
  892.       if (counterNameLength > 0) {
  893.          counterName[counterNameLength - 1] = '\0';
  894.       }
  895.    }
  896.  
  897.    if (counterDesc) {
  898.       /* TODO: No separate description text at the moment. We pass the name
  899.        * again for the moment.
  900.        */
  901.       strncpy(counterDesc, counter_obj->Name, counterDescLength);
  902.  
  903.       /* No specification given about whether the string needs to be
  904.        * zero-terminated. Zero-terminate the string always as we don't
  905.        * otherwise communicate the length of the returned string.
  906.        */
  907.       if (counterDescLength > 0) {
  908.          counterDesc[counterDescLength - 1] = '\0';
  909.       }
  910.    }
  911.  
  912.    if (counterOffset) {
  913.       unsigned offset = 0;
  914.       for (i = 0; i < counterIndex; ++i) {
  915.          /* What we get from the driver is group id (uint32_t) + counter id
  916.           * (uint32_t) + value.
  917.           */
  918.          offset += 2 * sizeof(uint32_t) + _mesa_perf_monitor_counter_size(&group_obj->Counters[i]);
  919.       }
  920.       *counterOffset = 2 * sizeof(uint32_t) + offset;
  921.    }
  922.  
  923.    if (counterDataSize) {
  924.       *counterDataSize = _mesa_perf_monitor_counter_size(counter_obj);
  925.    }
  926.  
  927.    if (counterTypeEnum) {
  928.       /* TODO: Different counter types (semantic type, not data type) not
  929.        * supported as of yet.
  930.        */
  931.       *counterTypeEnum = GL_PERFQUERY_COUNTER_RAW_INTEL;
  932.    }
  933.  
  934.    if (counterDataTypeEnum) {
  935.       switch (counter_obj->Type) {
  936.       case GL_FLOAT:
  937.       case GL_PERCENTAGE_AMD:
  938.          *counterDataTypeEnum = GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL;
  939.          break;
  940.       case GL_UNSIGNED_INT:
  941.          *counterDataTypeEnum = GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL;
  942.          break;
  943.       case GL_UNSIGNED_INT64_AMD:
  944.          *counterDataTypeEnum = GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL;
  945.          break;
  946.       default:
  947.          assert(!"Should not get here: invalid counter type");
  948.          return;
  949.       }
  950.    }
  951.  
  952.    if (rawCounterMaxValue) {
  953.       /* This value is (implicitly) specified to be used only with
  954.        * GL_PERFQUERY_COUNTER_RAW_INTEL counters. When semantic types for
  955.        * counters are added, that needs to be checked.
  956.        */
  957.  
  958.       /* The GL_INTEL_performance_query spec says:
  959.        *
  960.        *    "for some raw counters for which the maximal value is
  961.        *    deterministic, the maximal value of the counter in 1 second is
  962.        *    returned in the location pointed by rawCounterMaxValue, otherwise,
  963.        *    the location is written with the value of 0."
  964.        *
  965.        * The maximum value reported by the driver at the moment is not with
  966.        * these semantics, so write 0 always to be safe.
  967.        */
  968.       *rawCounterMaxValue = 0;
  969.    }
  970. }
  971.  
  972. extern void GLAPIENTRY
  973. _mesa_CreatePerfQueryINTEL(GLuint queryId, GLuint *queryHandle)
  974. {
  975.    GET_CURRENT_CONTEXT(ctx);
  976.    GLuint first;
  977.    GLuint group;
  978.    const struct gl_perf_monitor_group *group_obj;
  979.    struct gl_perf_monitor_object *m;
  980.    unsigned i;
  981.  
  982.    /* This is not specified in the extension, but is the only sane thing to
  983.     * do.
  984.     */
  985.    if (queryHandle == NULL) {
  986.       _mesa_error(ctx, GL_INVALID_VALUE,
  987.                   "glCreatePerfQueryINTEL(queryHandle == NULL)");
  988.       return;
  989.    }
  990.  
  991.    group = queryid_to_index(queryId);
  992.    group_obj = get_group(ctx, group);
  993.  
  994.    /* The GL_INTEL_performance_query spec says:
  995.     *
  996.     *    "If queryId does not reference a valid query type, an INVALID_VALUE
  997.     *    error is generated."
  998.     */
  999.    if (group_obj == NULL) {
  1000.       _mesa_error(ctx, GL_INVALID_VALUE,
  1001.                   "glCreatePerfQueryINTEL(invalid queryId)");
  1002.       return;
  1003.    }
  1004.  
  1005.    /* The query object created here is the counterpart of a `monitor' in
  1006.     * AMD_performance_monitor. This call is equivalent to calling
  1007.     * GenPerfMonitorsAMD and SelectPerfMonitorCountersAMD with a list of all
  1008.     * counters in a group.
  1009.     */
  1010.  
  1011.    /* We keep the monitor ids contiguous */
  1012.    first = _mesa_HashFindFreeKeyBlock(ctx->PerfMonitor.Monitors, 1);
  1013.    if (!first) {
  1014.       /* The GL_INTEL_performance_query spec says:
  1015.        *
  1016.        *    "If the query instance cannot be created due to exceeding the
  1017.        *    number of allowed instances or driver fails query creation due to
  1018.        *    an insufficient memory reason, an OUT_OF_MEMORY error is
  1019.        *    generated, and the location pointed by queryHandle returns NULL."
  1020.       */
  1021.       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCreatePerfQueryINTEL");
  1022.       return;
  1023.    }
  1024.  
  1025.    m = new_performance_monitor(ctx, first);
  1026.    if (m == NULL) {
  1027.       _mesa_error_no_memory(__func__);
  1028.       return;
  1029.    }
  1030.  
  1031.    _mesa_HashInsert(ctx->PerfMonitor.Monitors, first, m);
  1032.    *queryHandle = first;
  1033.  
  1034.    ctx->Driver.ResetPerfMonitor(ctx, m);
  1035.  
  1036.    for (i = 0; i < group_obj->NumCounters; ++i) {
  1037.       ++m->ActiveGroups[group];
  1038.       /* Counters are a continuous range of integers, 0 to NumCounters (excl),
  1039.        * so i is the counter value to use here.
  1040.        */
  1041.       BITSET_SET(m->ActiveCounters[group], i);
  1042.    }
  1043. }
  1044.  
  1045. extern void GLAPIENTRY
  1046. _mesa_DeletePerfQueryINTEL(GLuint queryHandle)
  1047. {
  1048.    GET_CURRENT_CONTEXT(ctx);
  1049.    struct gl_perf_monitor_object *m;
  1050.  
  1051.    /* The queryHandle is the counterpart to AMD_performance_monitor's monitor
  1052.     * id.
  1053.     */
  1054.    m = lookup_monitor(ctx, queryHandle);
  1055.  
  1056.    /* The GL_INTEL_performance_query spec says:
  1057.     *
  1058.     *    "If a query handle doesn't reference a previously created performance
  1059.     *    query instance, an INVALID_VALUE error is generated."
  1060.     */
  1061.    if (m == NULL) {
  1062.       _mesa_error(ctx, GL_INVALID_VALUE,
  1063.                   "glDeletePerfQueryINTEL(invalid queryHandle)");
  1064.       return;
  1065.    }
  1066.  
  1067.    /* Let the driver stop the monitor if it's active. */
  1068.    if (m->Active) {
  1069.       ctx->Driver.ResetPerfMonitor(ctx, m);
  1070.       m->Ended = false;
  1071.    }
  1072.  
  1073.    _mesa_HashRemove(ctx->PerfMonitor.Monitors, queryHandle);
  1074.    ralloc_free(m->ActiveGroups);
  1075.    ralloc_free(m->ActiveCounters);
  1076.    ctx->Driver.DeletePerfMonitor(ctx, m);
  1077. }
  1078.  
  1079. extern void GLAPIENTRY
  1080. _mesa_BeginPerfQueryINTEL(GLuint queryHandle)
  1081. {
  1082.    GET_CURRENT_CONTEXT(ctx);
  1083.    struct gl_perf_monitor_object *m;
  1084.  
  1085.    /* The queryHandle is the counterpart to AMD_performance_monitor's monitor
  1086.     * id.
  1087.     */
  1088.  
  1089.    m = lookup_monitor(ctx, queryHandle);
  1090.  
  1091.    /* The GL_INTEL_performance_query spec says:
  1092.     *
  1093.     *    "If a query handle doesn't reference a previously created performance
  1094.     *    query instance, an INVALID_VALUE error is generated."
  1095.     */
  1096.    if (m == NULL) {
  1097.       _mesa_error(ctx, GL_INVALID_VALUE,
  1098.                   "glBeginPerfQueryINTEL(invalid queryHandle)");
  1099.       return;
  1100.    }
  1101.  
  1102.    /* The GL_INTEL_performance_query spec says:
  1103.     *
  1104.     *    "Note that some query types, they cannot be collected in the same
  1105.     *    time. Therefore calls of BeginPerfQueryINTEL() cannot be nested if
  1106.     *    they refer to queries of such different types. In such case
  1107.     *    INVALID_OPERATION error is generated."
  1108.     *
  1109.     * We also generate an INVALID_OPERATION error if the driver can't begin
  1110.     * monitoring for its own reasons, and for nesting the same query.
  1111.     */
  1112.    if (m->Active) {
  1113.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1114.                   "glBeginPerfQueryINTEL(already active)");
  1115.       return;
  1116.    }
  1117.  
  1118.    if (ctx->Driver.BeginPerfMonitor(ctx, m)) {
  1119.       m->Active = true;
  1120.       m->Ended = false;
  1121.    } else {
  1122.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1123.                   "glBeginPerfQueryINTEL(driver unable to begin monitoring)");
  1124.    }
  1125. }
  1126.  
  1127. extern void GLAPIENTRY
  1128. _mesa_EndPerfQueryINTEL(GLuint queryHandle)
  1129. {
  1130.    GET_CURRENT_CONTEXT(ctx);
  1131.    struct gl_perf_monitor_object *m;
  1132.  
  1133.    /* The queryHandle is the counterpart to AMD_performance_monitor's monitor
  1134.     * id.
  1135.     */
  1136.  
  1137.    m = lookup_monitor(ctx, queryHandle);
  1138.  
  1139.    /* The GL_INTEL_performance_query spec says:
  1140.     *
  1141.     *    "If a performance query is not currently started, an
  1142.     *    INVALID_OPERATION error will be generated."
  1143.     *
  1144.     * The specification doesn't state that an invalid handle would be an
  1145.     * INVALID_VALUE error. Regardless, query for such a handle will not be
  1146.     * started, so we generate an INVALID_OPERATION in that case too.
  1147.     */
  1148.    if (m == NULL) {
  1149.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1150.                   "glEndPerfQueryINTEL(invalid queryHandle)");
  1151.       return;
  1152.    }
  1153.  
  1154.    if (!m->Active) {
  1155.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1156.                   "glEndPerfQueryINTEL(not active)");
  1157.       return;
  1158.    }
  1159.  
  1160.    ctx->Driver.EndPerfMonitor(ctx, m);
  1161.  
  1162.    m->Active = false;
  1163.    m->Ended = true;
  1164. }
  1165.  
  1166. extern void GLAPIENTRY
  1167. _mesa_GetPerfQueryDataINTEL(GLuint queryHandle, GLuint flags,
  1168.                             GLsizei dataSize, void *data, GLuint *bytesWritten)
  1169. {
  1170.    GET_CURRENT_CONTEXT(ctx);
  1171.    struct gl_perf_monitor_object *m;
  1172.    bool result_available;
  1173.  
  1174.    /* The GL_INTEL_performance_query spec says:
  1175.     *
  1176.     *    "If bytesWritten or data pointers are NULL then an INVALID_VALUE
  1177.     *    error is generated."
  1178.     */
  1179.    if (!bytesWritten || !data) {
  1180.       _mesa_error(ctx, GL_INVALID_VALUE,
  1181.                   "glGetPerfQueryDataINTEL(bytesWritten or data is NULL)");
  1182.       return;
  1183.    }
  1184.  
  1185.    /* The queryHandle is the counterpart to AMD_performance_monitor's monitor
  1186.     * id.
  1187.     */
  1188.  
  1189.    m = lookup_monitor(ctx, queryHandle);
  1190.  
  1191.    /* The specification doesn't state that an invalid handle generates an
  1192.     * error. We could interpret that to mean the case should be handled as
  1193.     * "measurement not ready for this query", but what should be done if
  1194.     * `flags' equals PERFQUERY_WAIT_INTEL?
  1195.     *
  1196.     * To resolve this, we just generate an INVALID_VALUE from an invalid query
  1197.     * handle.
  1198.     */
  1199.    if (m == NULL) {
  1200.       _mesa_error(ctx, GL_INVALID_VALUE,
  1201.                   "glGetPerfQueryDataINTEL(invalid queryHandle)");
  1202.       return;
  1203.    }
  1204.  
  1205.    /* We need at least enough room for a single value. */
  1206.    if (dataSize < sizeof(GLuint)) {
  1207.       *bytesWritten = 0;
  1208.       return;
  1209.    }
  1210.  
  1211.    /* The GL_INTEL_performance_query spec says:
  1212.     *
  1213.     *    "The call may end without returning any data if they are not ready
  1214.     *    for reading as the measurement session is still pending (the
  1215.     *    EndPerfQueryINTEL() command processing is not finished by
  1216.     *    hardware). In this case location pointed by the bytesWritten
  1217.     *    parameter will be set to 0."
  1218.     *
  1219.     * If EndPerfQueryINTEL() is not called at all, we follow this.
  1220.     */
  1221.    if (!m->Ended) {
  1222.       *bytesWritten = 0;
  1223.       return;
  1224.    }
  1225.  
  1226.    result_available = ctx->Driver.IsPerfMonitorResultAvailable(ctx, m);
  1227.  
  1228.    if (!result_available) {
  1229.       if (flags == GL_PERFQUERY_FLUSH_INTEL) {
  1230.          ctx->Driver.Flush(ctx);
  1231.       } else if (flags == GL_PERFQUERY_WAIT_INTEL) {
  1232.          /* Assume Finish() is both enough and not too much to wait for
  1233.           * results. If results are still not available after Finish(), the
  1234.           * later code automatically bails out with 0 for bytesWritten.
  1235.           */
  1236.          ctx->Driver.Finish(ctx);
  1237.          result_available =
  1238.             ctx->Driver.IsPerfMonitorResultAvailable(ctx, m);
  1239.       }
  1240.    }
  1241.  
  1242.    if (result_available) {
  1243.       ctx->Driver.GetPerfMonitorResult(ctx, m, dataSize, data, (GLint*)bytesWritten);
  1244.    } else {
  1245.       *bytesWritten = 0;
  1246.    }
  1247. }
  1248.