1848b8605Smrg/* 2848b8605Smrg * Mesa 3-D graphics library 3848b8605Smrg * 4848b8605Smrg * Copyright (C) 2010 VMware, Inc. All Rights Reserved. 5848b8605Smrg * 6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7848b8605Smrg * copy of this software and associated documentation files (the "Software"), 8848b8605Smrg * to deal in the Software without restriction, including without limitation 9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 11848b8605Smrg * Software is furnished to do so, subject to the following conditions: 12848b8605Smrg * 13848b8605Smrg * The above copyright notice and this permission notice shall be included 14848b8605Smrg * in all copies or substantial portions of the Software. 15848b8605Smrg * 16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 23848b8605Smrg */ 24848b8605Smrg 25848b8605Smrg 26848b8605Smrg/* 27848b8605Smrg * Transform feedback support. 28848b8605Smrg * 29848b8605Smrg * Authors: 30848b8605Smrg * Brian Paul 31848b8605Smrg */ 32848b8605Smrg 33848b8605Smrg 34848b8605Smrg#include "buffers.h" 35848b8605Smrg#include "context.h" 36848b8605Smrg#include "hash.h" 37848b8605Smrg#include "macros.h" 38848b8605Smrg#include "mtypes.h" 39848b8605Smrg#include "transformfeedback.h" 40848b8605Smrg#include "shaderapi.h" 41848b8605Smrg#include "shaderobj.h" 42848b8605Smrg 43b8e80941Smrg#include "program/program.h" 44848b8605Smrg#include "program/prog_parameter.h" 45848b8605Smrg 46848b8605Smrgstruct using_program_tuple 47848b8605Smrg{ 48b8e80941Smrg struct gl_program *prog; 49848b8605Smrg bool found; 50848b8605Smrg}; 51848b8605Smrg 52848b8605Smrgstatic void 53848b8605Smrgactive_xfb_object_references_program(GLuint key, void *data, void *user_data) 54848b8605Smrg{ 55848b8605Smrg struct using_program_tuple *callback_data = user_data; 56848b8605Smrg struct gl_transform_feedback_object *obj = data; 57b8e80941Smrg if (obj->Active && obj->program == callback_data->prog) 58848b8605Smrg callback_data->found = true; 59848b8605Smrg} 60848b8605Smrg 61848b8605Smrg/** 62848b8605Smrg * Return true if any active transform feedback object is using a program. 63848b8605Smrg */ 64848b8605Smrgbool 65848b8605Smrg_mesa_transform_feedback_is_using_program(struct gl_context *ctx, 66848b8605Smrg struct gl_shader_program *shProg) 67848b8605Smrg{ 68b8e80941Smrg if (!shProg->last_vert_prog) 69b8e80941Smrg return false; 70b8e80941Smrg 71848b8605Smrg struct using_program_tuple callback_data; 72848b8605Smrg callback_data.found = false; 73b8e80941Smrg callback_data.prog = shProg->last_vert_prog; 74848b8605Smrg 75b8e80941Smrg _mesa_HashWalkLocked(ctx->TransformFeedback.Objects, 76b8e80941Smrg active_xfb_object_references_program, &callback_data); 77848b8605Smrg 78848b8605Smrg /* Also check DefaultObject, as it's not in the Objects hash table. */ 79848b8605Smrg active_xfb_object_references_program(0, ctx->TransformFeedback.DefaultObject, 80848b8605Smrg &callback_data); 81848b8605Smrg 82848b8605Smrg return callback_data.found; 83848b8605Smrg} 84848b8605Smrg 85848b8605Smrg/** 86848b8605Smrg * Do reference counting of transform feedback buffers. 87848b8605Smrg */ 88848b8605Smrgstatic void 89848b8605Smrgreference_transform_feedback_object(struct gl_transform_feedback_object **ptr, 90848b8605Smrg struct gl_transform_feedback_object *obj) 91848b8605Smrg{ 92848b8605Smrg if (*ptr == obj) 93848b8605Smrg return; 94848b8605Smrg 95848b8605Smrg if (*ptr) { 96848b8605Smrg /* Unreference the old object */ 97848b8605Smrg struct gl_transform_feedback_object *oldObj = *ptr; 98848b8605Smrg 99b8e80941Smrg assert(oldObj->RefCount > 0); 100848b8605Smrg oldObj->RefCount--; 101848b8605Smrg 102848b8605Smrg if (oldObj->RefCount == 0) { 103848b8605Smrg GET_CURRENT_CONTEXT(ctx); 104848b8605Smrg if (ctx) 105848b8605Smrg ctx->Driver.DeleteTransformFeedback(ctx, oldObj); 106848b8605Smrg } 107848b8605Smrg 108848b8605Smrg *ptr = NULL; 109848b8605Smrg } 110b8e80941Smrg assert(!*ptr); 111848b8605Smrg 112848b8605Smrg if (obj) { 113b8e80941Smrg assert(obj->RefCount > 0); 114b8e80941Smrg 115848b8605Smrg /* reference new object */ 116b8e80941Smrg obj->RefCount++; 117b8e80941Smrg obj->EverBound = GL_TRUE; 118b8e80941Smrg *ptr = obj; 119848b8605Smrg } 120848b8605Smrg} 121848b8605Smrg 122848b8605Smrg 123848b8605Smrg/** 124848b8605Smrg * Per-context init for transform feedback. 125848b8605Smrg */ 126848b8605Smrgvoid 127848b8605Smrg_mesa_init_transform_feedback(struct gl_context *ctx) 128848b8605Smrg{ 129848b8605Smrg /* core mesa expects this, even a dummy one, to be available */ 130b8e80941Smrg assert(ctx->Driver.NewTransformFeedback); 131848b8605Smrg 132848b8605Smrg ctx->TransformFeedback.DefaultObject = 133848b8605Smrg ctx->Driver.NewTransformFeedback(ctx, 0); 134848b8605Smrg 135848b8605Smrg assert(ctx->TransformFeedback.DefaultObject->RefCount == 1); 136848b8605Smrg 137848b8605Smrg reference_transform_feedback_object(&ctx->TransformFeedback.CurrentObject, 138848b8605Smrg ctx->TransformFeedback.DefaultObject); 139848b8605Smrg 140848b8605Smrg assert(ctx->TransformFeedback.DefaultObject->RefCount == 2); 141848b8605Smrg 142848b8605Smrg ctx->TransformFeedback.Objects = _mesa_NewHashTable(); 143848b8605Smrg 144848b8605Smrg _mesa_reference_buffer_object(ctx, 145848b8605Smrg &ctx->TransformFeedback.CurrentBuffer, 146848b8605Smrg ctx->Shared->NullBufferObj); 147848b8605Smrg} 148848b8605Smrg 149848b8605Smrg 150848b8605Smrg 151848b8605Smrg/** 152848b8605Smrg * Callback for _mesa_HashDeleteAll(). 153848b8605Smrg */ 154848b8605Smrgstatic void 155848b8605Smrgdelete_cb(GLuint key, void *data, void *userData) 156848b8605Smrg{ 157848b8605Smrg struct gl_context *ctx = (struct gl_context *) userData; 158848b8605Smrg struct gl_transform_feedback_object *obj = 159848b8605Smrg (struct gl_transform_feedback_object *) data; 160848b8605Smrg 161848b8605Smrg ctx->Driver.DeleteTransformFeedback(ctx, obj); 162848b8605Smrg} 163848b8605Smrg 164848b8605Smrg 165848b8605Smrg/** 166848b8605Smrg * Per-context free/clean-up for transform feedback. 167848b8605Smrg */ 168848b8605Smrgvoid 169848b8605Smrg_mesa_free_transform_feedback(struct gl_context *ctx) 170848b8605Smrg{ 171848b8605Smrg /* core mesa expects this, even a dummy one, to be available */ 172b8e80941Smrg assert(ctx->Driver.NewTransformFeedback); 173848b8605Smrg 174848b8605Smrg _mesa_reference_buffer_object(ctx, 175848b8605Smrg &ctx->TransformFeedback.CurrentBuffer, 176848b8605Smrg NULL); 177848b8605Smrg 178848b8605Smrg /* Delete all feedback objects */ 179848b8605Smrg _mesa_HashDeleteAll(ctx->TransformFeedback.Objects, delete_cb, ctx); 180848b8605Smrg _mesa_DeleteHashTable(ctx->TransformFeedback.Objects); 181848b8605Smrg 182848b8605Smrg /* Delete the default feedback object */ 183848b8605Smrg assert(ctx->Driver.DeleteTransformFeedback); 184848b8605Smrg ctx->Driver.DeleteTransformFeedback(ctx, 185848b8605Smrg ctx->TransformFeedback.DefaultObject); 186848b8605Smrg 187848b8605Smrg ctx->TransformFeedback.CurrentObject = NULL; 188848b8605Smrg} 189848b8605Smrg 190848b8605Smrg 191848b8605Smrg/** Initialize the fields of a gl_transform_feedback_object. */ 192848b8605Smrgvoid 193848b8605Smrg_mesa_init_transform_feedback_object(struct gl_transform_feedback_object *obj, 194848b8605Smrg GLuint name) 195848b8605Smrg{ 196848b8605Smrg obj->Name = name; 197848b8605Smrg obj->RefCount = 1; 198848b8605Smrg obj->EverBound = GL_FALSE; 199848b8605Smrg} 200848b8605Smrg 201848b8605Smrg 202848b8605Smrg/** Default fallback for ctx->Driver.NewTransformFeedback() */ 203848b8605Smrgstatic struct gl_transform_feedback_object * 204b8e80941Smrgnew_transform_feedback_fallback(struct gl_context *ctx, GLuint name) 205848b8605Smrg{ 206848b8605Smrg struct gl_transform_feedback_object *obj; 207b8e80941Smrg 208848b8605Smrg obj = CALLOC_STRUCT(gl_transform_feedback_object); 209b8e80941Smrg if (!obj) 210b8e80941Smrg return NULL; 211b8e80941Smrg 212848b8605Smrg _mesa_init_transform_feedback_object(obj, name); 213848b8605Smrg return obj; 214848b8605Smrg} 215848b8605Smrg 216848b8605Smrg/** Default fallback for ctx->Driver.DeleteTransformFeedback() */ 217848b8605Smrgstatic void 218b8e80941Smrgdelete_transform_feedback_fallback(struct gl_context *ctx, 219b8e80941Smrg struct gl_transform_feedback_object *obj) 220848b8605Smrg{ 221848b8605Smrg GLuint i; 222848b8605Smrg 223b8e80941Smrg for (i = 0; i < ARRAY_SIZE(obj->Buffers); i++) { 224848b8605Smrg _mesa_reference_buffer_object(ctx, &obj->Buffers[i], NULL); 225848b8605Smrg } 226848b8605Smrg 227848b8605Smrg free(obj->Label); 228848b8605Smrg free(obj); 229848b8605Smrg} 230848b8605Smrg 231848b8605Smrg 232848b8605Smrg/** Default fallback for ctx->Driver.BeginTransformFeedback() */ 233848b8605Smrgstatic void 234b8e80941Smrgbegin_transform_feedback_fallback(struct gl_context *ctx, GLenum mode, 235b8e80941Smrg struct gl_transform_feedback_object *obj) 236848b8605Smrg{ 237848b8605Smrg /* nop */ 238848b8605Smrg} 239848b8605Smrg 240848b8605Smrg/** Default fallback for ctx->Driver.EndTransformFeedback() */ 241848b8605Smrgstatic void 242b8e80941Smrgend_transform_feedback_fallback(struct gl_context *ctx, 243b8e80941Smrg struct gl_transform_feedback_object *obj) 244848b8605Smrg{ 245848b8605Smrg /* nop */ 246848b8605Smrg} 247848b8605Smrg 248848b8605Smrg/** Default fallback for ctx->Driver.PauseTransformFeedback() */ 249848b8605Smrgstatic void 250b8e80941Smrgpause_transform_feedback_fallback(struct gl_context *ctx, 251b8e80941Smrg struct gl_transform_feedback_object *obj) 252848b8605Smrg{ 253848b8605Smrg /* nop */ 254848b8605Smrg} 255848b8605Smrg 256848b8605Smrg/** Default fallback for ctx->Driver.ResumeTransformFeedback() */ 257848b8605Smrgstatic void 258b8e80941Smrgresume_transform_feedback_fallback(struct gl_context *ctx, 259b8e80941Smrg struct gl_transform_feedback_object *obj) 260848b8605Smrg{ 261848b8605Smrg /* nop */ 262848b8605Smrg} 263848b8605Smrg 264848b8605Smrg 265848b8605Smrg/** 266848b8605Smrg * Plug in default device driver functions for transform feedback. 267848b8605Smrg * Most drivers will override some/all of these. 268848b8605Smrg */ 269848b8605Smrgvoid 270848b8605Smrg_mesa_init_transform_feedback_functions(struct dd_function_table *driver) 271848b8605Smrg{ 272b8e80941Smrg driver->NewTransformFeedback = new_transform_feedback_fallback; 273b8e80941Smrg driver->DeleteTransformFeedback = delete_transform_feedback_fallback; 274b8e80941Smrg driver->BeginTransformFeedback = begin_transform_feedback_fallback; 275b8e80941Smrg driver->EndTransformFeedback = end_transform_feedback_fallback; 276b8e80941Smrg driver->PauseTransformFeedback = pause_transform_feedback_fallback; 277b8e80941Smrg driver->ResumeTransformFeedback = resume_transform_feedback_fallback; 278848b8605Smrg} 279848b8605Smrg 280848b8605Smrg 281848b8605Smrg/** 282848b8605Smrg * Fill in the correct Size value for each buffer in \c obj. 283848b8605Smrg * 284848b8605Smrg * From the GL 4.3 spec, section 6.1.1 ("Binding Buffer Objects to Indexed 285848b8605Smrg * Targets"): 286848b8605Smrg * 287848b8605Smrg * BindBufferBase binds the entire buffer, even when the size of the buffer 288848b8605Smrg * is changed after the binding is established. It is equivalent to calling 289848b8605Smrg * BindBufferRange with offset zero, while size is determined by the size of 290848b8605Smrg * the bound buffer at the time the binding is used. 291848b8605Smrg * 292848b8605Smrg * Regardless of the size specified with BindBufferRange, or indirectly with 293848b8605Smrg * BindBufferBase, the GL will never read or write beyond the end of a bound 294848b8605Smrg * buffer. In some cases this constraint may result in visibly different 295848b8605Smrg * behavior when a buffer overflow would otherwise result, such as described 296848b8605Smrg * for transform feedback operations in section 13.2.2. 297848b8605Smrg */ 298848b8605Smrgstatic void 299848b8605Smrgcompute_transform_feedback_buffer_sizes( 300848b8605Smrg struct gl_transform_feedback_object *obj) 301848b8605Smrg{ 302848b8605Smrg unsigned i = 0; 303848b8605Smrg for (i = 0; i < MAX_FEEDBACK_BUFFERS; ++i) { 304848b8605Smrg GLintptr offset = obj->Offset[i]; 305848b8605Smrg GLsizeiptr buffer_size 306848b8605Smrg = obj->Buffers[i] == NULL ? 0 : obj->Buffers[i]->Size; 307848b8605Smrg GLsizeiptr available_space 308848b8605Smrg = buffer_size <= offset ? 0 : buffer_size - offset; 309848b8605Smrg GLsizeiptr computed_size; 310848b8605Smrg if (obj->RequestedSize[i] == 0) { 311848b8605Smrg /* No size was specified at the time the buffer was bound, so allow 312848b8605Smrg * writing to all available space in the buffer. 313848b8605Smrg */ 314848b8605Smrg computed_size = available_space; 315848b8605Smrg } else { 316848b8605Smrg /* A size was specified at the time the buffer was bound, however 317848b8605Smrg * it's possible that the buffer has shrunk since then. So only 318848b8605Smrg * allow writing to the minimum of the specified size and the space 319848b8605Smrg * available. 320848b8605Smrg */ 321848b8605Smrg computed_size = MIN2(available_space, obj->RequestedSize[i]); 322848b8605Smrg } 323848b8605Smrg 324848b8605Smrg /* Legal sizes must be multiples of four, so round down if necessary. */ 325848b8605Smrg obj->Size[i] = computed_size & ~0x3; 326848b8605Smrg } 327848b8605Smrg} 328848b8605Smrg 329848b8605Smrg 330848b8605Smrg/** 331848b8605Smrg * Compute the maximum number of vertices that can be written to the currently 332848b8605Smrg * enabled transform feedback buffers without overflowing any of them. 333848b8605Smrg */ 334848b8605Smrgunsigned 335b8e80941Smrg_mesa_compute_max_transform_feedback_vertices(struct gl_context *ctx, 336848b8605Smrg const struct gl_transform_feedback_object *obj, 337848b8605Smrg const struct gl_transform_feedback_info *info) 338848b8605Smrg{ 339848b8605Smrg unsigned max_index = 0xffffffff; 340848b8605Smrg unsigned i; 341848b8605Smrg 342b8e80941Smrg for (i = 0; i < ctx->Const.MaxTransformFeedbackBuffers; i++) { 343b8e80941Smrg if ((info->ActiveBuffers >> i) & 1) { 344b8e80941Smrg unsigned stride = info->Buffers[i].Stride; 345b8e80941Smrg unsigned max_for_this_buffer; 346848b8605Smrg 347b8e80941Smrg /* Skip any inactive buffers, which have a stride of 0. */ 348b8e80941Smrg if (stride == 0) 349b8e80941Smrg continue; 350848b8605Smrg 351b8e80941Smrg max_for_this_buffer = obj->Size[i] / (4 * stride); 352b8e80941Smrg max_index = MIN2(max_index, max_for_this_buffer); 353b8e80941Smrg } 354848b8605Smrg } 355848b8605Smrg 356848b8605Smrg return max_index; 357848b8605Smrg} 358848b8605Smrg 359848b8605Smrg 360848b8605Smrg/** 361848b8605Smrg ** Begin API functions 362848b8605Smrg **/ 363848b8605Smrg 364848b8605Smrg 365848b8605Smrg/** 366848b8605Smrg * Figure out which stage of the pipeline is the source of transform feedback 367b8e80941Smrg * data given the current context state, and return its gl_program. 368848b8605Smrg * 369848b8605Smrg * If no active program can generate transform feedback data (i.e. no vertex 370848b8605Smrg * shader is active), returns NULL. 371848b8605Smrg */ 372b8e80941Smrgstatic struct gl_program * 373848b8605Smrgget_xfb_source(struct gl_context *ctx) 374848b8605Smrg{ 375848b8605Smrg int i; 376848b8605Smrg for (i = MESA_SHADER_GEOMETRY; i >= MESA_SHADER_VERTEX; i--) { 377848b8605Smrg if (ctx->_Shader->CurrentProgram[i] != NULL) 378848b8605Smrg return ctx->_Shader->CurrentProgram[i]; 379848b8605Smrg } 380848b8605Smrg return NULL; 381848b8605Smrg} 382848b8605Smrg 383848b8605Smrg 384b8e80941Smrgstatic ALWAYS_INLINE void 385b8e80941Smrgbegin_transform_feedback(struct gl_context *ctx, GLenum mode, bool no_error) 386848b8605Smrg{ 387848b8605Smrg struct gl_transform_feedback_object *obj; 388848b8605Smrg struct gl_transform_feedback_info *info = NULL; 389b8e80941Smrg struct gl_program *source; 390848b8605Smrg GLuint i; 391848b8605Smrg unsigned vertices_per_prim; 392848b8605Smrg 393848b8605Smrg obj = ctx->TransformFeedback.CurrentObject; 394848b8605Smrg 395848b8605Smrg /* Figure out what pipeline stage is the source of data for transform 396848b8605Smrg * feedback. 397848b8605Smrg */ 398848b8605Smrg source = get_xfb_source(ctx); 399b8e80941Smrg if (!no_error && source == NULL) { 400848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 401848b8605Smrg "glBeginTransformFeedback(no program active)"); 402848b8605Smrg return; 403848b8605Smrg } 404848b8605Smrg 405b8e80941Smrg info = source->sh.LinkedTransformFeedback; 406848b8605Smrg 407b8e80941Smrg if (!no_error && info->NumOutputs == 0) { 408848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 409848b8605Smrg "glBeginTransformFeedback(no varyings to record)"); 410848b8605Smrg return; 411848b8605Smrg } 412848b8605Smrg 413848b8605Smrg switch (mode) { 414848b8605Smrg case GL_POINTS: 415848b8605Smrg vertices_per_prim = 1; 416848b8605Smrg break; 417848b8605Smrg case GL_LINES: 418848b8605Smrg vertices_per_prim = 2; 419848b8605Smrg break; 420848b8605Smrg case GL_TRIANGLES: 421848b8605Smrg vertices_per_prim = 3; 422848b8605Smrg break; 423848b8605Smrg default: 424b8e80941Smrg if (!no_error) { 425b8e80941Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBeginTransformFeedback(mode)"); 426b8e80941Smrg return; 427b8e80941Smrg } else { 428b8e80941Smrg /* Stop compiler warnings */ 429b8e80941Smrg unreachable("Error in API use when using KHR_no_error"); 430b8e80941Smrg } 431848b8605Smrg } 432848b8605Smrg 433b8e80941Smrg if (!no_error) { 434b8e80941Smrg if (obj->Active) { 435848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 436b8e80941Smrg "glBeginTransformFeedback(already active)"); 437848b8605Smrg return; 438848b8605Smrg } 439b8e80941Smrg 440b8e80941Smrg for (i = 0; i < ctx->Const.MaxTransformFeedbackBuffers; i++) { 441b8e80941Smrg if ((info->ActiveBuffers >> i) & 1) { 442b8e80941Smrg if (obj->BufferNames[i] == 0) { 443b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 444b8e80941Smrg "glBeginTransformFeedback(binding point %d does not " 445b8e80941Smrg "have a buffer object bound)", i); 446b8e80941Smrg return; 447b8e80941Smrg } 448b8e80941Smrg } 449b8e80941Smrg } 450848b8605Smrg } 451848b8605Smrg 452848b8605Smrg FLUSH_VERTICES(ctx, 0); 453848b8605Smrg ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback; 454848b8605Smrg 455848b8605Smrg obj->Active = GL_TRUE; 456848b8605Smrg ctx->TransformFeedback.Mode = mode; 457848b8605Smrg 458848b8605Smrg compute_transform_feedback_buffer_sizes(obj); 459848b8605Smrg 460848b8605Smrg if (_mesa_is_gles3(ctx)) { 461848b8605Smrg /* In GLES3, we are required to track the usage of the transform 462848b8605Smrg * feedback buffer and report INVALID_OPERATION if a draw call tries to 463848b8605Smrg * exceed it. So compute the maximum number of vertices that we can 464848b8605Smrg * write without overflowing any of the buffers currently being used for 465848b8605Smrg * feedback. 466848b8605Smrg */ 467848b8605Smrg unsigned max_vertices 468b8e80941Smrg = _mesa_compute_max_transform_feedback_vertices(ctx, obj, info); 469848b8605Smrg obj->GlesRemainingPrims = max_vertices / vertices_per_prim; 470848b8605Smrg } 471848b8605Smrg 472b8e80941Smrg if (obj->program != source) { 473848b8605Smrg ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedbackProg; 474b8e80941Smrg _mesa_reference_program_(ctx, &obj->program, source); 475b8e80941Smrg obj->program = source; 476848b8605Smrg } 477848b8605Smrg 478848b8605Smrg assert(ctx->Driver.BeginTransformFeedback); 479848b8605Smrg ctx->Driver.BeginTransformFeedback(ctx, mode, obj); 480848b8605Smrg} 481848b8605Smrg 482848b8605Smrg 483b8e80941Smrgvoid GLAPIENTRY 484b8e80941Smrg_mesa_BeginTransformFeedback_no_error(GLenum mode) 485b8e80941Smrg{ 486b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 487b8e80941Smrg begin_transform_feedback(ctx, mode, true); 488b8e80941Smrg} 489b8e80941Smrg 490b8e80941Smrg 491b8e80941Smrgvoid GLAPIENTRY 492b8e80941Smrg_mesa_BeginTransformFeedback(GLenum mode) 493b8e80941Smrg{ 494b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 495b8e80941Smrg begin_transform_feedback(ctx, mode, false); 496b8e80941Smrg} 497b8e80941Smrg 498b8e80941Smrg 499b8e80941Smrgstatic void 500b8e80941Smrgend_transform_feedback(struct gl_context *ctx, 501b8e80941Smrg struct gl_transform_feedback_object *obj) 502b8e80941Smrg{ 503b8e80941Smrg FLUSH_VERTICES(ctx, 0); 504b8e80941Smrg ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback; 505b8e80941Smrg 506b8e80941Smrg assert(ctx->Driver.EndTransformFeedback); 507b8e80941Smrg ctx->Driver.EndTransformFeedback(ctx, obj); 508b8e80941Smrg 509b8e80941Smrg _mesa_reference_program_(ctx, &obj->program, NULL); 510b8e80941Smrg ctx->TransformFeedback.CurrentObject->Active = GL_FALSE; 511b8e80941Smrg ctx->TransformFeedback.CurrentObject->Paused = GL_FALSE; 512b8e80941Smrg ctx->TransformFeedback.CurrentObject->EndedAnytime = GL_TRUE; 513b8e80941Smrg} 514b8e80941Smrg 515b8e80941Smrg 516b8e80941Smrgvoid GLAPIENTRY 517b8e80941Smrg_mesa_EndTransformFeedback_no_error(void) 518b8e80941Smrg{ 519b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 520b8e80941Smrg end_transform_feedback(ctx, ctx->TransformFeedback.CurrentObject); 521b8e80941Smrg} 522b8e80941Smrg 523b8e80941Smrg 524848b8605Smrgvoid GLAPIENTRY 525848b8605Smrg_mesa_EndTransformFeedback(void) 526848b8605Smrg{ 527848b8605Smrg struct gl_transform_feedback_object *obj; 528848b8605Smrg GET_CURRENT_CONTEXT(ctx); 529848b8605Smrg 530848b8605Smrg obj = ctx->TransformFeedback.CurrentObject; 531848b8605Smrg 532848b8605Smrg if (!obj->Active) { 533848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 534848b8605Smrg "glEndTransformFeedback(not active)"); 535848b8605Smrg return; 536848b8605Smrg } 537848b8605Smrg 538b8e80941Smrg end_transform_feedback(ctx, obj); 539848b8605Smrg} 540848b8605Smrg 541848b8605Smrg 542848b8605Smrg/** 543848b8605Smrg * Helper used by BindBufferRange() and BindBufferBase(). 544848b8605Smrg */ 545848b8605Smrgstatic void 546b8e80941Smrgbind_buffer_range(struct gl_context *ctx, 547b8e80941Smrg struct gl_transform_feedback_object *obj, 548b8e80941Smrg GLuint index, 549848b8605Smrg struct gl_buffer_object *bufObj, 550b8e80941Smrg GLintptr offset, GLsizeiptr size, 551b8e80941Smrg bool dsa) 552848b8605Smrg{ 553848b8605Smrg /* Note: no need to FLUSH_VERTICES or flag NewTransformFeedback, because 554848b8605Smrg * transform feedback buffers can't be changed while transform feedback is 555848b8605Smrg * active. 556848b8605Smrg */ 557848b8605Smrg 558b8e80941Smrg if (!dsa) { 559b8e80941Smrg /* The general binding point */ 560b8e80941Smrg _mesa_reference_buffer_object(ctx, 561b8e80941Smrg &ctx->TransformFeedback.CurrentBuffer, 562b8e80941Smrg bufObj); 563b8e80941Smrg } 564848b8605Smrg 565848b8605Smrg /* The per-attribute binding point */ 566848b8605Smrg _mesa_set_transform_feedback_binding(ctx, obj, index, bufObj, offset, size); 567848b8605Smrg} 568848b8605Smrg 569848b8605Smrg 570848b8605Smrg/** 571b8e80941Smrg * Validate the buffer object to receive transform feedback results. Plus, 572b8e80941Smrg * validate the starting offset to place the results, and max size. 573b8e80941Smrg * Called from the glBindBufferRange() and glTransformFeedbackBufferRange 574b8e80941Smrg * functions. 575848b8605Smrg */ 576b8e80941Smrgbool 577b8e80941Smrg_mesa_validate_buffer_range_xfb(struct gl_context *ctx, 578b8e80941Smrg struct gl_transform_feedback_object *obj, 579b8e80941Smrg GLuint index, struct gl_buffer_object *bufObj, 580b8e80941Smrg GLintptr offset, GLsizeiptr size, bool dsa) 581848b8605Smrg{ 582b8e80941Smrg const char *gl_methd_name; 583b8e80941Smrg if (dsa) 584b8e80941Smrg gl_methd_name = "glTransformFeedbackBufferRange"; 585b8e80941Smrg else 586b8e80941Smrg gl_methd_name = "glBindBufferRange"; 587848b8605Smrg 588848b8605Smrg 589848b8605Smrg if (obj->Active) { 590b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(transform feedback active)", 591b8e80941Smrg gl_methd_name); 592b8e80941Smrg return false; 593848b8605Smrg } 594848b8605Smrg 595848b8605Smrg if (index >= ctx->Const.MaxTransformFeedbackBuffers) { 596b8e80941Smrg /* OpenGL 4.5 core profile, 6.1, pdf page 82: "An INVALID_VALUE error is 597b8e80941Smrg * generated if index is greater than or equal to the number of binding 598b8e80941Smrg * points for transform feedback, as described in section 6.7.1." 599b8e80941Smrg */ 600b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(index=%d out of bounds)", 601b8e80941Smrg gl_methd_name, index); 602b8e80941Smrg return false; 603848b8605Smrg } 604848b8605Smrg 605848b8605Smrg if (size & 0x3) { 606b8e80941Smrg /* OpenGL 4.5 core profile, 6.7, pdf page 103: multiple of 4 */ 607b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(size=%d must be a multiple of " 608b8e80941Smrg "four)", gl_methd_name, (int) size); 609b8e80941Smrg return false; 610b8e80941Smrg } 611848b8605Smrg 612848b8605Smrg if (offset & 0x3) { 613b8e80941Smrg /* OpenGL 4.5 core profile, 6.7, pdf page 103: multiple of 4 */ 614b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset=%d must be a multiple " 615b8e80941Smrg "of four)", gl_methd_name, (int) offset); 616b8e80941Smrg return false; 617b8e80941Smrg } 618b8e80941Smrg 619b8e80941Smrg if (offset < 0) { 620b8e80941Smrg /* OpenGL 4.5 core profile, 6.1, pdf page 82: "An INVALID_VALUE error is 621b8e80941Smrg * generated by BindBufferRange if offset is negative." 622b8e80941Smrg * 623b8e80941Smrg * OpenGL 4.5 core profile, 13.2, pdf page 445: "An INVALID_VALUE error 624b8e80941Smrg * is generated by TransformFeedbackBufferRange if offset is negative." 625b8e80941Smrg */ 626b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset=%d must be >= 0)", 627b8e80941Smrg gl_methd_name, 628b8e80941Smrg (int) offset); 629b8e80941Smrg return false; 630b8e80941Smrg } 631848b8605Smrg 632b8e80941Smrg if (size <= 0 && (dsa || bufObj != ctx->Shared->NullBufferObj)) { 633b8e80941Smrg /* OpenGL 4.5 core profile, 6.1, pdf page 82: "An INVALID_VALUE error is 634b8e80941Smrg * generated by BindBufferRange if buffer is non-zero and size is less 635b8e80941Smrg * than or equal to zero." 636b8e80941Smrg * 637b8e80941Smrg * OpenGL 4.5 core profile, 13.2, pdf page 445: "An INVALID_VALUE error 638b8e80941Smrg * is generated by TransformFeedbackBufferRange if size is less than or 639b8e80941Smrg * equal to zero." 640b8e80941Smrg */ 641b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(size=%d must be > 0)", 642b8e80941Smrg gl_methd_name, (int) size); 643b8e80941Smrg return false; 644b8e80941Smrg } 645b8e80941Smrg 646b8e80941Smrg return true; 647848b8605Smrg} 648848b8605Smrg 649848b8605Smrg 650848b8605Smrg/** 651848b8605Smrg * Specify a buffer object to receive transform feedback results. 652848b8605Smrg * As above, but start at offset = 0. 653b8e80941Smrg * Called from the glBindBufferBase() and glTransformFeedbackBufferBase() 654b8e80941Smrg * functions. 655848b8605Smrg */ 656848b8605Smrgvoid 657848b8605Smrg_mesa_bind_buffer_base_transform_feedback(struct gl_context *ctx, 658b8e80941Smrg struct gl_transform_feedback_object *obj, 659b8e80941Smrg GLuint index, 660b8e80941Smrg struct gl_buffer_object *bufObj, 661b8e80941Smrg bool dsa) 662848b8605Smrg{ 663848b8605Smrg if (obj->Active) { 664848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 665b8e80941Smrg "%s(transform feedback active)", 666b8e80941Smrg dsa ? "glTransformFeedbackBufferBase" : "glBindBufferBase"); 667848b8605Smrg return; 668848b8605Smrg } 669848b8605Smrg 670848b8605Smrg if (index >= ctx->Const.MaxTransformFeedbackBuffers) { 671b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(index=%d out of bounds)", 672b8e80941Smrg dsa ? "glTransformFeedbackBufferBase" : "glBindBufferBase", 673b8e80941Smrg index); 674b8e80941Smrg return; 675b8e80941Smrg } 676b8e80941Smrg 677b8e80941Smrg bind_buffer_range(ctx, obj, index, bufObj, 0, 0, dsa); 678b8e80941Smrg} 679b8e80941Smrg 680b8e80941Smrg/** 681b8e80941Smrg * Wrapper around lookup_transform_feedback_object that throws 682b8e80941Smrg * GL_INVALID_OPERATION if id is not in the hash table. After calling 683b8e80941Smrg * _mesa_error, it returns NULL. 684b8e80941Smrg */ 685b8e80941Smrgstatic struct gl_transform_feedback_object * 686b8e80941Smrglookup_transform_feedback_object_err(struct gl_context *ctx, 687b8e80941Smrg GLuint xfb, const char* func) 688b8e80941Smrg{ 689b8e80941Smrg struct gl_transform_feedback_object *obj; 690b8e80941Smrg 691b8e80941Smrg obj = _mesa_lookup_transform_feedback_object(ctx, xfb); 692b8e80941Smrg if (!obj) { 693b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 694b8e80941Smrg "%s(xfb=%u: non-generated object name)", func, xfb); 695b8e80941Smrg } 696b8e80941Smrg 697b8e80941Smrg return obj; 698b8e80941Smrg} 699b8e80941Smrg 700b8e80941Smrg/** 701b8e80941Smrg * Wrapper around _mesa_lookup_bufferobj that throws GL_INVALID_VALUE if id 702b8e80941Smrg * is not in the hash table. Specialised version for the 703b8e80941Smrg * transform-feedback-related functions. After calling _mesa_error, it 704b8e80941Smrg * returns NULL. 705b8e80941Smrg */ 706b8e80941Smrgstatic struct gl_buffer_object * 707b8e80941Smrglookup_transform_feedback_bufferobj_err(struct gl_context *ctx, 708b8e80941Smrg GLuint buffer, const char* func) 709b8e80941Smrg{ 710b8e80941Smrg struct gl_buffer_object *bufObj; 711b8e80941Smrg 712b8e80941Smrg /* OpenGL 4.5 core profile, 13.2, pdf page 444: buffer must be zero or the 713b8e80941Smrg * name of an existing buffer object. 714b8e80941Smrg */ 715b8e80941Smrg if (buffer == 0) { 716b8e80941Smrg bufObj = ctx->Shared->NullBufferObj; 717b8e80941Smrg } else { 718b8e80941Smrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 719b8e80941Smrg if (!bufObj) { 720b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid buffer=%u)", func, 721b8e80941Smrg buffer); 722b8e80941Smrg } 723b8e80941Smrg } 724b8e80941Smrg 725b8e80941Smrg return bufObj; 726b8e80941Smrg} 727b8e80941Smrg 728b8e80941Smrgvoid GLAPIENTRY 729b8e80941Smrg_mesa_TransformFeedbackBufferBase(GLuint xfb, GLuint index, GLuint buffer) 730b8e80941Smrg{ 731b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 732b8e80941Smrg struct gl_transform_feedback_object *obj; 733b8e80941Smrg struct gl_buffer_object *bufObj; 734b8e80941Smrg 735b8e80941Smrg obj = lookup_transform_feedback_object_err(ctx, xfb, 736b8e80941Smrg "glTransformFeedbackBufferBase"); 737b8e80941Smrg if (!obj) { 738b8e80941Smrg return; 739b8e80941Smrg } 740b8e80941Smrg 741b8e80941Smrg bufObj = lookup_transform_feedback_bufferobj_err(ctx, buffer, 742b8e80941Smrg "glTransformFeedbackBufferBase"); 743b8e80941Smrg if (!bufObj) { 744848b8605Smrg return; 745848b8605Smrg } 746848b8605Smrg 747b8e80941Smrg _mesa_bind_buffer_base_transform_feedback(ctx, obj, index, bufObj, true); 748848b8605Smrg} 749848b8605Smrg 750b8e80941Smrgvoid GLAPIENTRY 751b8e80941Smrg_mesa_TransformFeedbackBufferRange(GLuint xfb, GLuint index, GLuint buffer, 752b8e80941Smrg GLintptr offset, GLsizeiptr size) 753b8e80941Smrg{ 754b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 755b8e80941Smrg struct gl_transform_feedback_object *obj; 756b8e80941Smrg struct gl_buffer_object *bufObj; 757b8e80941Smrg 758b8e80941Smrg obj = lookup_transform_feedback_object_err(ctx, xfb, 759b8e80941Smrg "glTransformFeedbackBufferRange"); 760b8e80941Smrg if (!obj) { 761b8e80941Smrg return; 762b8e80941Smrg } 763b8e80941Smrg 764b8e80941Smrg bufObj = lookup_transform_feedback_bufferobj_err(ctx, buffer, 765b8e80941Smrg "glTransformFeedbackBufferRange"); 766b8e80941Smrg if (!bufObj) { 767b8e80941Smrg return; 768b8e80941Smrg } 769b8e80941Smrg 770b8e80941Smrg if (!_mesa_validate_buffer_range_xfb(ctx, obj, index, bufObj, offset, 771b8e80941Smrg size, true)) 772b8e80941Smrg return; 773b8e80941Smrg 774b8e80941Smrg /* The per-attribute binding point */ 775b8e80941Smrg _mesa_set_transform_feedback_binding(ctx, obj, index, bufObj, offset, 776b8e80941Smrg size); 777b8e80941Smrg} 778848b8605Smrg 779848b8605Smrg/** 780848b8605Smrg * Specify a buffer object to receive transform feedback results, plus the 781848b8605Smrg * offset in the buffer to start placing results. 782848b8605Smrg * This function is part of GL_EXT_transform_feedback, but not GL3. 783848b8605Smrg */ 784b8e80941Smrgstatic ALWAYS_INLINE void 785b8e80941Smrgbind_buffer_offset(struct gl_context *ctx, 786b8e80941Smrg struct gl_transform_feedback_object *obj, GLuint index, 787b8e80941Smrg GLuint buffer, GLintptr offset, bool no_error) 788b8e80941Smrg{ 789b8e80941Smrg struct gl_buffer_object *bufObj; 790b8e80941Smrg 791b8e80941Smrg if (buffer == 0) { 792b8e80941Smrg bufObj = ctx->Shared->NullBufferObj; 793b8e80941Smrg } else { 794b8e80941Smrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 795b8e80941Smrg if (!no_error && !bufObj) { 796b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 797b8e80941Smrg "glBindBufferOffsetEXT(invalid buffer=%u)", buffer); 798b8e80941Smrg return; 799b8e80941Smrg } 800b8e80941Smrg } 801b8e80941Smrg 802b8e80941Smrg _mesa_bind_buffer_range_xfb(ctx, obj, index, bufObj, offset, 0); 803b8e80941Smrg} 804b8e80941Smrg 805b8e80941Smrg 806b8e80941Smrgvoid GLAPIENTRY 807b8e80941Smrg_mesa_BindBufferOffsetEXT_no_error(GLenum target, GLuint index, GLuint buffer, 808b8e80941Smrg GLintptr offset) 809b8e80941Smrg{ 810b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 811b8e80941Smrg bind_buffer_offset(ctx, ctx->TransformFeedback.CurrentObject, index, buffer, 812b8e80941Smrg offset, true); 813b8e80941Smrg} 814b8e80941Smrg 815b8e80941Smrg 816848b8605Smrgvoid GLAPIENTRY 817848b8605Smrg_mesa_BindBufferOffsetEXT(GLenum target, GLuint index, GLuint buffer, 818848b8605Smrg GLintptr offset) 819848b8605Smrg{ 820848b8605Smrg struct gl_transform_feedback_object *obj; 821848b8605Smrg GET_CURRENT_CONTEXT(ctx); 822848b8605Smrg 823848b8605Smrg if (target != GL_TRANSFORM_FEEDBACK_BUFFER) { 824848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferOffsetEXT(target)"); 825848b8605Smrg return; 826848b8605Smrg } 827848b8605Smrg 828848b8605Smrg obj = ctx->TransformFeedback.CurrentObject; 829848b8605Smrg 830848b8605Smrg if (obj->Active) { 831848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 832848b8605Smrg "glBindBufferOffsetEXT(transform feedback active)"); 833848b8605Smrg return; 834848b8605Smrg } 835848b8605Smrg 836848b8605Smrg if (index >= ctx->Const.MaxTransformFeedbackBuffers) { 837848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 838848b8605Smrg "glBindBufferOffsetEXT(index=%d)", index); 839848b8605Smrg return; 840848b8605Smrg } 841848b8605Smrg 842848b8605Smrg if (offset & 0x3) { 843848b8605Smrg /* must be multiple of four */ 844848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 845848b8605Smrg "glBindBufferOffsetEXT(offset=%d)", (int) offset); 846848b8605Smrg return; 847848b8605Smrg } 848848b8605Smrg 849b8e80941Smrg bind_buffer_offset(ctx, obj, index, buffer, offset, false); 850b8e80941Smrg} 851b8e80941Smrg 852b8e80941Smrg 853b8e80941Smrg/** 854b8e80941Smrg * This function specifies the transform feedback outputs to be written 855b8e80941Smrg * to the feedback buffer(s), and in what order. 856b8e80941Smrg */ 857b8e80941Smrgstatic ALWAYS_INLINE void 858b8e80941Smrgtransform_feedback_varyings(struct gl_context *ctx, 859b8e80941Smrg struct gl_shader_program *shProg, GLsizei count, 860b8e80941Smrg const GLchar *const *varyings, GLenum bufferMode) 861b8e80941Smrg{ 862b8e80941Smrg GLint i; 863b8e80941Smrg 864b8e80941Smrg /* free existing varyings, if any */ 865b8e80941Smrg for (i = 0; i < (GLint) shProg->TransformFeedback.NumVarying; i++) { 866b8e80941Smrg free(shProg->TransformFeedback.VaryingNames[i]); 867848b8605Smrg } 868b8e80941Smrg free(shProg->TransformFeedback.VaryingNames); 869848b8605Smrg 870b8e80941Smrg /* allocate new memory for varying names */ 871b8e80941Smrg shProg->TransformFeedback.VaryingNames = 872b8e80941Smrg malloc(count * sizeof(GLchar *)); 873b8e80941Smrg 874b8e80941Smrg if (!shProg->TransformFeedback.VaryingNames) { 875b8e80941Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTransformFeedbackVaryings()"); 876848b8605Smrg return; 877848b8605Smrg } 878848b8605Smrg 879b8e80941Smrg /* Save the new names and the count */ 880b8e80941Smrg for (i = 0; i < count; i++) { 881b8e80941Smrg shProg->TransformFeedback.VaryingNames[i] = strdup(varyings[i]); 882b8e80941Smrg } 883b8e80941Smrg shProg->TransformFeedback.NumVarying = count; 884b8e80941Smrg 885b8e80941Smrg shProg->TransformFeedback.BufferMode = bufferMode; 886b8e80941Smrg 887b8e80941Smrg /* No need to invoke FLUSH_VERTICES or flag NewTransformFeedback since 888b8e80941Smrg * the varyings won't be used until shader link time. 889b8e80941Smrg */ 890848b8605Smrg} 891848b8605Smrg 892848b8605Smrg 893b8e80941Smrgvoid GLAPIENTRY 894b8e80941Smrg_mesa_TransformFeedbackVaryings_no_error(GLuint program, GLsizei count, 895b8e80941Smrg const GLchar *const *varyings, 896b8e80941Smrg GLenum bufferMode) 897b8e80941Smrg{ 898b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 899b8e80941Smrg 900b8e80941Smrg struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, program); 901b8e80941Smrg transform_feedback_varyings(ctx, shProg, count, varyings, bufferMode); 902b8e80941Smrg} 903b8e80941Smrg 904848b8605Smrgvoid GLAPIENTRY 905848b8605Smrg_mesa_TransformFeedbackVaryings(GLuint program, GLsizei count, 906848b8605Smrg const GLchar * const *varyings, 907848b8605Smrg GLenum bufferMode) 908848b8605Smrg{ 909848b8605Smrg struct gl_shader_program *shProg; 910848b8605Smrg GLint i; 911848b8605Smrg GET_CURRENT_CONTEXT(ctx); 912848b8605Smrg 913848b8605Smrg /* From the ARB_transform_feedback2 specification: 914848b8605Smrg * "The error INVALID_OPERATION is generated by TransformFeedbackVaryings 915848b8605Smrg * if the current transform feedback object is active, even if paused." 916848b8605Smrg */ 917848b8605Smrg if (ctx->TransformFeedback.CurrentObject->Active) { 918848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 919848b8605Smrg "glTransformFeedbackVaryings(current object is active)"); 920848b8605Smrg return; 921848b8605Smrg } 922848b8605Smrg 923848b8605Smrg switch (bufferMode) { 924848b8605Smrg case GL_INTERLEAVED_ATTRIBS: 925848b8605Smrg break; 926848b8605Smrg case GL_SEPARATE_ATTRIBS: 927848b8605Smrg break; 928848b8605Smrg default: 929848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, 930848b8605Smrg "glTransformFeedbackVaryings(bufferMode)"); 931848b8605Smrg return; 932848b8605Smrg } 933848b8605Smrg 934848b8605Smrg if (count < 0 || 935848b8605Smrg (bufferMode == GL_SEPARATE_ATTRIBS && 936848b8605Smrg (GLuint) count > ctx->Const.MaxTransformFeedbackBuffers)) { 937848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 938848b8605Smrg "glTransformFeedbackVaryings(count=%d)", count); 939848b8605Smrg return; 940848b8605Smrg } 941848b8605Smrg 942b8e80941Smrg shProg = _mesa_lookup_shader_program_err(ctx, program, 943b8e80941Smrg "glTransformFeedbackVaryings"); 944b8e80941Smrg if (!shProg) 945848b8605Smrg return; 946848b8605Smrg 947848b8605Smrg if (ctx->Extensions.ARB_transform_feedback3) { 948848b8605Smrg if (bufferMode == GL_INTERLEAVED_ATTRIBS) { 949848b8605Smrg unsigned buffers = 1; 950848b8605Smrg 951848b8605Smrg for (i = 0; i < count; i++) { 952848b8605Smrg if (strcmp(varyings[i], "gl_NextBuffer") == 0) 953848b8605Smrg buffers++; 954848b8605Smrg } 955848b8605Smrg 956848b8605Smrg if (buffers > ctx->Const.MaxTransformFeedbackBuffers) { 957848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 958848b8605Smrg "glTransformFeedbackVaryings(too many gl_NextBuffer " 959b8e80941Smrg "occurrences)"); 960848b8605Smrg return; 961848b8605Smrg } 962848b8605Smrg } else { 963848b8605Smrg for (i = 0; i < count; i++) { 964848b8605Smrg if (strcmp(varyings[i], "gl_NextBuffer") == 0 || 965848b8605Smrg strcmp(varyings[i], "gl_SkipComponents1") == 0 || 966848b8605Smrg strcmp(varyings[i], "gl_SkipComponents2") == 0 || 967848b8605Smrg strcmp(varyings[i], "gl_SkipComponents3") == 0 || 968848b8605Smrg strcmp(varyings[i], "gl_SkipComponents4") == 0) { 969848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 970848b8605Smrg "glTransformFeedbackVaryings(SEPARATE_ATTRIBS," 971848b8605Smrg "varying=%s)", 972848b8605Smrg varyings[i]); 973848b8605Smrg return; 974848b8605Smrg } 975848b8605Smrg } 976848b8605Smrg } 977848b8605Smrg } 978848b8605Smrg 979b8e80941Smrg transform_feedback_varyings(ctx, shProg, count, varyings, bufferMode); 980848b8605Smrg} 981848b8605Smrg 982848b8605Smrg 983848b8605Smrg/** 984848b8605Smrg * Get info about the transform feedback outputs which are to be written 985848b8605Smrg * to the feedback buffer(s). 986848b8605Smrg */ 987848b8605Smrgvoid GLAPIENTRY 988848b8605Smrg_mesa_GetTransformFeedbackVarying(GLuint program, GLuint index, 989848b8605Smrg GLsizei bufSize, GLsizei *length, 990848b8605Smrg GLsizei *size, GLenum *type, GLchar *name) 991848b8605Smrg{ 992848b8605Smrg const struct gl_shader_program *shProg; 993b8e80941Smrg struct gl_program_resource *res; 994848b8605Smrg GET_CURRENT_CONTEXT(ctx); 995848b8605Smrg 996b8e80941Smrg shProg = _mesa_lookup_shader_program_err(ctx, program, 997b8e80941Smrg "glGetTransformFeedbackVarying"); 998b8e80941Smrg if (!shProg) 999848b8605Smrg return; 1000848b8605Smrg 1001b8e80941Smrg res = _mesa_program_resource_find_index((struct gl_shader_program *) shProg, 1002b8e80941Smrg GL_TRANSFORM_FEEDBACK_VARYING, 1003b8e80941Smrg index); 1004b8e80941Smrg if (!res) { 1005848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 1006848b8605Smrg "glGetTransformFeedbackVarying(index=%u)", index); 1007848b8605Smrg return; 1008848b8605Smrg } 1009848b8605Smrg 1010848b8605Smrg /* return the varying's name and length */ 1011b8e80941Smrg _mesa_copy_string(name, bufSize, length, _mesa_program_resource_name(res)); 1012848b8605Smrg 1013848b8605Smrg /* return the datatype and value's size (in datatype units) */ 1014848b8605Smrg if (type) 1015b8e80941Smrg _mesa_program_resource_prop((struct gl_shader_program *) shProg, 1016b8e80941Smrg res, index, GL_TYPE, (GLint*) type, 1017b8e80941Smrg "glGetTransformFeedbackVarying"); 1018848b8605Smrg if (size) 1019b8e80941Smrg _mesa_program_resource_prop((struct gl_shader_program *) shProg, 1020b8e80941Smrg res, index, GL_ARRAY_SIZE, (GLint*) size, 1021b8e80941Smrg "glGetTransformFeedbackVarying"); 1022848b8605Smrg} 1023848b8605Smrg 1024848b8605Smrg 1025848b8605Smrg 1026848b8605Smrgstruct gl_transform_feedback_object * 1027848b8605Smrg_mesa_lookup_transform_feedback_object(struct gl_context *ctx, GLuint name) 1028848b8605Smrg{ 1029b8e80941Smrg /* OpenGL 4.5 core profile, 13.2 pdf page 444: "xfb must be zero, indicating 1030b8e80941Smrg * the default transform feedback object, or the name of an existing 1031b8e80941Smrg * transform feedback object." 1032b8e80941Smrg */ 1033848b8605Smrg if (name == 0) { 1034848b8605Smrg return ctx->TransformFeedback.DefaultObject; 1035848b8605Smrg } 1036848b8605Smrg else 1037848b8605Smrg return (struct gl_transform_feedback_object *) 1038b8e80941Smrg _mesa_HashLookupLocked(ctx->TransformFeedback.Objects, name); 1039848b8605Smrg} 1040848b8605Smrg 1041b8e80941Smrgstatic void 1042b8e80941Smrgcreate_transform_feedbacks(struct gl_context *ctx, GLsizei n, GLuint *ids, 1043b8e80941Smrg bool dsa) 1044848b8605Smrg{ 1045848b8605Smrg GLuint first; 1046b8e80941Smrg const char* func; 1047b8e80941Smrg 1048b8e80941Smrg if (dsa) 1049b8e80941Smrg func = "glCreateTransformFeedbacks"; 1050b8e80941Smrg else 1051b8e80941Smrg func = "glGenTransformFeedbacks"; 1052848b8605Smrg 1053848b8605Smrg if (n < 0) { 1054b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func); 1055848b8605Smrg return; 1056848b8605Smrg } 1057848b8605Smrg 1058b8e80941Smrg if (!ids) 1059848b8605Smrg return; 1060848b8605Smrg 1061848b8605Smrg /* we don't need contiguous IDs, but this might be faster */ 1062848b8605Smrg first = _mesa_HashFindFreeKeyBlock(ctx->TransformFeedback.Objects, n); 1063848b8605Smrg if (first) { 1064848b8605Smrg GLsizei i; 1065848b8605Smrg for (i = 0; i < n; i++) { 1066848b8605Smrg struct gl_transform_feedback_object *obj 1067848b8605Smrg = ctx->Driver.NewTransformFeedback(ctx, first + i); 1068848b8605Smrg if (!obj) { 1069b8e80941Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); 1070848b8605Smrg return; 1071848b8605Smrg } 1072b8e80941Smrg ids[i] = first + i; 1073b8e80941Smrg _mesa_HashInsertLocked(ctx->TransformFeedback.Objects, first + i, 1074b8e80941Smrg obj); 1075b8e80941Smrg if (dsa) { 1076b8e80941Smrg /* this is normally done at bind time in the non-dsa case */ 1077b8e80941Smrg obj->EverBound = GL_TRUE; 1078b8e80941Smrg } 1079848b8605Smrg } 1080848b8605Smrg } 1081848b8605Smrg else { 1082b8e80941Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); 1083848b8605Smrg } 1084848b8605Smrg} 1085848b8605Smrg 1086b8e80941Smrg/** 1087b8e80941Smrg * Create new transform feedback objects. Transform feedback objects 1088b8e80941Smrg * encapsulate the state related to transform feedback to allow quickly 1089b8e80941Smrg * switching state (and drawing the results, below). 1090b8e80941Smrg * Part of GL_ARB_transform_feedback2. 1091b8e80941Smrg */ 1092b8e80941Smrgvoid GLAPIENTRY 1093b8e80941Smrg_mesa_GenTransformFeedbacks(GLsizei n, GLuint *names) 1094b8e80941Smrg{ 1095b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 1096b8e80941Smrg 1097b8e80941Smrg /* GenTransformFeedbacks should just reserve the object names that a 1098b8e80941Smrg * subsequent call to BindTransformFeedback should actively create. For 1099b8e80941Smrg * the sake of simplicity, we reserve the names and create the objects 1100b8e80941Smrg * straight away. 1101b8e80941Smrg */ 1102b8e80941Smrg 1103b8e80941Smrg create_transform_feedbacks(ctx, n, names, false); 1104b8e80941Smrg} 1105b8e80941Smrg 1106b8e80941Smrg/** 1107b8e80941Smrg * Create new transform feedback objects. Transform feedback objects 1108b8e80941Smrg * encapsulate the state related to transform feedback to allow quickly 1109b8e80941Smrg * switching state (and drawing the results, below). 1110b8e80941Smrg * Part of GL_ARB_direct_state_access. 1111b8e80941Smrg */ 1112b8e80941Smrgvoid GLAPIENTRY 1113b8e80941Smrg_mesa_CreateTransformFeedbacks(GLsizei n, GLuint *names) 1114b8e80941Smrg{ 1115b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 1116b8e80941Smrg 1117b8e80941Smrg create_transform_feedbacks(ctx, n, names, true); 1118b8e80941Smrg} 1119b8e80941Smrg 1120848b8605Smrg 1121848b8605Smrg/** 1122848b8605Smrg * Is the given ID a transform feedback object? 1123848b8605Smrg * Part of GL_ARB_transform_feedback2. 1124848b8605Smrg */ 1125848b8605SmrgGLboolean GLAPIENTRY 1126848b8605Smrg_mesa_IsTransformFeedback(GLuint name) 1127848b8605Smrg{ 1128848b8605Smrg struct gl_transform_feedback_object *obj; 1129848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1130848b8605Smrg 1131848b8605Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 1132848b8605Smrg 1133848b8605Smrg if (name == 0) 1134848b8605Smrg return GL_FALSE; 1135848b8605Smrg 1136848b8605Smrg obj = _mesa_lookup_transform_feedback_object(ctx, name); 1137848b8605Smrg if (obj == NULL) 1138848b8605Smrg return GL_FALSE; 1139848b8605Smrg 1140848b8605Smrg return obj->EverBound; 1141848b8605Smrg} 1142848b8605Smrg 1143848b8605Smrg 1144848b8605Smrg/** 1145848b8605Smrg * Bind the given transform feedback object. 1146848b8605Smrg * Part of GL_ARB_transform_feedback2. 1147848b8605Smrg */ 1148b8e80941Smrgstatic ALWAYS_INLINE void 1149b8e80941Smrgbind_transform_feedback(struct gl_context *ctx, GLuint name, bool no_error) 1150b8e80941Smrg{ 1151b8e80941Smrg struct gl_transform_feedback_object *obj; 1152b8e80941Smrg 1153b8e80941Smrg obj = _mesa_lookup_transform_feedback_object(ctx, name); 1154b8e80941Smrg if (!no_error && !obj) { 1155b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 1156b8e80941Smrg "glBindTransformFeedback(name=%u)", name); 1157b8e80941Smrg return; 1158b8e80941Smrg } 1159b8e80941Smrg 1160b8e80941Smrg reference_transform_feedback_object(&ctx->TransformFeedback.CurrentObject, 1161b8e80941Smrg obj); 1162b8e80941Smrg} 1163b8e80941Smrg 1164b8e80941Smrg 1165b8e80941Smrgvoid GLAPIENTRY 1166b8e80941Smrg_mesa_BindTransformFeedback_no_error(GLenum target, GLuint name) 1167b8e80941Smrg{ 1168b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 1169b8e80941Smrg bind_transform_feedback(ctx, name, true); 1170b8e80941Smrg} 1171b8e80941Smrg 1172b8e80941Smrg 1173848b8605Smrgvoid GLAPIENTRY 1174848b8605Smrg_mesa_BindTransformFeedback(GLenum target, GLuint name) 1175848b8605Smrg{ 1176848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1177848b8605Smrg 1178848b8605Smrg if (target != GL_TRANSFORM_FEEDBACK) { 1179848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindTransformFeedback(target)"); 1180848b8605Smrg return; 1181848b8605Smrg } 1182848b8605Smrg 1183848b8605Smrg if (_mesa_is_xfb_active_and_unpaused(ctx)) { 1184848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 1185848b8605Smrg "glBindTransformFeedback(transform is active, or not paused)"); 1186848b8605Smrg return; 1187848b8605Smrg } 1188848b8605Smrg 1189b8e80941Smrg bind_transform_feedback(ctx, name, false); 1190848b8605Smrg} 1191848b8605Smrg 1192848b8605Smrg 1193848b8605Smrg/** 1194848b8605Smrg * Delete the given transform feedback objects. 1195848b8605Smrg * Part of GL_ARB_transform_feedback2. 1196848b8605Smrg */ 1197848b8605Smrgvoid GLAPIENTRY 1198848b8605Smrg_mesa_DeleteTransformFeedbacks(GLsizei n, const GLuint *names) 1199848b8605Smrg{ 1200848b8605Smrg GLint i; 1201848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1202848b8605Smrg 1203848b8605Smrg if (n < 0) { 1204848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteTransformFeedbacks(n < 0)"); 1205848b8605Smrg return; 1206848b8605Smrg } 1207848b8605Smrg 1208848b8605Smrg if (!names) 1209848b8605Smrg return; 1210848b8605Smrg 1211848b8605Smrg for (i = 0; i < n; i++) { 1212848b8605Smrg if (names[i] > 0) { 1213848b8605Smrg struct gl_transform_feedback_object *obj 1214848b8605Smrg = _mesa_lookup_transform_feedback_object(ctx, names[i]); 1215848b8605Smrg if (obj) { 1216848b8605Smrg if (obj->Active) { 1217848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 1218848b8605Smrg "glDeleteTransformFeedbacks(object %u is active)", 1219848b8605Smrg names[i]); 1220848b8605Smrg return; 1221848b8605Smrg } 1222b8e80941Smrg _mesa_HashRemoveLocked(ctx->TransformFeedback.Objects, names[i]); 1223848b8605Smrg /* unref, but object may not be deleted until later */ 1224b8e80941Smrg if (obj == ctx->TransformFeedback.CurrentObject) { 1225b8e80941Smrg reference_transform_feedback_object( 1226b8e80941Smrg &ctx->TransformFeedback.CurrentObject, 1227b8e80941Smrg ctx->TransformFeedback.DefaultObject); 1228b8e80941Smrg } 1229848b8605Smrg reference_transform_feedback_object(&obj, NULL); 1230848b8605Smrg } 1231848b8605Smrg } 1232848b8605Smrg } 1233848b8605Smrg} 1234848b8605Smrg 1235848b8605Smrg 1236848b8605Smrg/** 1237848b8605Smrg * Pause transform feedback. 1238848b8605Smrg * Part of GL_ARB_transform_feedback2. 1239848b8605Smrg */ 1240b8e80941Smrgstatic void 1241b8e80941Smrgpause_transform_feedback(struct gl_context *ctx, 1242b8e80941Smrg struct gl_transform_feedback_object *obj) 1243b8e80941Smrg{ 1244b8e80941Smrg FLUSH_VERTICES(ctx, 0); 1245b8e80941Smrg ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback; 1246b8e80941Smrg 1247b8e80941Smrg assert(ctx->Driver.PauseTransformFeedback); 1248b8e80941Smrg ctx->Driver.PauseTransformFeedback(ctx, obj); 1249b8e80941Smrg 1250b8e80941Smrg obj->Paused = GL_TRUE; 1251b8e80941Smrg} 1252b8e80941Smrg 1253b8e80941Smrg 1254b8e80941Smrgvoid GLAPIENTRY 1255b8e80941Smrg_mesa_PauseTransformFeedback_no_error(void) 1256b8e80941Smrg{ 1257b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 1258b8e80941Smrg pause_transform_feedback(ctx, ctx->TransformFeedback.CurrentObject); 1259b8e80941Smrg} 1260b8e80941Smrg 1261b8e80941Smrg 1262848b8605Smrgvoid GLAPIENTRY 1263848b8605Smrg_mesa_PauseTransformFeedback(void) 1264848b8605Smrg{ 1265848b8605Smrg struct gl_transform_feedback_object *obj; 1266848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1267848b8605Smrg 1268848b8605Smrg obj = ctx->TransformFeedback.CurrentObject; 1269848b8605Smrg 1270848b8605Smrg if (!_mesa_is_xfb_active_and_unpaused(ctx)) { 1271848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 1272848b8605Smrg "glPauseTransformFeedback(feedback not active or already paused)"); 1273848b8605Smrg return; 1274848b8605Smrg } 1275848b8605Smrg 1276b8e80941Smrg pause_transform_feedback(ctx, obj); 1277848b8605Smrg} 1278848b8605Smrg 1279848b8605Smrg 1280848b8605Smrg/** 1281848b8605Smrg * Resume transform feedback. 1282848b8605Smrg * Part of GL_ARB_transform_feedback2. 1283848b8605Smrg */ 1284b8e80941Smrgstatic void 1285b8e80941Smrgresume_transform_feedback(struct gl_context *ctx, 1286b8e80941Smrg struct gl_transform_feedback_object *obj) 1287b8e80941Smrg{ 1288b8e80941Smrg FLUSH_VERTICES(ctx, 0); 1289b8e80941Smrg ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback; 1290b8e80941Smrg 1291b8e80941Smrg obj->Paused = GL_FALSE; 1292b8e80941Smrg 1293b8e80941Smrg assert(ctx->Driver.ResumeTransformFeedback); 1294b8e80941Smrg ctx->Driver.ResumeTransformFeedback(ctx, obj); 1295b8e80941Smrg} 1296b8e80941Smrg 1297b8e80941Smrg 1298b8e80941Smrgvoid GLAPIENTRY 1299b8e80941Smrg_mesa_ResumeTransformFeedback_no_error(void) 1300b8e80941Smrg{ 1301b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 1302b8e80941Smrg resume_transform_feedback(ctx, ctx->TransformFeedback.CurrentObject); 1303b8e80941Smrg} 1304b8e80941Smrg 1305b8e80941Smrg 1306848b8605Smrgvoid GLAPIENTRY 1307848b8605Smrg_mesa_ResumeTransformFeedback(void) 1308848b8605Smrg{ 1309848b8605Smrg struct gl_transform_feedback_object *obj; 1310848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1311848b8605Smrg 1312848b8605Smrg obj = ctx->TransformFeedback.CurrentObject; 1313848b8605Smrg 1314848b8605Smrg if (!obj->Active || !obj->Paused) { 1315848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 1316848b8605Smrg "glResumeTransformFeedback(feedback not active or not paused)"); 1317848b8605Smrg return; 1318848b8605Smrg } 1319848b8605Smrg 1320848b8605Smrg /* From the ARB_transform_feedback2 specification: 1321848b8605Smrg * "The error INVALID_OPERATION is generated by ResumeTransformFeedback if 1322848b8605Smrg * the program object being used by the current transform feedback object 1323848b8605Smrg * is not active." 1324848b8605Smrg */ 1325b8e80941Smrg if (obj->program != get_xfb_source(ctx)) { 1326848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 1327848b8605Smrg "glResumeTransformFeedback(wrong program bound)"); 1328848b8605Smrg return; 1329848b8605Smrg } 1330848b8605Smrg 1331b8e80941Smrg resume_transform_feedback(ctx, obj); 1332b8e80941Smrg} 1333848b8605Smrg 1334b8e80941Smrgextern void GLAPIENTRY 1335b8e80941Smrg_mesa_GetTransformFeedbackiv(GLuint xfb, GLenum pname, GLint *param) 1336b8e80941Smrg{ 1337b8e80941Smrg struct gl_transform_feedback_object *obj; 1338b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 1339b8e80941Smrg 1340b8e80941Smrg obj = lookup_transform_feedback_object_err(ctx, xfb, 1341b8e80941Smrg "glGetTransformFeedbackiv"); 1342b8e80941Smrg if (!obj) { 1343b8e80941Smrg return; 1344b8e80941Smrg } 1345b8e80941Smrg 1346b8e80941Smrg switch(pname) { 1347b8e80941Smrg case GL_TRANSFORM_FEEDBACK_PAUSED: 1348b8e80941Smrg *param = obj->Paused; 1349b8e80941Smrg break; 1350b8e80941Smrg case GL_TRANSFORM_FEEDBACK_ACTIVE: 1351b8e80941Smrg *param = obj->Active; 1352b8e80941Smrg break; 1353b8e80941Smrg default: 1354b8e80941Smrg _mesa_error(ctx, GL_INVALID_ENUM, 1355b8e80941Smrg "glGetTransformFeedbackiv(pname=%i)", pname); 1356b8e80941Smrg } 1357b8e80941Smrg} 1358848b8605Smrg 1359b8e80941Smrgextern void GLAPIENTRY 1360b8e80941Smrg_mesa_GetTransformFeedbacki_v(GLuint xfb, GLenum pname, GLuint index, 1361b8e80941Smrg GLint *param) 1362b8e80941Smrg{ 1363b8e80941Smrg struct gl_transform_feedback_object *obj; 1364b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 1365b8e80941Smrg 1366b8e80941Smrg obj = lookup_transform_feedback_object_err(ctx, xfb, 1367b8e80941Smrg "glGetTransformFeedbacki_v"); 1368b8e80941Smrg if (!obj) { 1369b8e80941Smrg return; 1370b8e80941Smrg } 1371b8e80941Smrg 1372b8e80941Smrg if (index >= ctx->Const.MaxTransformFeedbackBuffers) { 1373b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, 1374b8e80941Smrg "glGetTransformFeedbacki_v(index=%i)", index); 1375b8e80941Smrg return; 1376b8e80941Smrg } 1377b8e80941Smrg 1378b8e80941Smrg switch(pname) { 1379b8e80941Smrg case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: 1380b8e80941Smrg *param = obj->BufferNames[index]; 1381b8e80941Smrg break; 1382b8e80941Smrg default: 1383b8e80941Smrg _mesa_error(ctx, GL_INVALID_ENUM, 1384b8e80941Smrg "glGetTransformFeedbacki_v(pname=%i)", pname); 1385b8e80941Smrg } 1386b8e80941Smrg} 1387b8e80941Smrg 1388b8e80941Smrgextern void GLAPIENTRY 1389b8e80941Smrg_mesa_GetTransformFeedbacki64_v(GLuint xfb, GLenum pname, GLuint index, 1390b8e80941Smrg GLint64 *param) 1391b8e80941Smrg{ 1392b8e80941Smrg struct gl_transform_feedback_object *obj; 1393b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 1394b8e80941Smrg 1395b8e80941Smrg obj = lookup_transform_feedback_object_err(ctx, xfb, 1396b8e80941Smrg "glGetTransformFeedbacki64_v"); 1397b8e80941Smrg if (!obj) { 1398b8e80941Smrg return; 1399b8e80941Smrg } 1400b8e80941Smrg 1401b8e80941Smrg if (index >= ctx->Const.MaxTransformFeedbackBuffers) { 1402b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, 1403b8e80941Smrg "glGetTransformFeedbacki64_v(index=%i)", index); 1404b8e80941Smrg return; 1405b8e80941Smrg } 1406b8e80941Smrg 1407b8e80941Smrg /** 1408b8e80941Smrg * This follows the same general rules used for BindBufferBase: 1409b8e80941Smrg * 1410b8e80941Smrg * "To query the starting offset or size of the range of a buffer 1411b8e80941Smrg * object binding in an indexed array, call GetInteger64i_v with 1412b8e80941Smrg * target set to respectively the starting offset or binding size 1413b8e80941Smrg * name from table 6.5 for that array. Index must be in the range 1414b8e80941Smrg * zero to the number of bind points supported minus one. If the 1415b8e80941Smrg * starting offset or size was not specified when the buffer object 1416b8e80941Smrg * was bound (e.g. if it was bound with BindBufferBase), or if no 1417b8e80941Smrg * buffer object is bound to the target array at index, zero is 1418b8e80941Smrg * returned." 1419b8e80941Smrg */ 1420b8e80941Smrg if (obj->RequestedSize[index] == 0 && 1421b8e80941Smrg (pname == GL_TRANSFORM_FEEDBACK_BUFFER_START || 1422b8e80941Smrg pname == GL_TRANSFORM_FEEDBACK_BUFFER_SIZE)) { 1423b8e80941Smrg *param = 0; 1424b8e80941Smrg return; 1425b8e80941Smrg } 1426b8e80941Smrg 1427b8e80941Smrg compute_transform_feedback_buffer_sizes(obj); 1428b8e80941Smrg switch(pname) { 1429b8e80941Smrg case GL_TRANSFORM_FEEDBACK_BUFFER_START: 1430b8e80941Smrg assert(obj->RequestedSize[index] > 0); 1431b8e80941Smrg *param = obj->Offset[index]; 1432b8e80941Smrg break; 1433b8e80941Smrg case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: 1434b8e80941Smrg assert(obj->RequestedSize[index] > 0); 1435b8e80941Smrg *param = obj->Size[index]; 1436b8e80941Smrg break; 1437b8e80941Smrg default: 1438b8e80941Smrg _mesa_error(ctx, GL_INVALID_ENUM, 1439b8e80941Smrg "glGetTransformFeedbacki64_v(pname=%i)", pname); 1440b8e80941Smrg } 1441848b8605Smrg} 1442