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