#include <stdbool.h>
#include "glheader.h"
#include "api_validate.h"
+#include "arrayobj.h"
#include "bufferobj.h"
#include "context.h"
#include "imports.h"
/* For OpenGL ES, only draw if we have vertex positions
*/
if (!ctx->Array.VAO->VertexAttrib[VERT_ATTRIB_POS].Enabled)
- return false;
+ return false;
break;
case API_OPENGL_CORE:
unreachable("Invalid API value in check_valid_to_render()");
}
+ if (!_mesa_all_buffers_are_unmapped(ctx->Array.VAO)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(vertex buffers are mapped)", function);
+ return false;
+ }
+
return true;
}
*/
if (ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]) {
const GLenum geom_mode =
- ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]->Geom.InputType;
+ ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]->
+ _LinkedShaders[MESA_SHADER_GEOMETRY]->info.Geom.InputType;
struct gl_shader_program *tes =
ctx->_Shader->CurrentProgram[MESA_SHADER_TESS_EVAL];
GLenum mode_before_gs = mode;
if (tes) {
- if (tes->TessEval.PointMode)
+ struct gl_linked_shader *tes_sh =
+ tes->_LinkedShaders[MESA_SHADER_TESS_EVAL];
+ if (tes_sh->info.TessEval.PointMode)
mode_before_gs = GL_POINTS;
- else if (tes->TessEval.PrimitiveMode == GL_ISOLINES)
+ else if (tes_sh->info.TessEval.PrimitiveMode == GL_ISOLINES)
mode_before_gs = GL_LINES;
else
/* the GL_QUADS mode generates triangles too */
GLboolean pass = GL_TRUE;
if(ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]) {
- switch (ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]->Geom.OutputType) {
+ switch (ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]->
+ _LinkedShaders[MESA_SHADER_GEOMETRY]->
+ info.Geom.OutputType) {
case GL_POINTS:
pass = ctx->TransformFeedback.Mode == GL_POINTS;
break;
else if (ctx->_Shader->CurrentProgram[MESA_SHADER_TESS_EVAL]) {
struct gl_shader_program *tes =
ctx->_Shader->CurrentProgram[MESA_SHADER_TESS_EVAL];
-
- if (tes->TessEval.PointMode)
+ struct gl_linked_shader *tes_sh =
+ tes->_LinkedShaders[MESA_SHADER_TESS_EVAL];
+ if (tes_sh->info.TessEval.PointMode)
pass = ctx->TransformFeedback.Mode == GL_POINTS;
- else if (tes->TessEval.PrimitiveMode == GL_ISOLINES)
+ else if (tes_sh->info.TessEval.PrimitiveMode == GL_ISOLINES)
pass = ctx->TransformFeedback.Mode == GL_LINES;
else
pass = ctx->TransformFeedback.Mode == GL_TRIANGLES;
}
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));
+ "%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;
}
}
* 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)) {
+ 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;
*/
GLboolean
_mesa_validate_DrawElements(struct gl_context *ctx,
- GLenum mode, GLsizei count, GLenum type,
- const GLvoid *indices)
+ GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices)
{
FLUSH_CURRENT(ctx, 0);
*/
GLboolean
_mesa_validate_DrawRangeElements(struct gl_context *ctx, GLenum mode,
- GLuint start, GLuint end,
- GLsizei count, GLenum type,
- const GLvoid *indices)
+ GLuint start, GLuint end,
+ GLsizei count, GLenum type,
+ const GLvoid *indices)
{
FLUSH_CURRENT(ctx, 0);
"glDrawRangeElements");
}
-
-/**
- * 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, GLsizei count)
+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, "glDrawArrays(count)" );
- return GL_FALSE;
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(count)", func);
+ return false;
}
- if (!_mesa_valid_prim_mode(ctx, mode, "glDrawArrays")) {
- return GL_FALSE;
- }
+ if (!_mesa_valid_prim_mode(ctx, mode, func))
+ return false;
- if (!check_valid_to_render(ctx, "glDrawArrays"))
- return GL_FALSE;
+ if (!check_valid_to_render(ctx, func))
+ return false;
/* From the GLES3 specification, section 2.14.2 (Transform Feedback
* Primitive Capture):
*
* 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)) {
+ 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,
- "glDrawArrays(exceeds transform feedback size)");
- return GL_FALSE;
+ "%s(exceeds transform feedback size)", func);
+ return false;
}
xfb_obj->GlesRemainingPrims -= prim_count;
}
if (count == 0)
- return GL_FALSE;
+ return false;
- return GL_TRUE;
+ return 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, GLsizei count)
+{
+ return validate_draw_arrays(ctx, "glDrawArrays", mode, count, 1);
}
_mesa_validate_DrawArraysInstanced(struct gl_context *ctx, GLenum mode, GLint first,
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,
- "glDrawArraysInstanced(count=%d)", count);
- return GL_FALSE;
- }
-
if (first < 0) {
_mesa_error(ctx, GL_INVALID_VALUE,
- "glDrawArraysInstanced(start=%d)", first);
- return GL_FALSE;
- }
-
- if (!_mesa_valid_prim_mode(ctx, mode, "glDrawArraysInstanced")) {
+ "glDrawArraysInstanced(start=%d)", first);
return GL_FALSE;
}
return GL_FALSE;
}
- if (!check_valid_to_render(ctx, "glDrawArraysInstanced(invalid to render)"))
- 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, numInstances);
- if (xfb_obj->GlesRemainingPrims < prim_count) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glDrawArraysInstanced(exceeds transform feedback size)");
- return GL_FALSE;
- }
- xfb_obj->GlesRemainingPrims -= prim_count;
- }
-
- if (count == 0)
- return GL_FALSE;
-
- return GL_TRUE;
+ return validate_draw_arrays(ctx, "glDrawArraysInstanced", mode, count, 1);
}
return GL_FALSE;
}
+ /* From the GL 4.5 specification, page 429:
+ * "An INVALID_VALUE error is generated if id is not the name of a
+ * transform feedback object."
+ */
+ if (!obj->EverBound) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glDrawTransformFeedback*(name)");
+ return GL_FALSE;
+ }
+
if (stream >= ctx->Const.MaxVertexStreams) {
_mesa_error(ctx, GL_INVALID_VALUE,
"glDrawTransformFeedbackStream*(index>=MaxVertexStream)");
* "An INVALID_OPERATION error is generated if
* transform feedback is active and not paused."
*/
- if (_mesa_is_gles31(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) {
+ 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);
}
GLintptr indirect,
GLsizei size, const char *name)
{
- GLintptr end = (GLintptr)indirect + size;
+ const uint64_t end = (uint64_t) indirect + size;
if (!check_valid_to_compute(ctx, name))
return GL_FALSE;
* "An INVALID_VALUE error is generated if indirect is negative or is not a
* multiple of four."
*/
- if ((GLintptr)indirect & (sizeof(GLuint) - 1)) {
+ if (indirect & (sizeof(GLuint) - 1)) {
_mesa_error(ctx, GL_INVALID_VALUE,
"%s(indirect is not aligned)", name);
return GL_FALSE;
}
- if ((GLintptr)indirect < 0) {
+ if (indirect < 0) {
_mesa_error(ctx, GL_INVALID_VALUE,
"%s(indirect is less than zero)", name);
return GL_FALSE;