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 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 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: 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 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: 141 TransformFeedbackBufferBindingCase (Context& context, const char* name, const char* description) 142 : TransformFeedbackCase(context, name, description) 143 { 144 } 145 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: 186 TransformFeedbackBufferBufferCase (Context& context, const char* name, const char* description) 187 : TransformFeedbackCase(context, name, description) 188 { 189 } 190 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: 248 TransformFeedbackSwitchingBufferCase (Context& context, const char* name, const char* description) 249 : TransformFeedbackCase(context, name, description) 250 { 251 } 252 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: 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 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: 381 UniformBufferBindingCase (Context& context, const char* name, const char* description) 382 : UniformBufferCase(context, name, description) 383 { 384 } 385 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: 424 UniformBufferBufferCase (Context& context, const char* name, const char* description) 425 : UniformBufferCase(context, name, description) 426 { 427 } 428 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 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 510 IndexedStateQueryTests::IndexedStateQueryTests (Context& context) 511 : TestCaseGroup(context, "indexed", "Indexed Integer Values") 512 { 513 } 514 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