#include "transformfeedback.h"
#include "shaderapi.h"
#include "shaderobj.h"
-#include "main/dispatch.h"
+#include "program/program.h"
#include "program/prog_parameter.h"
struct using_program_tuple
/* Skip any inactive buffers, which have a stride of 0. */
if (stride == 0)
- continue;
+ continue;
max_for_this_buffer = obj->Size[i] / (4 * stride);
max_index = MIN2(max_index, max_for_this_buffer);
}
-void GLAPIENTRY
-_mesa_BeginTransformFeedback(GLenum mode)
+static ALWAYS_INLINE void
+begin_transform_feedback(struct gl_context *ctx, GLenum mode, bool no_error)
{
struct gl_transform_feedback_object *obj;
struct gl_transform_feedback_info *info = NULL;
+ struct gl_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.
*/
- struct gl_program *source = get_xfb_source(ctx);
- if (source == NULL) {
+ source = get_xfb_source(ctx);
+ if (!no_error && source == NULL) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBeginTransformFeedback(no program active)");
return;
info = source->sh.LinkedTransformFeedback;
- if (info->NumOutputs == 0) {
+ if (!no_error && info->NumOutputs == 0) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBeginTransformFeedback(no varyings to record)");
return;
vertices_per_prim = 3;
break;
default:
- _mesa_error(ctx, GL_INVALID_ENUM, "glBeginTransformFeedback(mode)");
- return;
+ if (!no_error) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBeginTransformFeedback(mode)");
+ return;
+ } else {
+ /* Stop compiler warnings */
+ unreachable("Error in API use when using KHR_no_error");
+ }
}
- if (obj->Active) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBeginTransformFeedback(already active)");
- return;
- }
+ if (!no_error) {
+ if (obj->Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBeginTransformFeedback(already active)");
+ return;
+ }
- for (i = 0; i < ctx->Const.MaxTransformFeedbackBuffers; i++) {
- if ((info->ActiveBuffers >> i) & 1) {
- if (obj->BufferNames[i] == 0) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBeginTransformFeedback(binding point %d does not "
- "have a buffer object bound)", i);
- return;
+ for (i = 0; i < ctx->Const.MaxTransformFeedbackBuffers; i++) {
+ if ((info->ActiveBuffers >> i) & 1) {
+ if (obj->BufferNames[i] == 0) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBeginTransformFeedback(binding point %d does not "
+ "have a buffer object bound)", i);
+ return;
+ }
}
}
}
if (obj->program != source) {
ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedbackProg;
+ _mesa_reference_program_(ctx, &obj->program, source);
obj->program = source;
}
void GLAPIENTRY
-_mesa_EndTransformFeedback(void)
+_mesa_BeginTransformFeedback_no_error(GLenum mode)
{
- struct gl_transform_feedback_object *obj;
GET_CURRENT_CONTEXT(ctx);
+ begin_transform_feedback(ctx, mode, true);
+}
- obj = ctx->TransformFeedback.CurrentObject;
- if (!obj->Active) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glEndTransformFeedback(not active)");
- return;
- }
+void GLAPIENTRY
+_mesa_BeginTransformFeedback(GLenum mode)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ begin_transform_feedback(ctx, mode, false);
+}
+
+static void
+end_transform_feedback(struct gl_context *ctx,
+ struct gl_transform_feedback_object *obj)
+{
FLUSH_VERTICES(ctx, 0);
ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback;
assert(ctx->Driver.EndTransformFeedback);
ctx->Driver.EndTransformFeedback(ctx, obj);
+ _mesa_reference_program_(ctx, &obj->program, NULL);
ctx->TransformFeedback.CurrentObject->Active = GL_FALSE;
ctx->TransformFeedback.CurrentObject->Paused = GL_FALSE;
ctx->TransformFeedback.CurrentObject->EndedAnytime = GL_TRUE;
}
+void GLAPIENTRY
+_mesa_EndTransformFeedback_no_error(void)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ end_transform_feedback(ctx, ctx->TransformFeedback.CurrentObject);
+}
+
+
+void GLAPIENTRY
+_mesa_EndTransformFeedback(void)
+{
+ struct gl_transform_feedback_object *obj;
+ GET_CURRENT_CONTEXT(ctx);
+
+ obj = ctx->TransformFeedback.CurrentObject;
+
+ if (!obj->Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glEndTransformFeedback(not active)");
+ return;
+ }
+
+ end_transform_feedback(ctx, obj);
+}
+
+
/**
* Helper used by BindBufferRange() and BindBufferBase().
*/
_mesa_error(ctx, GL_INVALID_VALUE, "%s(size=%d must be a multiple of "
"four)", gl_methd_name, (int) size);
return false;
- }
+ }
if (offset & 0x3) {
/* OpenGL 4.5 core profile, 6.7, pdf page 103: multiple of 4 */
obj = lookup_transform_feedback_object_err(ctx, xfb,
"glTransformFeedbackBufferBase");
- if(!obj) {
+ if (!obj) {
return;
}
bufObj = lookup_transform_feedback_bufferobj_err(ctx, buffer,
"glTransformFeedbackBufferBase");
- if(!bufObj) {
+ if (!bufObj) {
return;
}
obj = lookup_transform_feedback_object_err(ctx, xfb,
"glTransformFeedbackBufferRange");
- if(!obj) {
+ if (!obj) {
return;
}
bufObj = lookup_transform_feedback_bufferobj_err(ctx, buffer,
"glTransformFeedbackBufferRange");
- if(!bufObj) {
+ if (!bufObj) {
return;
}
* offset in the buffer to start placing results.
* This function is part of GL_EXT_transform_feedback, but not GL3.
*/
+static ALWAYS_INLINE void
+bind_buffer_offset(struct gl_context *ctx,
+ struct gl_transform_feedback_object *obj, GLuint index,
+ GLuint buffer, GLintptr offset, bool no_error)
+{
+ struct gl_buffer_object *bufObj;
+
+ if (buffer == 0) {
+ bufObj = ctx->Shared->NullBufferObj;
+ } else {
+ bufObj = _mesa_lookup_bufferobj(ctx, buffer);
+ if (!no_error && !bufObj) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindBufferOffsetEXT(invalid buffer=%u)", buffer);
+ return;
+ }
+ }
+
+ _mesa_bind_buffer_range_xfb(ctx, obj, index, bufObj, offset, 0);
+}
+
+
+void GLAPIENTRY
+_mesa_BindBufferOffsetEXT_no_error(GLenum target, GLuint index, GLuint buffer,
+ GLintptr offset)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ bind_buffer_offset(ctx, ctx->TransformFeedback.CurrentObject, index, buffer,
+ offset, true);
+}
+
+
void GLAPIENTRY
_mesa_BindBufferOffsetEXT(GLenum target, GLuint index, GLuint buffer,
GLintptr offset)
{
struct gl_transform_feedback_object *obj;
- struct gl_buffer_object *bufObj;
GET_CURRENT_CONTEXT(ctx);
if (target != GL_TRANSFORM_FEEDBACK_BUFFER) {
return;
}
- if (buffer == 0) {
- bufObj = ctx->Shared->NullBufferObj;
- } else {
- bufObj = _mesa_lookup_bufferobj(ctx, buffer);
- if (!bufObj) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBindBufferOffsetEXT(invalid buffer=%u)", buffer);
- return;
- }
- }
-
- _mesa_bind_buffer_range_xfb(ctx, obj, index, bufObj, offset, 0);
+ bind_buffer_offset(ctx, obj, index, buffer, offset, false);
}
* This function specifies the transform feedback outputs to be written
* to the feedback buffer(s), and in what order.
*/
+static ALWAYS_INLINE void
+transform_feedback_varyings(struct gl_context *ctx,
+ struct gl_shader_program *shProg, GLsizei count,
+ const GLchar *const *varyings, GLenum bufferMode)
+{
+ GLint i;
+
+ /* free existing varyings, if any */
+ for (i = 0; i < (GLint) shProg->TransformFeedback.NumVarying; i++) {
+ free(shProg->TransformFeedback.VaryingNames[i]);
+ }
+ free(shProg->TransformFeedback.VaryingNames);
+
+ /* allocate new memory for varying names */
+ shProg->TransformFeedback.VaryingNames =
+ malloc(count * sizeof(GLchar *));
+
+ if (!shProg->TransformFeedback.VaryingNames) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTransformFeedbackVaryings()");
+ return;
+ }
+
+ /* Save the new names and the count */
+ for (i = 0; i < count; i++) {
+ shProg->TransformFeedback.VaryingNames[i] = strdup(varyings[i]);
+ }
+ shProg->TransformFeedback.NumVarying = count;
+
+ shProg->TransformFeedback.BufferMode = bufferMode;
+
+ /* No need to invoke FLUSH_VERTICES or flag NewTransformFeedback since
+ * the varyings won't be used until shader link time.
+ */
+}
+
+
+void GLAPIENTRY
+_mesa_TransformFeedbackVaryings_no_error(GLuint program, GLsizei count,
+ const GLchar *const *varyings,
+ GLenum bufferMode)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, program);
+ transform_feedback_varyings(ctx, shProg, count, varyings, bufferMode);
+}
+
void GLAPIENTRY
_mesa_TransformFeedbackVaryings(GLuint program, GLsizei count,
const GLchar * const *varyings,
}
}
- /* free existing varyings, if any */
- for (i = 0; i < (GLint) shProg->TransformFeedback.NumVarying; i++) {
- free(shProg->TransformFeedback.VaryingNames[i]);
- }
- free(shProg->TransformFeedback.VaryingNames);
-
- /* allocate new memory for varying names */
- shProg->TransformFeedback.VaryingNames =
- malloc(count * sizeof(GLchar *));
-
- if (!shProg->TransformFeedback.VaryingNames) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTransformFeedbackVaryings()");
- return;
- }
-
- /* Save the new names and the count */
- for (i = 0; i < count; i++) {
- shProg->TransformFeedback.VaryingNames[i] = strdup(varyings[i]);
- }
- shProg->TransformFeedback.NumVarying = count;
-
- shProg->TransformFeedback.BufferMode = bufferMode;
-
- /* No need to invoke FLUSH_VERTICES or flag NewTransformFeedback since
- * the varyings won't be used until shader link time.
- */
+ transform_feedback_varyings(ctx, shProg, count, varyings, bufferMode);
}
}
+void GLAPIENTRY
+_mesa_BindTransformFeedback_no_error(GLenum target, GLuint name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ bind_transform_feedback(ctx, name, true);
+}
+
+
void GLAPIENTRY
_mesa_BindTransformFeedback(GLenum target, GLuint name)
{
* Pause transform feedback.
* Part of GL_ARB_transform_feedback2.
*/
+static void
+pause_transform_feedback(struct gl_context *ctx,
+ struct gl_transform_feedback_object *obj)
+{
+ FLUSH_VERTICES(ctx, 0);
+ ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback;
+
+ assert(ctx->Driver.PauseTransformFeedback);
+ ctx->Driver.PauseTransformFeedback(ctx, obj);
+
+ obj->Paused = GL_TRUE;
+}
+
+
+void GLAPIENTRY
+_mesa_PauseTransformFeedback_no_error(void)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ pause_transform_feedback(ctx, ctx->TransformFeedback.CurrentObject);
+}
+
+
void GLAPIENTRY
_mesa_PauseTransformFeedback(void)
{
return;
}
- FLUSH_VERTICES(ctx, 0);
- ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback;
-
- assert(ctx->Driver.PauseTransformFeedback);
- ctx->Driver.PauseTransformFeedback(ctx, obj);
-
- obj->Paused = GL_TRUE;
+ pause_transform_feedback(ctx, obj);
}
* Resume transform feedback.
* Part of GL_ARB_transform_feedback2.
*/
+static void
+resume_transform_feedback(struct gl_context *ctx,
+ struct gl_transform_feedback_object *obj)
+{
+ FLUSH_VERTICES(ctx, 0);
+ ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback;
+
+ obj->Paused = GL_FALSE;
+
+ assert(ctx->Driver.ResumeTransformFeedback);
+ ctx->Driver.ResumeTransformFeedback(ctx, obj);
+}
+
+
+void GLAPIENTRY
+_mesa_ResumeTransformFeedback_no_error(void)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ resume_transform_feedback(ctx, ctx->TransformFeedback.CurrentObject);
+}
+
+
void GLAPIENTRY
_mesa_ResumeTransformFeedback(void)
{
return;
}
- FLUSH_VERTICES(ctx, 0);
- ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback;
-
- obj->Paused = GL_FALSE;
-
- assert(ctx->Driver.ResumeTransformFeedback);
- ctx->Driver.ResumeTransformFeedback(ctx, obj);
+ resume_transform_feedback(ctx, obj);
}
extern void GLAPIENTRY
obj = lookup_transform_feedback_object_err(ctx, xfb,
"glGetTransformFeedbackiv");
- if(!obj) {
+ if (!obj) {
return;
}
obj = lookup_transform_feedback_object_err(ctx, xfb,
"glGetTransformFeedbacki_v");
- if(!obj) {
+ if (!obj) {
return;
}
obj = lookup_transform_feedback_object_err(ctx, xfb,
"glGetTransformFeedbacki64_v");
- if(!obj) {
+ if (!obj) {
return;
}
return;
}
+ /**
+ * This follows the same general rules used for BindBufferBase:
+ *
+ * "To query the starting offset or size of the range of a buffer
+ * object binding in an indexed array, call GetInteger64i_v with
+ * target set to respectively the starting offset or binding size
+ * name from table 6.5 for that array. Index must be in the range
+ * zero to the number of bind points supported minus one. If the
+ * starting offset or size was not specified when the buffer object
+ * was bound (e.g. if it was bound with BindBufferBase), or if no
+ * buffer object is bound to the target array at index, zero is
+ * returned."
+ */
+ if (obj->RequestedSize[index] == 0 &&
+ (pname == GL_TRANSFORM_FEEDBACK_BUFFER_START ||
+ pname == GL_TRANSFORM_FEEDBACK_BUFFER_SIZE)) {
+ *param = 0;
+ return;
+ }
+
compute_transform_feedback_buffer_sizes(obj);
switch(pname) {
case GL_TRANSFORM_FEEDBACK_BUFFER_START:
+ assert(obj->RequestedSize[index] > 0);
*param = obj->Offset[index];
break;
case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
+ assert(obj->RequestedSize[index] > 0);
*param = obj->Size[index];
break;
default: