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); }