void piglit_init(int argc, char **argv) { bool pass = true; GLuint framebuffer; GLuint default_framebuffer = 0; GLenum bufs[2] = {GL_BACK_LEFT, GL_BACK}; GLenum one_buf; bool subtest_pass; int i; glCreateFramebuffers(1, &framebuffer); piglit_check_gl_error(GL_NO_ERROR); /* * "An INVALID_OPERATION error is generated by * NamedFramebufferDrawBuffers if framebuffer is not zero or * the name of an existing framebuffer" */ glNamedFramebufferDrawBuffers(5, 2, bufs); PIGLIT_SUBTEST_ERROR(GL_INVALID_OPERATION, pass, "INVALID_OPERATION if " "framebuffer is not zero or the name of an existing " "framebuffer"); /* * "An INVALID_VALUE error is generated if n is negative, or greater than the * value of MAX_DRAW_BUFFERS." */ int max_draw_buffers; glGetIntegerv(GL_MAX_DRAW_BUFFERS, &max_draw_buffers); subtest_pass = true; glNamedFramebufferDrawBuffers(0, -1, bufs); subtest_pass = subtest_pass & piglit_check_gl_error(GL_INVALID_VALUE); glNamedFramebufferDrawBuffers(0, max_draw_buffers + 1, bufs); subtest_pass = subtest_pass & piglit_check_gl_error(GL_INVALID_VALUE); PIGLIT_SUBTEST_CONDITION(subtest_pass, pass, "INVALID_VALUE error is " "generated if n is negative, or greater than " "the value of MAX_DRAW_BUFFERS."); /* * From OpenGL 4.5 spec * "An INVALID_ENUM error is generated if any value in bufs * is not one of the values in tables 17.5 or 17.6." */ subtest_pass = true; one_buf = GL_RED; glNamedFramebufferDrawBuffers(default_framebuffer, 1, &one_buf); subtest_pass = subtest_pass && piglit_check_gl_error(GL_INVALID_ENUM); glNamedFramebufferDrawBuffers(framebuffer, 1, &one_buf); subtest_pass = subtest_pass && piglit_check_gl_error(GL_INVALID_ENUM); PIGLIT_SUBTEST_CONDITION(subtest_pass, pass, "INVALID_ENUM error is " "generated if any value in bufs is not one of " "the values in tables 17.5 or 17.6."); /* * (cont on error out of 17.5 or 17.6) Specifically for the default * framebuffer: * From OpenGL 4.5 spec, page 492 (515 PDF) * "If the default framebuffer is affected, then each of the * constants must be one of the values listed in table 17.6 * or the special value BACK ."" * * And: *"An INVALID_OPERATION error is generated if the default * framebuffer is affected and any value in bufs is a * constant (other than NONE or BACK) that does not indicate * one of the color buffers allocated to the default * framebuffer." * * So for the default framebuffer, and that table, we expect * GL_NO_ERROR or GL_INVALID_OPERATION. */ subtest_pass = true; for (i = 0; i < ARRAY_SIZE(table_17_6_and_back); i++) { GLenum err = 0; glNamedFramebufferDrawBuffers(default_framebuffer, 1, &table_17_6_and_back[i]); /* We manually check glGetError instead of relying on * piglit_check_gl_error like in other subtests * because for subtests that checks several enums, we * are interested on getting which one failed. That * makes debugging easier. */ err = glGetError(); if (err != GL_NO_ERROR && err != GL_INVALID_OPERATION) { printf("Expected GL_NO_ERROR or GL_INVALID_OPERATION " "with %s but received: %s\n", piglit_get_gl_enum_name(table_17_6_and_back[i]), piglit_get_gl_error_name(err)); subtest_pass = false; } } /* For that spec paragraph, we also test enums from table * 17.5. They should return INVALID_OPERATION, as after all, * they are not allocated to the default framebuffer. */ one_buf = GL_COLOR_ATTACHMENT0; glNamedFramebufferDrawBuffers(default_framebuffer, 1, &one_buf); subtest_pass = subtest_pass && piglit_check_gl_error(GL_INVALID_OPERATION); PIGLIT_SUBTEST_CONDITION(subtest_pass, pass, "If the default framebuffer" " is affected, then each of the constants must " "be one of the values listed in table 17.6 or " "the special value BACK. INVALID_OPERATION error" " is generated if the default framebuffer is " "affected and any value in bufs is a constant " "(other than NONE or BACK ) that does not indicate " "one of the color buffers allocated to the default" " framebuffer."); /* (cont default framebuffer) * From OpenGL 4.5 spec: * "When BACK is used, n must be 1 and color values are * written into the left buffer for single-buffered * contexts, or into the back left buffer for * double-buffered contexts" * * From the error table: * "An INVALID_OPERATION error is generated if any value in * bufs is BACK , and n is not one." * */ glNamedFramebufferDrawBuffers(default_framebuffer, 2, bufs); PIGLIT_SUBTEST_ERROR(GL_INVALID_OPERATION, pass, "(default framebuffer)" " An INVALID_OPERATION error is generated if any " "value in bufs is BACK, and n is not one."); /* * Now, specifically for a framebuffer object: * "If a framebuffer object is affected, then each of the * constants must be one of the values listed in table 17.5." * * 17.5 is GL_NONE, and COLOR_ATTACHMENTi, where i < * MAX_COLOR_ATTACHMENTS - 1 */ int max_attachments; glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &max_attachments); subtest_pass = true; for (i = 0; i < max_attachments; i++) { one_buf = GL_COLOR_ATTACHMENT0 + i; glNamedFramebufferDrawBuffers(framebuffer, 1, &one_buf); subtest_pass = subtest_pass && piglit_check_gl_error(GL_NO_ERROR); } PIGLIT_SUBTEST_CONDITION(subtest_pass, pass, "If a framebuffer object is " "affected, then each of constants must be one of the " "values listed in table 17.5."); /* * "An INVALID_OPERATION error is generated if a framebuffer * object is affected and any value in bufs is a constant * from table 17.6, or COLOR_ATTACHMENTm where m is greater * than or equal to the value of MAX_COLOR_ATTACHMENTS." */ subtest_pass = true; /* Starting at 1, as GL_NONE is valid */ for (i = 1; i < ARRAY_SIZE(table_17_6); i++) { GLenum err = 0; glNamedFramebufferDrawBuffers(framebuffer, 1, &table_17_6[i]); err = glGetError(); if (err != GL_INVALID_OPERATION) { printf("Expected GL_INVALID_OPERATION with" " %s but received: %s\n", piglit_get_gl_enum_name(table_17_6[i]), piglit_get_gl_error_name(err)); subtest_pass = false; } } one_buf = GL_COLOR_ATTACHMENT0 + max_attachments; glNamedFramebufferDrawBuffers(framebuffer, 1, &one_buf); subtest_pass = subtest_pass && piglit_check_gl_error(GL_INVALID_OPERATION); PIGLIT_SUBTEST_CONDITION(subtest_pass, pass, "INVALID_OPERATION error is " "generated if a framebuffer object is affected and any " "value in bufs is a constant from table 17.6, or " "COLOR_ATTACHMENTm where m is greater than or equal " "to the value of MAX_COLOR_ATTACHMENTS."); /* * "An INVALID_OPERATION error is generated if a buffer other * than NONE is specified more than once in the array pointed * to by bufs" */ bufs[0] = bufs[1] = GL_FRONT_LEFT; glNamedFramebufferDrawBuffers(framebuffer, 2, bufs); PIGLIT_SUBTEST_ERROR(GL_INVALID_OPERATION, pass, "INVALID_OPERATION error " "is generated if a buffer other than NONE is specified " "more than once in the array pointed to by bufs."); /* * From OpenGL 4.5 spec: * "An INVALID_ENUM error is generated if any value in bufs is * FRONT, LEFT, RIGHT, or FRONT_AND_BACK . This restriction * applies to both the default framebuffer and framebuffer * objects, and exists because these constants may themselves * refer to multiple buffers, as shown in table 17.4." */ subtest_pass = true; for (i = 0; i < ARRAY_SIZE(multiple_buffers); i++) { GLenum err = 0; bool local_pass = true; glNamedFramebufferDrawBuffers(default_framebuffer, 1, &multiple_buffers[i]); err = glGetError(); local_pass = local_pass && (err == GL_INVALID_ENUM); glNamedFramebufferDrawBuffers(framebuffer, 1, &multiple_buffers[i]); err = glGetError(); local_pass = local_pass && (err == GL_INVALID_ENUM); if (!local_pass) printf("Expected GL_INVALID_ENUM with" " %s but received: %s\n", piglit_get_gl_enum_name(table_17_6_and_back[i]), piglit_get_gl_error_name(err)); subtest_pass = subtest_pass && local_pass; } PIGLIT_SUBTEST_CONDITION(subtest_pass, pass, "INVALID_ENUM error is " "generated if any value in bufs is FRONT, LEFT," " RIGHT, or FRONT_AND_BACK "); /* clean up */ glDeleteFramebuffers(1, &framebuffer); piglit_report_result(pass ? PIGLIT_PASS : PIGLIT_FAIL); }
enum piglit_result piglit_display(void) { GLint max_bind_points = 0; GLuint q, num_prims; bool pass = true, test = true; GLfloat *v, *w; int i; /* init the transform feedback buffers */ glGenBuffers(3, xfb_buf); glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buf[2]); piglit_check_gl_error(GL_NO_ERROR); /* Fetch the number of bind points */ glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_BUFFERS, &max_bind_points); PIGLIT_SUBTEST_ERROR(GL_NO_ERROR, pass, "fetch maximum number of bind " "points"); if (piglit_khr_no_error) goto valid_calls; /* bind a non-existing transform feedback BO */ glTransformFeedbackBufferBase(1337, 0, 0); PIGLIT_SUBTEST_ERROR(GL_INVALID_OPERATION, pass, "bind non-existing transform feedback BO"); /* bind a non-existing output BO */ glTransformFeedbackBufferBase(0, 0, 1337); PIGLIT_SUBTEST_ERROR(GL_INVALID_VALUE, pass, "bind a non-existing " "output BO"); /* bind to a negative index */ glTransformFeedbackBufferBase(0, -1, xfb_buf[2]); PIGLIT_SUBTEST_ERROR(GL_INVALID_VALUE, pass, "bind negative index"); /* bind to an index == max */ glTransformFeedbackBufferBase(0, max_bind_points, xfb_buf[2]); PIGLIT_SUBTEST_ERROR(GL_INVALID_VALUE, pass, "bind to index == " "max_bind_points (%i)", max_bind_points); valid_calls: /* Set up the transform feedback buffer */ for (i = 0; i < 2; i++) { glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buf[i]); glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buf_size, NULL, GL_STREAM_READ); glTransformFeedbackBufferBase(0, i, xfb_buf[i]); piglit_check_gl_error(GL_NO_ERROR); } /* Set up the query that checks the # of primitives handled */ glGenQueries(1, &q); glBeginQuery(GL_PRIMITIVES_GENERATED, q); piglit_check_gl_error(GL_NO_ERROR); /* do the transform feedback */ glBeginTransformFeedback(GL_POINTS); glBindBuffer(GL_ARRAY_BUFFER, input_buf); glDrawArrays(GL_POINTS, 0, NUM_INPUTS); glEndTransformFeedback(); glEndQuery(GL_PRIMITIVES_GENERATED); /* check the number of primitives */ glGetQueryObjectuiv(q, GL_QUERY_RESULT, &num_prims); glDeleteQueries(1, &q); printf("%u primitives generated:\n", num_prims); if (num_prims != NUM_INPUTS) { printf("Incorrect number of prims generated.\n"); printf("Found %u, expected %u\n", num_prims, NUM_INPUTS); pass = false; test = false; } /* check the result */ glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buf[0]); v = glMapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY); piglit_check_gl_error(GL_NO_ERROR); glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buf[1]); w = glMapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY); piglit_check_gl_error(GL_NO_ERROR); for (i = 0; i < num_prims; i++) { printf("%2d: (%2.0g, %2.0g) : ", i, v[i], w[i]); if (!equal(v[i], out1_ret[i]) || !equal(w[i], out2_ret[i])) { printf("NOK, expected (%2.0g, %2.0g)\n", out1_ret[i], out2_ret[i]); test = false; } else printf("OK\n"); } PIGLIT_SUBTEST_CONDITION(test, pass, "general test"); piglit_present_results(); /* clean-up everything */ glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buf[0]); glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER); glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buf[1]); glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER); glDeleteBuffers(3, xfb_buf); glDeleteBuffers(1, &input_buf); glDeleteVertexArrays(1, &vao); glDeleteProgram(prog); return pass ? PIGLIT_PASS : PIGLIT_FAIL; }