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 30using namespace glw; // GLint and other GL types 31using deqp::gls::StateQueryUtil::StateQueryMemoryWriteGuard; 32 33namespace deqp 34{ 35namespace gles3 36{ 37namespace Functional 38{ 39namespace 40{ 41 42void 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 54void 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 66class TransformFeedbackCase : public ApiCase 67{ 68public: 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 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 135class TransformFeedbackBufferBindingCase : public TransformFeedbackCase 136{ 137public: 138 TransformFeedbackBufferBindingCase (Context& context, const char* name, const char* description) 139 : TransformFeedbackCase(context, name, description) 140 { 141 } 142 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 180class TransformFeedbackBufferBufferCase : public TransformFeedbackCase 181{ 182public: 183 TransformFeedbackBufferBufferCase (Context& context, const char* name, const char* description) 184 : TransformFeedbackCase(context, name, description) 185 { 186 } 187 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 242class UniformBufferCase : public ApiCase 243{ 244public: 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 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 295protected: 296 GLuint m_program; 297}; 298 299class UniformBufferBindingCase : public UniformBufferCase 300{ 301public: 302 UniformBufferBindingCase (Context& context, const char* name, const char* description) 303 : UniformBufferCase(context, name, description) 304 { 305 } 306 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 342class UniformBufferBufferCase : public UniformBufferCase 343{ 344public: 345 UniformBufferBufferCase (Context& context, const char* name, const char* description) 346 : UniformBufferCase(context, name, description) 347 { 348 } 349 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 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 431IndexedStateQueryTests::IndexedStateQueryTests (Context& context) 432 : TestCaseGroup(context, "indexed", "Indexed Integer Values") 433{ 434} 435 436void 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