1 /*
2  * Copyright © 2015 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 /** @file transformfeedback-bufferbase.c
25  * Simple transform feedback test drawing GL_POINTS and making use of the
26  * transform-feedback-related direct state access entry points.
27  *
28  * Greatly inspired from ext_transform_feedback/points.c.
29  *
30  * From OpenGL 4.5, section 13.2.2 "Transform Feedback Primitive Capture",
31  * page 422:
32  *
33  * "void TransformFeedbackBufferBase( uint xfb, uint index, uint buffer );
34  *
35  * xfb must be zero, indicating the default transform feedback object, or the
36  * name of an existing transform feedback object. buffer must be zero or the
37  * name of an existing buffer object.
38  *
39  * TransformFeedbackBufferRange and TransformFeedbackBufferBase behave
40  * similarly to BindBufferRange and BindBufferBase, respectively, except
41  * that the target of the operation is xfb, and they do not affect any binding
42  * to the generic TRANSFORM_FEEDBACK_BUFFER target.
43  *
44  * Errors
45  * An INVALID_OPERATION error is generated if xfb is not zero or the name
46  *  of an existing transform feedback object.
47  * An INVALID_VALUE error is generated if buffer is not zero or the name of
48  *  an existing buffer object.
49  * An INVALID_VALUE error is generated if index is greater than or equal
50  *  to the number of binding points for transform feedback, as described in
51  *  section 6.7.1.
52  * An INVALID_VALUE error is generated by TransformFeedbackBufferRange
53  *  if offset is negative.
54  * An INVALID_VALUE error is generated by TransformFeedbackBufferRange
55  *  if size is less than or equal to zero.
56  * An INVALID_VALUE error is generated by TransformFeedbackBufferRange
57  *  if offset or size do not satisfy the constraints described for those
58  * parameters for transform feedback array bindings, as described in
59  *  section 6.7.1."
60  */
61 
62 #include "piglit-util-gl.h"
63 #include "dsa-utils.h"
64 
65 PIGLIT_GL_TEST_CONFIG_BEGIN
66 	config.supports_gl_core_version = 31;
67 	config.window_visual = PIGLIT_GL_VISUAL_DOUBLE | PIGLIT_GL_VISUAL_RGBA;
68 	config.khr_no_error_support = PIGLIT_NO_ERRORS;
69 PIGLIT_GL_TEST_CONFIG_END
70 
71 
72 static GLuint prog;
73 static GLuint xfb_buf[3], input_buf, vao;
74 static const int xfb_buf_size = 500;
75 
76 static const char *vstext = {
77 	"#version 140\n"
78 	"in float valIn;"
79 	"out float valOut1;"
80 	"out float valOut2;"
81 	"void main() {"
82 	"   valOut1 = valIn + 1;"
83 	"   valOut2 = valIn * 2;"
84 	"}"
85 };
86 
87 #define NUM_INPUTS 4
88 static const GLfloat inputs[NUM_INPUTS] =   {-1.0, 0.0, 1.0, 3.0};
89 static const GLfloat out1_ret[NUM_INPUTS] = { 0.0, 1.0, 2.0, 4.0};
90 static const GLfloat out2_ret[NUM_INPUTS] = {-2.0, 0.0, 2.0, 6.0};
91 
92 void
piglit_init(int argc,char ** argv)93 piglit_init(int argc, char **argv)
94 {
95 	static const char *varyings[] = { "valOut1", "valOut2" };
96 	GLint inAttrib;
97 
98 	/* Check the driver. */
99 	piglit_require_extension("GL_ARB_transform_feedback3");
100 	piglit_require_extension("GL_ARB_direct_state_access");
101 
102 	/* Create shaders. */
103 	prog = piglit_build_simple_program_unlinked(vstext, NULL);
104 	glTransformFeedbackVaryings(prog, 2, varyings,
105 					GL_SEPARATE_ATTRIBS);
106 	glLinkProgram(prog);
107 	if (!piglit_link_check_status(prog)) {
108 		glDeleteProgram(prog);
109 		piglit_report_result(PIGLIT_FAIL);
110 	}
111 	glUseProgram(prog);
112 
113 	/* Set up the Vertex Array Buffer */
114 	glEnable(GL_VERTEX_ARRAY);
115 	glGenVertexArrays(1, &vao);
116 	glBindVertexArray(vao);
117 
118 	/* Set up the input data buffer */
119 	glGenBuffers(1, &input_buf);
120 	glBindBuffer(GL_ARRAY_BUFFER, input_buf);
121 	glBufferData(GL_ARRAY_BUFFER, sizeof(inputs), inputs, GL_STATIC_DRAW);
122 	inAttrib = glGetAttribLocation(prog, "valIn");
123 	piglit_check_gl_error(GL_NO_ERROR);
124 	glVertexAttribPointer(inAttrib, 1, GL_FLOAT, GL_FALSE, 0, 0);
125 	glEnableVertexAttribArray(inAttrib);
126 }
127 
128 static bool
equal(float a,float b)129 equal(float a, float b)
130 {
131 	return fabsf(a - b) < piglit_tolerance[0];
132 }
133 
134 enum piglit_result
piglit_display(void)135 piglit_display(void)
136 {
137 	GLint max_bind_points = 0;
138 	GLuint q, num_prims;
139 	bool pass = true, test = true;
140 	GLfloat *v, *w;
141 	int i;
142 
143 	/* init the transform feedback buffers */
144 	glGenBuffers(3, xfb_buf);
145 	glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buf[2]);
146 	piglit_check_gl_error(GL_NO_ERROR);
147 
148 	/* Fetch the number of bind points */
149 	glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_BUFFERS, &max_bind_points);
150 	PIGLIT_SUBTEST_ERROR(GL_NO_ERROR, pass, "fetch maximum number of bind "
151 			     "points");
152 
153 	if (piglit_khr_no_error)
154 		goto valid_calls;
155 
156 	/* bind a non-existing transform feedback BO */
157 	glTransformFeedbackBufferBase(1337, 0, 0);
158 	PIGLIT_SUBTEST_ERROR(GL_INVALID_OPERATION, pass,
159 			"bind non-existing transform feedback BO");
160 
161 	/* bind a non-existing output BO */
162 	glTransformFeedbackBufferBase(0, 0, 1337);
163 	PIGLIT_SUBTEST_ERROR(GL_INVALID_VALUE, pass, "bind a non-existing "
164 			     "output BO");
165 
166 	/* bind to a negative index */
167 	glTransformFeedbackBufferBase(0, -1, xfb_buf[2]);
168 	PIGLIT_SUBTEST_ERROR(GL_INVALID_VALUE, pass, "bind negative index");
169 
170 	/* bind to an index == max */
171 	glTransformFeedbackBufferBase(0, max_bind_points, xfb_buf[2]);
172 	PIGLIT_SUBTEST_ERROR(GL_INVALID_VALUE, pass, "bind to index == "
173 			     "max_bind_points (%i)", max_bind_points);
174 
175 valid_calls:
176 	/* Set up the transform feedback buffer */
177 	for (i = 0; i < 2; i++) {
178 		glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buf[i]);
179 		glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER,
180 				 xfb_buf_size, NULL, GL_STREAM_READ);
181 		glTransformFeedbackBufferBase(0, i, xfb_buf[i]);
182 		piglit_check_gl_error(GL_NO_ERROR);
183 	}
184 
185 	/* Set up the query that checks the # of primitives handled */
186 	glGenQueries(1, &q);
187 	glBeginQuery(GL_PRIMITIVES_GENERATED, q);
188 	piglit_check_gl_error(GL_NO_ERROR);
189 
190 	/* do the transform feedback */
191 	glBeginTransformFeedback(GL_POINTS);
192 	glBindBuffer(GL_ARRAY_BUFFER, input_buf);
193 	glDrawArrays(GL_POINTS, 0, NUM_INPUTS);
194 	glEndTransformFeedback();
195 
196 	glEndQuery(GL_PRIMITIVES_GENERATED);
197 
198 	/* check the number of primitives */
199 	glGetQueryObjectuiv(q, GL_QUERY_RESULT, &num_prims);
200 	glDeleteQueries(1, &q);
201 	printf("%u primitives generated:\n", num_prims);
202 	if (num_prims != NUM_INPUTS) {
203 		printf("Incorrect number of prims generated.\n");
204 		printf("Found %u, expected %u\n", num_prims, NUM_INPUTS);
205 		pass = false;
206 		test = false;
207 	}
208 
209 	/* check the result */
210 	glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buf[0]);
211 	v = glMapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
212 	piglit_check_gl_error(GL_NO_ERROR);
213 	glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buf[1]);
214 	w = glMapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
215 	piglit_check_gl_error(GL_NO_ERROR);
216 
217 	for (i = 0; i < num_prims; i++) {
218 		printf("%2d: (%2.0g, %2.0g) : ", i, v[i], w[i]);
219 		if (!equal(v[i], out1_ret[i]) || !equal(w[i], out2_ret[i])) {
220 			printf("NOK, expected (%2.0g, %2.0g)\n",
221 			       out1_ret[i], out2_ret[i]);
222 			test = false;
223 		} else
224 			printf("OK\n");
225 	}
226 	PIGLIT_SUBTEST_CONDITION(test, pass, "general test");
227 
228 	piglit_present_results();
229 
230 	/* clean-up everything */
231 	glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buf[0]);
232 	glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
233 	glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buf[1]);
234 	glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
235 	glDeleteBuffers(3, xfb_buf);
236 	glDeleteBuffers(1, &input_buf);
237 	glDeleteVertexArrays(1, &vao);
238 	glDeleteProgram(prog);
239 
240 	return pass ? PIGLIT_PASS : PIGLIT_FAIL;
241 }
242