Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Mesa 3-D graphics library
  3.  *
  4.  * Copyright (C) 2010  VMware, Inc.  All Rights Reserved.
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the "Software"),
  8.  * to deal in the Software without restriction, including without limitation
  9.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10.  * and/or sell copies of the Software, and to permit persons to whom the
  11.  * Software is furnished to do so, subject to the following conditions:
  12.  *
  13.  * The above copyright notice and this permission notice shall be included
  14.  * in all copies or substantial portions of the Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  17.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  19.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  20.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  21.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  22.  * OTHER DEALINGS IN THE SOFTWARE.
  23.  */
  24.  
  25.  
  26. /*
  27.  * Transform feedback support.
  28.  *
  29.  * Authors:
  30.  *   Brian Paul
  31.  */
  32.  
  33.  
  34. #include "buffers.h"
  35. #include "context.h"
  36. #include "hash.h"
  37. #include "macros.h"
  38. #include "mtypes.h"
  39. #include "transformfeedback.h"
  40. #include "shaderapi.h"
  41. #include "shaderobj.h"
  42. #include "main/dispatch.h"
  43.  
  44. #include "program/prog_parameter.h"
  45.  
  46. struct using_program_tuple
  47. {
  48.    struct gl_shader_program *shProg;
  49.    bool found;
  50. };
  51.  
  52. static void
  53. active_xfb_object_references_program(GLuint key, void *data, void *user_data)
  54. {
  55.    struct using_program_tuple *callback_data = user_data;
  56.    struct gl_transform_feedback_object *obj = data;
  57.    if (obj->Active && obj->shader_program == callback_data->shProg)
  58.       callback_data->found = true;
  59. }
  60.  
  61. /**
  62.  * Return true if any active transform feedback object is using a program.
  63.  */
  64. bool
  65. _mesa_transform_feedback_is_using_program(struct gl_context *ctx,
  66.                                           struct gl_shader_program *shProg)
  67. {
  68.    struct using_program_tuple callback_data;
  69.    callback_data.shProg = shProg;
  70.    callback_data.found = false;
  71.  
  72.    _mesa_HashWalk(ctx->TransformFeedback.Objects,
  73.                   active_xfb_object_references_program, &callback_data);
  74.  
  75.    /* Also check DefaultObject, as it's not in the Objects hash table. */
  76.    active_xfb_object_references_program(0, ctx->TransformFeedback.DefaultObject,
  77.                                         &callback_data);
  78.  
  79.    return callback_data.found;
  80. }
  81.  
  82. /**
  83.  * Do reference counting of transform feedback buffers.
  84.  */
  85. static void
  86. reference_transform_feedback_object(struct gl_transform_feedback_object **ptr,
  87.                                     struct gl_transform_feedback_object *obj)
  88. {
  89.    if (*ptr == obj)
  90.       return;
  91.  
  92.    if (*ptr) {
  93.       /* Unreference the old object */
  94.       struct gl_transform_feedback_object *oldObj = *ptr;
  95.  
  96.       assert(oldObj->RefCount > 0);
  97.       oldObj->RefCount--;
  98.  
  99.       if (oldObj->RefCount == 0) {
  100.          GET_CURRENT_CONTEXT(ctx);
  101.          if (ctx)
  102.             ctx->Driver.DeleteTransformFeedback(ctx, oldObj);
  103.       }
  104.  
  105.       *ptr = NULL;
  106.    }
  107.    assert(!*ptr);
  108.  
  109.    if (obj) {
  110.       /* reference new object */
  111.       if (obj->RefCount == 0) {
  112.          _mesa_problem(NULL, "referencing deleted transform feedback object");
  113.          *ptr = NULL;
  114.       }
  115.       else {
  116.          obj->RefCount++;
  117.          obj->EverBound = GL_TRUE;
  118.          *ptr = obj;
  119.       }
  120.    }
  121. }
  122.  
  123.  
  124. /**
  125.  * Check that all the buffer objects currently bound for transform
  126.  * feedback actually exist.  Raise a GL_INVALID_OPERATION error if
  127.  * any buffers are missing.
  128.  * \return GL_TRUE for success, GL_FALSE if error
  129.  */
  130. GLboolean
  131. _mesa_validate_transform_feedback_buffers(struct gl_context *ctx)
  132. {
  133.    /* XXX to do */
  134.    return GL_TRUE;
  135. }
  136.  
  137.  
  138.  
  139. /**
  140.  * Per-context init for transform feedback.
  141.  */
  142. void
  143. _mesa_init_transform_feedback(struct gl_context *ctx)
  144. {
  145.    /* core mesa expects this, even a dummy one, to be available */
  146.    assert(ctx->Driver.NewTransformFeedback);
  147.  
  148.    ctx->TransformFeedback.DefaultObject =
  149.       ctx->Driver.NewTransformFeedback(ctx, 0);
  150.  
  151.    assert(ctx->TransformFeedback.DefaultObject->RefCount == 1);
  152.  
  153.    reference_transform_feedback_object(&ctx->TransformFeedback.CurrentObject,
  154.                                        ctx->TransformFeedback.DefaultObject);
  155.  
  156.    assert(ctx->TransformFeedback.DefaultObject->RefCount == 2);
  157.  
  158.    ctx->TransformFeedback.Objects = _mesa_NewHashTable();
  159.  
  160.    _mesa_reference_buffer_object(ctx,
  161.                                  &ctx->TransformFeedback.CurrentBuffer,
  162.                                  ctx->Shared->NullBufferObj);
  163. }
  164.  
  165.  
  166.  
  167. /**
  168.  * Callback for _mesa_HashDeleteAll().
  169.  */
  170. static void
  171. delete_cb(GLuint key, void *data, void *userData)
  172. {
  173.    struct gl_context *ctx = (struct gl_context *) userData;
  174.    struct gl_transform_feedback_object *obj =
  175.       (struct gl_transform_feedback_object *) data;
  176.  
  177.    ctx->Driver.DeleteTransformFeedback(ctx, obj);
  178. }
  179.  
  180.  
  181. /**
  182.  * Per-context free/clean-up for transform feedback.
  183.  */
  184. void
  185. _mesa_free_transform_feedback(struct gl_context *ctx)
  186. {
  187.    /* core mesa expects this, even a dummy one, to be available */
  188.    assert(ctx->Driver.NewTransformFeedback);
  189.  
  190.    _mesa_reference_buffer_object(ctx,
  191.                                  &ctx->TransformFeedback.CurrentBuffer,
  192.                                  NULL);
  193.  
  194.    /* Delete all feedback objects */
  195.    _mesa_HashDeleteAll(ctx->TransformFeedback.Objects, delete_cb, ctx);
  196.    _mesa_DeleteHashTable(ctx->TransformFeedback.Objects);
  197.  
  198.    /* Delete the default feedback object */
  199.    assert(ctx->Driver.DeleteTransformFeedback);
  200.    ctx->Driver.DeleteTransformFeedback(ctx,
  201.                                        ctx->TransformFeedback.DefaultObject);
  202.  
  203.    ctx->TransformFeedback.CurrentObject = NULL;
  204. }
  205.  
  206.  
  207. /** Initialize the fields of a gl_transform_feedback_object. */
  208. void
  209. _mesa_init_transform_feedback_object(struct gl_transform_feedback_object *obj,
  210.                                      GLuint name)
  211. {
  212.    if (!obj)
  213.       return;
  214.  
  215.    obj->Name = name;
  216.    obj->RefCount = 1;
  217.    obj->EverBound = GL_FALSE;
  218. }
  219.  
  220.  
  221. /** Default fallback for ctx->Driver.NewTransformFeedback() */
  222. static struct gl_transform_feedback_object *
  223. new_transform_feedback(struct gl_context *ctx, GLuint name)
  224. {
  225.    struct gl_transform_feedback_object *obj;
  226.    obj = CALLOC_STRUCT(gl_transform_feedback_object);
  227.    _mesa_init_transform_feedback_object(obj, name);
  228.    return obj;
  229. }
  230.  
  231. /** Default fallback for ctx->Driver.DeleteTransformFeedback() */
  232. static void
  233. delete_transform_feedback(struct gl_context *ctx,
  234.                           struct gl_transform_feedback_object *obj)
  235. {
  236.    GLuint i;
  237.  
  238.    for (i = 0; i < ARRAY_SIZE(obj->Buffers); i++) {
  239.       _mesa_reference_buffer_object(ctx, &obj->Buffers[i], NULL);
  240.    }
  241.  
  242.    free(obj->Label);
  243.    free(obj);
  244. }
  245.  
  246.  
  247. /** Default fallback for ctx->Driver.BeginTransformFeedback() */
  248. static void
  249. begin_transform_feedback(struct gl_context *ctx, GLenum mode,
  250.                          struct gl_transform_feedback_object *obj)
  251. {
  252.    /* nop */
  253. }
  254.  
  255. /** Default fallback for ctx->Driver.EndTransformFeedback() */
  256. static void
  257. end_transform_feedback(struct gl_context *ctx,
  258.                        struct gl_transform_feedback_object *obj)
  259. {
  260.    /* nop */
  261. }
  262.  
  263. /** Default fallback for ctx->Driver.PauseTransformFeedback() */
  264. static void
  265. pause_transform_feedback(struct gl_context *ctx,
  266.                          struct gl_transform_feedback_object *obj)
  267. {
  268.    /* nop */
  269. }
  270.  
  271. /** Default fallback for ctx->Driver.ResumeTransformFeedback() */
  272. static void
  273. resume_transform_feedback(struct gl_context *ctx,
  274.                           struct gl_transform_feedback_object *obj)
  275. {
  276.    /* nop */
  277. }
  278.  
  279.  
  280. /**
  281.  * Plug in default device driver functions for transform feedback.
  282.  * Most drivers will override some/all of these.
  283.  */
  284. void
  285. _mesa_init_transform_feedback_functions(struct dd_function_table *driver)
  286. {
  287.    driver->NewTransformFeedback = new_transform_feedback;
  288.    driver->DeleteTransformFeedback = delete_transform_feedback;
  289.    driver->BeginTransformFeedback = begin_transform_feedback;
  290.    driver->EndTransformFeedback = end_transform_feedback;
  291.    driver->PauseTransformFeedback = pause_transform_feedback;
  292.    driver->ResumeTransformFeedback = resume_transform_feedback;
  293. }
  294.  
  295.  
  296. /**
  297.  * Fill in the correct Size value for each buffer in \c obj.
  298.  *
  299.  * From the GL 4.3 spec, section 6.1.1 ("Binding Buffer Objects to Indexed
  300.  * Targets"):
  301.  *
  302.  *   BindBufferBase binds the entire buffer, even when the size of the buffer
  303.  *   is changed after the binding is established. It is equivalent to calling
  304.  *   BindBufferRange with offset zero, while size is determined by the size of
  305.  *   the bound buffer at the time the binding is used.
  306.  *
  307.  *   Regardless of the size specified with BindBufferRange, or indirectly with
  308.  *   BindBufferBase, the GL will never read or write beyond the end of a bound
  309.  *   buffer. In some cases this constraint may result in visibly different
  310.  *   behavior when a buffer overflow would otherwise result, such as described
  311.  *   for transform feedback operations in section 13.2.2.
  312.  */
  313. static void
  314. compute_transform_feedback_buffer_sizes(
  315.       struct gl_transform_feedback_object *obj)
  316. {
  317.    unsigned i = 0;
  318.    for (i = 0; i < MAX_FEEDBACK_BUFFERS; ++i) {
  319.       GLintptr offset = obj->Offset[i];
  320.       GLsizeiptr buffer_size
  321.          = obj->Buffers[i] == NULL ? 0 : obj->Buffers[i]->Size;
  322.       GLsizeiptr available_space
  323.          = buffer_size <= offset ? 0 : buffer_size - offset;
  324.       GLsizeiptr computed_size;
  325.       if (obj->RequestedSize[i] == 0) {
  326.          /* No size was specified at the time the buffer was bound, so allow
  327.           * writing to all available space in the buffer.
  328.           */
  329.          computed_size = available_space;
  330.       } else {
  331.          /* A size was specified at the time the buffer was bound, however
  332.           * it's possible that the buffer has shrunk since then.  So only
  333.           * allow writing to the minimum of the specified size and the space
  334.           * available.
  335.           */
  336.          computed_size = MIN2(available_space, obj->RequestedSize[i]);
  337.       }
  338.  
  339.       /* Legal sizes must be multiples of four, so round down if necessary. */
  340.       obj->Size[i] = computed_size & ~0x3;
  341.    }
  342. }
  343.  
  344.  
  345. /**
  346.  * Compute the maximum number of vertices that can be written to the currently
  347.  * enabled transform feedback buffers without overflowing any of them.
  348.  */
  349. unsigned
  350. _mesa_compute_max_transform_feedback_vertices(
  351.       const struct gl_transform_feedback_object *obj,
  352.       const struct gl_transform_feedback_info *info)
  353. {
  354.    unsigned max_index = 0xffffffff;
  355.    unsigned i;
  356.  
  357.    for (i = 0; i < info->NumBuffers; ++i) {
  358.       unsigned stride = info->BufferStride[i];
  359.       unsigned max_for_this_buffer;
  360.  
  361.       /* Skip any inactive buffers, which have a stride of 0. */
  362.       if (stride == 0)
  363.          continue;
  364.  
  365.       max_for_this_buffer = obj->Size[i] / (4 * stride);
  366.       max_index = MIN2(max_index, max_for_this_buffer);
  367.    }
  368.  
  369.    return max_index;
  370. }
  371.  
  372.  
  373. /**
  374.  ** Begin API functions
  375.  **/
  376.  
  377.  
  378. /**
  379.  * Figure out which stage of the pipeline is the source of transform feedback
  380.  * data given the current context state, and return its gl_shader_program.
  381.  *
  382.  * If no active program can generate transform feedback data (i.e. no vertex
  383.  * shader is active), returns NULL.
  384.  */
  385. static struct gl_shader_program *
  386. get_xfb_source(struct gl_context *ctx)
  387. {
  388.    int i;
  389.    for (i = MESA_SHADER_GEOMETRY; i >= MESA_SHADER_VERTEX; i--) {
  390.       if (ctx->_Shader->CurrentProgram[i] != NULL)
  391.          return ctx->_Shader->CurrentProgram[i];
  392.    }
  393.    return NULL;
  394. }
  395.  
  396.  
  397. void GLAPIENTRY
  398. _mesa_BeginTransformFeedback(GLenum mode)
  399. {
  400.    struct gl_transform_feedback_object *obj;
  401.    struct gl_transform_feedback_info *info = NULL;
  402.    struct gl_shader_program *source;
  403.    GLuint i;
  404.    unsigned vertices_per_prim;
  405.    GET_CURRENT_CONTEXT(ctx);
  406.  
  407.    obj = ctx->TransformFeedback.CurrentObject;
  408.  
  409.    /* Figure out what pipeline stage is the source of data for transform
  410.     * feedback.
  411.     */
  412.    source = get_xfb_source(ctx);
  413.    if (source == NULL) {
  414.       _mesa_error(ctx, GL_INVALID_OPERATION,
  415.                   "glBeginTransformFeedback(no program active)");
  416.       return;
  417.    }
  418.  
  419.    info = &source->LinkedTransformFeedback;
  420.  
  421.    if (info->NumOutputs == 0) {
  422.       _mesa_error(ctx, GL_INVALID_OPERATION,
  423.                   "glBeginTransformFeedback(no varyings to record)");
  424.       return;
  425.    }
  426.  
  427.    switch (mode) {
  428.    case GL_POINTS:
  429.       vertices_per_prim = 1;
  430.       break;
  431.    case GL_LINES:
  432.       vertices_per_prim = 2;
  433.       break;
  434.    case GL_TRIANGLES:
  435.       vertices_per_prim = 3;
  436.       break;
  437.    default:
  438.       _mesa_error(ctx, GL_INVALID_ENUM, "glBeginTransformFeedback(mode)");
  439.       return;
  440.    }
  441.  
  442.    if (obj->Active) {
  443.       _mesa_error(ctx, GL_INVALID_OPERATION,
  444.                   "glBeginTransformFeedback(already active)");
  445.       return;
  446.    }
  447.  
  448.    for (i = 0; i < info->NumBuffers; ++i) {
  449.       if (obj->BufferNames[i] == 0) {
  450.          _mesa_error(ctx, GL_INVALID_OPERATION,
  451.                      "glBeginTransformFeedback(binding point %d does not have "
  452.                      "a buffer object bound)", i);
  453.          return;
  454.       }
  455.    }
  456.  
  457.    FLUSH_VERTICES(ctx, 0);
  458.    ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback;
  459.  
  460.    obj->Active = GL_TRUE;
  461.    ctx->TransformFeedback.Mode = mode;
  462.  
  463.    compute_transform_feedback_buffer_sizes(obj);
  464.  
  465.    if (_mesa_is_gles3(ctx)) {
  466.       /* In GLES3, we are required to track the usage of the transform
  467.        * feedback buffer and report INVALID_OPERATION if a draw call tries to
  468.        * exceed it.  So compute the maximum number of vertices that we can
  469.        * write without overflowing any of the buffers currently being used for
  470.        * feedback.
  471.        */
  472.       unsigned max_vertices
  473.          = _mesa_compute_max_transform_feedback_vertices(obj, info);
  474.       obj->GlesRemainingPrims = max_vertices / vertices_per_prim;
  475.    }
  476.  
  477.    if (obj->shader_program != source) {
  478.       ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedbackProg;
  479.       obj->shader_program = source;
  480.    }
  481.  
  482.    assert(ctx->Driver.BeginTransformFeedback);
  483.    ctx->Driver.BeginTransformFeedback(ctx, mode, obj);
  484. }
  485.  
  486.  
  487. void GLAPIENTRY
  488. _mesa_EndTransformFeedback(void)
  489. {
  490.    struct gl_transform_feedback_object *obj;
  491.    GET_CURRENT_CONTEXT(ctx);
  492.  
  493.    obj = ctx->TransformFeedback.CurrentObject;
  494.  
  495.    if (!obj->Active) {
  496.       _mesa_error(ctx, GL_INVALID_OPERATION,
  497.                   "glEndTransformFeedback(not active)");
  498.       return;
  499.    }
  500.  
  501.    FLUSH_VERTICES(ctx, 0);
  502.    ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback;
  503.  
  504.    ctx->TransformFeedback.CurrentObject->Active = GL_FALSE;
  505.    ctx->TransformFeedback.CurrentObject->Paused = GL_FALSE;
  506.    ctx->TransformFeedback.CurrentObject->EndedAnytime = GL_TRUE;
  507.  
  508.    assert(ctx->Driver.EndTransformFeedback);
  509.    ctx->Driver.EndTransformFeedback(ctx, obj);
  510. }
  511.  
  512.  
  513. /**
  514.  * Helper used by BindBufferRange() and BindBufferBase().
  515.  */
  516. static void
  517. bind_buffer_range(struct gl_context *ctx,
  518.                   struct gl_transform_feedback_object *obj,
  519.                   GLuint index,
  520.                   struct gl_buffer_object *bufObj,
  521.                   GLintptr offset, GLsizeiptr size,
  522.                   bool dsa)
  523. {
  524.    /* Note: no need to FLUSH_VERTICES or flag NewTransformFeedback, because
  525.     * transform feedback buffers can't be changed while transform feedback is
  526.     * active.
  527.     */
  528.  
  529.    if (!dsa) {
  530.       /* The general binding point */
  531.       _mesa_reference_buffer_object(ctx,
  532.                                     &ctx->TransformFeedback.CurrentBuffer,
  533.                                     bufObj);
  534.    }
  535.  
  536.    /* The per-attribute binding point */
  537.    _mesa_set_transform_feedback_binding(ctx, obj, index, bufObj, offset, size);
  538. }
  539.  
  540.  
  541. /**
  542.  * Specify a buffer object to receive transform feedback results.  Plus,
  543.  * specify the starting offset to place the results, and max size.
  544.  * Called from the glBindBufferRange() and glTransformFeedbackBufferRange
  545.  * functions.
  546.  */
  547. void
  548. _mesa_bind_buffer_range_transform_feedback(struct gl_context *ctx,
  549.                                            struct gl_transform_feedback_object *obj,
  550.                                            GLuint index,
  551.                                            struct gl_buffer_object *bufObj,
  552.                                            GLintptr offset,
  553.                                            GLsizeiptr size,
  554.                                            bool dsa)
  555. {
  556.    const char *gl_methd_name;
  557.    if (dsa)
  558.       gl_methd_name = "glTransformFeedbackBufferRange";
  559.    else
  560.       gl_methd_name = "glBindBufferRange";
  561.  
  562.  
  563.    if (obj->Active) {
  564.       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(transform feedback active)",
  565.                   gl_methd_name);
  566.       return;
  567.    }
  568.  
  569.    if (index >= ctx->Const.MaxTransformFeedbackBuffers) {
  570.       /* OpenGL 4.5 core profile, 6.1, pdf page 82: "An INVALID_VALUE error is
  571.        * generated if index is greater than or equal to the number of binding
  572.        * points for transform feedback, as described in section 6.7.1."
  573.        */
  574.       _mesa_error(ctx, GL_INVALID_VALUE, "%s(index=%d out of bounds)",
  575.                   gl_methd_name, index);
  576.       return;
  577.    }
  578.  
  579.    if (size & 0x3) {
  580.       /* OpenGL 4.5 core profile, 6.7, pdf page 103: multiple of 4 */
  581.       _mesa_error(ctx, GL_INVALID_VALUE, "%s(size=%d must be a multiple of "
  582.                   "four)", gl_methd_name, (int) size);
  583.       return;
  584.    }  
  585.  
  586.    if (offset & 0x3) {
  587.       /* OpenGL 4.5 core profile, 6.7, pdf page 103: multiple of 4 */
  588.       _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset=%d must be a multiple "
  589.                   "of four)", gl_methd_name, (int) offset);
  590.       return;
  591.    }
  592.  
  593.    if (offset < 0) {
  594.       /* OpenGL 4.5 core profile, 6.1, pdf page 82: "An INVALID_VALUE error is
  595.        * generated by BindBufferRange if offset is negative."
  596.        *
  597.        * OpenGL 4.5 core profile, 13.2, pdf page 445: "An INVALID_VALUE error
  598.        * is generated by TransformFeedbackBufferRange if offset is negative."
  599.        */
  600.       _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset=%d must be >= 0)",
  601.                   gl_methd_name,
  602.                   (int) offset);
  603.       return;
  604.    }
  605.  
  606.    if (size <= 0 && (dsa || bufObj != ctx->Shared->NullBufferObj)) {
  607.       /* OpenGL 4.5 core profile, 6.1, pdf page 82: "An INVALID_VALUE error is
  608.        * generated by BindBufferRange if buffer is non-zero and size is less
  609.        * than or equal to zero."
  610.        *
  611.        * OpenGL 4.5 core profile, 13.2, pdf page 445: "An INVALID_VALUE error
  612.        * is generated by TransformFeedbackBufferRange if size is less than or
  613.        * equal to zero."
  614.        */
  615.       _mesa_error(ctx, GL_INVALID_VALUE, "%s(size=%d must be > 0)",
  616.                   gl_methd_name, (int) size);
  617.       return;
  618.    }
  619.  
  620.    bind_buffer_range(ctx, obj, index, bufObj, offset, size, dsa);
  621. }
  622.  
  623.  
  624. /**
  625.  * Specify a buffer object to receive transform feedback results.
  626.  * As above, but start at offset = 0.
  627.  * Called from the glBindBufferBase() and glTransformFeedbackBufferBase()
  628.  * functions.
  629.  */
  630. void
  631. _mesa_bind_buffer_base_transform_feedback(struct gl_context *ctx,
  632.                                           struct gl_transform_feedback_object *obj,
  633.                                           GLuint index,
  634.                                           struct gl_buffer_object *bufObj,
  635.                                           bool dsa)
  636. {
  637.    if (obj->Active) {
  638.       _mesa_error(ctx, GL_INVALID_OPERATION,
  639.                   "%s(transform feedback active)",
  640.                   dsa ? "glTransformFeedbackBufferBase" : "glBindBufferBase");
  641.       return;
  642.    }
  643.  
  644.    if (index >= ctx->Const.MaxTransformFeedbackBuffers) {
  645.       _mesa_error(ctx, GL_INVALID_VALUE, "%s(index=%d out of bounds)",
  646.                   dsa ? "glTransformFeedbackBufferBase" : "glBindBufferBase",
  647.                   index);
  648.       return;
  649.    }
  650.  
  651.    bind_buffer_range(ctx, obj, index, bufObj, 0, 0, dsa);
  652. }
  653.  
  654. /**
  655.  * Wrapper around lookup_transform_feedback_object that throws
  656.  * GL_INVALID_OPERATION if id is not in the hash table. After calling
  657.  * _mesa_error, it returns NULL.
  658.  */
  659. static struct gl_transform_feedback_object *
  660. lookup_transform_feedback_object_err(struct gl_context *ctx,
  661.                                      GLuint xfb, const char* func)
  662. {
  663.    struct gl_transform_feedback_object *obj;
  664.  
  665.    obj = _mesa_lookup_transform_feedback_object(ctx, xfb);
  666.    if (!obj) {
  667.       _mesa_error(ctx, GL_INVALID_OPERATION,
  668.                   "%s(xfb=%u: non-generated object name)", func, xfb);
  669.    }
  670.  
  671.    return obj;
  672. }
  673.  
  674. /**
  675.  * Wrapper around _mesa_lookup_bufferobj that throws GL_INVALID_VALUE if id
  676.  * is not in the hash table. Specialised version for the
  677.  * transform-feedback-related functions. After calling _mesa_error, it
  678.  * returns NULL.
  679.  */
  680. static struct gl_buffer_object *
  681. lookup_transform_feedback_bufferobj_err(struct gl_context *ctx,
  682.                                         GLuint buffer, const char* func)
  683. {
  684.    struct gl_buffer_object *bufObj;
  685.  
  686.    /* OpenGL 4.5 core profile, 13.2, pdf page 444: buffer must be zero or the
  687.     * name of an existing buffer object.
  688.     */
  689.    if (buffer == 0) {
  690.       bufObj = ctx->Shared->NullBufferObj;
  691.    } else {
  692.       bufObj = _mesa_lookup_bufferobj(ctx, buffer);
  693.       if (!bufObj) {
  694.          _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid buffer=%u)", func,
  695.                      buffer);
  696.       }
  697.    }
  698.  
  699.    return bufObj;
  700. }
  701.  
  702. void GLAPIENTRY
  703. _mesa_TransformFeedbackBufferBase(GLuint xfb, GLuint index, GLuint buffer)
  704. {
  705.    GET_CURRENT_CONTEXT(ctx);
  706.    struct gl_transform_feedback_object *obj;
  707.    struct gl_buffer_object *bufObj;
  708.  
  709.    if (!ctx->Extensions.ARB_direct_state_access) {
  710.       _mesa_error(ctx, GL_INVALID_OPERATION,
  711.                   "glTransformFeedbackBufferBase(GL_ARB_direct_state_access "
  712.                   "is not supported)");
  713.       return;
  714.    }
  715.  
  716.    obj = lookup_transform_feedback_object_err(ctx, xfb,
  717.                                               "glTransformFeedbackBufferBase");
  718.    if(!obj) {
  719.       return;
  720.    }
  721.  
  722.    bufObj = lookup_transform_feedback_bufferobj_err(ctx, buffer,
  723.                                               "glTransformFeedbackBufferBase");
  724.    if(!bufObj) {
  725.       return;
  726.    }
  727.  
  728.    _mesa_bind_buffer_base_transform_feedback(ctx, obj, index, bufObj, true);
  729. }
  730.  
  731. void GLAPIENTRY
  732. _mesa_TransformFeedbackBufferRange(GLuint xfb, GLuint index, GLuint buffer,
  733.                                    GLintptr offset, GLsizeiptr size)
  734. {
  735.    GET_CURRENT_CONTEXT(ctx);
  736.    struct gl_transform_feedback_object *obj;
  737.    struct gl_buffer_object *bufObj;
  738.  
  739.    if (!ctx->Extensions.ARB_direct_state_access) {
  740.       _mesa_error(ctx, GL_INVALID_OPERATION,
  741.                   "glTransformFeedbackBufferRange(GL_ARB_direct_state_access "
  742.                   "is not supported)");
  743.       return;
  744.    }
  745.  
  746.    obj = lookup_transform_feedback_object_err(ctx, xfb,
  747.                                               "glTransformFeedbackBufferRange");
  748.    if(!obj) {
  749.       return;
  750.    }
  751.  
  752.    bufObj = lookup_transform_feedback_bufferobj_err(ctx, buffer,
  753.                                               "glTransformFeedbackBufferRange");
  754.    if(!bufObj) {
  755.       return;
  756.    }
  757.  
  758.    _mesa_bind_buffer_range_transform_feedback(ctx, obj, index, bufObj, offset,
  759.                                               size, true);
  760. }
  761.  
  762. /**
  763.  * Specify a buffer object to receive transform feedback results, plus the
  764.  * offset in the buffer to start placing results.
  765.  * This function is part of GL_EXT_transform_feedback, but not GL3.
  766.  */
  767. void GLAPIENTRY
  768. _mesa_BindBufferOffsetEXT(GLenum target, GLuint index, GLuint buffer,
  769.                           GLintptr offset)
  770. {
  771.    struct gl_transform_feedback_object *obj;
  772.    struct gl_buffer_object *bufObj;
  773.    GET_CURRENT_CONTEXT(ctx);
  774.  
  775.    if (target != GL_TRANSFORM_FEEDBACK_BUFFER) {
  776.       _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferOffsetEXT(target)");
  777.       return;
  778.    }
  779.  
  780.    obj = ctx->TransformFeedback.CurrentObject;
  781.  
  782.    if (obj->Active) {
  783.       _mesa_error(ctx, GL_INVALID_OPERATION,
  784.                   "glBindBufferOffsetEXT(transform feedback active)");
  785.       return;
  786.    }
  787.  
  788.    if (index >= ctx->Const.MaxTransformFeedbackBuffers) {
  789.       _mesa_error(ctx, GL_INVALID_VALUE,
  790.                   "glBindBufferOffsetEXT(index=%d)", index);
  791.       return;
  792.    }
  793.  
  794.    if (offset & 0x3) {
  795.       /* must be multiple of four */
  796.       _mesa_error(ctx, GL_INVALID_VALUE,
  797.                   "glBindBufferOffsetEXT(offset=%d)", (int) offset);
  798.       return;
  799.    }
  800.  
  801.    if (buffer == 0) {
  802.       bufObj = ctx->Shared->NullBufferObj;
  803.    } else {
  804.       bufObj = _mesa_lookup_bufferobj(ctx, buffer);
  805.    }
  806.  
  807.    if (!bufObj) {
  808.       _mesa_error(ctx, GL_INVALID_OPERATION,
  809.                   "glBindBufferOffsetEXT(invalid buffer=%u)", buffer);
  810.       return;
  811.    }
  812.  
  813.    bind_buffer_range(ctx, obj, index, bufObj, offset, 0, false);
  814. }
  815.  
  816.  
  817. /**
  818.  * This function specifies the transform feedback outputs to be written
  819.  * to the feedback buffer(s), and in what order.
  820.  */
  821. void GLAPIENTRY
  822. _mesa_TransformFeedbackVaryings(GLuint program, GLsizei count,
  823.                                 const GLchar * const *varyings,
  824.                                 GLenum bufferMode)
  825. {
  826.    struct gl_shader_program *shProg;
  827.    GLint i;
  828.    GET_CURRENT_CONTEXT(ctx);
  829.  
  830.    /* From the ARB_transform_feedback2 specification:
  831.     * "The error INVALID_OPERATION is generated by TransformFeedbackVaryings
  832.     *  if the current transform feedback object is active, even if paused."
  833.     */
  834.    if (ctx->TransformFeedback.CurrentObject->Active) {
  835.       _mesa_error(ctx, GL_INVALID_OPERATION,
  836.                "glTransformFeedbackVaryings(current object is active)");
  837.       return;
  838.    }
  839.  
  840.    switch (bufferMode) {
  841.    case GL_INTERLEAVED_ATTRIBS:
  842.       break;
  843.    case GL_SEPARATE_ATTRIBS:
  844.       break;
  845.    default:
  846.       _mesa_error(ctx, GL_INVALID_ENUM,
  847.                   "glTransformFeedbackVaryings(bufferMode)");
  848.       return;
  849.    }
  850.  
  851.    if (count < 0 ||
  852.        (bufferMode == GL_SEPARATE_ATTRIBS &&
  853.         (GLuint) count > ctx->Const.MaxTransformFeedbackBuffers)) {
  854.       _mesa_error(ctx, GL_INVALID_VALUE,
  855.                   "glTransformFeedbackVaryings(count=%d)", count);
  856.       return;
  857.    }
  858.  
  859.    shProg = _mesa_lookup_shader_program(ctx, program);
  860.    if (!shProg) {
  861.       _mesa_error(ctx, GL_INVALID_VALUE,
  862.                   "glTransformFeedbackVaryings(program=%u)", program);
  863.       return;
  864.    }
  865.  
  866.    if (ctx->Extensions.ARB_transform_feedback3) {
  867.       if (bufferMode == GL_INTERLEAVED_ATTRIBS) {
  868.          unsigned buffers = 1;
  869.  
  870.          for (i = 0; i < count; i++) {
  871.             if (strcmp(varyings[i], "gl_NextBuffer") == 0)
  872.                buffers++;
  873.          }
  874.  
  875.          if (buffers > ctx->Const.MaxTransformFeedbackBuffers) {
  876.             _mesa_error(ctx, GL_INVALID_OPERATION,
  877.                         "glTransformFeedbackVaryings(too many gl_NextBuffer "
  878.                         "occurences)");
  879.             return;
  880.          }
  881.       } else {
  882.          for (i = 0; i < count; i++) {
  883.             if (strcmp(varyings[i], "gl_NextBuffer") == 0 ||
  884.                 strcmp(varyings[i], "gl_SkipComponents1") == 0 ||
  885.                 strcmp(varyings[i], "gl_SkipComponents2") == 0 ||
  886.                 strcmp(varyings[i], "gl_SkipComponents3") == 0 ||
  887.                 strcmp(varyings[i], "gl_SkipComponents4") == 0) {
  888.                _mesa_error(ctx, GL_INVALID_OPERATION,
  889.                            "glTransformFeedbackVaryings(SEPARATE_ATTRIBS,"
  890.                            "varying=%s)",
  891.                            varyings[i]);
  892.                return;
  893.             }
  894.          }
  895.       }
  896.    }
  897.  
  898.    /* free existing varyings, if any */
  899.    for (i = 0; i < (GLint) shProg->TransformFeedback.NumVarying; i++) {
  900.       free(shProg->TransformFeedback.VaryingNames[i]);
  901.    }
  902.    free(shProg->TransformFeedback.VaryingNames);
  903.  
  904.    /* allocate new memory for varying names */
  905.    shProg->TransformFeedback.VaryingNames =
  906.       malloc(count * sizeof(GLchar *));
  907.  
  908.    if (!shProg->TransformFeedback.VaryingNames) {
  909.       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTransformFeedbackVaryings()");
  910.       return;
  911.    }
  912.  
  913.    /* Save the new names and the count */
  914.    for (i = 0; i < count; i++) {
  915.       shProg->TransformFeedback.VaryingNames[i] = strdup(varyings[i]);
  916.    }
  917.    shProg->TransformFeedback.NumVarying = count;
  918.  
  919.    shProg->TransformFeedback.BufferMode = bufferMode;
  920.  
  921.    /* No need to invoke FLUSH_VERTICES or flag NewTransformFeedback since
  922.     * the varyings won't be used until shader link time.
  923.     */
  924. }
  925.  
  926.  
  927. /**
  928.  * Get info about the transform feedback outputs which are to be written
  929.  * to the feedback buffer(s).
  930.  */
  931. void GLAPIENTRY
  932. _mesa_GetTransformFeedbackVarying(GLuint program, GLuint index,
  933.                                   GLsizei bufSize, GLsizei *length,
  934.                                   GLsizei *size, GLenum *type, GLchar *name)
  935. {
  936.    const struct gl_shader_program *shProg;
  937.    struct gl_program_resource *res;
  938.    GET_CURRENT_CONTEXT(ctx);
  939.  
  940.    shProg = _mesa_lookup_shader_program(ctx, program);
  941.    if (!shProg) {
  942.       _mesa_error(ctx, GL_INVALID_VALUE,
  943.                   "glGetTransformFeedbackVarying(program=%u)", program);
  944.       return;
  945.    }
  946.  
  947.    res = _mesa_program_resource_find_index((struct gl_shader_program *) shProg,
  948.                                            GL_TRANSFORM_FEEDBACK_VARYING,
  949.                                            index);
  950.    if (!res) {
  951.       _mesa_error(ctx, GL_INVALID_VALUE,
  952.                   "glGetTransformFeedbackVarying(index=%u)", index);
  953.       return;
  954.    }
  955.  
  956.    /* return the varying's name and length */
  957.    _mesa_copy_string(name, bufSize, length, _mesa_program_resource_name(res));
  958.  
  959.    /* return the datatype and value's size (in datatype units) */
  960.    if (type)
  961.       _mesa_program_resource_prop((struct gl_shader_program *) shProg,
  962.                                   res, index, GL_TYPE, (GLint*) type,
  963.                                   "glGetTransformFeedbackVarying");
  964.    if (size)
  965.       _mesa_program_resource_prop((struct gl_shader_program *) shProg,
  966.                                   res, index, GL_ARRAY_SIZE, (GLint*) size,
  967.                                   "glGetTransformFeedbackVarying");
  968. }
  969.  
  970.  
  971.  
  972. struct gl_transform_feedback_object *
  973. _mesa_lookup_transform_feedback_object(struct gl_context *ctx, GLuint name)
  974. {
  975.    /* OpenGL 4.5 core profile, 13.2 pdf page 444: "xfb must be zero, indicating
  976.     * the default transform feedback object, or the name of an existing
  977.     * transform feedback object."
  978.     */
  979.    if (name == 0) {
  980.       return ctx->TransformFeedback.DefaultObject;
  981.    }
  982.    else
  983.       return (struct gl_transform_feedback_object *)
  984.          _mesa_HashLookup(ctx->TransformFeedback.Objects, name);
  985. }
  986.  
  987. static void
  988. create_transform_feedbacks(struct gl_context *ctx, GLsizei n, GLuint *ids,
  989.                            bool dsa)
  990. {
  991.    GLuint first;
  992.    const char* func;
  993.  
  994.    if (dsa)
  995.       func = "glCreateTransformFeedbacks";
  996.    else
  997.       func = "glGenTransformFeedbacks";
  998.  
  999.    if (n < 0) {
  1000.       _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func);
  1001.       return;
  1002.    }
  1003.  
  1004.    if (!ids)
  1005.       return;
  1006.  
  1007.    /* we don't need contiguous IDs, but this might be faster */
  1008.    first = _mesa_HashFindFreeKeyBlock(ctx->TransformFeedback.Objects, n);
  1009.    if (first) {
  1010.       GLsizei i;
  1011.       for (i = 0; i < n; i++) {
  1012.          struct gl_transform_feedback_object *obj
  1013.             = ctx->Driver.NewTransformFeedback(ctx, first + i);
  1014.          if (!obj) {
  1015.             _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
  1016.             return;
  1017.          }
  1018.          ids[i] = first + i;
  1019.          _mesa_HashInsert(ctx->TransformFeedback.Objects, first + i, obj);
  1020.          if (dsa) {
  1021.             /* this is normally done at bind time in the non-dsa case */
  1022.             obj->EverBound = GL_TRUE;
  1023.          }
  1024.       }
  1025.    }
  1026.    else {
  1027.       _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
  1028.    }
  1029. }
  1030.  
  1031. /**
  1032.  * Create new transform feedback objects.   Transform feedback objects
  1033.  * encapsulate the state related to transform feedback to allow quickly
  1034.  * switching state (and drawing the results, below).
  1035.  * Part of GL_ARB_transform_feedback2.
  1036.  */
  1037. void GLAPIENTRY
  1038. _mesa_GenTransformFeedbacks(GLsizei n, GLuint *names)
  1039. {
  1040.    GET_CURRENT_CONTEXT(ctx);
  1041.  
  1042.    /* GenTransformFeedbacks should just reserve the object names that a
  1043.     * subsequent call to BindTransformFeedback should actively create. For
  1044.     * the sake of simplicity, we reserve the names and create the objects
  1045.     * straight away.
  1046.     */
  1047.  
  1048.    create_transform_feedbacks(ctx, n, names, false);
  1049. }
  1050.  
  1051. /**
  1052.  * Create new transform feedback objects.   Transform feedback objects
  1053.  * encapsulate the state related to transform feedback to allow quickly
  1054.  * switching state (and drawing the results, below).
  1055.  * Part of GL_ARB_direct_state_access.
  1056.  */
  1057. void GLAPIENTRY
  1058. _mesa_CreateTransformFeedbacks(GLsizei n, GLuint *names)
  1059. {
  1060.    GET_CURRENT_CONTEXT(ctx);
  1061.  
  1062.    if (!ctx->Extensions.ARB_direct_state_access) {
  1063.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1064.                   "glCreateTransformFeedbacks(GL_ARB_direct_state_access "
  1065.                   "is not supported)");
  1066.       return;
  1067.    }
  1068.  
  1069.    create_transform_feedbacks(ctx, n, names, true);
  1070. }
  1071.  
  1072.  
  1073. /**
  1074.  * Is the given ID a transform feedback object?
  1075.  * Part of GL_ARB_transform_feedback2.
  1076.  */
  1077. GLboolean GLAPIENTRY
  1078. _mesa_IsTransformFeedback(GLuint name)
  1079. {
  1080.    struct gl_transform_feedback_object *obj;
  1081.    GET_CURRENT_CONTEXT(ctx);
  1082.  
  1083.    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
  1084.  
  1085.    if (name == 0)
  1086.       return GL_FALSE;
  1087.  
  1088.    obj = _mesa_lookup_transform_feedback_object(ctx, name);
  1089.    if (obj == NULL)
  1090.       return GL_FALSE;
  1091.  
  1092.    return obj->EverBound;
  1093. }
  1094.  
  1095.  
  1096. /**
  1097.  * Bind the given transform feedback object.
  1098.  * Part of GL_ARB_transform_feedback2.
  1099.  */
  1100. void GLAPIENTRY
  1101. _mesa_BindTransformFeedback(GLenum target, GLuint name)
  1102. {
  1103.    struct gl_transform_feedback_object *obj;
  1104.    GET_CURRENT_CONTEXT(ctx);
  1105.  
  1106.    if (target != GL_TRANSFORM_FEEDBACK) {
  1107.       _mesa_error(ctx, GL_INVALID_ENUM, "glBindTransformFeedback(target)");
  1108.       return;
  1109.    }
  1110.  
  1111.    if (_mesa_is_xfb_active_and_unpaused(ctx)) {
  1112.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1113.               "glBindTransformFeedback(transform is active, or not paused)");
  1114.       return;
  1115.    }
  1116.  
  1117.    obj = _mesa_lookup_transform_feedback_object(ctx, name);
  1118.    if (!obj) {
  1119.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1120.                   "glBindTransformFeedback(name=%u)", name);
  1121.       return;
  1122.    }
  1123.  
  1124.    reference_transform_feedback_object(&ctx->TransformFeedback.CurrentObject,
  1125.                                        obj);
  1126. }
  1127.  
  1128.  
  1129. /**
  1130.  * Delete the given transform feedback objects.
  1131.  * Part of GL_ARB_transform_feedback2.
  1132.  */
  1133. void GLAPIENTRY
  1134. _mesa_DeleteTransformFeedbacks(GLsizei n, const GLuint *names)
  1135. {
  1136.    GLint i;
  1137.    GET_CURRENT_CONTEXT(ctx);
  1138.  
  1139.    if (n < 0) {
  1140.       _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteTransformFeedbacks(n < 0)");
  1141.       return;
  1142.    }
  1143.  
  1144.    if (!names)
  1145.       return;
  1146.  
  1147.    for (i = 0; i < n; i++) {
  1148.       if (names[i] > 0) {
  1149.          struct gl_transform_feedback_object *obj
  1150.             = _mesa_lookup_transform_feedback_object(ctx, names[i]);
  1151.          if (obj) {
  1152.             if (obj->Active) {
  1153.                _mesa_error(ctx, GL_INVALID_OPERATION,
  1154.                            "glDeleteTransformFeedbacks(object %u is active)",
  1155.                            names[i]);
  1156.                return;
  1157.             }
  1158.             _mesa_HashRemove(ctx->TransformFeedback.Objects, names[i]);
  1159.             /* unref, but object may not be deleted until later */
  1160.             reference_transform_feedback_object(&obj, NULL);
  1161.          }
  1162.       }
  1163.    }
  1164. }
  1165.  
  1166.  
  1167. /**
  1168.  * Pause transform feedback.
  1169.  * Part of GL_ARB_transform_feedback2.
  1170.  */
  1171. void GLAPIENTRY
  1172. _mesa_PauseTransformFeedback(void)
  1173. {
  1174.    struct gl_transform_feedback_object *obj;
  1175.    GET_CURRENT_CONTEXT(ctx);
  1176.  
  1177.    obj = ctx->TransformFeedback.CurrentObject;
  1178.  
  1179.    if (!_mesa_is_xfb_active_and_unpaused(ctx)) {
  1180.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1181.            "glPauseTransformFeedback(feedback not active or already paused)");
  1182.       return;
  1183.    }
  1184.  
  1185.    FLUSH_VERTICES(ctx, 0);
  1186.    ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback;
  1187.  
  1188.    obj->Paused = GL_TRUE;
  1189.  
  1190.    assert(ctx->Driver.PauseTransformFeedback);
  1191.    ctx->Driver.PauseTransformFeedback(ctx, obj);
  1192. }
  1193.  
  1194.  
  1195. /**
  1196.  * Resume transform feedback.
  1197.  * Part of GL_ARB_transform_feedback2.
  1198.  */
  1199. void GLAPIENTRY
  1200. _mesa_ResumeTransformFeedback(void)
  1201. {
  1202.    struct gl_transform_feedback_object *obj;
  1203.    GET_CURRENT_CONTEXT(ctx);
  1204.  
  1205.    obj = ctx->TransformFeedback.CurrentObject;
  1206.  
  1207.    if (!obj->Active || !obj->Paused) {
  1208.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1209.                "glResumeTransformFeedback(feedback not active or not paused)");
  1210.       return;
  1211.    }
  1212.  
  1213.    /* From the ARB_transform_feedback2 specification:
  1214.     * "The error INVALID_OPERATION is generated by ResumeTransformFeedback if
  1215.     *  the program object being used by the current transform feedback object
  1216.     *  is not active."
  1217.     */
  1218.    if (obj->shader_program != get_xfb_source(ctx)) {
  1219.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1220.                   "glResumeTransformFeedback(wrong program bound)");
  1221.       return;
  1222.    }
  1223.  
  1224.    FLUSH_VERTICES(ctx, 0);
  1225.    ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback;
  1226.  
  1227.    obj->Paused = GL_FALSE;
  1228.  
  1229.    assert(ctx->Driver.ResumeTransformFeedback);
  1230.    ctx->Driver.ResumeTransformFeedback(ctx, obj);
  1231. }
  1232.  
  1233. extern void GLAPIENTRY
  1234. _mesa_GetTransformFeedbackiv(GLuint xfb, GLenum pname, GLint *param)
  1235. {
  1236.     struct gl_transform_feedback_object *obj;
  1237.     GET_CURRENT_CONTEXT(ctx);
  1238.  
  1239.     if (!ctx->Extensions.ARB_direct_state_access) {
  1240.        _mesa_error(ctx, GL_INVALID_OPERATION,
  1241.                    "glGetTransformFeedbackiv(GL_ARB_direct_state_access "
  1242.                    "is not supported)");
  1243.        return;
  1244.     }
  1245.  
  1246.     obj = lookup_transform_feedback_object_err(ctx, xfb,
  1247.                                                "glGetTransformFeedbackiv");
  1248.     if(!obj) {
  1249.        return;
  1250.     }
  1251.  
  1252.     switch(pname) {
  1253.     case GL_TRANSFORM_FEEDBACK_PAUSED:
  1254.        *param = obj->Paused;
  1255.        break;
  1256.     case GL_TRANSFORM_FEEDBACK_ACTIVE:
  1257.        *param = obj->Active;
  1258.        break;
  1259.     default:
  1260.        _mesa_error(ctx, GL_INVALID_ENUM,
  1261.                    "glGetTransformFeedbackiv(pname=%i)", pname);
  1262.     }
  1263. }
  1264.  
  1265. extern void GLAPIENTRY
  1266. _mesa_GetTransformFeedbacki_v(GLuint xfb, GLenum pname, GLuint index,
  1267.                               GLint *param)
  1268. {
  1269.    struct gl_transform_feedback_object *obj;
  1270.    GET_CURRENT_CONTEXT(ctx);
  1271.  
  1272.    if (!ctx->Extensions.ARB_direct_state_access) {
  1273.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1274.                   "glGetTransformFeedbacki_v(GL_ARB_direct_state_access "
  1275.                   "is not supported)");
  1276.       return;
  1277.    }
  1278.  
  1279.    obj = lookup_transform_feedback_object_err(ctx, xfb,
  1280.                                               "glGetTransformFeedbacki_v");
  1281.    if(!obj) {
  1282.       return;
  1283.    }
  1284.  
  1285.    if (index >= ctx->Const.MaxTransformFeedbackBuffers) {
  1286.       _mesa_error(ctx, GL_INVALID_VALUE,
  1287.                   "glGetTransformFeedbacki_v(index=%i)", index);
  1288.       return;
  1289.    }
  1290.  
  1291.    switch(pname) {
  1292.    case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
  1293.       *param = obj->BufferNames[index];
  1294.       break;
  1295.    default:
  1296.       _mesa_error(ctx, GL_INVALID_ENUM,
  1297.                   "glGetTransformFeedbacki_v(pname=%i)", pname);
  1298.    }
  1299. }
  1300.  
  1301. extern void GLAPIENTRY
  1302. _mesa_GetTransformFeedbacki64_v(GLuint xfb, GLenum pname, GLuint index,
  1303.                                 GLint64 *param)
  1304. {
  1305.    struct gl_transform_feedback_object *obj;
  1306.    GET_CURRENT_CONTEXT(ctx);
  1307.  
  1308.    if (!ctx->Extensions.ARB_direct_state_access) {
  1309.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1310.                   "glGetTransformFeedbacki64_v(GL_ARB_direct_state_access "
  1311.                   "is not supported)");
  1312.       return;
  1313.    }
  1314.  
  1315.    obj = lookup_transform_feedback_object_err(ctx, xfb,
  1316.                                               "glGetTransformFeedbacki64_v");
  1317.    if(!obj) {
  1318.       return;
  1319.    }
  1320.  
  1321.    if (index >= ctx->Const.MaxTransformFeedbackBuffers) {
  1322.       _mesa_error(ctx, GL_INVALID_VALUE,
  1323.                   "glGetTransformFeedbacki64_v(index=%i)", index);
  1324.       return;
  1325.    }
  1326.  
  1327.    switch(pname) {
  1328.    case GL_TRANSFORM_FEEDBACK_BUFFER_START:
  1329.       *param = obj->Offset[index];
  1330.       break;
  1331.    case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
  1332.       *param = obj->RequestedSize[index];
  1333.       break;
  1334.    default:
  1335.       _mesa_error(ctx, GL_INVALID_ENUM,
  1336.                   "glGetTransformFeedbacki64_v(pname=%i)", pname);
  1337.    }
  1338. }
  1339.