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 GLuint transformFeedbackId = 0;
117 glGenTransformFeedbacks(1, &transformFeedbackId);
118 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedbackId);
119 expectError(GL_NO_ERROR);
120
121 testTransformFeedback();
122
123 // cleanup
124
125 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
126
127 glDeleteTransformFeedbacks(1, &transformFeedbackId);
128 glDeleteShader(shaderVert);
129 glDeleteShader(shaderFrag);
130 glDeleteProgram(shaderProg);
131 expectError(GL_NO_ERROR);
132 }
133 };
134
135 class TransformFeedbackBufferBindingCase : public TransformFeedbackCase
136 {
137 public:
TransformFeedbackBufferBindingCase(Context & context,const char * name,const char * description)138 TransformFeedbackBufferBindingCase (Context& context, const char* name, const char* description)
139 : TransformFeedbackCase(context, name, description)
140 {
141 }
142
testTransformFeedback(void)143 void testTransformFeedback (void)
144 {
145 const int feedbackPositionIndex = 0;
146 const int feedbackOutputIndex = 1;
147 const int feedbackIndex[2] = {feedbackPositionIndex, feedbackOutputIndex};
148
149 // bind bffers
150
151 GLuint feedbackBuffers[2];
152 glGenBuffers(2, feedbackBuffers);
153 expectError(GL_NO_ERROR);
154
155 for (int ndx = 0; ndx < 2; ++ndx)
156 {
157 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackBuffers[ndx]);
158 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 16, NULL, GL_DYNAMIC_READ);
159 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackIndex[ndx], feedbackBuffers[ndx]);
160 expectError(GL_NO_ERROR);
161 }
162
163 // test TRANSFORM_FEEDBACK_BUFFER_BINDING
164
165 for (int ndx = 0; ndx < 2; ++ndx)
166 {
167 StateQueryMemoryWriteGuard<GLint> boundBuffer;
168 glGetIntegeri_v(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, feedbackIndex[ndx], &boundBuffer);
169 boundBuffer.verifyValidity(m_testCtx);
170 checkIntEquals(m_testCtx, boundBuffer, feedbackBuffers[ndx]);
171 }
172
173
174 // cleanup
175
176 glDeleteBuffers(2, feedbackBuffers);
177 }
178 };
179
180 class TransformFeedbackBufferBufferCase : public TransformFeedbackCase
181 {
182 public:
TransformFeedbackBufferBufferCase(Context & context,const char * name,const char * description)183 TransformFeedbackBufferBufferCase (Context& context, const char* name, const char* description)
184 : TransformFeedbackCase(context, name, description)
185 {
186 }
187
testTransformFeedback(void)188 void testTransformFeedback (void)
189 {
190 const int feedbackPositionIndex = 0;
191 const int feedbackOutputIndex = 1;
192
193 const int rangeBufferOffset = 4;
194 const int rangeBufferSize = 8;
195
196 // bind buffers
197
198 GLuint feedbackBuffers[2];
199 glGenBuffers(2, feedbackBuffers);
200 expectError(GL_NO_ERROR);
201
202 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackBuffers[0]);
203 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 16, NULL, GL_DYNAMIC_READ);
204 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackPositionIndex, feedbackBuffers[0]);
205 expectError(GL_NO_ERROR);
206
207 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackBuffers[1]);
208 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 16, NULL, GL_DYNAMIC_READ);
209 glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackOutputIndex, feedbackBuffers[1], rangeBufferOffset, rangeBufferSize);
210 expectError(GL_NO_ERROR);
211
212 // test TRANSFORM_FEEDBACK_BUFFER_START and TRANSFORM_FEEDBACK_BUFFER_SIZE
213
214 const struct BufferRequirements
215 {
216 GLint index;
217 GLenum pname;
218 GLint64 value;
219 } requirements[] =
220 {
221 { feedbackPositionIndex, GL_TRANSFORM_FEEDBACK_BUFFER_START, 0 },
222 { feedbackPositionIndex, GL_TRANSFORM_FEEDBACK_BUFFER_SIZE, 0 },
223 { feedbackOutputIndex, GL_TRANSFORM_FEEDBACK_BUFFER_START, rangeBufferOffset },
224 { feedbackOutputIndex, GL_TRANSFORM_FEEDBACK_BUFFER_SIZE, rangeBufferSize }
225 };
226
227 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(requirements); ++ndx)
228 {
229 StateQueryMemoryWriteGuard<GLint64> state;
230 glGetInteger64i_v(requirements[ndx].pname, requirements[ndx].index, &state);
231
232 if (state.verifyValidity(m_testCtx))
233 checkIntEquals(m_testCtx, state, requirements[ndx].value);
234 }
235
236 // cleanup
237
238 glDeleteBuffers(2, feedbackBuffers);
239 }
240 };
241
242 class UniformBufferCase : public ApiCase
243 {
244 public:
UniformBufferCase(Context & context,const char * name,const char * description)245 UniformBufferCase (Context& context, const char* name, const char* description)
246 : ApiCase (context, name, description)
247 , m_program (0)
248 {
249 }
250
251 virtual void testUniformBuffers (void) = DE_NULL;
252
test(void)253 void test (void)
254 {
255 static const char* testVertSource = "#version 300 es\n"
256 "uniform highp vec4 input1;\n"
257 "uniform highp vec4 input2;\n"
258 "void main (void)\n"
259 "{\n"
260 " gl_Position = input1 + input2;\n"
261 "}\n\0";
262 static const char* testFragSource = "#version 300 es\n"
263 "layout(location = 0) out mediump vec4 fragColor;"
264 "void main (void)\n"
265 "{\n"
266 " fragColor = vec4(0.0);\n"
267 "}\n\0";
268
269 GLuint shaderVert = glCreateShader(GL_VERTEX_SHADER);
270 GLuint shaderFrag = glCreateShader(GL_FRAGMENT_SHADER);
271
272 glShaderSource(shaderVert, 1, &testVertSource, DE_NULL);
273 glShaderSource(shaderFrag, 1, &testFragSource, DE_NULL);
274
275 glCompileShader(shaderVert);
276 glCompileShader(shaderFrag);
277 expectError(GL_NO_ERROR);
278
279 m_program = glCreateProgram();
280 glAttachShader(m_program, shaderVert);
281 glAttachShader(m_program, shaderFrag);
282 glLinkProgram(m_program);
283 glUseProgram(m_program);
284 expectError(GL_NO_ERROR);
285
286 testUniformBuffers();
287
288 glUseProgram(0);
289 glDeleteShader(shaderVert);
290 glDeleteShader(shaderFrag);
291 glDeleteProgram(m_program);
292 expectError(GL_NO_ERROR);
293 }
294
295 protected:
296 GLuint m_program;
297 };
298
299 class UniformBufferBindingCase : public UniformBufferCase
300 {
301 public:
UniformBufferBindingCase(Context & context,const char * name,const char * description)302 UniformBufferBindingCase (Context& context, const char* name, const char* description)
303 : UniformBufferCase(context, name, description)
304 {
305 }
306
testUniformBuffers(void)307 void testUniformBuffers (void)
308 {
309 const char* uniformNames[] =
310 {
311 "input1",
312 "input2"
313 };
314 GLuint uniformIndices[2] = {0};
315 glGetUniformIndices(m_program, 2, uniformNames, uniformIndices);
316
317 GLuint buffers[2];
318 glGenBuffers(2, buffers);
319
320 for (int ndx = 0; ndx < 2; ++ndx)
321 {
322 glBindBuffer(GL_UNIFORM_BUFFER, buffers[ndx]);
323 glBufferData(GL_UNIFORM_BUFFER, 32, DE_NULL, GL_DYNAMIC_DRAW);
324 glBindBufferBase(GL_UNIFORM_BUFFER, uniformIndices[ndx], buffers[ndx]);
325 expectError(GL_NO_ERROR);
326 }
327
328 for (int ndx = 0; ndx < 2; ++ndx)
329 {
330 StateQueryMemoryWriteGuard<GLint> boundBuffer;
331 glGetIntegeri_v(GL_UNIFORM_BUFFER_BINDING, uniformIndices[ndx], &boundBuffer);
332
333 if (boundBuffer.verifyValidity(m_testCtx))
334 checkIntEquals(m_testCtx, boundBuffer, buffers[ndx]);
335 expectError(GL_NO_ERROR);
336 }
337
338 glDeleteBuffers(2, buffers);
339 }
340 };
341
342 class UniformBufferBufferCase : public UniformBufferCase
343 {
344 public:
UniformBufferBufferCase(Context & context,const char * name,const char * description)345 UniformBufferBufferCase (Context& context, const char* name, const char* description)
346 : UniformBufferCase(context, name, description)
347 {
348 }
349
testUniformBuffers(void)350 void testUniformBuffers (void)
351 {
352 const char* uniformNames[] =
353 {
354 "input1",
355 "input2"
356 };
357 GLuint uniformIndices[2] = {0};
358 glGetUniformIndices(m_program, 2, uniformNames, uniformIndices);
359
360 const GLint alignment = GetAlignment();
361 if (alignment == -1) // cannot continue without this
362 return;
363
364 m_testCtx.getLog() << tcu::TestLog::Message << "Alignment is " << alignment << tcu::TestLog::EndMessage;
365
366 int rangeBufferOffset = alignment;
367 int rangeBufferSize = alignment * 2;
368 int rangeBufferTotalSize = rangeBufferOffset + rangeBufferSize + 8; // + 8 has no special meaning, just to make it != with the size of the range
369
370 GLuint buffers[2];
371 glGenBuffers(2, buffers);
372
373 glBindBuffer(GL_UNIFORM_BUFFER, buffers[0]);
374 glBufferData(GL_UNIFORM_BUFFER, 32, DE_NULL, GL_DYNAMIC_DRAW);
375 glBindBufferBase(GL_UNIFORM_BUFFER, uniformIndices[0], buffers[0]);
376 expectError(GL_NO_ERROR);
377
378 glBindBuffer(GL_UNIFORM_BUFFER, buffers[1]);
379 glBufferData(GL_UNIFORM_BUFFER, rangeBufferTotalSize, DE_NULL, GL_DYNAMIC_DRAW);
380 glBindBufferRange(GL_UNIFORM_BUFFER, uniformIndices[1], buffers[1], rangeBufferOffset, rangeBufferSize);
381 expectError(GL_NO_ERROR);
382
383 // test UNIFORM_BUFFER_START and UNIFORM_BUFFER_SIZE
384
385 const struct BufferRequirements
386 {
387 GLuint index;
388 GLenum pname;
389 GLint64 value;
390 } requirements[] =
391 {
392 { uniformIndices[0], GL_UNIFORM_BUFFER_START, 0 },
393 { uniformIndices[0], GL_UNIFORM_BUFFER_SIZE, 0 },
394 { uniformIndices[1], GL_UNIFORM_BUFFER_START, rangeBufferOffset },
395 { uniformIndices[1], GL_UNIFORM_BUFFER_SIZE, rangeBufferSize }
396 };
397
398 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(requirements); ++ndx)
399 {
400 StateQueryMemoryWriteGuard<GLint64> state;
401 glGetInteger64i_v(requirements[ndx].pname, requirements[ndx].index, &state);
402
403 if (state.verifyValidity(m_testCtx))
404 checkIntEquals(m_testCtx, state, requirements[ndx].value);
405 expectError(GL_NO_ERROR);
406 }
407
408 glDeleteBuffers(2, buffers);
409 }
410
GetAlignment()411 int GetAlignment()
412 {
413 StateQueryMemoryWriteGuard<GLint> state;
414 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &state);
415
416 if (!state.verifyValidity(m_testCtx))
417 return -1;
418
419 if (state <= 256)
420 return state;
421
422 m_testCtx.getLog() << tcu::TestLog::Message << "// ERROR: UNIFORM_BUFFER_OFFSET_ALIGNMENT has a maximum value of 256." << tcu::TestLog::EndMessage;
423 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid UNIFORM_BUFFER_OFFSET_ALIGNMENT value");
424
425 return -1;
426 }
427 };
428
429 } // anonymous
430
IndexedStateQueryTests(Context & context)431 IndexedStateQueryTests::IndexedStateQueryTests (Context& context)
432 : TestCaseGroup(context, "indexed", "Indexed Integer Values")
433 {
434 }
435
init(void)436 void IndexedStateQueryTests::init (void)
437 {
438 // transform feedback
439 addChild(new TransformFeedbackBufferBindingCase(m_context, "transform_feedback_buffer_binding", "TRANSFORM_FEEDBACK_BUFFER_BINDING"));
440 addChild(new TransformFeedbackBufferBufferCase(m_context, "transform_feedback_buffer_start_size", "TRANSFORM_FEEDBACK_BUFFER_START and TRANSFORM_FEEDBACK_BUFFER_SIZE"));
441
442 // uniform buffers
443 addChild(new UniformBufferBindingCase(m_context, "uniform_buffer_binding", "UNIFORM_BUFFER_BINDING"));
444 addChild(new UniformBufferBufferCase(m_context, "uniform_buffer_start_size", "UNIFORM_BUFFER_START and UNIFORM_BUFFER_SIZE"));
445 }
446
447 } // Functional
448 } // gles3
449 } // deqp
450