Includes GL_ARB_transform_feedback2 which encapsulates transform feedback state in objects.undefined
@@ -176,6 +176,7 @@ if env['platform'] != 'winddk': | |||
'state_tracker/st_cb_readpixels.c', | |||
'state_tracker/st_cb_strings.c', | |||
'state_tracker/st_cb_texture.c', | |||
'state_tracker/st_cb_xformfb.c', | |||
'state_tracker/st_context.c', | |||
'state_tracker/st_debug.c', | |||
'state_tracker/st_draw.c', |
@@ -47,6 +47,9 @@ | |||
#if FEATURE_ARB_sync | |||
#include "main/syncobj.h" | |||
#endif | |||
#if FEATURE_EXT_transform_feedback | |||
#include "main/transformfeedback.h" | |||
#endif | |||
#include "shader/program.h" | |||
#include "shader/shader_api.h" | |||
@@ -205,6 +208,10 @@ _mesa_init_driver_functions(struct dd_function_table *driver) | |||
driver->DeleteArrayObject = _mesa_delete_array_object; | |||
driver->BindArrayObject = NULL; | |||
#if FEATURE_EXT_transform_feedback | |||
_mesa_init_transform_feedback_functions(driver); | |||
#endif | |||
/* T&L stuff */ | |||
driver->NeedValidate = GL_FALSE; | |||
driver->ValidateTnlModule = NULL; |
@@ -1038,6 +1038,22 @@ struct dd_function_table { | |||
void *image_handle); | |||
#endif | |||
#if FEATURE_EXT_transform_feedback | |||
struct gl_transform_feedback_object * | |||
(*NewTransformFeedback)(GLcontext *ctx, GLuint name); | |||
void (*DeleteTransformFeedback)(GLcontext *ctx, | |||
struct gl_transform_feedback_object *obj); | |||
void (*BeginTransformFeedback)(GLcontext *ctx, GLenum mode, | |||
struct gl_transform_feedback_object *obj); | |||
void (*EndTransformFeedback)(GLcontext *ctx, | |||
struct gl_transform_feedback_object *obj); | |||
void (*PauseTransformFeedback)(GLcontext *ctx, | |||
struct gl_transform_feedback_object *obj); | |||
void (*ResumeTransformFeedback)(GLcontext *ctx, | |||
struct gl_transform_feedback_object *obj); | |||
void (*DrawTransformFeedback)(GLcontext *ctx, GLenum mode, | |||
struct gl_transform_feedback_object *obj); | |||
#endif | |||
}; | |||
@@ -86,6 +86,7 @@ static const struct { | |||
{ OFF, "GL_ARB_texture_non_power_of_two", F(ARB_texture_non_power_of_two)}, | |||
{ OFF, "GL_ARB_texture_rectangle", F(NV_texture_rectangle) }, | |||
{ ON, "GL_ARB_transpose_matrix", F(ARB_transpose_matrix) }, | |||
{ OFF, "GL_ARB_transform_feedback2", F(ARB_transform_feedback2) }, | |||
{ OFF, "GL_ARB_vertex_array_bgra", F(EXT_vertex_array_bgra) }, | |||
{ OFF, "GL_ARB_vertex_array_object", F(ARB_vertex_array_object) }, | |||
{ ON, "GL_ARB_vertex_buffer_object", F(ARB_vertex_buffer_object) }, |
@@ -7786,7 +7786,7 @@ _mesa_GetBooleanIndexedv( GLenum pname, GLuint index, GLboolean *params ) | |||
_mesa_error(ctx, GL_INVALID_VALUE, "glGetBooleanIndexedv(index=%u), index", pname); | |||
return; | |||
} | |||
params[0] = INT64_TO_BOOLEAN(ctx->TransformFeedback.Offset[index]); | |||
params[0] = INT64_TO_BOOLEAN(ctx->TransformFeedback.CurrentObject->Offset[index]); | |||
break; | |||
case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: | |||
CHECK_EXT1(EXT_transform_feedback); | |||
@@ -7794,7 +7794,7 @@ _mesa_GetBooleanIndexedv( GLenum pname, GLuint index, GLboolean *params ) | |||
_mesa_error(ctx, GL_INVALID_VALUE, "glGetBooleanIndexedv(index=%u), index", pname); | |||
return; | |||
} | |||
params[0] = INT64_TO_BOOLEAN(ctx->TransformFeedback.Size[index]); | |||
params[0] = INT64_TO_BOOLEAN(ctx->TransformFeedback.CurrentObject->Size[index]); | |||
break; | |||
case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: | |||
CHECK_EXT1(EXT_transform_feedback); | |||
@@ -7802,7 +7802,7 @@ _mesa_GetBooleanIndexedv( GLenum pname, GLuint index, GLboolean *params ) | |||
_mesa_error(ctx, GL_INVALID_VALUE, "glGetBooleanIndexedv(index=%u), index", pname); | |||
return; | |||
} | |||
params[0] = INT_TO_BOOLEAN(ctx->TransformFeedback.Buffers[index]->Name); | |||
params[0] = INT_TO_BOOLEAN(ctx->TransformFeedback.CurrentObject->Buffers[index]->Name); | |||
break; | |||
default: | |||
goto invalid_enum_error; | |||
@@ -7850,7 +7850,7 @@ _mesa_GetIntegerIndexedv( GLenum pname, GLuint index, GLint *params ) | |||
_mesa_error(ctx, GL_INVALID_VALUE, "glGetIntegerIndexedv(index=%u), index", pname); | |||
return; | |||
} | |||
params[0] = INT64_TO_INT(ctx->TransformFeedback.Offset[index]); | |||
params[0] = INT64_TO_INT(ctx->TransformFeedback.CurrentObject->Offset[index]); | |||
break; | |||
case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: | |||
CHECK_EXT1(EXT_transform_feedback); | |||
@@ -7858,7 +7858,7 @@ _mesa_GetIntegerIndexedv( GLenum pname, GLuint index, GLint *params ) | |||
_mesa_error(ctx, GL_INVALID_VALUE, "glGetIntegerIndexedv(index=%u), index", pname); | |||
return; | |||
} | |||
params[0] = INT64_TO_INT(ctx->TransformFeedback.Size[index]); | |||
params[0] = INT64_TO_INT(ctx->TransformFeedback.CurrentObject->Size[index]); | |||
break; | |||
case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: | |||
CHECK_EXT1(EXT_transform_feedback); | |||
@@ -7866,7 +7866,7 @@ _mesa_GetIntegerIndexedv( GLenum pname, GLuint index, GLint *params ) | |||
_mesa_error(ctx, GL_INVALID_VALUE, "glGetIntegerIndexedv(index=%u), index", pname); | |||
return; | |||
} | |||
params[0] = ctx->TransformFeedback.Buffers[index]->Name; | |||
params[0] = ctx->TransformFeedback.CurrentObject->Buffers[index]->Name; | |||
break; | |||
default: | |||
goto invalid_enum_error; | |||
@@ -7915,7 +7915,7 @@ _mesa_GetInteger64Indexedv( GLenum pname, GLuint index, GLint64 *params ) | |||
_mesa_error(ctx, GL_INVALID_VALUE, "glGetInteger64Indexedv(index=%u), index", pname); | |||
return; | |||
} | |||
params[0] = ctx->TransformFeedback.Offset[index]; | |||
params[0] = ctx->TransformFeedback.CurrentObject->Offset[index]; | |||
break; | |||
case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: | |||
CHECK_EXT1(EXT_transform_feedback); | |||
@@ -7923,7 +7923,7 @@ _mesa_GetInteger64Indexedv( GLenum pname, GLuint index, GLint64 *params ) | |||
_mesa_error(ctx, GL_INVALID_VALUE, "glGetInteger64Indexedv(index=%u), index", pname); | |||
return; | |||
} | |||
params[0] = ctx->TransformFeedback.Size[index]; | |||
params[0] = ctx->TransformFeedback.CurrentObject->Size[index]; | |||
break; | |||
case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: | |||
CHECK_EXT1(EXT_transform_feedback); | |||
@@ -7931,7 +7931,7 @@ _mesa_GetInteger64Indexedv( GLenum pname, GLuint index, GLint64 *params ) | |||
_mesa_error(ctx, GL_INVALID_VALUE, "glGetInteger64Indexedv(index=%u), index", pname); | |||
return; | |||
} | |||
params[0] = (GLint64)(ctx->TransformFeedback.Buffers[index]->Name); | |||
params[0] = (GLint64)(ctx->TransformFeedback.CurrentObject->Buffers[index]->Name); | |||
break; | |||
default: | |||
goto invalid_enum_error; |
@@ -1178,15 +1178,15 @@ IndexedStateVars = [ | |||
# GL_EXT_transform_feedback | |||
( "GL_TRANSFORM_FEEDBACK_BUFFER_START", GLint64, | |||
["ctx->TransformFeedback.Offset[index]"], | |||
["ctx->TransformFeedback.CurrentObject->Offset[index]"], | |||
"ctx->Const.MaxTransformFeedbackSeparateAttribs", | |||
NoState, ["EXT_transform_feedback"] ), | |||
( "GL_TRANSFORM_FEEDBACK_BUFFER_SIZE", GLint64, | |||
["ctx->TransformFeedback.Size[index]"], | |||
["ctx->TransformFeedback.CurrentObject->Size[index]"], | |||
"ctx->Const.MaxTransformFeedbackSeparateAttribs", | |||
NoState, ["EXT_transform_feedback"] ), | |||
( "GL_TRANSFORM_FEEDBACK_BUFFER_BINDING", GLint, | |||
["ctx->TransformFeedback.Buffers[index]->Name"], | |||
["ctx->TransformFeedback.CurrentObject->Buffers[index]->Name"], | |||
"ctx->Const.MaxTransformFeedbackSeparateAttribs", | |||
NoState, ["EXT_transform_feedback"] ), | |||
@@ -2034,24 +2034,46 @@ struct gl_shader_state | |||
/** | |||
* Context state for transform feedback. | |||
* Transform feedback object state | |||
*/ | |||
struct gl_transform_feedback | |||
struct gl_transform_feedback_object | |||
{ | |||
GLuint Name; /**< AKA the object ID */ | |||
GLint RefCount; | |||
GLboolean Active; /**< Is transform feedback enabled? */ | |||
GLenum Mode; /**< GL_POINTS, GL_LINES or GL_TRIANGLES */ | |||
GLboolean Paused; /**< Is transform feedback paused? */ | |||
/** The feedback buffers */ | |||
GLuint BufferNames[MAX_FEEDBACK_ATTRIBS]; | |||
struct gl_buffer_object *Buffers[MAX_FEEDBACK_ATTRIBS]; | |||
/** Start of feedback data in dest buffer */ | |||
GLintptr Offset[MAX_FEEDBACK_ATTRIBS]; | |||
/** Max data to put into dest buffer (in bytes) */ | |||
GLsizeiptr Size[MAX_FEEDBACK_ATTRIBS]; | |||
}; | |||
/** | |||
* Context state for transform feedback. | |||
*/ | |||
struct gl_transform_feedback | |||
{ | |||
GLenum Mode; /**< GL_POINTS, GL_LINES or GL_TRIANGLES */ | |||
GLboolean RasterDiscard; /**< GL_RASTERIZER_DISCARD */ | |||
/** The general binding point (GL_TRANSFORM_FEEDBACK_BUFFER) */ | |||
struct gl_buffer_object *CurrentBuffer; | |||
/** The feedback buffers */ | |||
GLuint BufferNames[MAX_FEEDBACK_ATTRIBS]; | |||
struct gl_buffer_object *Buffers[MAX_FEEDBACK_ATTRIBS]; | |||
/** The table of all transform feedback objects */ | |||
struct _mesa_HashTable *Objects; | |||
/** The current xform-fb object (GL_TRANSFORM_FEEDBACK_BINDING) */ | |||
struct gl_transform_feedback_object *CurrentObject; | |||
/** The default xform-fb object (Name==0) */ | |||
struct gl_transform_feedback_object *DefaultObject; | |||
}; | |||
@@ -2480,6 +2502,7 @@ struct gl_extensions | |||
GLboolean ARB_texture_float; | |||
GLboolean ARB_texture_mirrored_repeat; | |||
GLboolean ARB_texture_non_power_of_two; | |||
GLboolean ARB_transform_feedback2; | |||
GLboolean ARB_transpose_matrix; | |||
GLboolean ARB_vertex_array_object; | |||
GLboolean ARB_vertex_buffer_object; |
@@ -33,12 +33,54 @@ | |||
#include "buffers.h" | |||
#include "bufferobj.h" | |||
#include "context.h" | |||
#include "hash.h" | |||
#include "transformfeedback.h" | |||
#include "shader/prog_parameter.h" | |||
#include "shader/shader_api.h" | |||
/** | |||
* Do reference counting of transform feedback buffers. | |||
*/ | |||
static void | |||
reference_transform_feedback_object(struct gl_transform_feedback_object **ptr, | |||
struct gl_transform_feedback_object *obj) | |||
{ | |||
if (*ptr == obj) | |||
return; | |||
if (*ptr) { | |||
/* Unreference the old object */ | |||
struct gl_transform_feedback_object *oldObj = *ptr; | |||
ASSERT(oldObj->RefCount > 0); | |||
oldObj->RefCount--; | |||
if (oldObj->RefCount == 0) { | |||
GET_CURRENT_CONTEXT(ctx); | |||
if (ctx) | |||
ctx->Driver.DeleteTransformFeedback(ctx, oldObj); | |||
} | |||
*ptr = NULL; | |||
} | |||
ASSERT(!*ptr); | |||
if (obj) { | |||
/* reference new object */ | |||
if (obj->RefCount == 0) { | |||
_mesa_problem(NULL, "referencing deleted transform feedback object"); | |||
*ptr = NULL; | |||
} | |||
else { | |||
obj->RefCount++; | |||
*ptr = obj; | |||
} | |||
} | |||
} | |||
/** | |||
* Check if the given primitive mode (as in glBegin(mode)) is compatible | |||
* with the current transform feedback mode (if it's enabled). | |||
@@ -49,7 +91,7 @@ | |||
GLboolean | |||
_mesa_validate_primitive_mode(GLcontext *ctx, GLenum mode) | |||
{ | |||
if (ctx->TransformFeedback.Active) { | |||
if (ctx->TransformFeedback.CurrentObject->Active) { | |||
switch (mode) { | |||
case GL_POINTS: | |||
return ctx->TransformFeedback.Mode == GL_POINTS; | |||
@@ -74,7 +116,7 @@ _mesa_validate_primitive_mode(GLcontext *ctx, GLenum mode) | |||
GLboolean | |||
_mesa_validate_transform_feedback_buffers(GLcontext *ctx) | |||
{ | |||
/* XXX to do */ | |||
return GL_TRUE; | |||
} | |||
@@ -86,29 +128,173 @@ _mesa_validate_transform_feedback_buffers(GLcontext *ctx) | |||
void | |||
_mesa_init_transform_feedback(GLcontext *ctx) | |||
{ | |||
if (!ctx->Driver.NewTransformFeedback) { | |||
/* this feature/extension may not be supported by the driver */ | |||
return; | |||
} | |||
ctx->TransformFeedback.DefaultObject = | |||
ctx->Driver.NewTransformFeedback(ctx, 0); | |||
assert(ctx->TransformFeedback.DefaultObject->RefCount == 1); | |||
reference_transform_feedback_object(&ctx->TransformFeedback.CurrentObject, | |||
ctx->TransformFeedback.DefaultObject); | |||
assert(ctx->TransformFeedback.DefaultObject->RefCount == 2); | |||
ctx->TransformFeedback.Objects = _mesa_NewHashTable(); | |||
_mesa_reference_buffer_object(ctx, | |||
&ctx->TransformFeedback.CurrentBuffer, | |||
ctx->Shared->NullBufferObj); | |||
} | |||
/** | |||
* Callback for _mesa_HashDeleteAll(). | |||
*/ | |||
static void | |||
delete_cb(GLuint key, void *data, void *userData) | |||
{ | |||
GLcontext *ctx = (GLcontext *) userData; | |||
struct gl_transform_feedback_object *obj = | |||
(struct gl_transform_feedback_object *) data; | |||
ctx->Driver.DeleteTransformFeedback(ctx, obj); | |||
} | |||
/** | |||
* Per-context free/clean-up for transform feedback. | |||
*/ | |||
void | |||
_mesa_free_transform_feedback(GLcontext *ctx) | |||
{ | |||
if (!ctx->Driver.NewTransformFeedback) { | |||
/* this feature/extension may not be supported by the driver */ | |||
return; | |||
} | |||
_mesa_reference_buffer_object(ctx, | |||
&ctx->TransformFeedback.CurrentBuffer, | |||
NULL); | |||
/* Delete all feedback objects */ | |||
_mesa_HashDeleteAll(ctx->TransformFeedback.Objects, delete_cb, ctx); | |||
/* Delete the default feedback object */ | |||
assert(ctx->Driver.DeleteTransformFeedback); | |||
ctx->Driver.DeleteTransformFeedback(ctx, ctx->TransformFeedback.DefaultObject); | |||
ctx->TransformFeedback.CurrentObject = NULL; | |||
} | |||
/** Default fallback for ctx->Driver.NewTransformFeedback() */ | |||
static struct gl_transform_feedback_object * | |||
new_transform_feedback(GLcontext *ctx, GLuint name) | |||
{ | |||
struct gl_transform_feedback_object *obj; | |||
obj = CALLOC_STRUCT(gl_transform_feedback_object); | |||
if (obj) { | |||
obj->Name = name; | |||
obj->RefCount = 1; | |||
} | |||
return obj; | |||
} | |||
/** Default fallback for ctx->Driver.DeleteTransformFeedback() */ | |||
static void | |||
delete_transform_feedback(GLcontext *ctx, | |||
struct gl_transform_feedback_object *obj) | |||
{ | |||
GLuint i; | |||
for (i = 0; i < Elements(obj->Buffers); i++) { | |||
_mesa_reference_buffer_object(ctx, &obj->Buffers[i], NULL); | |||
} | |||
free(obj); | |||
} | |||
/** Default fallback for ctx->Driver.BeginTransformFeedback() */ | |||
static void | |||
begin_transform_feedback(GLcontext *ctx, GLenum mode, | |||
struct gl_transform_feedback_object *obj) | |||
{ | |||
/* nop */ | |||
} | |||
/** Default fallback for ctx->Driver.EndTransformFeedback() */ | |||
static void | |||
end_transform_feedback(GLcontext *ctx, | |||
struct gl_transform_feedback_object *obj) | |||
{ | |||
/* nop */ | |||
} | |||
/** Default fallback for ctx->Driver.PauseTransformFeedback() */ | |||
static void | |||
pause_transform_feedback(GLcontext *ctx, | |||
struct gl_transform_feedback_object *obj) | |||
{ | |||
/* nop */ | |||
} | |||
/** Default fallback for ctx->Driver.ResumeTransformFeedback() */ | |||
static void | |||
resume_transform_feedback(GLcontext *ctx, | |||
struct gl_transform_feedback_object *obj) | |||
{ | |||
/* nop */ | |||
} | |||
/** Default fallback for ctx->Driver.DrawTransformFeedback() */ | |||
static void | |||
draw_transform_feedback(GLcontext *ctx, GLenum mode, | |||
struct gl_transform_feedback_object *obj) | |||
{ | |||
/* XXX to do */ | |||
/* | |||
* Get number of vertices in obj's feedback buffer. | |||
* Call ctx->Exec.DrawArrays(mode, 0, count); | |||
*/ | |||
} | |||
/** | |||
* Plug in default device driver functions for transform feedback. | |||
* Most drivers will override some/all of these. | |||
*/ | |||
void | |||
_mesa_init_transform_feedback_functions(struct dd_function_table *driver) | |||
{ | |||
driver->NewTransformFeedback = new_transform_feedback; | |||
driver->DeleteTransformFeedback = delete_transform_feedback; | |||
driver->BeginTransformFeedback = begin_transform_feedback; | |||
driver->EndTransformFeedback = end_transform_feedback; | |||
driver->PauseTransformFeedback = pause_transform_feedback; | |||
driver->ResumeTransformFeedback = resume_transform_feedback; | |||
driver->DrawTransformFeedback = draw_transform_feedback; | |||
} | |||
/** | |||
** Begin API functions | |||
**/ | |||
void GLAPIENTRY | |||
_mesa_BeginTransformFeedback(GLenum mode) | |||
{ | |||
struct gl_transform_feedback_object *obj; | |||
GET_CURRENT_CONTEXT(ctx); | |||
obj = ctx->TransformFeedback.CurrentObject; | |||
switch (mode) { | |||
case GL_POINTS: | |||
case GL_LINES: | |||
@@ -120,29 +306,38 @@ _mesa_BeginTransformFeedback(GLenum mode) | |||
return; | |||
} | |||
if (ctx->TransformFeedback.Active) { | |||
if (obj->Active) { | |||
_mesa_error(ctx, GL_INVALID_OPERATION, | |||
"glBeginTransformFeedback(already active)"); | |||
return; | |||
} | |||
ctx->TransformFeedback.Active = GL_TRUE; | |||
obj->Active = GL_TRUE; | |||
ctx->TransformFeedback.Mode = mode; | |||
assert(ctx->Driver.BeginTransformFeedback); | |||
ctx->Driver.BeginTransformFeedback(ctx, mode, obj); | |||
} | |||
void GLAPIENTRY | |||
_mesa_EndTransformFeedback(void) | |||
{ | |||
struct gl_transform_feedback_object *obj; | |||
GET_CURRENT_CONTEXT(ctx); | |||
if (!ctx->TransformFeedback.Active) { | |||
obj = ctx->TransformFeedback.CurrentObject; | |||
if (!obj->Active) { | |||
_mesa_error(ctx, GL_INVALID_OPERATION, | |||
"glEndTransformFeedback(not active)"); | |||
return; | |||
} | |||
ctx->TransformFeedback.Active = GL_FALSE; | |||
ctx->TransformFeedback.CurrentObject->Active = GL_FALSE; | |||
assert(ctx->Driver.EndTransformFeedback); | |||
ctx->Driver.EndTransformFeedback(ctx, obj); | |||
} | |||
@@ -154,6 +349,9 @@ bind_buffer_range(GLcontext *ctx, GLuint index, | |||
struct gl_buffer_object *bufObj, | |||
GLintptr offset, GLsizeiptr size) | |||
{ | |||
struct gl_transform_feedback_object *obj = | |||
ctx->TransformFeedback.CurrentObject; | |||
/* The general binding point */ | |||
_mesa_reference_buffer_object(ctx, | |||
&ctx->TransformFeedback.CurrentBuffer, | |||
@@ -161,13 +359,13 @@ bind_buffer_range(GLcontext *ctx, GLuint index, | |||
/* The per-attribute binding point */ | |||
_mesa_reference_buffer_object(ctx, | |||
&ctx->TransformFeedback.Buffers[index], | |||
&obj->Buffers[index], | |||
bufObj); | |||
ctx->TransformFeedback.BufferNames[index] = bufObj->Name; | |||
obj->BufferNames[index] = bufObj->Name; | |||
ctx->TransformFeedback.Offset[index] = offset; | |||
ctx->TransformFeedback.Size[index] = size; | |||
obj->Offset[index] = offset; | |||
obj->Size[index] = size; | |||
} | |||
@@ -179,6 +377,7 @@ void GLAPIENTRY | |||
_mesa_BindBufferRange(GLenum target, GLuint index, | |||
GLuint buffer, GLintptr offset, GLsizeiptr size) | |||
{ | |||
struct gl_transform_feedback_object *obj; | |||
struct gl_buffer_object *bufObj; | |||
GET_CURRENT_CONTEXT(ctx); | |||
@@ -187,7 +386,9 @@ _mesa_BindBufferRange(GLenum target, GLuint index, | |||
return; | |||
} | |||
if (ctx->TransformFeedback.Active) { | |||
obj = ctx->TransformFeedback.CurrentObject; | |||
if (obj->Active) { | |||
_mesa_error(ctx, GL_INVALID_OPERATION, | |||
"glBindBufferRange(transform feedback active)"); | |||
return; | |||
@@ -235,16 +436,19 @@ _mesa_BindBufferRange(GLenum target, GLuint index, | |||
void GLAPIENTRY | |||
_mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer) | |||
{ | |||
struct gl_transform_feedback_object *obj; | |||
struct gl_buffer_object *bufObj; | |||
GET_CURRENT_CONTEXT(ctx); | |||
GLsizeiptr size; | |||
GET_CURRENT_CONTEXT(ctx); | |||
if (target != GL_TRANSFORM_FEEDBACK_BUFFER) { | |||
_mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferBase(target)"); | |||
return; | |||
} | |||
if (ctx->TransformFeedback.Active) { | |||
obj = ctx->TransformFeedback.CurrentObject; | |||
if (obj->Active) { | |||
_mesa_error(ctx, GL_INVALID_OPERATION, | |||
"glBindBufferRange(transform feedback active)"); | |||
return; | |||
@@ -280,6 +484,7 @@ 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); | |||
GLsizeiptr size; | |||
@@ -289,7 +494,9 @@ _mesa_BindBufferOffsetEXT(GLenum target, GLuint index, GLuint buffer, | |||
return; | |||
} | |||
if (ctx->TransformFeedback.Active) { | |||
obj = ctx->TransformFeedback.CurrentObject; | |||
if (obj->Active) { | |||
_mesa_error(ctx, GL_INVALID_OPERATION, | |||
"glBindBufferRange(transform feedback active)"); | |||
return; | |||
@@ -433,3 +640,242 @@ _mesa_GetTransformFeedbackVarying(GLuint program, GLuint index, | |||
} | |||
} | |||
static struct gl_transform_feedback_object * | |||
lookup_transform_feedback_object(GLcontext *ctx, GLuint name) | |||
{ | |||
if (name == 0) { | |||
return ctx->TransformFeedback.DefaultObject; | |||
} | |||
else | |||
return (struct gl_transform_feedback_object *) | |||
_mesa_HashLookup(ctx->TransformFeedback.Objects, name); | |||
} | |||
/** | |||
* Create new transform feedback objects. Transform feedback objects | |||
* encapsulate the state related to transform feedback to allow quickly | |||
* switching state (and drawing the results, below). | |||
* Part of GL_ARB_transform_feedback2. | |||
*/ | |||
void GLAPIENTRY | |||
_mesa_GenTransformFeedbacks(GLsizei n, GLuint *names) | |||
{ | |||
GLuint first; | |||
GET_CURRENT_CONTEXT(ctx); | |||
ASSERT_OUTSIDE_BEGIN_END(ctx); | |||
if (n < 0) { | |||
_mesa_error(ctx, GL_INVALID_VALUE, "glGenTransformFeedbacks(n < 0)"); | |||
return; | |||
} | |||
if (!names) | |||
return; | |||
/* we don't need contiguous IDs, but this might be faster */ | |||
first = _mesa_HashFindFreeKeyBlock(ctx->TransformFeedback.Objects, n); | |||
if (first) { | |||
GLsizei i; | |||
for (i = 0; i < n; i++) { | |||
struct gl_transform_feedback_object *obj | |||
= ctx->Driver.NewTransformFeedback(ctx, first + i); | |||
if (!obj) { | |||
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTransformFeedbacks"); | |||
return; | |||
} | |||
names[i] = first + i; | |||
_mesa_HashInsert(ctx->TransformFeedback.Objects, first + i, obj); | |||
} | |||
} | |||
else { | |||
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTransformFeedbacks"); | |||
} | |||
} | |||
/** | |||
* Is the given ID a transform feedback object? | |||
* Part of GL_ARB_transform_feedback2. | |||
*/ | |||
GLboolean GLAPIENTRY | |||
_mesa_IsTransformFeedback(GLuint name) | |||
{ | |||
GET_CURRENT_CONTEXT(ctx); | |||
ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); | |||
if (name && lookup_transform_feedback_object(ctx, name)) | |||
return GL_TRUE; | |||
else | |||
return GL_FALSE; | |||
} | |||
/** | |||
* Bind the given transform feedback object. | |||
* Part of GL_ARB_transform_feedback2. | |||
*/ | |||
void GLAPIENTRY | |||
_mesa_BindTransformFeedback(GLenum target, uint name) | |||
{ | |||
struct gl_transform_feedback_object *obj; | |||
GET_CURRENT_CONTEXT(ctx); | |||
if (target != GL_TRANSFORM_FEEDBACK) { | |||
_mesa_error(ctx, GL_INVALID_ENUM, "glBindTransformFeedback(target)"); | |||
return; | |||
} | |||
if (ctx->TransformFeedback.CurrentObject->Active && | |||
!ctx->TransformFeedback.CurrentObject->Paused) { | |||
_mesa_error(ctx, GL_INVALID_OPERATION, | |||
"glBindTransformFeedback(transform is active, or not paused)"); | |||
return; | |||
} | |||
obj = lookup_transform_feedback_object(ctx, name); | |||
if (!obj) { | |||
_mesa_error(ctx, GL_INVALID_OPERATION, | |||
"glBindTransformFeedback(name=%u)", name); | |||
return; | |||
} | |||
reference_transform_feedback_object(&ctx->TransformFeedback.CurrentObject, | |||
obj); | |||
} | |||
/** | |||
* Delete the given transform feedback objects. | |||
* Part of GL_ARB_transform_feedback2. | |||
*/ | |||
void GLAPIENTRY | |||
_mesa_DeleteTransformFeedbacks(GLsizei n, const GLuint *names) | |||
{ | |||
GLint i; | |||
GET_CURRENT_CONTEXT(ctx); | |||
ASSERT_OUTSIDE_BEGIN_END(ctx); | |||
if (n < 0) { | |||
_mesa_error(ctx, GL_INVALID_VALUE, "glDeleteTransformFeedbacks(n < 0)"); | |||
return; | |||
} | |||
if (!names) | |||
return; | |||
for (i = 0; i < n; i++) { | |||
if (names[i] > 0) { | |||
struct gl_transform_feedback_object *obj | |||
= lookup_transform_feedback_object(ctx, names[i]); | |||
if (obj) { | |||
if (obj->Active) { | |||
_mesa_error(ctx, GL_INVALID_OPERATION, | |||
"glDeleteTransformFeedbacks(object %u is active)", | |||
names[i]); | |||
return; | |||
} | |||
_mesa_HashRemove(ctx->TransformFeedback.Objects, names[i]); | |||
/* unref, but object may not be deleted until later */ | |||
reference_transform_feedback_object(&obj, NULL); | |||
} | |||
} | |||
} | |||
} | |||
/** | |||
* Pause transform feedback. | |||
* Part of GL_ARB_transform_feedback2. | |||
*/ | |||
void GLAPIENTRY | |||
_mesa_PauseTransformFeedback(void) | |||
{ | |||
struct gl_transform_feedback_object *obj; | |||
GET_CURRENT_CONTEXT(ctx); | |||
obj = ctx->TransformFeedback.CurrentObject; | |||
if (!obj->Active || obj->Paused) { | |||
_mesa_error(ctx, GL_INVALID_OPERATION, | |||
"glPauseTransformFeedback(feedback not active or already paused)"); | |||
return; | |||
} | |||
obj->Paused = GL_TRUE; | |||
assert(ctx->Driver.PauseTransformFeedback); | |||
ctx->Driver.PauseTransformFeedback(ctx, obj); | |||
} | |||
/** | |||
* Resume transform feedback. | |||
* Part of GL_ARB_transform_feedback2. | |||
*/ | |||
void GLAPIENTRY | |||
_mesa_ResumeTransformFeedback(void) | |||
{ | |||
struct gl_transform_feedback_object *obj; | |||
GET_CURRENT_CONTEXT(ctx); | |||
obj = ctx->TransformFeedback.CurrentObject; | |||
if (!obj->Active || !obj->Paused) { | |||
_mesa_error(ctx, GL_INVALID_OPERATION, | |||
"glPauseTransformFeedback(feedback not active or not paused)"); | |||
return; | |||
} | |||
obj->Paused = GL_FALSE; | |||
assert(ctx->Driver.ResumeTransformFeedback); | |||
ctx->Driver.ResumeTransformFeedback(ctx, obj); | |||
} | |||
/** | |||
* Draw the vertex data in a transform feedback object. | |||
* \param mode GL_POINTS, GL_LINES, GL_TRIANGLE_STRIP, etc. | |||
* \param name the transform feedback object | |||
* The number of vertices comes from the transform feedback object. | |||
* User still has to setup of the vertex attribute info with | |||
* glVertexPointer, glColorPointer, etc. | |||
* Part of GL_ARB_transform_feedback2. | |||
*/ | |||
void GLAPIENTRY | |||
_mesa_DrawTransformFeedback(GLenum mode, GLuint name) | |||
{ | |||
GET_CURRENT_CONTEXT(ctx); | |||
struct gl_transform_feedback_object *obj = | |||
lookup_transform_feedback_object(ctx, name); | |||
if (!obj) { | |||
_mesa_error(ctx, GL_INVALID_VALUE, | |||
"glDrawTransformFeedback(name = %u)", name); | |||
return; | |||
} | |||
/* XXX check if EndTransformFeedback has never been called while | |||
* the object was bound | |||
*/ | |||
assert(ctx->Driver.DrawTransformFeedback); | |||
ctx->Driver.DrawTransformFeedback(ctx, mode, obj); | |||
} | |||
/* | |||
XXX misc to do: | |||
glGet*() for | |||
GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED | |||
GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE | |||
GL_TRANSFORM_FEEDBACK_BINDING | |||
*/ |
@@ -41,6 +41,12 @@ extern void | |||
_mesa_free_transform_feedback(GLcontext *ctx); | |||
extern void | |||
_mesa_init_transform_feedback_functions(struct dd_function_table *driver); | |||
/*** GL_EXT_transform_feedback ***/ | |||
extern void GLAPIENTRY | |||
_mesa_BeginTransformFeedback(GLenum mode); | |||
@@ -68,4 +74,29 @@ _mesa_GetTransformFeedbackVarying(GLuint program, GLuint index, | |||
GLsizei *size, GLenum *type, GLchar *name); | |||
/*** GL_ARB_transform_feedback2 ***/ | |||
extern void GLAPIENTRY | |||
_mesa_GenTransformFeedbacks(GLsizei n, GLuint *names); | |||
extern GLboolean GLAPIENTRY | |||
_mesa_IsTransformFeedback(GLuint name); | |||
extern void GLAPIENTRY | |||
_mesa_BindTransformFeedback(GLenum target, uint name); | |||
extern void GLAPIENTRY | |||
_mesa_DeleteTransformFeedbacks(GLsizei n, const GLuint *names); | |||
extern void GLAPIENTRY | |||
_mesa_PauseTransformFeedback(void); | |||
extern void GLAPIENTRY | |||
_mesa_ResumeTransformFeedback(void); | |||
extern void GLAPIENTRY | |||
_mesa_DrawTransformFeedback(GLenum mode, GLuint name); | |||
#endif /* TRANSFORM_FEEDBACK_H */ |
@@ -1517,12 +1517,14 @@ static void | |||
_mesa_link_program(GLcontext *ctx, GLuint program) | |||
{ | |||
struct gl_shader_program *shProg; | |||
struct gl_transform_feedback_object *obj = | |||
ctx->TransformFeedback.CurrentObject; | |||
shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram"); | |||
if (!shProg) | |||
return; | |||
if (ctx->TransformFeedback.Active && shProg == ctx->Shader.CurrentProgram) { | |||
if (obj->Active && shProg == ctx->Shader.CurrentProgram) { | |||
_mesa_error(ctx, GL_INVALID_OPERATION, | |||
"glLinkProgram(transform feedback active"); | |||
return; | |||
@@ -1591,8 +1593,10 @@ void | |||
_mesa_use_program(GLcontext *ctx, GLuint program) | |||
{ | |||
struct gl_shader_program *shProg; | |||
struct gl_transform_feedback_object *obj = | |||
ctx->TransformFeedback.CurrentObject; | |||
if (ctx->TransformFeedback.Active) { | |||
if (obj->Active) { | |||
_mesa_error(ctx, GL_INVALID_OPERATION, | |||
"glUseProgram(transform feedback active)"); | |||
return; |
@@ -210,6 +210,7 @@ STATETRACKER_SOURCES = \ | |||
state_tracker/st_cb_readpixels.c \ | |||
state_tracker/st_cb_strings.c \ | |||
state_tracker/st_cb_texture.c \ | |||
state_tracker/st_cb_xformfb.c \ | |||
state_tracker/st_context.c \ | |||
state_tracker/st_debug.c \ | |||
state_tracker/st_draw.c \ |
@@ -0,0 +1,129 @@ | |||
/************************************************************************** | |||
* | |||
* Copyright 2010 VMware, Inc. | |||
* All Rights Reserved. | |||
* | |||
* Permission is hereby granted, free of charge, to any person obtaining a | |||
* copy of this software and associated documentation files (the | |||
* "Software"), to deal in the Software without restriction, including | |||
* without limitation the rights to use, copy, modify, merge, publish, | |||
* distribute, sub license, and/or sell copies of the Software, and to | |||
* permit persons to whom the Software is furnished to do so, subject to | |||
* the following conditions: | |||
* | |||
* The above copyright notice and this permission notice (including the | |||
* next paragraph) shall be included in all copies or substantial portions | |||
* of the Software. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. | |||
* IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR | |||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | |||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
* | |||
**************************************************************************/ | |||
/** | |||
* Transform feedback functions. | |||
* | |||
* \author Brian Paul | |||
*/ | |||
#include "main/imports.h" | |||
#include "main/context.h" | |||
#include "main/transformfeedback.h" | |||
#include "st_cb_xformfb.h" | |||
#if 0 | |||
static struct gl_transform_feedback_object * | |||
st_new_transform_feedback(GLcontext *ctx, GLuint name) | |||
{ | |||
struct gl_transform_feedback_object *obj; | |||
obj = CALLOC_STRUCT(gl_transform_feedback_object); | |||
if (obj) { | |||
obj->Name = name; | |||
obj->RefCount = 1; | |||
} | |||
return obj; | |||
} | |||
#endif | |||
#if 0 | |||
static void | |||
st_delete_transform_feedback(GLcontext *ctx, | |||
struct gl_transform_feedback_object *obj) | |||
{ | |||
GLuint i; | |||
for (i = 0; i < Elements(obj->Buffers); i++) { | |||
_mesa_reference_buffer_object(ctx, &obj->Buffers[i], NULL); | |||
} | |||
free(obj); | |||
} | |||
#endif | |||
static void | |||
st_begin_transform_feedback(GLcontext *ctx, GLenum mode, | |||
struct gl_transform_feedback_object *obj) | |||
{ | |||
/* to-do */ | |||
} | |||
static void | |||
st_end_transform_feedback(GLcontext *ctx, | |||
struct gl_transform_feedback_object *obj) | |||
{ | |||
/* to-do */ | |||
} | |||
static void | |||
st_pause_transform_feedback(GLcontext *ctx, | |||
struct gl_transform_feedback_object *obj) | |||
{ | |||
/* to-do */ | |||
} | |||
static void | |||
st_resume_transform_feedback(GLcontext *ctx, | |||
struct gl_transform_feedback_object *obj) | |||
{ | |||
/* to-do */ | |||
} | |||
static void | |||
st_draw_transform_feedback(GLcontext *ctx, GLenum mode, | |||
struct gl_transform_feedback_object *obj) | |||
{ | |||
/* XXX to do */ | |||
/* | |||
* Get number of vertices in obj's feedback buffer. | |||
* Call ctx->Exec.DrawArrays(mode, 0, count); | |||
*/ | |||
} | |||
void | |||
st_init_xformfb_functions(struct dd_function_table *functions) | |||
{ | |||
/* let core Mesa plug in its functions */ | |||
_mesa_init_transform_feedback_functions(functions); | |||
/* then override a few: */ | |||
functions->BeginTransformFeedback = st_begin_transform_feedback; | |||
functions->EndTransformFeedback = st_end_transform_feedback; | |||
functions->PauseTransformFeedback = st_pause_transform_feedback; | |||
functions->ResumeTransformFeedback = st_resume_transform_feedback; | |||
functions->DrawTransformFeedback = st_draw_transform_feedback; | |||
} |
@@ -0,0 +1,36 @@ | |||
/************************************************************************** | |||
* | |||
* Copyright 2010 VMware, Inc. | |||
* All Rights Reserved. | |||
* | |||
* Permission is hereby granted, free of charge, to any person obtaining a | |||
* copy of this software and associated documentation files (the | |||
* "Software"), to deal in the Software without restriction, including | |||
* without limitation the rights to use, copy, modify, merge, publish, | |||
* distribute, sub license, and/or sell copies of the Software, and to | |||
* permit persons to whom the Software is furnished to do so, subject to | |||
* the following conditions: | |||
* | |||
* The above copyright notice and this permission notice (including the | |||
* next paragraph) shall be included in all copies or substantial portions | |||
* of the Software. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. | |||
* IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR | |||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | |||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
* | |||
**************************************************************************/ | |||
#ifndef ST_CB_XFORMFB_H | |||
#define ST_CB_XFORMFB_H | |||
extern void | |||
st_init_xformfb_functions(struct dd_function_table *functions); | |||
#endif /* ST_CB_XFORMFB_H */ |
@@ -54,6 +54,9 @@ | |||
#include "st_cb_queryobj.h" | |||
#include "st_cb_readpixels.h" | |||
#include "st_cb_texture.h" | |||
#if FEATURE_EXT_transform_feedback | |||
#include "st_cb_xformfb.h" | |||
#endif | |||
#include "st_cb_flush.h" | |||
#include "st_cb_strings.h" | |||
#include "st_atom.h" | |||
@@ -335,5 +338,9 @@ void st_init_driver_functions(struct dd_function_table *functions) | |||
st_init_flush_functions(functions); | |||
st_init_string_functions(functions); | |||
#if FEATURE_EXT_transform_feedback | |||
st_init_xformfb_functions(functions); | |||
#endif | |||
functions->UpdateState = st_invalidate_state; | |||
} |