1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Indexed State Query tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "es3fIndexedStateQueryTests.hpp"
25 #include "es3fApiCase.hpp"
26 #include "glsStateQueryUtil.hpp"
27 #include "tcuRenderTarget.hpp"
28 #include "glwEnums.hpp"
29
30 using namespace glw; // GLint and other GL types
31 using deqp::gls::StateQueryUtil::StateQueryMemoryWriteGuard;
32
33 namespace deqp
34 {
35 namespace gles3
36 {
37 namespace Functional
38 {
39 namespace
40 {
41
checkIntEquals(tcu::TestContext & testCtx,GLint got,GLint expected)42 void checkIntEquals (tcu::TestContext& testCtx, GLint got, GLint expected)
43 {
44 using tcu::TestLog;
45
46 if (got != expected)
47 {
48 testCtx.getLog() << TestLog::Message << "// ERROR: Expected " << expected << "; got " << got << TestLog::EndMessage;
49 if (testCtx.getTestResult() == QP_TEST_RESULT_PASS)
50 testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid value");
51 }
52 }
53
checkIntEquals(tcu::TestContext & testCtx,GLint64 got,GLint64 expected)54 void checkIntEquals (tcu::TestContext& testCtx, GLint64 got, GLint64 expected)
55 {
56 using tcu::TestLog;
57
58 if (got != expected)
59 {
60 testCtx.getLog() << TestLog::Message << "// ERROR: Expected " << expected << "; got " << got << TestLog::EndMessage;
61 if (testCtx.getTestResult() == QP_TEST_RESULT_PASS)
62 testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid value");
63 }
64 }
65
66 class TransformFeedbackCase : public ApiCase
67 {
68 public:
TransformFeedbackCase(Context & context,const char * name,const char * description)69 TransformFeedbackCase (Context& context, const char* name, const char* description)
70 : ApiCase(context, name, description)
71 {
72 }
73
74 virtual void testTransformFeedback (void) = DE_NULL;
75
test(void)76 void test (void)
77 {
78 static const char* transformFeedbackTestVertSource = "#version 300 es\n"
79 "out highp vec4 anotherOutput;\n"
80 "void main (void)\n"
81 "{\n"
82 " gl_Position = vec4(0.0);\n"
83 " anotherOutput = vec4(0.0);\n"
84 "}\n\0";
85 static const char* transformFeedbackTestFragSource = "#version 300 es\n"
86 "layout(location = 0) out mediump vec4 fragColor;"
87 "void main (void)\n"
88 "{\n"
89 " fragColor = vec4(0.0);\n"
90 "}\n\0";
91
92 GLuint shaderVert = glCreateShader(GL_VERTEX_SHADER);
93 GLuint shaderFrag = glCreateShader(GL_FRAGMENT_SHADER);
94
95 glShaderSource(shaderVert, 1, &transformFeedbackTestVertSource, DE_NULL);
96 glShaderSource(shaderFrag, 1, &transformFeedbackTestFragSource, DE_NULL);
97
98 glCompileShader(shaderVert);
99 glCompileShader(shaderFrag);
100 expectError(GL_NO_ERROR);
101
102 GLuint shaderProg = glCreateProgram();
103 glAttachShader(shaderProg, shaderVert);
104 glAttachShader(shaderProg, shaderFrag);
105
106 const char* transformFeedbackOutputs[] =
107 {
108 "gl_Position",
109 "anotherOutput"
110 };
111
112 glTransformFeedbackVaryings(shaderProg, 2, transformFeedbackOutputs, GL_INTERLEAVED_ATTRIBS);
113 glLinkProgram(shaderProg);
114 expectError(GL_NO_ERROR);
115
116 glGenTransformFeedbacks(2, transformFeedbacks);
117 // Also store the default transform feedback in the array.
118 transformFeedbacks[2] = 0;
119 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedbacks[0]);
120 expectError(GL_NO_ERROR);
121
122 testTransformFeedback();
123
124 // cleanup
125
126 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
127
128 glDeleteTransformFeedbacks(2, transformFeedbacks);
129 glDeleteShader(shaderVert);
130 glDeleteShader(shaderFrag);
131 glDeleteProgram(shaderProg);
132 expectError(GL_NO_ERROR);
133 }
134 protected:
135 GLuint transformFeedbacks[3];
136 };
137
138 class TransformFeedbackBufferBindingCase : public TransformFeedbackCase
139 {
140 public:
TransformFeedbackBufferBindingCase(Context & context,const char * name,const char * description)141 TransformFeedbackBufferBindingCase (Context& context, const char* name, const char* description)
142 : TransformFeedbackCase(context, name, description)
143 {
144 }
145
testTransformFeedback(void)146 void testTransformFeedback (void)
147 {
148 const int feedbackPositionIndex = 0;
149 const int feedbackOutputIndex = 1;
150 const int feedbackIndex[2] = {feedbackPositionIndex, feedbackOutputIndex};
151
152 // bind bffers
153
154 GLuint feedbackBuffers[2];
155 glGenBuffers(2, feedbackBuffers);
156 expectError(GL_NO_ERROR);
157
158 for (int ndx = 0; ndx < 2; ++ndx)
159 {
160 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackBuffers[ndx]);
161 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 16, NULL, GL_DYNAMIC_READ);
162 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackIndex[ndx], feedbackBuffers[ndx]);
163 expectError(GL_NO_ERROR);
164 }
165
166 // test TRANSFORM_FEEDBACK_BUFFER_BINDING
167
168 for (int ndx = 0; ndx < 2; ++ndx)
169 {
170 StateQueryMemoryWriteGuard<GLint> boundBuffer;
171 glGetIntegeri_v(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, feedbackIndex[ndx], &boundBuffer);
172 boundBuffer.verifyValidity(m_testCtx);
173 checkIntEquals(m_testCtx, boundBuffer, feedbackBuffers[ndx]);
174 }
175
176
177 // cleanup
178
179 glDeleteBuffers(2, feedbackBuffers);
180 }
181 };
182
183 class TransformFeedbackBufferBufferCase : public TransformFeedbackCase
184 {
185 public:
TransformFeedbackBufferBufferCase(Context & context,const char * name,const char * description)186 TransformFeedbackBufferBufferCase (Context& context, const char* name, const char* description)
187 : TransformFeedbackCase(context, name, description)
188 {
189 }
190
testTransformFeedback(void)191 void testTransformFeedback (void)
192 {
193 const int feedbackPositionIndex = 0;
194 const int feedbackOutputIndex = 1;
195
196 const int rangeBufferOffset = 4;
197 const int rangeBufferSize = 8;
198
199 // bind buffers
200
201 GLuint feedbackBuffers[2];
202 glGenBuffers(2, feedbackBuffers);
203 expectError(GL_NO_ERROR);
204
205 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackBuffers[0]);
206 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 16, NULL, GL_DYNAMIC_READ);
207 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackPositionIndex, feedbackBuffers[0]);
208 expectError(GL_NO_ERROR);
209
210 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackBuffers[1]);
211 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 16, NULL, GL_DYNAMIC_READ);
212 glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackOutputIndex, feedbackBuffers[1], rangeBufferOffset, rangeBufferSize);
213 expectError(GL_NO_ERROR);
214
215 // test TRANSFORM_FEEDBACK_BUFFER_START and TRANSFORM_FEEDBACK_BUFFER_SIZE
216
217 const struct BufferRequirements
218 {
219 GLint index;
220 GLenum pname;
221 GLint64 value;
222 } requirements[] =
223 {
224 { feedbackPositionIndex, GL_TRANSFORM_FEEDBACK_BUFFER_START, 0 },
225 { feedbackPositionIndex, GL_TRANSFORM_FEEDBACK_BUFFER_SIZE, 0 },
226 { feedbackOutputIndex, GL_TRANSFORM_FEEDBACK_BUFFER_START, rangeBufferOffset },
227 { feedbackOutputIndex, GL_TRANSFORM_FEEDBACK_BUFFER_SIZE, rangeBufferSize }
228 };
229
230 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(requirements); ++ndx)
231 {
232 StateQueryMemoryWriteGuard<GLint64> state;
233 glGetInteger64i_v(requirements[ndx].pname, requirements[ndx].index, &state);
234
235 if (state.verifyValidity(m_testCtx))
236 checkIntEquals(m_testCtx, state, requirements[ndx].value);
237 }
238
239 // cleanup
240
241 glDeleteBuffers(2, feedbackBuffers);
242 }
243 };
244
245 class TransformFeedbackSwitchingBufferCase : public TransformFeedbackCase
246 {
247 public:
TransformFeedbackSwitchingBufferCase(Context & context,const char * name,const char * description)248 TransformFeedbackSwitchingBufferCase (Context& context, const char* name, const char* description)
249 : TransformFeedbackCase(context, name, description)
250 {
251 }
252
testTransformFeedback(void)253 void testTransformFeedback (void)
254 {
255 GLuint feedbackBuffers[3];
256 glGenBuffers(3, feedbackBuffers);
257 expectError(GL_NO_ERROR);
258
259 for (int i = 0; i < 3; ++i)
260 {
261 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedbacks[i]);
262 expectError(GL_NO_ERROR);
263 GLint value;
264 glGetIntegeri_v(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, 0, &value);
265 expectError(GL_NO_ERROR);
266 checkIntEquals(m_testCtx, value, 0);
267 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, feedbackBuffers[i]);
268 expectError(GL_NO_ERROR);
269 // glBindBufferBase should also set the generic binding point.
270 glGetIntegerv(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, &value);
271 expectError(GL_NO_ERROR);
272 checkIntEquals(m_testCtx, value, feedbackBuffers[i]);
273 }
274
275 for (int i = 0; i < 3; ++i)
276 {
277 // glBindTransformFeedback should change the indexed binding points, but
278 // not the generic one.
279 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedbacks[i]);
280 expectError(GL_NO_ERROR);
281 GLint value;
282 glGetIntegeri_v(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, 0, &value);
283 expectError(GL_NO_ERROR);
284 checkIntEquals(m_testCtx, value, feedbackBuffers[i]);
285 glGetIntegerv(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, &value);
286 expectError(GL_NO_ERROR);
287 // Should be unchanged.
288 checkIntEquals(m_testCtx, value, feedbackBuffers[2]);
289 }
290
291 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedbacks[0]);
292 expectError(GL_NO_ERROR);
293 glDeleteBuffers(3, feedbackBuffers);
294 expectError(GL_NO_ERROR);
295
296 // After deleting buffers the bound state should be changed but unbound
297 // state should be unchanged.
298
299 GLint value;
300 glGetIntegeri_v(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, 0, &value);
301 expectError(GL_NO_ERROR);
302 checkIntEquals(m_testCtx, value, 0);
303 glGetIntegerv(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, &value);
304 expectError(GL_NO_ERROR);
305 checkIntEquals(m_testCtx, value, 0);
306
307 for (int i = 1; i < 3; ++i)
308 {
309 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedbacks[i]);
310 expectError(GL_NO_ERROR);
311 glGetIntegeri_v(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, 0, &value);
312 expectError(GL_NO_ERROR);
313 checkIntEquals(m_testCtx, value, feedbackBuffers[i]);
314 glGetIntegerv(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, &value);
315 expectError(GL_NO_ERROR);
316 checkIntEquals(m_testCtx, value, 0);
317 }
318 }
319 };
320
321 class UniformBufferCase : public ApiCase
322 {
323 public:
UniformBufferCase(Context & context,const char * name,const char * description)324 UniformBufferCase (Context& context, const char* name, const char* description)
325 : ApiCase (context, name, description)
326 , m_program (0)
327 {
328 }
329
330 virtual void testUniformBuffers (void) = DE_NULL;
331
test(void)332 void test (void)
333 {
334 static const char* testVertSource = "#version 300 es\n"
335 "uniform highp vec4 input1;\n"
336 "uniform highp vec4 input2;\n"
337 "void main (void)\n"
338 "{\n"
339 " gl_Position = input1 + input2;\n"
340 "}\n\0";
341 static const char* testFragSource = "#version 300 es\n"
342 "layout(location = 0) out mediump vec4 fragColor;"
343 "void main (void)\n"
344 "{\n"
345 " fragColor = vec4(0.0);\n"
346 "}\n\0";
347
348 GLuint shaderVert = glCreateShader(GL_VERTEX_SHADER);
349 GLuint shaderFrag = glCreateShader(GL_FRAGMENT_SHADER);
350
351 glShaderSource(shaderVert, 1, &testVertSource, DE_NULL);
352 glShaderSource(shaderFrag, 1, &testFragSource, DE_NULL);
353
354 glCompileShader(shaderVert);
355 glCompileShader(shaderFrag);
356 expectError(GL_NO_ERROR);
357
358 m_program = glCreateProgram();
359 glAttachShader(m_program, shaderVert);
360 glAttachShader(m_program, shaderFrag);
361 glLinkProgram(m_program);
362 glUseProgram(m_program);
363 expectError(GL_NO_ERROR);
364
365 testUniformBuffers();
366
367 glUseProgram(0);
368 glDeleteShader(shaderVert);
369 glDeleteShader(shaderFrag);
370 glDeleteProgram(m_program);
371 expectError(GL_NO_ERROR);
372 }
373
374 protected:
375 GLuint m_program;
376 };
377
378 class UniformBufferBindingCase : public UniformBufferCase
379 {
380 public:
UniformBufferBindingCase(Context & context,const char * name,const char * description)381 UniformBufferBindingCase (Context& context, const char* name, const char* description)
382 : UniformBufferCase(context, name, description)
383 {
384 }
385
testUniformBuffers(void)386 void testUniformBuffers (void)
387 {
388 const char* uniformNames[] =
389 {
390 "input1",
391 "input2"
392 };
393 GLuint uniformIndices[2] = {0};
394 glGetUniformIndices(m_program, 2, uniformNames, uniformIndices);
395
396 GLuint buffers[2];
397 glGenBuffers(2, buffers);
398
399 for (int ndx = 0; ndx < 2; ++ndx)
400 {
401 glBindBuffer(GL_UNIFORM_BUFFER, buffers[ndx]);
402 glBufferData(GL_UNIFORM_BUFFER, 32, DE_NULL, GL_DYNAMIC_DRAW);
403 glBindBufferBase(GL_UNIFORM_BUFFER, uniformIndices[ndx], buffers[ndx]);
404 expectError(GL_NO_ERROR);
405 }
406
407 for (int ndx = 0; ndx < 2; ++ndx)
408 {
409 StateQueryMemoryWriteGuard<GLint> boundBuffer;
410 glGetIntegeri_v(GL_UNIFORM_BUFFER_BINDING, uniformIndices[ndx], &boundBuffer);
411
412 if (boundBuffer.verifyValidity(m_testCtx))
413 checkIntEquals(m_testCtx, boundBuffer, buffers[ndx]);
414 expectError(GL_NO_ERROR);
415 }
416
417 glDeleteBuffers(2, buffers);
418 }
419 };
420
421 class UniformBufferBufferCase : public UniformBufferCase
422 {
423 public:
UniformBufferBufferCase(Context & context,const char * name,const char * description)424 UniformBufferBufferCase (Context& context, const char* name, const char* description)
425 : UniformBufferCase(context, name, description)
426 {
427 }
428
testUniformBuffers(void)429 void testUniformBuffers (void)
430 {
431 const char* uniformNames[] =
432 {
433 "input1",
434 "input2"
435 };
436 GLuint uniformIndices[2] = {0};
437 glGetUniformIndices(m_program, 2, uniformNames, uniformIndices);
438
439 const GLint alignment = GetAlignment();
440 if (alignment == -1) // cannot continue without this
441 return;
442
443 m_testCtx.getLog() << tcu::TestLog::Message << "Alignment is " << alignment << tcu::TestLog::EndMessage;
444
445 int rangeBufferOffset = alignment;
446 int rangeBufferSize = alignment * 2;
447 int rangeBufferTotalSize = rangeBufferOffset + rangeBufferSize + 8; // + 8 has no special meaning, just to make it != with the size of the range
448
449 GLuint buffers[2];
450 glGenBuffers(2, buffers);
451
452 glBindBuffer(GL_UNIFORM_BUFFER, buffers[0]);
453 glBufferData(GL_UNIFORM_BUFFER, 32, DE_NULL, GL_DYNAMIC_DRAW);
454 glBindBufferBase(GL_UNIFORM_BUFFER, uniformIndices[0], buffers[0]);
455 expectError(GL_NO_ERROR);
456
457 glBindBuffer(GL_UNIFORM_BUFFER, buffers[1]);
458 glBufferData(GL_UNIFORM_BUFFER, rangeBufferTotalSize, DE_NULL, GL_DYNAMIC_DRAW);
459 glBindBufferRange(GL_UNIFORM_BUFFER, uniformIndices[1], buffers[1], rangeBufferOffset, rangeBufferSize);
460 expectError(GL_NO_ERROR);
461
462 // test UNIFORM_BUFFER_START and UNIFORM_BUFFER_SIZE
463
464 const struct BufferRequirements
465 {
466 GLuint index;
467 GLenum pname;
468 GLint64 value;
469 } requirements[] =
470 {
471 { uniformIndices[0], GL_UNIFORM_BUFFER_START, 0 },
472 { uniformIndices[0], GL_UNIFORM_BUFFER_SIZE, 0 },
473 { uniformIndices[1], GL_UNIFORM_BUFFER_START, rangeBufferOffset },
474 { uniformIndices[1], GL_UNIFORM_BUFFER_SIZE, rangeBufferSize }
475 };
476
477 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(requirements); ++ndx)
478 {
479 StateQueryMemoryWriteGuard<GLint64> state;
480 glGetInteger64i_v(requirements[ndx].pname, requirements[ndx].index, &state);
481
482 if (state.verifyValidity(m_testCtx))
483 checkIntEquals(m_testCtx, state, requirements[ndx].value);
484 expectError(GL_NO_ERROR);
485 }
486
487 glDeleteBuffers(2, buffers);
488 }
489
GetAlignment()490 int GetAlignment()
491 {
492 StateQueryMemoryWriteGuard<GLint> state;
493 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &state);
494
495 if (!state.verifyValidity(m_testCtx))
496 return -1;
497
498 if (state <= 256)
499 return state;
500
501 m_testCtx.getLog() << tcu::TestLog::Message << "// ERROR: UNIFORM_BUFFER_OFFSET_ALIGNMENT has a maximum value of 256." << tcu::TestLog::EndMessage;
502 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid UNIFORM_BUFFER_OFFSET_ALIGNMENT value");
503
504 return -1;
505 }
506 };
507
508 } // anonymous
509
IndexedStateQueryTests(Context & context)510 IndexedStateQueryTests::IndexedStateQueryTests (Context& context)
511 : TestCaseGroup(context, "indexed", "Indexed Integer Values")
512 {
513 }
514
init(void)515 void IndexedStateQueryTests::init (void)
516 {
517 // transform feedback
518 addChild(new TransformFeedbackBufferBindingCase(m_context, "transform_feedback_buffer_binding", "TRANSFORM_FEEDBACK_BUFFER_BINDING"));
519 addChild(new TransformFeedbackBufferBufferCase(m_context, "transform_feedback_buffer_start_size", "TRANSFORM_FEEDBACK_BUFFER_START and TRANSFORM_FEEDBACK_BUFFER_SIZE"));
520 addChild(new TransformFeedbackSwitchingBufferCase(m_context, "transform_feedback_switching_buffer", "TRANSFORM_FEEDBACK_BUFFER_BINDING while switching transform feedback objects"));
521
522 // uniform buffers
523 addChild(new UniformBufferBindingCase(m_context, "uniform_buffer_binding", "UNIFORM_BUFFER_BINDING"));
524 addChild(new UniformBufferBufferCase(m_context, "uniform_buffer_start_size", "UNIFORM_BUFFER_START and UNIFORM_BUFFER_SIZE"));
525 }
526
527 } // Functional
528 } // gles3
529 } // deqp
530