Subversion Repositories Kolibri OS

Rev

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

  1. /*
  2.  * Mesa 3-D graphics library
  3.  *
  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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  20.  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21.  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22.  */
  23.  
  24.  
  25. /*
  26.  * Vertex transform feedback support.
  27.  *
  28.  * Authors:
  29.  *   Brian Paul
  30.  */
  31.  
  32.  
  33. #include "buffers.h"
  34. #include "bufferobj.h"
  35. #include "context.h"
  36. #include "hash.h"
  37. #include "transformfeedback.h"
  38. #include "shaderapi.h"
  39. #include "shaderobj.h"
  40. #include "main/dispatch.h"
  41.  
  42. #include "program/prog_parameter.h"
  43. //#include "program/shader_api.h"
  44.  
  45.  
  46. #if FEATURE_EXT_transform_feedback
  47.  
  48.  
  49. /**
  50.  * Do reference counting of transform feedback buffers.
  51.  */
  52. static void
  53. reference_transform_feedback_object(struct gl_transform_feedback_object **ptr,
  54.                                     struct gl_transform_feedback_object *obj)
  55. {
  56.    if (*ptr == obj)
  57.       return;
  58.  
  59.    if (*ptr) {
  60.       /* Unreference the old object */
  61.       struct gl_transform_feedback_object *oldObj = *ptr;
  62.  
  63.       ASSERT(oldObj->RefCount > 0);
  64.       oldObj->RefCount--;
  65.  
  66.       if (oldObj->RefCount == 0) {
  67.          GET_CURRENT_CONTEXT(ctx);
  68.          if (ctx)
  69.             ctx->Driver.DeleteTransformFeedback(ctx, oldObj);
  70.       }
  71.  
  72.       *ptr = NULL;
  73.    }
  74.    ASSERT(!*ptr);
  75.  
  76.    if (obj) {
  77.       /* reference new object */
  78.       if (obj->RefCount == 0) {
  79.          _mesa_problem(NULL, "referencing deleted transform feedback object");
  80.          *ptr = NULL;
  81.       }
  82.       else {
  83.          obj->RefCount++;
  84.          *ptr = obj;
  85.       }
  86.    }
  87. }
  88.  
  89.  
  90. /**
  91.  * Check if the given primitive mode (as in glBegin(mode)) is compatible
  92.  * with the current transform feedback mode (if it's enabled).
  93.  * This is to be called from glBegin(), glDrawArrays(), glDrawElements(), etc.
  94.  *
  95.  * \return GL_TRUE if the mode is OK, GL_FALSE otherwise.
  96.  */
  97. GLboolean
  98. _mesa_validate_primitive_mode(struct gl_context *ctx, GLenum mode)
  99. {
  100.    if (ctx->TransformFeedback.CurrentObject->Active) {
  101.       switch (mode) {
  102.       case GL_POINTS:
  103.          return ctx->TransformFeedback.Mode == GL_POINTS;
  104.       case GL_LINES:
  105.       case GL_LINE_STRIP:
  106.       case GL_LINE_LOOP:
  107.          return ctx->TransformFeedback.Mode == GL_LINES;
  108.       default:
  109.          return ctx->TransformFeedback.Mode == GL_TRIANGLES;
  110.       }
  111.    }
  112.    return GL_TRUE;
  113. }
  114.  
  115.  
  116. /**
  117.  * Check that all the buffer objects currently bound for transform
  118.  * feedback actually exist.  Raise a GL_INVALID_OPERATION error if
  119.  * any buffers are missing.
  120.  * \return GL_TRUE for success, GL_FALSE if error
  121.  */
  122. GLboolean
  123. _mesa_validate_transform_feedback_buffers(struct gl_context *ctx)
  124. {
  125.    /* XXX to do */
  126.    return GL_TRUE;
  127. }
  128.  
  129.  
  130.  
  131. /**
  132.  * Per-context init for transform feedback.
  133.  */
  134. void
  135. _mesa_init_transform_feedback(struct gl_context *ctx)
  136. {
  137.    /* core mesa expects this, even a dummy one, to be available */
  138.    ASSERT(ctx->Driver.NewTransformFeedback);
  139.  
  140.    ctx->TransformFeedback.DefaultObject =
  141.       ctx->Driver.NewTransformFeedback(ctx, 0);
  142.  
  143.    assert(ctx->TransformFeedback.DefaultObject->RefCount == 1);
  144.  
  145.    reference_transform_feedback_object(&ctx->TransformFeedback.CurrentObject,
  146.                                        ctx->TransformFeedback.DefaultObject);
  147.  
  148.    assert(ctx->TransformFeedback.DefaultObject->RefCount == 2);
  149.  
  150.    ctx->TransformFeedback.Objects = _mesa_NewHashTable();
  151.  
  152.    _mesa_reference_buffer_object(ctx,
  153.                                  &ctx->TransformFeedback.CurrentBuffer,
  154.                                  ctx->Shared->NullBufferObj);
  155. }
  156.  
  157.  
  158.  
  159. /**
  160.  * Callback for _mesa_HashDeleteAll().
  161.  */
  162. static void
  163. delete_cb(GLuint key, void *data, void *userData)
  164. {
  165.    struct gl_context *ctx = (struct gl_context *) userData;
  166.    struct gl_transform_feedback_object *obj =
  167.       (struct gl_transform_feedback_object *) data;
  168.  
  169.    ctx->Driver.DeleteTransformFeedback(ctx, obj);
  170. }
  171.  
  172.  
  173. /**
  174.  * Per-context free/clean-up for transform feedback.
  175.  */
  176. void
  177. _mesa_free_transform_feedback(struct gl_context *ctx)
  178. {
  179.    /* core mesa expects this, even a dummy one, to be available */
  180.    ASSERT(ctx->Driver.NewTransformFeedback);
  181.  
  182.    _mesa_reference_buffer_object(ctx,
  183.                                  &ctx->TransformFeedback.CurrentBuffer,
  184.                                  NULL);
  185.  
  186.    /* Delete all feedback objects */
  187.    _mesa_HashDeleteAll(ctx->TransformFeedback.Objects, delete_cb, ctx);
  188.    _mesa_DeleteHashTable(ctx->TransformFeedback.Objects);
  189.  
  190.    /* Delete the default feedback object */
  191.    assert(ctx->Driver.DeleteTransformFeedback);
  192.    ctx->Driver.DeleteTransformFeedback(ctx,
  193.                                        ctx->TransformFeedback.DefaultObject);
  194.  
  195.    ctx->TransformFeedback.CurrentObject = NULL;
  196. }
  197.  
  198.  
  199. #else /* FEATURE_EXT_transform_feedback */
  200.  
  201. /* forward declarations */
  202. static struct gl_transform_feedback_object *
  203. new_transform_feedback(struct gl_context *ctx, GLuint name);
  204.  
  205. static void
  206. delete_transform_feedback(struct gl_context *ctx,
  207.                           struct gl_transform_feedback_object *obj);
  208.  
  209. /* dummy per-context init/clean-up for transform feedback */
  210. void
  211. _mesa_init_transform_feedback(struct gl_context *ctx)
  212. {
  213.    ctx->TransformFeedback.DefaultObject = new_transform_feedback(ctx, 0);
  214.    ctx->TransformFeedback.CurrentObject = ctx->TransformFeedback.DefaultObject;
  215.    _mesa_reference_buffer_object(ctx,
  216.                                  &ctx->TransformFeedback.CurrentBuffer,
  217.                                  ctx->Shared->NullBufferObj);
  218. }
  219.  
  220. void
  221. _mesa_free_transform_feedback(struct gl_context *ctx)
  222. {
  223.    _mesa_reference_buffer_object(ctx,
  224.                                  &ctx->TransformFeedback.CurrentBuffer,
  225.                                  NULL);
  226.    ctx->TransformFeedback.CurrentObject = NULL;
  227.    delete_transform_feedback(ctx, ctx->TransformFeedback.DefaultObject);
  228. }
  229.  
  230. #endif /* FEATURE_EXT_transform_feedback */
  231.  
  232.  
  233. /** Default fallback for ctx->Driver.NewTransformFeedback() */
  234. static struct gl_transform_feedback_object *
  235. new_transform_feedback(struct gl_context *ctx, GLuint name)
  236. {
  237.    struct gl_transform_feedback_object *obj;
  238.    obj = CALLOC_STRUCT(gl_transform_feedback_object);
  239.    if (obj) {
  240.       obj->Name = name;
  241.       obj->RefCount = 1;
  242.    }
  243.    return obj;
  244. }
  245.  
  246. /** Default fallback for ctx->Driver.DeleteTransformFeedback() */
  247. static void
  248. delete_transform_feedback(struct gl_context *ctx,
  249.                           struct gl_transform_feedback_object *obj)
  250. {
  251.    GLuint i;
  252.  
  253.    for (i = 0; i < Elements(obj->Buffers); i++) {
  254.       _mesa_reference_buffer_object(ctx, &obj->Buffers[i], NULL);
  255.    }
  256.  
  257.    free(obj);
  258. }
  259.  
  260.  
  261. #if FEATURE_EXT_transform_feedback
  262.  
  263.  
  264. /** Default fallback for ctx->Driver.BeginTransformFeedback() */
  265. static void
  266. begin_transform_feedback(struct gl_context *ctx, GLenum mode,
  267.                          struct gl_transform_feedback_object *obj)
  268. {
  269.    /* nop */
  270. }
  271.  
  272. /** Default fallback for ctx->Driver.EndTransformFeedback() */
  273. static void
  274. end_transform_feedback(struct gl_context *ctx,
  275.                        struct gl_transform_feedback_object *obj)
  276. {
  277.    /* nop */
  278. }
  279.  
  280. /** Default fallback for ctx->Driver.PauseTransformFeedback() */
  281. static void
  282. pause_transform_feedback(struct gl_context *ctx,
  283.                          struct gl_transform_feedback_object *obj)
  284. {
  285.    /* nop */
  286. }
  287.  
  288. /** Default fallback for ctx->Driver.ResumeTransformFeedback() */
  289. static void
  290. resume_transform_feedback(struct gl_context *ctx,
  291.                           struct gl_transform_feedback_object *obj)
  292. {
  293.    /* nop */
  294. }
  295.  
  296. /** Default fallback for ctx->Driver.DrawTransformFeedback() */
  297. static void
  298. draw_transform_feedback(struct gl_context *ctx, GLenum mode,
  299.                         struct gl_transform_feedback_object *obj)
  300. {
  301.    /* XXX to do */
  302.    /*
  303.     * Get number of vertices in obj's feedback buffer.
  304.     * Call ctx->Exec.DrawArrays(mode, 0, count);
  305.     */
  306. }
  307.  
  308.  
  309. /**
  310.  * Plug in default device driver functions for transform feedback.
  311.  * Most drivers will override some/all of these.
  312.  */
  313. void
  314. _mesa_init_transform_feedback_functions(struct dd_function_table *driver)
  315. {
  316.    driver->NewTransformFeedback = new_transform_feedback;
  317.    driver->DeleteTransformFeedback = delete_transform_feedback;
  318.    driver->BeginTransformFeedback = begin_transform_feedback;
  319.    driver->EndTransformFeedback = end_transform_feedback;
  320.    driver->PauseTransformFeedback = pause_transform_feedback;
  321.    driver->ResumeTransformFeedback = resume_transform_feedback;
  322.    driver->DrawTransformFeedback = draw_transform_feedback;
  323. }
  324.  
  325.  
  326. void
  327. _mesa_init_transform_feedback_dispatch(struct _glapi_table *disp)
  328. {
  329.    SET_BeginTransformFeedbackEXT(disp, _mesa_BeginTransformFeedback);
  330.    SET_EndTransformFeedbackEXT(disp, _mesa_EndTransformFeedback);
  331.    SET_BindBufferRangeEXT(disp, _mesa_BindBufferRange);
  332.    SET_BindBufferBaseEXT(disp, _mesa_BindBufferBase);
  333.    SET_BindBufferOffsetEXT(disp, _mesa_BindBufferOffsetEXT);
  334.    SET_TransformFeedbackVaryingsEXT(disp, _mesa_TransformFeedbackVaryings);
  335.    SET_GetTransformFeedbackVaryingEXT(disp, _mesa_GetTransformFeedbackVarying);
  336. }
  337.  
  338.  
  339. /**
  340.  ** Begin API functions
  341.  **/
  342.  
  343.  
  344. void GLAPIENTRY
  345. _mesa_BeginTransformFeedback(GLenum mode)
  346. {
  347.    struct gl_transform_feedback_object *obj;
  348.    GET_CURRENT_CONTEXT(ctx);
  349.  
  350.    obj = ctx->TransformFeedback.CurrentObject;
  351.  
  352.    switch (mode) {
  353.    case GL_POINTS:
  354.    case GL_LINES:
  355.    case GL_TRIANGLES:
  356.       /* legal */
  357.       break;
  358.    default:
  359.       _mesa_error(ctx, GL_INVALID_ENUM, "glBeginTransformFeedback(mode)");
  360.       return;
  361.    }
  362.  
  363.    if (obj->Active) {
  364.       _mesa_error(ctx, GL_INVALID_OPERATION,
  365.                   "glBeginTransformFeedback(already active)");
  366.       return;
  367.    }
  368.  
  369.    obj->Active = GL_TRUE;
  370.    ctx->TransformFeedback.Mode = mode;
  371.  
  372.    assert(ctx->Driver.BeginTransformFeedback);
  373.    ctx->Driver.BeginTransformFeedback(ctx, mode, obj);
  374. }
  375.  
  376.  
  377. void GLAPIENTRY
  378. _mesa_EndTransformFeedback(void)
  379. {
  380.    struct gl_transform_feedback_object *obj;
  381.    GET_CURRENT_CONTEXT(ctx);
  382.  
  383.    obj = ctx->TransformFeedback.CurrentObject;
  384.  
  385.    if (!obj->Active) {
  386.       _mesa_error(ctx, GL_INVALID_OPERATION,
  387.                   "glEndTransformFeedback(not active)");
  388.       return;
  389.    }
  390.  
  391.    ctx->TransformFeedback.CurrentObject->Active = GL_FALSE;
  392.  
  393.    assert(ctx->Driver.EndTransformFeedback);
  394.    ctx->Driver.EndTransformFeedback(ctx, obj);
  395. }
  396.  
  397.  
  398. /**
  399.  * Helper used by BindBufferRange() and BindBufferBase().
  400.  */
  401. static void
  402. bind_buffer_range(struct gl_context *ctx, GLuint index,
  403.                   struct gl_buffer_object *bufObj,
  404.                   GLintptr offset, GLsizeiptr size)
  405. {
  406.    struct gl_transform_feedback_object *obj =
  407.       ctx->TransformFeedback.CurrentObject;
  408.  
  409.    /* The general binding point */
  410.    _mesa_reference_buffer_object(ctx,
  411.                                  &ctx->TransformFeedback.CurrentBuffer,
  412.                                  bufObj);
  413.  
  414.    /* The per-attribute binding point */
  415.    _mesa_reference_buffer_object(ctx,
  416.                                  &obj->Buffers[index],
  417.                                  bufObj);
  418.  
  419.    obj->BufferNames[index] = bufObj->Name;
  420.  
  421.    obj->Offset[index] = offset;
  422.    obj->Size[index] = size;
  423. }
  424.  
  425.  
  426. /**
  427.  * Specify a buffer object to receive vertex shader results.  Plus,
  428.  * specify the starting offset to place the results, and max size.
  429.  */
  430. void GLAPIENTRY
  431. _mesa_BindBufferRange(GLenum target, GLuint index,
  432.                       GLuint buffer, GLintptr offset, GLsizeiptr size)
  433. {
  434.    struct gl_transform_feedback_object *obj;
  435.    struct gl_buffer_object *bufObj;
  436.    GET_CURRENT_CONTEXT(ctx);
  437.  
  438.    if (target != GL_TRANSFORM_FEEDBACK_BUFFER) {
  439.       _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferRange(target)");
  440.       return;
  441.    }
  442.  
  443.    obj = ctx->TransformFeedback.CurrentObject;
  444.  
  445.    if (obj->Active) {
  446.       _mesa_error(ctx, GL_INVALID_OPERATION,
  447.                   "glBindBufferRange(transform feedback active)");
  448.       return;
  449.    }
  450.  
  451.    if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) {
  452.       _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d)", index);
  453.       return;
  454.    }
  455.  
  456.    if ((size <= 0) || (size & 0x3)) {
  457.       /* must be positive and multiple of four */
  458.       _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(size%d)", (int) size);
  459.       return;
  460.    }  
  461.  
  462.    if (offset & 0x3) {
  463.       /* must be multiple of four */
  464.       _mesa_error(ctx, GL_INVALID_VALUE,
  465.                   "glBindBufferRange(offset=%d)", (int) offset);
  466.       return;
  467.    }  
  468.  
  469.    bufObj = _mesa_lookup_bufferobj(ctx, buffer);
  470.    if (!bufObj) {
  471.       _mesa_error(ctx, GL_INVALID_OPERATION,
  472.                   "glBindBufferRange(invalid buffer=%u)", buffer);
  473.       return;
  474.    }
  475.  
  476.    if (offset + size >= bufObj->Size) {
  477.       _mesa_error(ctx, GL_INVALID_VALUE,
  478.                   "glBindBufferRange(offset + size %d > buffer size %d)",
  479.                   (int) (offset + size), (int) (bufObj->Size));
  480.       return;
  481.    }  
  482.  
  483.    bind_buffer_range(ctx, index, bufObj, offset, size);
  484. }
  485.  
  486.  
  487. /**
  488.  * Specify a buffer object to receive vertex shader results.
  489.  * As above, but start at offset = 0.
  490.  */
  491. void GLAPIENTRY
  492. _mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer)
  493. {
  494.    struct gl_transform_feedback_object *obj;
  495.    struct gl_buffer_object *bufObj;
  496.    GLsizeiptr size;
  497.    GET_CURRENT_CONTEXT(ctx);
  498.  
  499.    if (target != GL_TRANSFORM_FEEDBACK_BUFFER) {
  500.       _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferBase(target)");
  501.       return;
  502.    }
  503.  
  504.    obj = ctx->TransformFeedback.CurrentObject;
  505.  
  506.    if (obj->Active) {
  507.       _mesa_error(ctx, GL_INVALID_OPERATION,
  508.                   "glBindBufferRange(transform feedback active)");
  509.       return;
  510.    }
  511.  
  512.    if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) {
  513.       _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index);
  514.       return;
  515.    }
  516.  
  517.    bufObj = _mesa_lookup_bufferobj(ctx, buffer);
  518.    if (!bufObj) {
  519.       _mesa_error(ctx, GL_INVALID_OPERATION,
  520.                   "glBindBufferBase(invalid buffer=%u)", buffer);
  521.       return;
  522.    }
  523.  
  524.    /* default size is the buffer size rounded down to nearest
  525.     * multiple of four.
  526.     */
  527.    size = bufObj->Size & ~0x3;
  528.  
  529.    bind_buffer_range(ctx, index, bufObj, 0, size);
  530. }
  531.  
  532.  
  533. /**
  534.  * Specify a buffer object to receive vertex shader results, plus the
  535.  * offset in the buffer to start placing results.
  536.  * This function is part of GL_EXT_transform_feedback, but not GL3.
  537.  */
  538. void GLAPIENTRY
  539. _mesa_BindBufferOffsetEXT(GLenum target, GLuint index, GLuint buffer,
  540.                           GLintptr offset)
  541. {
  542.    struct gl_transform_feedback_object *obj;
  543.    struct gl_buffer_object *bufObj;
  544.    GET_CURRENT_CONTEXT(ctx);
  545.    GLsizeiptr size;
  546.  
  547.    if (target != GL_TRANSFORM_FEEDBACK_BUFFER) {
  548.       _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferOffsetEXT(target)");
  549.       return;
  550.    }
  551.  
  552.    obj = ctx->TransformFeedback.CurrentObject;
  553.  
  554.    if (obj->Active) {
  555.       _mesa_error(ctx, GL_INVALID_OPERATION,
  556.                   "glBindBufferRange(transform feedback active)");
  557.       return;
  558.    }
  559.  
  560.    if (index >= ctx->Const.MaxTransformFeedbackSeparateAttribs) {
  561.       _mesa_error(ctx, GL_INVALID_VALUE,
  562.                   "glBindBufferOffsetEXT(index=%d)", index);
  563.       return;
  564.    }
  565.  
  566.    bufObj = _mesa_lookup_bufferobj(ctx, buffer);
  567.    if (!bufObj) {
  568.       _mesa_error(ctx, GL_INVALID_OPERATION,
  569.                   "glBindBufferOffsetEXT(invalid buffer=%u)", buffer);
  570.       return;
  571.    }
  572.  
  573.    /* default size is the buffer size rounded down to nearest
  574.     * multiple of four.
  575.     */
  576.    size = (bufObj->Size - offset) & ~0x3;
  577.  
  578.    bind_buffer_range(ctx, index, bufObj, offset, size);
  579. }
  580.  
  581.  
  582. /**
  583.  * This function specifies the vertex shader outputs to be written
  584.  * to the feedback buffer(s), and in what order.
  585.  */
  586. void GLAPIENTRY
  587. _mesa_TransformFeedbackVaryings(GLuint program, GLsizei count,
  588.                                 const GLchar **varyings, GLenum bufferMode)
  589. {
  590.    struct gl_shader_program *shProg;
  591.    GLuint i;
  592.    GET_CURRENT_CONTEXT(ctx);
  593.  
  594.    switch (bufferMode) {
  595.    case GL_INTERLEAVED_ATTRIBS:
  596.       break;
  597.    case GL_SEPARATE_ATTRIBS:
  598.       break;
  599.    default:
  600.       _mesa_error(ctx, GL_INVALID_ENUM,
  601.                   "glTransformFeedbackVaryings(bufferMode)");
  602.       return;
  603.    }
  604.  
  605.    if (count < 0 || count > ctx->Const.MaxTransformFeedbackSeparateAttribs) {
  606.       _mesa_error(ctx, GL_INVALID_VALUE,
  607.                   "glTransformFeedbackVaryings(count=%d)", count);
  608.       return;
  609.    }
  610.  
  611.    shProg = _mesa_lookup_shader_program(ctx, program);
  612.    if (!shProg) {
  613.       _mesa_error(ctx, GL_INVALID_VALUE,
  614.                   "glTransformFeedbackVaryings(program=%u)", program);
  615.       return;
  616.    }
  617.  
  618.    /* free existing varyings, if any */
  619.    for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) {
  620.       free(shProg->TransformFeedback.VaryingNames[i]);
  621.    }
  622.    free(shProg->TransformFeedback.VaryingNames);
  623.  
  624.    /* allocate new memory for varying names */
  625.    shProg->TransformFeedback.VaryingNames =
  626.       (GLchar **) malloc(count * sizeof(GLchar *));
  627.  
  628.    if (!shProg->TransformFeedback.VaryingNames) {
  629.       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTransformFeedbackVaryings()");
  630.       return;
  631.    }
  632.  
  633.    /* Save the new names and the count */
  634.    for (i = 0; i < (GLuint) count; i++) {
  635.       shProg->TransformFeedback.VaryingNames[i] = _mesa_strdup(varyings[i]);
  636.    }
  637.    shProg->TransformFeedback.NumVarying = count;
  638.  
  639.    shProg->TransformFeedback.BufferMode = bufferMode;
  640.  
  641.    /* The varyings won't be used until shader link time */
  642. }
  643.  
  644.  
  645. /**
  646.  * Get info about the vertex shader's outputs which are to be written
  647.  * to the feedback buffer(s).
  648.  */
  649. void GLAPIENTRY
  650. _mesa_GetTransformFeedbackVarying(GLuint program, GLuint index,
  651.                                   GLsizei bufSize, GLsizei *length,
  652.                                   GLsizei *size, GLenum *type, GLchar *name)
  653. {
  654.    const struct gl_shader_program *shProg;
  655.    const GLchar *varyingName;
  656.    GLint v;
  657.    GET_CURRENT_CONTEXT(ctx);
  658.  
  659.    shProg = _mesa_lookup_shader_program(ctx, program);
  660.    if (!shProg) {
  661.       _mesa_error(ctx, GL_INVALID_VALUE,
  662.                   "glGetTransformFeedbackVaryings(program=%u)", program);
  663.       return;
  664.    }
  665.  
  666.    if (index >= shProg->TransformFeedback.NumVarying) {
  667.       _mesa_error(ctx, GL_INVALID_VALUE,
  668.                   "glGetTransformFeedbackVaryings(index=%u)", index);
  669.       return;
  670.    }
  671.  
  672.    varyingName = shProg->TransformFeedback.VaryingNames[index];
  673.  
  674.    v = _mesa_lookup_parameter_index(shProg->Varying, -1, varyingName);
  675.    if (v >= 0) {
  676.       struct gl_program_parameter *param = &shProg->Varying->Parameters[v];
  677.  
  678.       /* return the varying's name and length */
  679.       _mesa_copy_string(name, bufSize, length, varyingName);
  680.  
  681.       /* return the datatype and value's size (in datatype units) */
  682.       if (type)
  683.          *type = param->DataType;
  684.       if (size)
  685.          *size = param->Size;
  686.    }
  687.    else {
  688.       name[0] = 0;
  689.       if (length)
  690.          *length = 0;
  691.       if (type)
  692.          *type = 0;
  693.       if (size)
  694.          *size = 0;
  695.    }
  696. }
  697.  
  698.  
  699.  
  700. static struct gl_transform_feedback_object *
  701. lookup_transform_feedback_object(struct gl_context *ctx, GLuint name)
  702. {
  703.    if (name == 0) {
  704.       return ctx->TransformFeedback.DefaultObject;
  705.    }
  706.    else
  707.       return (struct gl_transform_feedback_object *)
  708.          _mesa_HashLookup(ctx->TransformFeedback.Objects, name);
  709. }
  710.  
  711.  
  712. /**
  713.  * Create new transform feedback objects.   Transform feedback objects
  714.  * encapsulate the state related to transform feedback to allow quickly
  715.  * switching state (and drawing the results, below).
  716.  * Part of GL_ARB_transform_feedback2.
  717.  */
  718. void GLAPIENTRY
  719. _mesa_GenTransformFeedbacks(GLsizei n, GLuint *names)
  720. {
  721.    GLuint first;
  722.    GET_CURRENT_CONTEXT(ctx);
  723.  
  724.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  725.  
  726.    if (n < 0) {
  727.       _mesa_error(ctx, GL_INVALID_VALUE, "glGenTransformFeedbacks(n < 0)");
  728.       return;
  729.    }
  730.  
  731.    if (!names)
  732.       return;
  733.  
  734.    /* we don't need contiguous IDs, but this might be faster */
  735.    first = _mesa_HashFindFreeKeyBlock(ctx->TransformFeedback.Objects, n);
  736.    if (first) {
  737.       GLsizei i;
  738.       for (i = 0; i < n; i++) {
  739.          struct gl_transform_feedback_object *obj
  740.             = ctx->Driver.NewTransformFeedback(ctx, first + i);
  741.          if (!obj) {
  742.             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTransformFeedbacks");
  743.             return;
  744.          }
  745.          names[i] = first + i;
  746.          _mesa_HashInsert(ctx->TransformFeedback.Objects, first + i, obj);
  747.       }
  748.    }
  749.    else {
  750.       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTransformFeedbacks");
  751.    }
  752. }
  753.  
  754.  
  755. /**
  756.  * Is the given ID a transform feedback object?
  757.  * Part of GL_ARB_transform_feedback2.
  758.  */
  759. GLboolean GLAPIENTRY
  760. _mesa_IsTransformFeedback(GLuint name)
  761. {
  762.    GET_CURRENT_CONTEXT(ctx);
  763.  
  764.    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
  765.  
  766.    if (name && lookup_transform_feedback_object(ctx, name))
  767.       return GL_TRUE;
  768.    else
  769.       return GL_FALSE;
  770. }
  771.  
  772.  
  773. /**
  774.  * Bind the given transform feedback object.
  775.  * Part of GL_ARB_transform_feedback2.
  776.  */
  777. void GLAPIENTRY
  778. _mesa_BindTransformFeedback(GLenum target, GLuint name)
  779. {
  780.    struct gl_transform_feedback_object *obj;
  781.    GET_CURRENT_CONTEXT(ctx);
  782.  
  783.    if (target != GL_TRANSFORM_FEEDBACK) {
  784.       _mesa_error(ctx, GL_INVALID_ENUM, "glBindTransformFeedback(target)");
  785.       return;
  786.    }
  787.  
  788.    if (ctx->TransformFeedback.CurrentObject->Active &&
  789.        !ctx->TransformFeedback.CurrentObject->Paused) {
  790.       _mesa_error(ctx, GL_INVALID_OPERATION,
  791.               "glBindTransformFeedback(transform is active, or not paused)");
  792.       return;
  793.    }
  794.  
  795.    obj = lookup_transform_feedback_object(ctx, name);
  796.    if (!obj) {
  797.       _mesa_error(ctx, GL_INVALID_OPERATION,
  798.                   "glBindTransformFeedback(name=%u)", name);
  799.       return;
  800.    }
  801.  
  802.    reference_transform_feedback_object(&ctx->TransformFeedback.CurrentObject,
  803.                                        obj);
  804. }
  805.  
  806.  
  807. /**
  808.  * Delete the given transform feedback objects.
  809.  * Part of GL_ARB_transform_feedback2.
  810.  */
  811. void GLAPIENTRY
  812. _mesa_DeleteTransformFeedbacks(GLsizei n, const GLuint *names)
  813. {
  814.    GLint i;
  815.    GET_CURRENT_CONTEXT(ctx);
  816.  
  817.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  818.  
  819.    if (n < 0) {
  820.       _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteTransformFeedbacks(n < 0)");
  821.       return;
  822.    }
  823.  
  824.    if (!names)
  825.       return;
  826.  
  827.    for (i = 0; i < n; i++) {
  828.       if (names[i] > 0) {
  829.          struct gl_transform_feedback_object *obj
  830.             = lookup_transform_feedback_object(ctx, names[i]);
  831.          if (obj) {
  832.             if (obj->Active) {
  833.                _mesa_error(ctx, GL_INVALID_OPERATION,
  834.                            "glDeleteTransformFeedbacks(object %u is active)",
  835.                            names[i]);
  836.                return;
  837.             }
  838.             _mesa_HashRemove(ctx->TransformFeedback.Objects, names[i]);
  839.             /* unref, but object may not be deleted until later */
  840.             reference_transform_feedback_object(&obj, NULL);
  841.          }
  842.       }
  843.    }
  844. }
  845.  
  846.  
  847. /**
  848.  * Pause transform feedback.
  849.  * Part of GL_ARB_transform_feedback2.
  850.  */
  851. void GLAPIENTRY
  852. _mesa_PauseTransformFeedback(void)
  853. {
  854.    struct gl_transform_feedback_object *obj;
  855.    GET_CURRENT_CONTEXT(ctx);
  856.  
  857.    obj = ctx->TransformFeedback.CurrentObject;
  858.  
  859.    if (!obj->Active || obj->Paused) {
  860.       _mesa_error(ctx, GL_INVALID_OPERATION,
  861.            "glPauseTransformFeedback(feedback not active or already paused)");
  862.       return;
  863.    }
  864.  
  865.    obj->Paused = GL_TRUE;
  866.  
  867.    assert(ctx->Driver.PauseTransformFeedback);
  868.    ctx->Driver.PauseTransformFeedback(ctx, obj);
  869. }
  870.  
  871.  
  872. /**
  873.  * Resume transform feedback.
  874.  * Part of GL_ARB_transform_feedback2.
  875.  */
  876. void GLAPIENTRY
  877. _mesa_ResumeTransformFeedback(void)
  878. {
  879.    struct gl_transform_feedback_object *obj;
  880.    GET_CURRENT_CONTEXT(ctx);
  881.  
  882.    obj = ctx->TransformFeedback.CurrentObject;
  883.  
  884.    if (!obj->Active || !obj->Paused) {
  885.       _mesa_error(ctx, GL_INVALID_OPERATION,
  886.                "glPauseTransformFeedback(feedback not active or not paused)");
  887.       return;
  888.    }
  889.  
  890.    obj->Paused = GL_FALSE;
  891.  
  892.    assert(ctx->Driver.ResumeTransformFeedback);
  893.    ctx->Driver.ResumeTransformFeedback(ctx, obj);
  894. }
  895.  
  896.  
  897. /**
  898.  * Draw the vertex data in a transform feedback object.
  899.  * \param mode  GL_POINTS, GL_LINES, GL_TRIANGLE_STRIP, etc.
  900.  * \param name  the transform feedback object
  901.  * The number of vertices comes from the transform feedback object.
  902.  * User still has to setup of the vertex attribute info with
  903.  * glVertexPointer, glColorPointer, etc.
  904.  * Part of GL_ARB_transform_feedback2.
  905.  */
  906. void GLAPIENTRY
  907. _mesa_DrawTransformFeedback(GLenum mode, GLuint name)
  908. {
  909.    GET_CURRENT_CONTEXT(ctx);
  910.    struct gl_transform_feedback_object *obj =
  911.       lookup_transform_feedback_object(ctx, name);
  912.  
  913.    if (mode > GL_POLYGON) {
  914.       _mesa_error(ctx, GL_INVALID_ENUM,
  915.                   "glDrawTransformFeedback(mode=0x%x)", mode);
  916.       return;
  917.    }
  918.    if (!obj) {
  919.       _mesa_error(ctx, GL_INVALID_VALUE,
  920.                   "glDrawTransformFeedback(name = %u)", name);
  921.       return;
  922.    }
  923.  
  924.    /* XXX check if EndTransformFeedback has never been called while
  925.     * the object was bound
  926.     */
  927.  
  928.    assert(ctx->Driver.DrawTransformFeedback);
  929.    ctx->Driver.DrawTransformFeedback(ctx, mode, obj);
  930. }
  931.  
  932.  
  933. /*
  934. XXX misc to do:
  935.  
  936. glGet*() for
  937.  
  938. GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED
  939. GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE
  940. GL_TRANSFORM_FEEDBACK_BINDING
  941. */
  942.  
  943.  
  944. #endif /* FEATURE_EXT_transform_feedback */
  945.