static void upload_sol_state(struct brw_context *brw) { struct intel_context *intel = &brw->intel; struct gl_context *ctx = &intel->ctx; /* BRW_NEW_TRANSFORM_FEEDBACK */ bool active = _mesa_is_xfb_active_and_unpaused(ctx); if (active) { upload_3dstate_so_buffers(brw); /* BRW_NEW_VUE_MAP_GEOM_OUT */ upload_3dstate_so_decl_list(brw, &brw->vue_map_geom_out); /* If we don't have hardware contexts, then some other client may have * changed the SO write offsets, and we need to rewrite them. */ if (!intel->hw_ctx) intel->batch.needs_sol_reset = true; } /* Finally, set up the SOL stage. This command must always follow updates to * the nonpipelined SOL state (3DSTATE_SO_BUFFER, 3DSTATE_SO_DECL_LIST) or * MMIO register updates (current performed by the kernel at each batch * emit). */ upload_3dstate_streamout(brw, active, &brw->vue_map_geom_out); }
static void gen6_update_sol_surfaces(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; /* BRW_NEW_TRANSFORM_FEEDBACK */ struct gl_transform_feedback_object *xfb_obj = ctx->TransformFeedback.CurrentObject; /* BRW_NEW_VERTEX_PROGRAM */ const struct gl_shader_program *shaderprog = ctx->Shader.CurrentVertexProgram; const struct gl_transform_feedback_info *linked_xfb_info = &shaderprog->LinkedTransformFeedback; int i; for (i = 0; i < BRW_MAX_SOL_BINDINGS; ++i) { const int surf_index = SURF_INDEX_GEN6_SOL_BINDING(i); if (_mesa_is_xfb_active_and_unpaused(ctx) && i < linked_xfb_info->NumOutputs) { unsigned buffer = linked_xfb_info->Outputs[i].OutputBuffer; unsigned buffer_offset = xfb_obj->Offset[buffer] / 4 + linked_xfb_info->Outputs[i].DstOffset; brw_update_sol_surface( brw, xfb_obj->Buffers[buffer], &brw->ff_gs.surf_offset[surf_index], linked_xfb_info->Outputs[i].NumComponents, linked_xfb_info->BufferStride[buffer], buffer_offset); } else { brw->ff_gs.surf_offset[surf_index] = 0; } } brw->state.dirty.brw |= BRW_NEW_SURFACES; }
/** * For GL_EXT_separate_shader_objects */ void GLAPIENTRY _mesa_UseShaderProgramEXT(GLenum type, GLuint program) { GET_CURRENT_CONTEXT(ctx); struct gl_shader_program *shProg = NULL; if (!validate_shader_target(ctx, type)) { _mesa_error(ctx, GL_INVALID_ENUM, "glUseShaderProgramEXT(type)"); return; } if (_mesa_is_xfb_active_and_unpaused(ctx)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUseShaderProgramEXT(transform feedback is active)"); return; } if (program) { shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseShaderProgramEXT"); if (shProg == NULL) return; if (!shProg->LinkStatus) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUseShaderProgramEXT(program not linked)"); return; } } _mesa_use_shader_program(ctx, type, shProg); }
void GLAPIENTRY _mesa_UseProgram(GLhandleARB program) { GET_CURRENT_CONTEXT(ctx); struct gl_shader_program *shProg; if (_mesa_is_xfb_active_and_unpaused(ctx)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUseProgram(transform feedback active)"); return; } if (program) { shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram"); if (!shProg) { return; } if (!shProg->LinkStatus) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUseProgram(program %u not linked)", program); return; } /* debug code */ if (ctx->Shader.Flags & GLSL_USE_PROG) { print_shader_info(shProg); } } else { shProg = NULL; } _mesa_use_program(ctx, shProg); }
/** * Update internal counters based on the the drawing operation described in * prim. */ static void brw_update_primitive_count(struct brw_context *brw, const struct _mesa_prim *prim) { uint32_t count = vbo_count_tessellated_primitives(prim->mode, prim->count, prim->num_instances); brw->sol.primitives_generated += count; if (_mesa_is_xfb_active_and_unpaused(&brw->intel.ctx)) { /* Update brw->sol.svbi_0_max_index to reflect the amount by which the * hardware is going to increment SVBI 0 when this drawing operation * occurs. This is necessary because the kernel does not (yet) save and * restore GPU registers when context switching, so we'll need to be * able to reload SVBI 0 with the correct value in case we have to start * a new batch buffer. */ unsigned verts = verts_per_prim(prim->mode); uint32_t space_avail = (brw->sol.svbi_0_max_index - brw->sol.svbi_0_starting_index) / verts; uint32_t primitives_written = MIN2 (space_avail, count); brw->sol.svbi_0_starting_index += verts * primitives_written; /* And update the TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query. */ brw->sol.primitives_written += primitives_written; } }
/** * Bind the given transform feedback object. * Part of GL_ARB_transform_feedback2. */ void GLAPIENTRY _mesa_BindTransformFeedback(GLenum target, GLuint 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 (_mesa_is_xfb_active_and_unpaused(ctx)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBindTransformFeedback(transform is active, or not paused)"); return; } obj = _mesa_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); }
/** * Error checking for glDrawElements(). Includes parameter checking * and VBO bounds checking. * \return GL_TRUE if OK to render, GL_FALSE if error found */ GLboolean _mesa_validate_DrawElements(struct gl_context *ctx, GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex) { FLUSH_CURRENT(ctx, 0); /* From the GLES3 specification, section 2.14.2 (Transform Feedback * Primitive Capture): * * The error INVALID_OPERATION is also generated by DrawElements, * DrawElementsInstanced, and DrawRangeElements while transform feedback * is active and not paused, regardless of mode. */ if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawElements(transform feedback active)"); return GL_FALSE; } if (count <= 0) { if (count < 0) _mesa_error(ctx, GL_INVALID_VALUE, "glDrawElements(count)" ); return GL_FALSE; } if (!_mesa_valid_prim_mode(ctx, mode, "glDrawElements")) { return GL_FALSE; } if (!valid_elements_type(ctx, type, "glDrawElements")) return GL_FALSE; if (!check_valid_to_render(ctx, "glDrawElements")) return GL_FALSE; /* Vertex buffer object tests */ if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) { /* use indices in the buffer object */ /* make sure count doesn't go outside buffer bounds */ if (index_bytes(type, count) > ctx->Array.ArrayObj->ElementArrayBufferObj->Size) { _mesa_warning(ctx, "glDrawElements index out of buffer bounds"); return GL_FALSE; } } else { /* not using a VBO */ if (!indices) return GL_FALSE; } if (!check_index_bounds(ctx, count, type, indices, basevertex)) return GL_FALSE; return GL_TRUE; }
static void gen6_update_sol_surfaces(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; /* BRW_NEW_TRANSFORM_FEEDBACK */ struct gl_transform_feedback_object *xfb_obj = ctx->TransformFeedback.CurrentObject; const struct gl_shader_program *shaderprog; const struct gl_transform_feedback_info *linked_xfb_info; int i; if (brw->geometry_program) { /* BRW_NEW_GEOMETRY_PROGRAM */ shaderprog = ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]; } else { /* BRW_NEW_VERTEX_PROGRAM */ shaderprog = ctx->_Shader->CurrentProgram[MESA_SHADER_VERTEX]; } linked_xfb_info = &shaderprog->LinkedTransformFeedback; for (i = 0; i < BRW_MAX_SOL_BINDINGS; ++i) { const int surf_index = SURF_INDEX_GEN6_SOL_BINDING(i); if (_mesa_is_xfb_active_and_unpaused(ctx) && i < linked_xfb_info->NumOutputs) { unsigned buffer = linked_xfb_info->Outputs[i].OutputBuffer; unsigned buffer_offset = xfb_obj->Offset[buffer] / 4 + linked_xfb_info->Outputs[i].DstOffset; if (brw->geometry_program) { brw_update_sol_surface( brw, xfb_obj->Buffers[buffer], &brw->gs.base.surf_offset[surf_index], linked_xfb_info->Outputs[i].NumComponents, linked_xfb_info->Buffers[buffer].Stride, buffer_offset); } else { brw_update_sol_surface( brw, xfb_obj->Buffers[buffer], &brw->ff_gs.surf_offset[surf_index], linked_xfb_info->Outputs[i].NumComponents, linked_xfb_info->Buffers[buffer].Stride, buffer_offset); } } else { if (!brw->geometry_program) brw->ff_gs.surf_offset[surf_index] = 0; else brw->gs.base.surf_offset[surf_index] = 0; } } brw->ctx.NewDriverState |= BRW_NEW_SURFACES; }
/** * Is 'mode' a valid value for glBegin(), glDrawArrays(), glDrawElements(), * etc? Also, do additional checking related to transformation feedback. * Note: this function cannot be called during glNewList(GL_COMPILE) because * this code depends on current transform feedback state. */ GLboolean _mesa_valid_prim_mode(struct gl_context *ctx, GLenum mode, const char *name) { bool valid_enum = _mesa_is_valid_prim_mode(ctx, mode); if (!valid_enum) { _mesa_error(ctx, GL_INVALID_ENUM, "%s(mode=%x)", name, mode); return GL_FALSE; } /* From the GL_EXT_transform_feedback spec: * * "The error INVALID_OPERATION is generated if Begin, or any command * that performs an explicit Begin, is called when: * * * a geometry shader is not active and <mode> does not match the * allowed begin modes for the current transform feedback state as * given by table X.1. * * * a geometry shader is active and the output primitive type of the * geometry shader does not match the allowed begin modes for the * current transform feedback state as given by table X.1. * */ if (_mesa_is_xfb_active_and_unpaused(ctx)) { GLboolean pass = GL_TRUE; switch (mode) { case GL_POINTS: pass = ctx->TransformFeedback.Mode == GL_POINTS; break; case GL_LINES: case GL_LINE_STRIP: case GL_LINE_LOOP: pass = ctx->TransformFeedback.Mode == GL_LINES; break; default: pass = ctx->TransformFeedback.Mode == GL_TRIANGLES; break; } if (!pass) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(mode=%s vs transform feedback %s)", name, _mesa_lookup_prim_by_nr(mode), _mesa_lookup_prim_by_nr(ctx->TransformFeedback.Mode)); return GL_FALSE; } } return GL_TRUE; }
/** * Called from the tnl module to error check the function parameters and * verify that we really can draw something. * \return GL_TRUE if OK to render, GL_FALSE if error found */ GLboolean _mesa_validate_DrawArrays(struct gl_context *ctx, GLenum mode, GLint start, GLsizei count) { struct gl_transform_feedback_object *xfb_obj = ctx->TransformFeedback.CurrentObject; FLUSH_CURRENT(ctx, 0); if (count <= 0) { if (count < 0) _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" ); return GL_FALSE; } if (!_mesa_valid_prim_mode(ctx, mode, "glDrawArrays")) { return GL_FALSE; } if (!check_valid_to_render(ctx, "glDrawArrays")) return GL_FALSE; if (ctx->Const.CheckArrayBounds) { if (start + count > (GLint) ctx->Array.ArrayObj->_MaxElement) return GL_FALSE; } /* From the GLES3 specification, section 2.14.2 (Transform Feedback * Primitive Capture): * * The error INVALID_OPERATION is generated by DrawArrays and * DrawArraysInstanced if recording the vertices of a primitive to the * buffer objects being used for transform feedback purposes would result * in either exceeding the limits of any buffer object’s size, or in * exceeding the end position offset + size − 1, as set by * BindBufferRange. * * This is in contrast to the behaviour of desktop GL, where the extra * primitives are silently dropped from the transform feedback buffer. */ if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) { size_t prim_count = vbo_count_tessellated_primitives(mode, count, 1); if (xfb_obj->GlesRemainingPrims < prim_count) { _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawArrays(exceeds transform feedback size)"); return GL_FALSE; } xfb_obj->GlesRemainingPrims -= prim_count; } return GL_TRUE; }
/** * Make program of the pipeline current */ void GLAPIENTRY _mesa_BindProgramPipeline(GLuint pipeline) { GET_CURRENT_CONTEXT(ctx); struct gl_pipeline_object *newObj = NULL; if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glBindProgramPipeline(%u)\n", pipeline); /* Rebinding the same pipeline object: no change. */ if (ctx->_Shader->Name == pipeline) return; /* Section 2.17.2 (Transform Feedback Primitive Capture) of the OpenGL 4.1 * spec says: * * "The error INVALID_OPERATION is generated: * * ... * * - by BindProgramPipeline if the current transform feedback * object is active and not paused; */ if (_mesa_is_xfb_active_and_unpaused(ctx)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBindProgramPipeline(transform feedback active)"); return; } /* Get pointer to new pipeline object (newObj) */ if (pipeline) { /* non-default pipeline object */ newObj = _mesa_lookup_pipeline_object(ctx, pipeline); if (!newObj) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBindProgramPipeline(non-gen name)"); return; } /* Object is created by any Pipeline call but glGenProgramPipelines, * glIsProgramPipeline and GetProgramPipelineInfoLog */ newObj->EverBound = GL_TRUE; } _mesa_bind_pipeline(ctx, newObj); }
static void upload_sol_state(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; /* BRW_NEW_TRANSFORM_FEEDBACK */ bool active = _mesa_is_xfb_active_and_unpaused(ctx); if (active) { gen8_upload_3dstate_so_buffers(brw); /* BRW_NEW_VUE_MAP_GEOM_OUT */ gen7_upload_3dstate_so_decl_list(brw, &brw->vue_map_geom_out); } gen8_upload_3dstate_streamout(brw, active, &brw->vue_map_geom_out); }
static bool validate_DrawElements_common(struct gl_context *ctx, GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, const char *caller) { /* From the GLES3 specification, section 2.14.2 (Transform Feedback * Primitive Capture): * * The error INVALID_OPERATION is also generated by DrawElements, * DrawElementsInstanced, and DrawRangeElements while transform feedback * is active and not paused, regardless of mode. */ if (_mesa_is_gles3(ctx) && !ctx->Extensions.OES_geometry_shader && _mesa_is_xfb_active_and_unpaused(ctx)) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(transform feedback active)", caller); return false; } if (count < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(count)", caller); return false; } if (!_mesa_valid_prim_mode(ctx, mode, caller)) { return false; } if (!valid_elements_type(ctx, type, caller)) return false; if (!check_valid_to_render(ctx, caller)) return false; /* Not using a VBO for indices, so avoid NULL pointer derefs later. */ if (!_mesa_is_bufferobj(ctx->Array.VAO->IndexBufferObj) && indices == NULL) return false; if (count == 0) return false; return true; }
static void upload_sol_state(struct brw_context *brw) { struct gl_context *ctx = &brw->ctx; /* BRW_NEW_TRANSFORM_FEEDBACK */ bool active = _mesa_is_xfb_active_and_unpaused(ctx); if (active) { upload_3dstate_so_buffers(brw); /* BRW_NEW_VUE_MAP_GEOM_OUT */ gen7_upload_3dstate_so_decl_list(brw, &brw->vue_map_geom_out); } /* Finally, set up the SOL stage. This command must always follow updates to * the nonpipelined SOL state (3DSTATE_SO_BUFFER, 3DSTATE_SO_DECL_LIST) or * MMIO register updates (current performed by the kernel at each batch * emit). */ upload_3dstate_streamout(brw, active, &brw->vue_map_geom_out); }
/** * 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 (!_mesa_is_xfb_active_and_unpaused(ctx)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glPauseTransformFeedback(feedback not active or already paused)"); return; } FLUSH_VERTICES(ctx, 0); ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback; obj->Paused = GL_TRUE; assert(ctx->Driver.PauseTransformFeedback); ctx->Driver.PauseTransformFeedback(ctx, obj); }
/** * Bound program to severals stages of the pipeline */ void GLAPIENTRY _mesa_UseProgramStages(GLuint pipeline, GLbitfield stages, GLuint program) { GET_CURRENT_CONTEXT(ctx); struct gl_pipeline_object *pipe = lookup_pipeline_object(ctx, pipeline); struct gl_shader_program *shProg = NULL; GLbitfield any_valid_stages; if (!pipe) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUseProgramStages(pipeline)"); return; } /* Object is created by any Pipeline call but glGenProgramPipelines, * glIsProgramPipeline and GetProgramPipelineInfoLog */ pipe->EverBound = GL_TRUE; /* Section 2.11.4 (Program Pipeline Objects) of the OpenGL 4.1 spec says: * * "If stages is not the special value ALL_SHADER_BITS, and has a bit * set that is not recognized, the error INVALID_VALUE is generated." * * NOT YET SUPPORTED: * GL_TESS_CONTROL_SHADER_BIT * GL_TESS_EVALUATION_SHADER_BIT */ any_valid_stages = GL_VERTEX_SHADER_BIT | GL_FRAGMENT_SHADER_BIT; if (_mesa_has_geometry_shaders(ctx)) any_valid_stages |= GL_GEOMETRY_SHADER_BIT; if (stages != GL_ALL_SHADER_BITS && (stages & ~any_valid_stages) != 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glUseProgramStages(Stages)"); return; } /* Section 2.17.2 (Transform Feedback Primitive Capture) of the OpenGL 4.1 * spec says: * * "The error INVALID_OPERATION is generated: * * ... * * - by UseProgramStages if the program pipeline object it refers * to is current and the current transform feedback object is * active and not paused; */ if (ctx->_Shader == pipe) { if (_mesa_is_xfb_active_and_unpaused(ctx)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUseProgramStages(transform feedback active)"); return; } } if (program) { shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgramStages"); if (shProg == NULL) return; /* Section 2.11.4 (Program Pipeline Objects) of the OpenGL 4.1 spec * says: * * "If the program object named by program was linked without the * PROGRAM_SEPARABLE parameter set, or was not linked successfully, * the error INVALID_OPERATION is generated and the corresponding * shader stages in the pipeline program pipeline object are not * modified." */ if (!shProg->LinkStatus) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUseProgramStages(program not linked)"); return; } if (!shProg->SeparateShader) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUseProgramStages(program wasn't linked with the " "PROGRAM_SEPARABLE flag)"); return; } } /* Enable individual stages from the program as requested by the * application. If there is no shader for a requested stage in the * program, _mesa_use_shader_program will enable fixed-function processing * as dictated by the spec. * * Section 2.11.4 (Program Pipeline Objects) of the OpenGL 4.1 spec * says: * * "If UseProgramStages is called with program set to zero or with a * program object that contains no executable code for the given * stages, it is as if the pipeline object has no programmable stage * configured for the indicated shader stages." */ if ((stages & GL_VERTEX_SHADER_BIT) != 0) _mesa_use_shader_program(ctx, GL_VERTEX_SHADER, shProg, pipe); if ((stages & GL_FRAGMENT_SHADER_BIT) != 0) _mesa_use_shader_program(ctx, GL_FRAGMENT_SHADER, shProg, pipe); if ((stages & GL_GEOMETRY_SHADER_BIT) != 0) _mesa_use_shader_program(ctx, GL_GEOMETRY_SHADER, shProg, pipe); }
static GLboolean valid_draw_indirect(struct gl_context *ctx, GLenum mode, const GLvoid *indirect, GLsizei size, const char *name) { const uint64_t end = (uint64_t) (uintptr_t) indirect + size; /* OpenGL ES 3.1 spec. section 10.5: * * "DrawArraysIndirect requires that all data sourced for the * command, including the DrawArraysIndirectCommand * structure, be in buffer objects, and may not be called when * the default vertex array object is bound." */ if (ctx->Array.VAO == ctx->Array.DefaultVAO) { _mesa_error(ctx, GL_INVALID_OPERATION, "(no VAO bound)"); return GL_FALSE; } /* From OpenGL ES 3.1 spec. section 10.5: * "An INVALID_OPERATION error is generated if zero is bound to * VERTEX_ARRAY_BINDING, DRAW_INDIRECT_BUFFER or to any enabled * vertex array." * * Here we check that for each enabled vertex array we have a vertex * buffer bound. */ if (_mesa_is_gles31(ctx) && ctx->Array.VAO->_Enabled != ctx->Array.VAO->VertexAttribBufferMask) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(No VBO bound)", name); return GL_FALSE; } if (!_mesa_valid_prim_mode(ctx, mode, name)) return GL_FALSE; /* OpenGL ES 3.1 specification, section 10.5: * * "An INVALID_OPERATION error is generated if * transform feedback is active and not paused." */ if (_mesa_is_gles31(ctx) && !ctx->Extensions.OES_geometry_shader && _mesa_is_xfb_active_and_unpaused(ctx)) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(TransformFeedback is active and not paused)", name); } /* From OpenGL version 4.4. section 10.5 * and OpenGL ES 3.1, section 10.6: * * "An INVALID_VALUE error is generated if indirect is not a * multiple of the size, in basic machine units, of uint." */ if ((GLsizeiptr)indirect & (sizeof(GLuint) - 1)) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(indirect is not aligned)", name); return GL_FALSE; } if (!_mesa_is_bufferobj(ctx->DrawIndirectBuffer)) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s: no buffer bound to DRAW_INDIRECT_BUFFER", name); return GL_FALSE; } if (_mesa_check_disallowed_mapping(ctx->DrawIndirectBuffer)) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(DRAW_INDIRECT_BUFFER is mapped)", name); return GL_FALSE; } /* From the ARB_draw_indirect specification: * "An INVALID_OPERATION error is generated if the commands source data * beyond the end of the buffer object [...]" */ if (ctx->DrawIndirectBuffer->Size < end) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(DRAW_INDIRECT_BUFFER too small)", name); return GL_FALSE; } if (!check_valid_to_render(ctx, name)) return GL_FALSE; return GL_TRUE; }
/** * Is 'mode' a valid value for glBegin(), glDrawArrays(), glDrawElements(), * etc? Also, do additional checking related to transformation feedback. * Note: this function cannot be called during glNewList(GL_COMPILE) because * this code depends on current transform feedback state. * Also, do additional checking related to tessellation shaders. */ GLboolean _mesa_valid_prim_mode(struct gl_context *ctx, GLenum mode, const char *name) { bool valid_enum = _mesa_is_valid_prim_mode(ctx, mode); if (!valid_enum) { _mesa_error(ctx, GL_INVALID_ENUM, "%s(mode=%x)", name, mode); return GL_FALSE; } /* From the OpenGL 4.5 specification, section 11.3.1: * * The error INVALID_OPERATION is generated if Begin, or any command that * implicitly calls Begin, is called when a geometry shader is active and: * * * the input primitive type of the current geometry shader is * POINTS and <mode> is not POINTS, * * * the input primitive type of the current geometry shader is * LINES and <mode> is not LINES, LINE_STRIP, or LINE_LOOP, * * * the input primitive type of the current geometry shader is * TRIANGLES and <mode> is not TRIANGLES, TRIANGLE_STRIP or * TRIANGLE_FAN, * * * the input primitive type of the current geometry shader is * LINES_ADJACENCY_ARB and <mode> is not LINES_ADJACENCY_ARB or * LINE_STRIP_ADJACENCY_ARB, or * * * the input primitive type of the current geometry shader is * TRIANGLES_ADJACENCY_ARB and <mode> is not * TRIANGLES_ADJACENCY_ARB or TRIANGLE_STRIP_ADJACENCY_ARB. * * The GL spec doesn't mention any interaction with tessellation, which * is clearly a spec bug. The same rule should apply, but instead of * the draw primitive mode, the tessellation evaluation shader primitive * mode should be used for the checking. */ if (ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]) { const GLenum geom_mode = ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]-> _LinkedShaders[MESA_SHADER_GEOMETRY]->Geom.InputType; struct gl_shader_program *tes = ctx->_Shader->CurrentProgram[MESA_SHADER_TESS_EVAL]; GLenum mode_before_gs = mode; if (tes) { struct gl_shader *tes_sh = tes->_LinkedShaders[MESA_SHADER_TESS_EVAL]; if (tes_sh->TessEval.PointMode) mode_before_gs = GL_POINTS; else if (tes_sh->TessEval.PrimitiveMode == GL_ISOLINES) mode_before_gs = GL_LINES; else /* the GL_QUADS mode generates triangles too */ mode_before_gs = GL_TRIANGLES; } switch (mode_before_gs) { case GL_POINTS: valid_enum = (geom_mode == GL_POINTS); break; case GL_LINES: case GL_LINE_LOOP: case GL_LINE_STRIP: valid_enum = (geom_mode == GL_LINES); break; case GL_TRIANGLES: case GL_TRIANGLE_STRIP: case GL_TRIANGLE_FAN: valid_enum = (geom_mode == GL_TRIANGLES); break; case GL_QUADS: case GL_QUAD_STRIP: case GL_POLYGON: valid_enum = false; break; case GL_LINES_ADJACENCY: case GL_LINE_STRIP_ADJACENCY: valid_enum = (geom_mode == GL_LINES_ADJACENCY); break; case GL_TRIANGLES_ADJACENCY: case GL_TRIANGLE_STRIP_ADJACENCY: valid_enum = (geom_mode == GL_TRIANGLES_ADJACENCY); break; default: valid_enum = false; break; } if (!valid_enum) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(mode=%s vs geometry shader input %s)", name, _mesa_lookup_prim_by_nr(mode_before_gs), _mesa_lookup_prim_by_nr(geom_mode)); return GL_FALSE; } } /* From the OpenGL 4.0 (Core Profile) spec (section 2.12): * * "Tessellation operates only on patch primitives. If tessellation is * active, any command that transfers vertices to the GL will * generate an INVALID_OPERATION error if the primitive mode is not * PATCHES. * Patch primitives are not supported by pipeline stages below the * tessellation evaluation shader. If there is no active program * object or the active program object does not contain a tessellation * evaluation shader, the error INVALID_OPERATION is generated by any * command that transfers vertices to the GL if the primitive mode is * PATCHES." * */ if (ctx->_Shader->CurrentProgram[MESA_SHADER_TESS_EVAL] || ctx->_Shader->CurrentProgram[MESA_SHADER_TESS_CTRL]) { if (mode != GL_PATCHES) { _mesa_error(ctx, GL_INVALID_OPERATION, "only GL_PATCHES valid with tessellation"); return GL_FALSE; } } else { if (mode == GL_PATCHES) { _mesa_error(ctx, GL_INVALID_OPERATION, "GL_PATCHES only valid with tessellation"); return GL_FALSE; } } /* From the GL_EXT_transform_feedback spec: * * "The error INVALID_OPERATION is generated if Begin, or any command * that performs an explicit Begin, is called when: * * * a geometry shader is not active and <mode> does not match the * allowed begin modes for the current transform feedback state as * given by table X.1. * * * a geometry shader is active and the output primitive type of the * geometry shader does not match the allowed begin modes for the * current transform feedback state as given by table X.1. * */ if (_mesa_is_xfb_active_and_unpaused(ctx)) { GLboolean pass = GL_TRUE; if(ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]) { switch (ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]-> _LinkedShaders[MESA_SHADER_GEOMETRY]->Geom.OutputType) { case GL_POINTS: pass = ctx->TransformFeedback.Mode == GL_POINTS; break; case GL_LINE_STRIP: pass = ctx->TransformFeedback.Mode == GL_LINES; break; case GL_TRIANGLE_STRIP: pass = ctx->TransformFeedback.Mode == GL_TRIANGLES; break; default: pass = GL_FALSE; } } else if (ctx->_Shader->CurrentProgram[MESA_SHADER_TESS_EVAL]) { struct gl_shader_program *tes = ctx->_Shader->CurrentProgram[MESA_SHADER_TESS_EVAL]; struct gl_shader *tes_sh = tes->_LinkedShaders[MESA_SHADER_TESS_EVAL]; if (tes_sh->TessEval.PointMode) pass = ctx->TransformFeedback.Mode == GL_POINTS; else if (tes_sh->TessEval.PrimitiveMode == GL_ISOLINES) pass = ctx->TransformFeedback.Mode == GL_LINES; else pass = ctx->TransformFeedback.Mode == GL_TRIANGLES; } else { switch (mode) { case GL_POINTS: pass = ctx->TransformFeedback.Mode == GL_POINTS; break; case GL_LINES: case GL_LINE_STRIP: case GL_LINE_LOOP: pass = ctx->TransformFeedback.Mode == GL_LINES; break; default: pass = ctx->TransformFeedback.Mode == GL_TRIANGLES; break; } } if (!pass) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(mode=%s vs transform feedback %s)", name, _mesa_lookup_prim_by_nr(mode), _mesa_lookup_prim_by_nr(ctx->TransformFeedback.Mode)); return GL_FALSE; } } return GL_TRUE; }
static bool validate_draw_arrays(struct gl_context *ctx, const char *func, GLenum mode, GLsizei count, GLsizei numInstances) { struct gl_transform_feedback_object *xfb_obj = ctx->TransformFeedback.CurrentObject; FLUSH_CURRENT(ctx, 0); if (count < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(count)", func); return false; } if (!_mesa_valid_prim_mode(ctx, mode, func)) return false; if (!check_valid_to_render(ctx, func)) return false; /* From the GLES3 specification, section 2.14.2 (Transform Feedback * Primitive Capture): * * The error INVALID_OPERATION is generated by DrawArrays and * DrawArraysInstanced if recording the vertices of a primitive to the * buffer objects being used for transform feedback purposes would result * in either exceeding the limits of any buffer object’s size, or in * exceeding the end position offset + size − 1, as set by * BindBufferRange. * * This is in contrast to the behaviour of desktop GL, where the extra * primitives are silently dropped from the transform feedback buffer. * * This text is removed in ES 3.2, presumably because it's not really * implementable with geometry and tessellation shaders. In fact, * the OES_geometry_shader spec says: * * "(13) Does this extension change how transform feedback operates * compared to unextended OpenGL ES 3.0 or 3.1? * * RESOLVED: Yes. Because dynamic geometry amplification in a geometry * shader can make it difficult if not impossible to predict the amount * of geometry that may be generated in advance of executing the shader, * the draw-time error for transform feedback buffer overflow conditions * is removed and replaced with the GL behavior (primitives are not * written and the corresponding counter is not updated)..." */ if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx) && !_mesa_has_OES_geometry_shader(ctx) && !_mesa_has_OES_tessellation_shader(ctx)) { size_t prim_count = vbo_count_tessellated_primitives(mode, count, 1); if (xfb_obj->GlesRemainingPrims < prim_count) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(exceeds transform feedback size)", func); return false; } xfb_obj->GlesRemainingPrims -= prim_count; } if (count == 0) return false; return true; }
static bool validate_DrawElements_common(struct gl_context *ctx, GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, const char *caller) { /* Section 2.14.2 (Transform Feedback Primitive Capture) of the OpenGL ES * 3.1 spec says: * * The error INVALID_OPERATION is also generated by DrawElements, * DrawElementsInstanced, and DrawRangeElements while transform feedback * is active and not paused, regardless of mode. * * The OES_geometry_shader_spec says: * * Issues: * * ... * * (13) Does this extension change how transform feedback operates * compared to unextended OpenGL ES 3.0 or 3.1? * * RESOLVED: Yes... Since we no longer require being able to predict how * much geometry will be generated, we also lift the restriction that * only DrawArray* commands are supported and also support the * DrawElements* commands for transform feedback. * * This should also be reflected in the body of the spec, but that appears * to have been overlooked. The body of the spec only explicitly allows * the indirect versions. */ if (_mesa_is_gles3(ctx) && !ctx->Extensions.OES_geometry_shader && _mesa_is_xfb_active_and_unpaused(ctx)) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(transform feedback active)", caller); return false; } if (count < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(count)", caller); return false; } if (!_mesa_valid_prim_mode(ctx, mode, caller)) { return false; } if (!valid_elements_type(ctx, type, caller)) return false; if (!check_valid_to_render(ctx, caller)) return false; /* Not using a VBO for indices, so avoid NULL pointer derefs later. */ if (!_mesa_is_bufferobj(ctx->Array.VAO->IndexBufferObj) && indices == NULL) return false; if (count == 0) return false; return true; }
static void populate_key(struct brw_context *brw, struct brw_ff_gs_prog_key *key) { static const unsigned swizzle_for_offset[4] = { BRW_SWIZZLE4(0, 1, 2, 3), BRW_SWIZZLE4(1, 2, 3, 3), BRW_SWIZZLE4(2, 3, 3, 3), BRW_SWIZZLE4(3, 3, 3, 3) }; struct gl_context *ctx = &brw->ctx; memset(key, 0, sizeof(*key)); /* CACHE_NEW_VS_PROG (part of VUE map) */ key->attrs = brw->vs.prog_data->base.vue_map.slots_valid; /* BRW_NEW_PRIMITIVE */ key->primitive = brw->primitive; /* _NEW_LIGHT */ key->pv_first = (ctx->Light.ProvokingVertex == GL_FIRST_VERTEX_CONVENTION); if (key->primitive == _3DPRIM_QUADLIST && ctx->Light.ShadeModel != GL_FLAT) { /* Provide consistent primitive order with brw_set_prim's * optimization of single quads to trifans. */ key->pv_first = true; } if (brw->gen >= 7) { /* On Gen7 and later, we don't use GS (yet). */ key->need_gs_prog = false; } else if (brw->gen == 6) { /* On Gen6, GS is used for transform feedback. */ /* BRW_NEW_TRANSFORM_FEEDBACK */ if (_mesa_is_xfb_active_and_unpaused(ctx)) { const struct gl_shader_program *shaderprog = ctx->Shader.CurrentProgram[MESA_SHADER_VERTEX]; const struct gl_transform_feedback_info *linked_xfb_info = &shaderprog->LinkedTransformFeedback; int i; /* Make sure that the VUE slots won't overflow the unsigned chars in * key->transform_feedback_bindings[]. */ STATIC_ASSERT(BRW_VARYING_SLOT_COUNT <= 256); /* Make sure that we don't need more binding table entries than we've * set aside for use in transform feedback. (We shouldn't, since we * set aside enough binding table entries to have one per component). */ assert(linked_xfb_info->NumOutputs <= BRW_MAX_SOL_BINDINGS); key->need_gs_prog = true; key->num_transform_feedback_bindings = linked_xfb_info->NumOutputs; for (i = 0; i < key->num_transform_feedback_bindings; ++i) { key->transform_feedback_bindings[i] = linked_xfb_info->Outputs[i].OutputRegister; key->transform_feedback_swizzles[i] = swizzle_for_offset[linked_xfb_info->Outputs[i].ComponentOffset]; } } } else { /* Pre-gen6, GS is used to transform QUADLIST, QUADSTRIP, and LINELOOP * into simpler primitives. */ key->need_gs_prog = (brw->primitive == _3DPRIM_QUADLIST || brw->primitive == _3DPRIM_QUADSTRIP || brw->primitive == _3DPRIM_LINELOOP); } }
/** * Is 'mode' a valid value for glBegin(), glDrawArrays(), glDrawElements(), * etc? Also, do additional checking related to transformation feedback. * Note: this function cannot be called during glNewList(GL_COMPILE) because * this code depends on current transform feedback state. */ GLboolean _mesa_valid_prim_mode(struct gl_context *ctx, GLenum mode, const char *name) { bool valid_enum = _mesa_is_valid_prim_mode(ctx, mode); if (!valid_enum) { _mesa_error(ctx, GL_INVALID_ENUM, "%s(mode=%x)", name, mode); return GL_FALSE; } /* From the ARB_geometry_shader4 spec: * * The error INVALID_OPERATION is generated if Begin, or any command that * implicitly calls Begin, is called when a geometry shader is active and: * * * the input primitive type of the current geometry shader is * POINTS and <mode> is not POINTS, * * * the input primitive type of the current geometry shader is * LINES and <mode> is not LINES, LINE_STRIP, or LINE_LOOP, * * * the input primitive type of the current geometry shader is * TRIANGLES and <mode> is not TRIANGLES, TRIANGLE_STRIP or * TRIANGLE_FAN, * * * the input primitive type of the current geometry shader is * LINES_ADJACENCY_ARB and <mode> is not LINES_ADJACENCY_ARB or * LINE_STRIP_ADJACENCY_ARB, or * * * the input primitive type of the current geometry shader is * TRIANGLES_ADJACENCY_ARB and <mode> is not * TRIANGLES_ADJACENCY_ARB or TRIANGLE_STRIP_ADJACENCY_ARB. * */ if (ctx->Shader.CurrentGeometryProgram) { const GLenum geom_mode = ctx->Shader.CurrentGeometryProgram->Geom.InputType; switch (mode) { case GL_POINTS: valid_enum = (geom_mode == GL_POINTS); break; case GL_LINES: case GL_LINE_LOOP: case GL_LINE_STRIP: valid_enum = (geom_mode == GL_LINES); break; case GL_TRIANGLES: case GL_TRIANGLE_STRIP: case GL_TRIANGLE_FAN: valid_enum = (geom_mode == GL_TRIANGLES); break; case GL_QUADS: case GL_QUAD_STRIP: case GL_POLYGON: valid_enum = false; break; case GL_LINES_ADJACENCY: case GL_LINE_STRIP_ADJACENCY: valid_enum = (geom_mode == GL_LINES_ADJACENCY); break; case GL_TRIANGLES_ADJACENCY: case GL_TRIANGLE_STRIP_ADJACENCY: valid_enum = (geom_mode == GL_TRIANGLES_ADJACENCY); break; default: valid_enum = false; break; } if (!valid_enum) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(mode=%s vs geometry shader input %s)", name, _mesa_lookup_prim_by_nr(mode), _mesa_lookup_prim_by_nr(geom_mode)); return GL_FALSE; } } /* From the GL_EXT_transform_feedback spec: * * "The error INVALID_OPERATION is generated if Begin, or any command * that performs an explicit Begin, is called when: * * * a geometry shader is not active and <mode> does not match the * allowed begin modes for the current transform feedback state as * given by table X.1. * * * a geometry shader is active and the output primitive type of the * geometry shader does not match the allowed begin modes for the * current transform feedback state as given by table X.1. * */ if (_mesa_is_xfb_active_and_unpaused(ctx)) { GLboolean pass = GL_TRUE; switch (mode) { case GL_POINTS: pass = ctx->TransformFeedback.Mode == GL_POINTS; break; case GL_LINES: case GL_LINE_STRIP: case GL_LINE_LOOP: pass = ctx->TransformFeedback.Mode == GL_LINES; break; default: pass = ctx->TransformFeedback.Mode == GL_TRIANGLES; break; } if (!pass) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(mode=%s vs transform feedback %s)", name, _mesa_lookup_prim_by_nr(mode), _mesa_lookup_prim_by_nr(ctx->TransformFeedback.Mode)); return GL_FALSE; } } return GL_TRUE; }