void
brw_begin_transform_feedback(struct gl_context *ctx, GLenum mode,
			     struct gl_transform_feedback_object *obj)
{
   struct brw_context *brw = brw_context(ctx);
   const struct gl_shader_program *shaderprog;
   const struct gl_transform_feedback_info *linked_xfb_info;
   struct gl_transform_feedback_object *xfb_obj =
      ctx->TransformFeedback.CurrentObject;

   assert(brw->gen == 6);

   if (brw->geometry_program) {
      /* BRW_NEW_GEOMETRY_PROGRAM */
      shaderprog =
         ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY];
   } else {
      /* BRW_NEW_VERTEX_PROGRAM */
      shaderprog =
         ctx->_Shader->CurrentProgram[MESA_SHADER_VERTEX];
   }
   linked_xfb_info = &shaderprog->LinkedTransformFeedback;

   /* Compute the maximum number of vertices that we can write without
    * overflowing any of the buffers currently being used for feedback.
    */
   unsigned max_index
      = _mesa_compute_max_transform_feedback_vertices(xfb_obj,
                                                      linked_xfb_info);

   /* 3DSTATE_GS_SVB_INDEX is non-pipelined. */
   intel_emit_post_sync_nonzero_flush(brw);

   /* Initialize the SVBI 0 register to zero and set the maximum index. */
   BEGIN_BATCH(4);
   OUT_BATCH(_3DSTATE_GS_SVB_INDEX << 16 | (4 - 2));
   OUT_BATCH(0); /* SVBI 0 */
   OUT_BATCH(0); /* starting index */
   OUT_BATCH(max_index);
   ADVANCE_BATCH();

   /* Initialize the rest of the unused streams to sane values.  Otherwise,
    * they may indicate that there is no room to write data and prevent
    * anything from happening at all.
    */
   for (int i = 1; i < 4; i++) {
      BEGIN_BATCH(4);
      OUT_BATCH(_3DSTATE_GS_SVB_INDEX << 16 | (4 - 2));
      OUT_BATCH(i << SVB_INDEX_SHIFT);
      OUT_BATCH(0); /* starting index */
      OUT_BATCH(0xffffffff);
      ADVANCE_BATCH();
   }
}
void GLAPIENTRY
_mesa_BeginTransformFeedback(GLenum mode)
{
   struct gl_transform_feedback_object *obj;
   struct gl_transform_feedback_info *info = NULL;
   struct gl_shader_program *source;
   GLuint i;
   unsigned vertices_per_prim;
   GET_CURRENT_CONTEXT(ctx);

   obj = ctx->TransformFeedback.CurrentObject;

   /* Figure out what pipeline stage is the source of data for transform
    * feedback.
    */
   source = get_xfb_source(ctx);
   if (source == NULL) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glBeginTransformFeedback(no program active)");
      return;
   }

   info = &source->LinkedTransformFeedback;

   if (info->NumOutputs == 0) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glBeginTransformFeedback(no varyings to record)");
      return;
   }

   switch (mode) {
   case GL_POINTS:
      vertices_per_prim = 1;
      break;
   case GL_LINES:
      vertices_per_prim = 2;
      break;
   case GL_TRIANGLES:
      vertices_per_prim = 3;
      break;
   default:
      _mesa_error(ctx, GL_INVALID_ENUM, "glBeginTransformFeedback(mode)");
      return;
   }

   if (obj->Active) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glBeginTransformFeedback(already active)");
      return;
   }

   for (i = 0; i < info->NumBuffers; ++i) {
      if (obj->BufferNames[i] == 0) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glBeginTransformFeedback(binding point %d does not have "
                     "a buffer object bound)", i);
         return;
      }
   }

   FLUSH_VERTICES(ctx, 0);
   ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback;

   obj->Active = GL_TRUE;
   ctx->TransformFeedback.Mode = mode;

   compute_transform_feedback_buffer_sizes(obj);

   if (_mesa_is_gles3(ctx)) {
      /* In GLES3, we are required to track the usage of the transform
       * feedback buffer and report INVALID_OPERATION if a draw call tries to
       * exceed it.  So compute the maximum number of vertices that we can
       * write without overflowing any of the buffers currently being used for
       * feedback.
       */
      unsigned max_vertices
         = _mesa_compute_max_transform_feedback_vertices(obj, info);
      obj->GlesRemainingPrims = max_vertices / vertices_per_prim;
   }

   if (obj->shader_program != source) {
      ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedbackProg;
      obj->shader_program = source;
   }

   assert(ctx->Driver.BeginTransformFeedback);
   ctx->Driver.BeginTransformFeedback(ctx, mode, obj);
}