1 /*------------------------------------------------------------------------- 2 * OpenGL Conformance Test Suite 3 * ----------------------------- 4 * 5 * Copyright (c) 2016 The Khronos Group Inc. 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 glcRobustBufferAccessBehaviorTests.cpp 21 * \brief Implements conformance tests for "Robust Buffer Access Behavior" functionality. 22 */ /*-------------------------------------------------------------------*/ 23 24 #include "glcRobustBufferAccessBehaviorTests.hpp" 25 26 #include "deSharedPtr.hpp" 27 #include "gluContextInfo.hpp" 28 #include "gluDefs.hpp" 29 #include "gluShaderUtil.hpp" 30 #include "glwEnums.hpp" 31 #include "glwFunctions.hpp" 32 #include "tcuCommandLine.hpp" 33 #include "tcuStringTemplate.hpp" 34 #include "tcuTestLog.hpp" 35 36 #include <cstring> 37 #include <string> 38 39 using namespace glw; 40 41 namespace glcts 42 { 43 namespace RobustBufferAccessBehavior 44 { 45 /* Buffer constants */ 46 const GLuint Buffer::m_invalid_id = -1; 47 48 const GLenum Buffer::m_targets[Buffer::m_n_targets] = { 49 GL_ARRAY_BUFFER, /* 0 */ 50 GL_ATOMIC_COUNTER_BUFFER, /* 1 */ 51 GL_COPY_READ_BUFFER, /* 2 */ 52 GL_COPY_WRITE_BUFFER, /* 3 */ 53 GL_DISPATCH_INDIRECT_BUFFER, /* 4 */ 54 GL_DRAW_INDIRECT_BUFFER, /* 5 */ 55 GL_ELEMENT_ARRAY_BUFFER, /* 6 */ 56 GL_PIXEL_PACK_BUFFER, /* 7 */ 57 GL_PIXEL_UNPACK_BUFFER, /* 8 */ 58 GL_QUERY_BUFFER, /* 9 */ 59 GL_SHADER_STORAGE_BUFFER, /* 10 */ 60 GL_TRANSFORM_FEEDBACK_BUFFER, /* 11 */ 61 GL_UNIFORM_BUFFER, /* 12 */ 62 }; 63 64 /** Constructor. 65 * 66 * @param context CTS context. 67 **/ 68 Buffer::Buffer(const glw::Functions& gl) : m_id(m_invalid_id), m_gl(gl), m_target(GL_ARRAY_BUFFER) 69 { 70 } 71 72 /** Destructor 73 * 74 **/ 75 Buffer::~Buffer() 76 { 77 Release(); 78 } 79 80 /** Initialize buffer instance 81 * 82 * @param target Buffer target 83 * @param usage Buffer usage enum 84 * @param size <size> parameter 85 * @param data <data> parameter 86 **/ 87 void Buffer::InitData(glw::GLenum target, glw::GLenum usage, glw::GLsizeiptr size, const glw::GLvoid* data) 88 { 89 /* Delete previous buffer instance */ 90 Release(); 91 92 m_target = target; 93 94 Generate(m_gl, m_id); 95 Bind(m_gl, m_id, m_target); 96 Data(m_gl, m_target, usage, size, data); 97 } 98 99 /** Release buffer instance 100 * 101 **/ 102 void Buffer::Release() 103 { 104 if (m_invalid_id != m_id) 105 { 106 m_gl.deleteBuffers(1, &m_id); 107 m_id = m_invalid_id; 108 } 109 } 110 111 /** Binds buffer to its target 112 * 113 **/ 114 void Buffer::Bind() const 115 { 116 Bind(m_gl, m_id, m_target); 117 } 118 119 /** Binds indexed buffer 120 * 121 * @param index <index> parameter 122 **/ 123 void Buffer::BindBase(glw::GLuint index) const 124 { 125 BindBase(m_gl, m_id, m_target, index); 126 } 127 128 /** Bind buffer to given target 129 * 130 * @param gl GL functions 131 * @param id Id of buffer 132 * @param target Buffer target 133 **/ 134 void Buffer::Bind(const glw::Functions& gl, glw::GLuint id, glw::GLenum target) 135 { 136 gl.bindBuffer(target, id); 137 GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffer"); 138 } 139 140 /** Binds indexed buffer 141 * 142 * @param gl GL functions 143 * @param id Id of buffer 144 * @param target Buffer target 145 * @param index <index> parameter 146 **/ 147 void Buffer::BindBase(const glw::Functions& gl, glw::GLuint id, glw::GLenum target, glw::GLuint index) 148 { 149 gl.bindBufferBase(target, index, id); 150 GLU_EXPECT_NO_ERROR(gl.getError(), "BindBufferBase"); 151 } 152 153 /** Allocate memory for buffer and sends initial content 154 * 155 * @param gl GL functions 156 * @param target Buffer target 157 * @param usage Buffer usage enum 158 * @param size <size> parameter 159 * @param data <data> parameter 160 **/ 161 void Buffer::Data(const glw::Functions& gl, glw::GLenum target, glw::GLenum usage, glw::GLsizeiptr size, 162 const glw::GLvoid* data) 163 { 164 gl.bufferData(target, size, data, usage); 165 GLU_EXPECT_NO_ERROR(gl.getError(), "BufferData"); 166 } 167 168 /** Generate buffer 169 * 170 * @param gl GL functions 171 * @param out_id Id of buffer 172 **/ 173 void Buffer::Generate(const glw::Functions& gl, glw::GLuint& out_id) 174 { 175 GLuint id = m_invalid_id; 176 177 gl.genBuffers(1, &id); 178 GLU_EXPECT_NO_ERROR(gl.getError(), "GenBuffers"); 179 180 if (m_invalid_id == id) 181 { 182 TCU_FAIL("Got invalid id"); 183 } 184 185 out_id = id; 186 } 187 188 /** Update range of buffer 189 * 190 * @param gl GL functions 191 * @param target Buffer target 192 * @param offset Offset in buffer 193 * @param size <size> parameter 194 * @param data <data> parameter 195 **/ 196 void Buffer::SubData(const glw::Functions& gl, glw::GLenum target, glw::GLintptr offset, glw::GLsizeiptr size, 197 glw::GLvoid* data) 198 { 199 gl.bufferSubData(target, offset, size, data); 200 GLU_EXPECT_NO_ERROR(gl.getError(), "BufferSubData"); 201 } 202 203 /* Framebuffer constants */ 204 const GLuint Framebuffer::m_invalid_id = -1; 205 206 /** Constructor. 207 * 208 * @param context CTS context. 209 **/ 210 Framebuffer::Framebuffer(const glw::Functions& gl) : m_id(m_invalid_id), m_gl(gl) 211 { 212 /* Nothing to done here */ 213 } 214 215 /** Destructor 216 * 217 **/ 218 Framebuffer::~Framebuffer() 219 { 220 Release(); 221 } 222 223 /** Release texture instance 224 * 225 **/ 226 void Framebuffer::Release() 227 { 228 if (m_invalid_id != m_id) 229 { 230 m_gl.deleteFramebuffers(1, &m_id); 231 m_id = m_invalid_id; 232 } 233 } 234 235 /** Attach texture to specified attachment 236 * 237 * @param gl GL functions 238 * @param target Framebuffer target 239 * @param attachment Attachment 240 * @param texture_id Texture id 241 * @param level Level of mipmap 242 * @param width Texture width 243 * @param height Texture height 244 **/ 245 void Framebuffer::AttachTexture(const glw::Functions& gl, glw::GLenum target, glw::GLenum attachment, 246 glw::GLuint texture_id, glw::GLint level, glw::GLuint width, glw::GLuint height) 247 { 248 gl.framebufferTexture(target, attachment, texture_id, level); 249 GLU_EXPECT_NO_ERROR(gl.getError(), "FramebufferTexture"); 250 251 gl.viewport(0 /* x */, 0 /* y */, width, height); 252 GLU_EXPECT_NO_ERROR(gl.getError(), "Viewport"); 253 } 254 255 /** Binds framebuffer to DRAW_FRAMEBUFFER 256 * 257 * @param gl GL functions 258 * @param target Framebuffer target 259 * @param id ID of framebuffer 260 **/ 261 void Framebuffer::Bind(const glw::Functions& gl, glw::GLenum target, glw::GLuint id) 262 { 263 gl.bindFramebuffer(target, id); 264 GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer"); 265 } 266 267 /** Generate framebuffer 268 * 269 **/ 270 void Framebuffer::Generate(const glw::Functions& gl, glw::GLuint& out_id) 271 { 272 GLuint id = m_invalid_id; 273 274 gl.genFramebuffers(1, &id); 275 GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers"); 276 277 if (m_invalid_id == id) 278 { 279 TCU_FAIL("Invalid id"); 280 } 281 282 out_id = id; 283 } 284 285 /* Program constants */ 286 const GLuint Program::m_invalid_id = 0; 287 288 /** Constructor. 289 * 290 * @param context CTS context. 291 **/ 292 Program::Program(const glw::Functions& gl) 293 : m_id(m_invalid_id) 294 , m_compute(gl) 295 , m_fragment(gl) 296 , m_geometry(gl) 297 , m_tess_ctrl(gl) 298 , m_tess_eval(gl) 299 , m_vertex(gl) 300 , m_gl(gl) 301 { 302 /* Nothing to be done here */ 303 } 304 305 /** Destructor 306 * 307 **/ 308 Program::~Program() 309 { 310 Release(); 311 } 312 313 /** Initialize program instance 314 * 315 * @param compute_shader Compute shader source code 316 * @param fragment_shader Fragment shader source code 317 * @param geometry_shader Geometry shader source code 318 * @param tesselation_control_shader Tesselation control shader source code 319 * @param tesselation_evaluation_shader Tesselation evaluation shader source code 320 * @param vertex_shader Vertex shader source code 321 **/ 322 void Program::Init(const std::string& compute_shader, const std::string& fragment_shader, 323 const std::string& geometry_shader, const std::string& tesselation_control_shader, 324 const std::string& tesselation_evaluation_shader, const std::string& vertex_shader) 325 { 326 /* Delete previous program */ 327 Release(); 328 329 /* Initialize shaders */ 330 m_compute.Init(GL_COMPUTE_SHADER, compute_shader); 331 m_fragment.Init(GL_FRAGMENT_SHADER, fragment_shader); 332 m_geometry.Init(GL_GEOMETRY_SHADER, geometry_shader); 333 m_tess_ctrl.Init(GL_TESS_CONTROL_SHADER, tesselation_control_shader); 334 m_tess_eval.Init(GL_TESS_EVALUATION_SHADER, tesselation_evaluation_shader); 335 m_vertex.Init(GL_VERTEX_SHADER, vertex_shader); 336 337 /* Create program, set up transform feedback and attach shaders */ 338 Create(m_gl, m_id); 339 Attach(m_gl, m_id, m_compute.m_id); 340 Attach(m_gl, m_id, m_fragment.m_id); 341 Attach(m_gl, m_id, m_geometry.m_id); 342 Attach(m_gl, m_id, m_tess_ctrl.m_id); 343 Attach(m_gl, m_id, m_tess_eval.m_id); 344 Attach(m_gl, m_id, m_vertex.m_id); 345 346 /* Link program */ 347 Link(m_gl, m_id); 348 } 349 350 /** Release program instance 351 * 352 **/ 353 void Program::Release() 354 { 355 if (m_invalid_id != m_id) 356 { 357 Use(m_gl, m_invalid_id); 358 359 m_gl.deleteProgram(m_id); 360 m_id = m_invalid_id; 361 } 362 363 m_compute.Release(); 364 m_fragment.Release(); 365 m_geometry.Release(); 366 m_tess_ctrl.Release(); 367 m_tess_eval.Release(); 368 m_vertex.Release(); 369 } 370 371 /** Set program as active 372 * 373 **/ 374 void Program::Use() const 375 { 376 Use(m_gl, m_id); 377 } 378 379 /** Attach shader to program 380 * 381 * @param gl GL functions 382 * @param program_id Id of program 383 * @param shader_id Id of shader 384 **/ 385 void Program::Attach(const glw::Functions& gl, glw::GLuint program_id, glw::GLuint shader_id) 386 { 387 /* Sanity checks */ 388 if ((m_invalid_id == program_id) || (Shader::m_invalid_id == shader_id)) 389 { 390 return; 391 } 392 393 gl.attachShader(program_id, shader_id); 394 GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader"); 395 } 396 397 /** Create program instance 398 * 399 * @param gl GL functions 400 * @param out_id Id of program 401 **/ 402 void Program::Create(const glw::Functions& gl, glw::GLuint& out_id) 403 { 404 const GLuint id = gl.createProgram(); 405 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateProgram"); 406 407 if (m_invalid_id == id) 408 { 409 TCU_FAIL("Failed to create program"); 410 } 411 412 out_id = id; 413 } 414 415 /** Link program 416 * 417 * @param gl GL functions 418 * @param id Id of program 419 **/ 420 void Program::Link(const glw::Functions& gl, glw::GLuint id) 421 { 422 GLint status = GL_FALSE; 423 424 gl.linkProgram(id); 425 GLU_EXPECT_NO_ERROR(gl.getError(), "LinkProgram"); 426 427 /* Get link status */ 428 gl.getProgramiv(id, GL_LINK_STATUS, &status); 429 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv"); 430 431 /* Log link error */ 432 if (GL_TRUE != status) 433 { 434 glw::GLint length = 0; 435 std::string message; 436 437 /* Get error log length */ 438 gl.getProgramiv(id, GL_INFO_LOG_LENGTH, &length); 439 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv"); 440 441 message.resize(length, 0); 442 443 /* Get error log */ 444 gl.getProgramInfoLog(id, length, 0, &message[0]); 445 GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramInfoLog"); 446 447 TCU_FAIL(message.c_str()); 448 } 449 } 450 451 /** Use program 452 * 453 * @param gl GL functions 454 * @param id Id of program 455 **/ 456 void Program::Use(const glw::Functions& gl, glw::GLuint id) 457 { 458 gl.useProgram(id); 459 GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram"); 460 } 461 462 /* Shader's constants */ 463 const GLuint Shader::m_invalid_id = 0; 464 465 /** Constructor. 466 * 467 * @param context CTS context. 468 **/ 469 Shader::Shader(const glw::Functions& gl) : m_id(m_invalid_id), m_gl(gl) 470 { 471 /* Nothing to be done here */ 472 } 473 474 /** Destructor 475 * 476 **/ 477 Shader::~Shader() 478 { 479 Release(); 480 } 481 482 /** Initialize shader instance 483 * 484 * @param stage Shader stage 485 * @param source Source code 486 **/ 487 void Shader::Init(glw::GLenum stage, const std::string& source) 488 { 489 if (true == source.empty()) 490 { 491 /* No source == no shader */ 492 return; 493 } 494 495 /* Delete any previous shader */ 496 Release(); 497 498 Create(m_gl, stage, m_id); 499 Source(m_gl, m_id, source); 500 501 Compile(m_gl, m_id); 502 } 503 504 /** Release shader instance 505 * 506 **/ 507 void Shader::Release() 508 { 509 if (m_invalid_id != m_id) 510 { 511 m_gl.deleteShader(m_id); 512 m_id = m_invalid_id; 513 } 514 } 515 516 /** Compile shader 517 * 518 * @param gl GL functions 519 * @param id Shader id 520 **/ 521 void Shader::Compile(const glw::Functions& gl, glw::GLuint id) 522 { 523 GLint status = GL_FALSE; 524 525 /* Compile */ 526 gl.compileShader(id); 527 GLU_EXPECT_NO_ERROR(gl.getError(), "CompileShader"); 528 529 /* Get compilation status */ 530 gl.getShaderiv(id, GL_COMPILE_STATUS, &status); 531 GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv"); 532 533 /* Log compilation error */ 534 if (GL_TRUE != status) 535 { 536 glw::GLint length = 0; 537 std::string message; 538 539 /* Error log length */ 540 gl.getShaderiv(id, GL_INFO_LOG_LENGTH, &length); 541 GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv"); 542 543 /* Prepare storage */ 544 message.resize(length, 0); 545 546 /* Get error log */ 547 gl.getShaderInfoLog(id, length, 0, &message[0]); 548 GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderInfoLog"); 549 550 TCU_FAIL(message.c_str()); 551 } 552 } 553 554 /** Create shader 555 * 556 * @param gl GL functions 557 * @param stage Shader stage 558 * @param out_id Shader id 559 **/ 560 void Shader::Create(const glw::Functions& gl, glw::GLenum stage, glw::GLuint& out_id) 561 { 562 const GLuint id = gl.createShader(stage); 563 GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader"); 564 565 if (m_invalid_id == id) 566 { 567 TCU_FAIL("Failed to create shader"); 568 } 569 570 out_id = id; 571 } 572 573 /** Set shader's source code 574 * 575 * @param gl GL functions 576 * @param id Shader id 577 * @param source Shader source code 578 **/ 579 void Shader::Source(const glw::Functions& gl, glw::GLuint id, const std::string& source) 580 { 581 const GLchar* code = source.c_str(); 582 583 gl.shaderSource(id, 1 /* count */, &code, 0 /* lengths */); 584 GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderSource"); 585 } 586 587 /* Texture static fields */ 588 const GLuint Texture::m_invalid_id = -1; 589 590 /** Constructor. 591 * 592 * @param context CTS context. 593 **/ 594 Texture::Texture(const glw::Functions& gl) : m_id(m_invalid_id), m_gl(gl) 595 { 596 /* Nothing to done here */ 597 } 598 599 /** Destructor 600 * 601 **/ 602 Texture::~Texture() 603 { 604 Release(); 605 } 606 607 /** Release texture instance 608 * 609 **/ 610 void Texture::Release() 611 { 612 if (m_invalid_id != m_id) 613 { 614 m_gl.deleteTextures(1, &m_id); 615 m_id = m_invalid_id; 616 } 617 } 618 619 /** Bind texture to target 620 * 621 * @param gl GL functions 622 * @param id Id of texture 623 * @param tex_type Type of texture 624 **/ 625 void Texture::Bind(const glw::Functions& gl, glw::GLuint id, glw::GLenum target) 626 { 627 gl.bindTexture(target, id); 628 GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); 629 } 630 631 /** Set contents of compressed texture 632 * 633 * @param gl GL functions 634 * @param target Texture target 635 * @param level Mipmap level 636 * @param internal_format Format of data 637 * @param width Width of texture 638 * @param height Height of texture 639 * @param depth Depth of texture 640 * @param image_size Size of data 641 * @param data Buffer with image data 642 **/ 643 void Texture::CompressedImage(const glw::Functions& gl, glw::GLenum target, glw::GLint level, 644 glw::GLenum internal_format, glw::GLuint width, glw::GLuint height, glw::GLuint depth, 645 glw::GLsizei image_size, const glw::GLvoid* data) 646 { 647 switch (target) 648 { 649 case GL_TEXTURE_1D: 650 gl.compressedTexImage1D(target, level, internal_format, width, 0 /* border */, image_size, data); 651 GLU_EXPECT_NO_ERROR(gl.getError(), "CompressedTexImage1D"); 652 break; 653 case GL_TEXTURE_1D_ARRAY: 654 case GL_TEXTURE_2D: 655 case GL_TEXTURE_RECTANGLE: 656 gl.compressedTexImage2D(target, level, internal_format, width, height, 0 /* border */, image_size, data); 657 GLU_EXPECT_NO_ERROR(gl.getError(), "CompressedTexImage2D"); 658 break; 659 case GL_TEXTURE_CUBE_MAP: 660 gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, internal_format, width, height, 0 /* border */, 661 image_size, data); 662 gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, level, internal_format, width, height, 0 /* border */, 663 image_size, data); 664 gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, level, internal_format, width, height, 0 /* border */, 665 image_size, data); 666 gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, level, internal_format, width, height, 0 /* border */, 667 image_size, data); 668 gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, level, internal_format, width, height, 0 /* border */, 669 image_size, data); 670 gl.compressedTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, level, internal_format, width, height, 0 /* border */, 671 image_size, data); 672 GLU_EXPECT_NO_ERROR(gl.getError(), "CompressedTexImage2D"); 673 break; 674 case GL_TEXTURE_3D: 675 case GL_TEXTURE_2D_ARRAY: 676 gl.compressedTexImage3D(target, level, internal_format, width, height, depth, 0 /* border */, image_size, data); 677 GLU_EXPECT_NO_ERROR(gl.getError(), "CompressedTexImage3D"); 678 break; 679 default: 680 TCU_FAIL("Invliad enum"); 681 break; 682 } 683 } 684 685 /** Generate texture instance 686 * 687 * @param gl GL functions 688 * @param out_id Id of texture 689 **/ 690 void Texture::Generate(const glw::Functions& gl, glw::GLuint& out_id) 691 { 692 GLuint id = m_invalid_id; 693 694 gl.genTextures(1, &id); 695 GLU_EXPECT_NO_ERROR(gl.getError(), "GenTextures"); 696 697 if (m_invalid_id == id) 698 { 699 TCU_FAIL("Invalid id"); 700 } 701 702 out_id = id; 703 } 704 705 /** Get texture data 706 * 707 * @param gl GL functions 708 * @param target Texture target 709 * @param format Format of data 710 * @param type Type of data 711 * @param out_data Buffer for data 712 **/ 713 void Texture::GetData(const glw::Functions& gl, glw::GLint level, glw::GLenum target, glw::GLenum format, 714 glw::GLenum type, glw::GLvoid* out_data) 715 { 716 gl.getTexImage(target, level, format, type, out_data); 717 GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexImage"); 718 } 719 720 /** Get texture data 721 * 722 * @param gl GL functions 723 * @param id Texture id 724 * @param level Mipmap level 725 * @param width Texture width 726 * @param height Texture height 727 * @param format Format of data 728 * @param type Type of data 729 * @param out_data Buffer for data 730 **/ 731 void Texture::GetData(const glw::Functions& gl, glw::GLuint id, glw::GLint level, glw::GLuint width, glw::GLuint height, 732 glw::GLenum format, glw::GLenum type, glw::GLvoid* out_data) 733 { 734 GLuint fbo; 735 gl.genFramebuffers(1, &fbo); 736 GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers"); 737 gl.bindFramebuffer(GL_FRAMEBUFFER, fbo); 738 GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer"); 739 gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, id, level); 740 GLU_EXPECT_NO_ERROR(gl.getError(), "FramebufferTexture2D"); 741 742 gl.readPixels(0, 0, width, height, format, type, out_data); 743 GLU_EXPECT_NO_ERROR(gl.getError(), "ReadPixels"); 744 745 gl.bindFramebuffer(GL_FRAMEBUFFER, 0); 746 } 747 748 /** Generate texture instance 749 * 750 * @param gl GL functions 751 * @param target Texture target 752 * @param level Mipmap level 753 * @param pname Parameter to query 754 * @param param Result of query 755 **/ 756 void Texture::GetLevelParameter(const glw::Functions& gl, glw::GLenum target, glw::GLint level, glw::GLenum pname, 757 glw::GLint* param) 758 { 759 gl.getTexLevelParameteriv(target, level, pname, param); 760 GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexLevelParameteriv"); 761 } 762 763 /** Set contents of texture 764 * 765 * @param gl GL functions 766 * @param target Texture target 767 * @param level Mipmap level 768 * @param internal_format Format of data 769 * @param width Width of texture 770 * @param height Height of texture 771 * @param depth Depth of texture 772 * @param format Format of data 773 * @param type Type of data 774 * @param data Buffer with image data 775 **/ 776 void Texture::Image(const glw::Functions& gl, glw::GLenum target, glw::GLint level, glw::GLenum internal_format, 777 glw::GLuint width, glw::GLuint height, glw::GLuint depth, glw::GLenum format, glw::GLenum type, 778 const glw::GLvoid* data) 779 { 780 switch (target) 781 { 782 case GL_TEXTURE_1D: 783 gl.texImage1D(target, level, internal_format, width, 0 /* border */, format, type, data); 784 GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage1D"); 785 break; 786 case GL_TEXTURE_1D_ARRAY: 787 case GL_TEXTURE_2D: 788 case GL_TEXTURE_RECTANGLE: 789 gl.texImage2D(target, level, internal_format, width, height, 0 /* border */, format, type, data); 790 GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage2D"); 791 break; 792 case GL_TEXTURE_CUBE_MAP: 793 gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, internal_format, width, height, 0 /* border */, format, 794 type, data); 795 gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, level, internal_format, width, height, 0 /* border */, format, 796 type, data); 797 gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, level, internal_format, width, height, 0 /* border */, format, 798 type, data); 799 gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, level, internal_format, width, height, 0 /* border */, format, 800 type, data); 801 gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, level, internal_format, width, height, 0 /* border */, format, 802 type, data); 803 gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, level, internal_format, width, height, 0 /* border */, format, 804 type, data); 805 GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage2D"); 806 break; 807 case GL_TEXTURE_3D: 808 case GL_TEXTURE_2D_ARRAY: 809 gl.texImage3D(target, level, internal_format, width, height, depth, 0 /* border */, format, type, data); 810 GLU_EXPECT_NO_ERROR(gl.getError(), "TexImage3D"); 811 break; 812 default: 813 TCU_FAIL("Invliad enum"); 814 break; 815 } 816 } 817 818 /** Allocate storage for texture 819 * 820 * @param gl GL functions 821 * @param target Texture target 822 * @param levels Number of levels 823 * @param internal_format Internal format of texture 824 * @param width Width of texture 825 * @param height Height of texture 826 * @param depth Depth of texture 827 **/ 828 void Texture::Storage(const glw::Functions& gl, glw::GLenum target, glw::GLsizei levels, glw::GLenum internal_format, 829 glw::GLuint width, glw::GLuint height, glw::GLuint depth) 830 { 831 switch (target) 832 { 833 case GL_TEXTURE_1D: 834 gl.texStorage1D(target, levels, internal_format, width); 835 GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage1D"); 836 break; 837 case GL_TEXTURE_1D_ARRAY: 838 case GL_TEXTURE_2D: 839 case GL_TEXTURE_RECTANGLE: 840 case GL_TEXTURE_CUBE_MAP: 841 gl.texStorage2D(target, levels, internal_format, width, height); 842 GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2D"); 843 break; 844 case GL_TEXTURE_2D_MULTISAMPLE: 845 gl.texStorage2DMultisample(target, levels, internal_format, width, height, GL_FALSE); 846 GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2DMultisample"); 847 break; 848 case GL_TEXTURE_3D: 849 case GL_TEXTURE_2D_ARRAY: 850 gl.texStorage3D(target, levels, internal_format, width, height, depth); 851 GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage3D"); 852 break; 853 default: 854 TCU_FAIL("Invliad enum"); 855 break; 856 } 857 } 858 859 /** Set contents of texture 860 * 861 * @param gl GL functions 862 * @param target Texture target 863 * @param level Mipmap level 864 * @param x X offset 865 * @param y Y offset 866 * @param z Z offset 867 * @param width Width of texture 868 * @param height Height of texture 869 * @param depth Depth of texture 870 * @param format Format of data 871 * @param type Type of data 872 * @param pixels Buffer with image data 873 **/ 874 void Texture::SubImage(const glw::Functions& gl, glw::GLenum target, glw::GLint level, glw::GLint x, glw::GLint y, 875 glw::GLint z, glw::GLsizei width, glw::GLsizei height, glw::GLsizei depth, glw::GLenum format, 876 glw::GLenum type, const glw::GLvoid* pixels) 877 { 878 switch (target) 879 { 880 case GL_TEXTURE_1D: 881 gl.texSubImage1D(target, level, x, width, format, type, pixels); 882 GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage1D"); 883 break; 884 case GL_TEXTURE_1D_ARRAY: 885 case GL_TEXTURE_2D: 886 case GL_TEXTURE_RECTANGLE: 887 gl.texSubImage2D(target, level, x, y, width, height, format, type, pixels); 888 GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage2D"); 889 break; 890 case GL_TEXTURE_CUBE_MAP: 891 gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, x, y, width, height, format, type, pixels); 892 gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, level, x, y, width, height, format, type, pixels); 893 gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, level, x, y, width, height, format, type, pixels); 894 gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, level, x, y, width, height, format, type, pixels); 895 gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, level, x, y, width, height, format, type, pixels); 896 gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, level, x, y, width, height, format, type, pixels); 897 GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage2D"); 898 break; 899 case GL_TEXTURE_3D: 900 case GL_TEXTURE_2D_ARRAY: 901 gl.texSubImage3D(target, level, x, y, z, width, height, depth, format, type, pixels); 902 GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage3D"); 903 break; 904 default: 905 TCU_FAIL("Invliad enum"); 906 break; 907 } 908 } 909 910 /* VertexArray constants */ 911 const GLuint VertexArray::m_invalid_id = -1; 912 913 /** Constructor. 914 * 915 * @param context CTS context. 916 **/ 917 VertexArray::VertexArray(const glw::Functions& gl) : m_id(m_invalid_id), m_gl(gl) 918 { 919 } 920 921 /** Destructor 922 * 923 **/ 924 VertexArray::~VertexArray() 925 { 926 Release(); 927 } 928 929 /** Release vertex array object instance 930 * 931 **/ 932 void VertexArray::Release() 933 { 934 if (m_invalid_id != m_id) 935 { 936 Bind(m_gl, 0); 937 938 m_gl.deleteVertexArrays(1, &m_id); 939 940 m_id = m_invalid_id; 941 } 942 } 943 944 /** Binds Vertex array object 945 * 946 * @param gl GL functions 947 * @param id ID of vertex array object 948 **/ 949 void VertexArray::Bind(const glw::Functions& gl, glw::GLuint id) 950 { 951 gl.bindVertexArray(id); 952 GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexArray"); 953 } 954 955 /** Generates Vertex array object 956 * 957 * @param gl GL functions 958 * @param out_id ID of vertex array object 959 **/ 960 void VertexArray::Generate(const glw::Functions& gl, glw::GLuint& out_id) 961 { 962 GLuint id = m_invalid_id; 963 964 gl.genVertexArrays(1, &id); 965 GLU_EXPECT_NO_ERROR(gl.getError(), "GenVertexArrays"); 966 967 if (m_invalid_id == id) 968 { 969 TCU_FAIL("Invalid id"); 970 } 971 972 out_id = id; 973 } 974 975 template <typename TYPE> 976 void initPixels(std::vector<TYPE>& pixels, GLuint n_pixels, GLuint n_channels) 977 { 978 if (n_channels == 1) 979 { 980 for (GLuint i = 0; i < n_pixels; ++i) 981 pixels[i] = static_cast<TYPE>(i); 982 } 983 else if (n_channels == 2) 984 { 985 for (GLuint i = 0; i < n_pixels; ++i) 986 { 987 GLuint idx = i * 2; 988 pixels[idx] = static_cast<TYPE>(i); 989 pixels[idx + 1] = pixels[idx]; 990 } 991 } 992 else if (n_channels == 4) 993 { 994 for (GLuint i = 0; i < n_pixels; ++i) 995 { 996 GLuint idx = i * 4; 997 pixels[idx] = static_cast<TYPE>(i); 998 pixels[idx + 1] = pixels[idx]; 999 pixels[idx + 2] = pixels[idx]; 1000 pixels[idx + 3] = pixels[idx]; 1001 } 1002 } 1003 else 1004 TCU_FAIL("Unsuported number of channels"); 1005 } 1006 1007 RobustnessBase::RobustnessBase(tcu::TestContext& testCtx, const char* name, const char* description, 1008 glu::ApiType apiType) 1009 : tcu::TestCase(testCtx, name, description), m_api_type(apiType), m_has_khr_robust_buffer_access(false) 1010 { 1011 } 1012 1013 glu::RenderContext* RobustnessBase::createRobustContext(glu::ResetNotificationStrategy reset) 1014 { 1015 // Create test context to verify if required extensions are available 1016 { 1017 deqp::Context context(m_testCtx, glu::ContextType(m_api_type)); 1018 const glu::ContextInfo& contextInfo = context.getContextInfo(); 1019 glu::ContextType context_type = context.getRenderContext().getType(); 1020 if (!contextInfo.isExtensionSupported("GL_KHR_robustness") && 1021 !contextSupports(context_type, glu::ApiType::es(3, 2))) 1022 { 1023 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_KHR_robustness extension not supported"); 1024 return NULL; 1025 } 1026 1027 m_has_khr_robust_buffer_access = contextInfo.isExtensionSupported("GL_KHR_robust_buffer_access_behavior") || 1028 contextInfo.isExtensionSupported("GL_ARB_robust_buffer_access_behavior") || 1029 contextSupports(context_type, glu::ApiType::core(4, 5)); 1030 if (!m_has_khr_robust_buffer_access && !contextSupports(context_type, glu::ApiType::core(4, 3))) 1031 { 1032 m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, 1033 "robust_buffer_access_behavior extension not supported"); 1034 return NULL; 1035 } 1036 1037 glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(context_type); 1038 m_specializationMap["VERSION"] = glu::getGLSLVersionDeclaration(glslVersion); 1039 m_context_is_es = glu::isContextTypeES(context_type); 1040 } 1041 1042 glu::RenderConfig renderCfg(glu::ContextType(m_api_type, glu::CONTEXT_ROBUST)); 1043 const tcu::CommandLine& commandLine = m_testCtx.getCommandLine(); 1044 glu::parseRenderConfig(&renderCfg, commandLine); 1045 1046 if (commandLine.getSurfaceType() == tcu::SURFACETYPE_WINDOW) 1047 renderCfg.resetNotificationStrategy = reset; 1048 else 1049 throw tcu::NotSupportedError("Test not supported in non-windowed context"); 1050 1051 /* Try to create core/es robusness context */ 1052 return createRenderContext(m_testCtx.getPlatform(), commandLine, renderCfg); 1053 } 1054 1055 /** Constructor 1056 * 1057 * @param testCtx Test context 1058 **/ 1059 VertexBufferObjectsTest::VertexBufferObjectsTest(tcu::TestContext& testCtx, glu::ApiType apiType) 1060 : RobustnessBase(testCtx, "vertex_buffer_objects", "Verifies that out-of-bound reads from VB result in zero", 1061 apiType) 1062 { 1063 /* Nothing to be done */ 1064 } 1065 1066 /** Execute test 1067 * 1068 * @return tcu::TestNode::STOP 1069 **/ 1070 tcu::TestNode::IterateResult VertexBufferObjectsTest::iterate() 1071 { 1072 de::SharedPtr<glu::RenderContext> robustContext(createRobustContext()); 1073 if (!robustContext.get()) 1074 return STOP; 1075 1076 static const GLuint invalid_elements[] = { 1077 9, 1, 12, 10, 2, 3, 11, 3, 4, 12, 4, 5, 13, 5, 6, 14, 6, 7, 15, 7, 8, 16, 8, 1, 1078 }; 1079 1080 static const GLuint valid_elements[] = { 1081 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 6, 0, 6, 7, 0, 7, 8, 0, 8, 1, 1082 }; 1083 1084 static const GLfloat vertices[] = { 1085 0.0f, 0.0f, 0.0f, /* 0 */ 1086 -1.0f, 0.0f, 0.0f, /* 1 */ 1087 -1.0f, 1.0f, 0.0f, /* 2 */ 1088 0.0f, 1.0f, 0.0f, /* 3 */ 1089 1.0f, 1.0f, 0.0f, /* 4 */ 1090 1.0f, 0.0f, 0.0f, /* 5 */ 1091 1.0f, -1.0f, 0.0f, /* 6 */ 1092 0.0f, -1.0f, 0.0f, /* 7 */ 1093 -1.0f, -1.0f, 0.0f, /* 8 */ 1094 }; 1095 1096 static const GLuint height = 8; 1097 static const GLuint n_vertices = 24; 1098 static const GLuint width = 8; 1099 1100 /* GL entry points */ 1101 const Functions& gl = robustContext->getFunctions(); 1102 1103 /* Test case objects */ 1104 Framebuffer framebuffer(gl); 1105 Program program(gl); 1106 Texture texture(gl); 1107 Buffer elements_buffer(gl); 1108 Buffer vertices_buffer(gl); 1109 VertexArray vao(gl); 1110 1111 /* Vertex array */ 1112 VertexArray::Generate(gl, vao.m_id); 1113 VertexArray::Bind(gl, vao.m_id); 1114 1115 /* Buffers initialization */ 1116 elements_buffer.InitData(GL_ELEMENT_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(valid_elements), valid_elements); 1117 vertices_buffer.InitData(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(vertices), vertices); 1118 1119 /* Texture initialization */ 1120 Texture::Generate(gl, texture.m_id); 1121 Texture::Bind(gl, texture.m_id, GL_TEXTURE_2D); 1122 Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R8UI, width, height, 0); 1123 Texture::Bind(gl, 0, GL_TEXTURE_2D); 1124 1125 /* Framebuffer initialization*/ 1126 Framebuffer::Generate(gl, framebuffer.m_id); 1127 Framebuffer::Bind(gl, GL_DRAW_FRAMEBUFFER, framebuffer.m_id); 1128 Framebuffer::AttachTexture(gl, GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.m_id, 0 /* level */, width, 1129 height); 1130 1131 /* Shaders initialization */ 1132 program.Init("" /* cs */, getFragmentShader(), "" /* gs */, "" /* tcs */, "" /* tes */, getVertexShader()); 1133 Program::Use(gl, program.m_id); 1134 1135 /* Vertex buffer initialization */ 1136 vertices_buffer.Bind(); 1137 gl.bindVertexBuffer(0 /* bindindex = location */, vertices_buffer.m_id, 0 /* offset */, 12 /* stride */); 1138 gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 12, NULL); 1139 gl.enableVertexAttribArray(0 /* location */); 1140 1141 /* Binding elements/indices buffer */ 1142 elements_buffer.Bind(); 1143 1144 cleanTexture(gl, texture.m_id); 1145 1146 gl.drawElements(GL_TRIANGLES, n_vertices, GL_UNSIGNED_INT, 0 /* indices */); 1147 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawElements"); 1148 1149 if (false == verifyValidResults(gl, texture.m_id)) 1150 { 1151 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid result for valid input" << tcu::TestLog::EndMessage; 1152 1153 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 1154 return tcu::TestNode::STOP; 1155 } 1156 1157 /* Generate invalid data sets */ 1158 const GLuint invalid_elements_offsets[] = { 1159 0, // close fetch 1160 4 * 1024, // near fetch (4K of the end of the object) 1161 1024 * 1024, // medium fetch (1MB past the end of the object) 1162 10 * 1024 * 1024 // high fetch (10MB beyond the end of the object) 1163 }; 1164 const GLuint invalid_buffers_count = DE_LENGTH_OF_ARRAY(invalid_elements_offsets); 1165 const GLuint item_count = DE_LENGTH_OF_ARRAY(invalid_elements); 1166 GLuint invalid_elements_set[invalid_buffers_count][item_count]; 1167 for (GLuint buffer_index = 0; buffer_index < invalid_buffers_count; ++buffer_index) 1168 { 1169 for (GLuint item_index = 0; item_index < item_count; ++item_index) 1170 invalid_elements_set[buffer_index][item_index] = 1171 invalid_elements[item_index] + invalid_elements_offsets[buffer_index]; 1172 } 1173 1174 for (GLuint buffer_index = 0; buffer_index < invalid_buffers_count; ++buffer_index) 1175 { 1176 /* Create elements/indices buffer */ 1177 elements_buffer.InitData(GL_ELEMENT_ARRAY_BUFFER, GL_DYNAMIC_DRAW, sizeof(invalid_elements_set[buffer_index]), 1178 invalid_elements_set[buffer_index]); 1179 elements_buffer.Bind(); 1180 1181 cleanTexture(gl, texture.m_id); 1182 1183 gl.drawElements(GL_TRIANGLES, n_vertices, GL_UNSIGNED_INT, 0 /* indices */); 1184 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawElements"); 1185 1186 if (false == verifyInvalidResults(gl, texture.m_id)) 1187 { 1188 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid result for invalid input" 1189 << tcu::TestLog::EndMessage; 1190 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 1191 return tcu::TestNode::STOP; 1192 } 1193 } 1194 1195 /* Done */ 1196 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1197 return tcu::TestNode::STOP; 1198 } 1199 1200 /** Prepare shader for current test case 1201 * 1202 * @return Source 1203 **/ 1204 std::string VertexBufferObjectsTest::getFragmentShader() 1205 { 1206 const char* source = "${VERSION}\n" 1207 "layout (location = 0) out lowp uvec4 out_fs_color;\n" 1208 "void main()\n" 1209 "{\n" 1210 " out_fs_color = uvec4(1, 255, 255, 255);\n" 1211 "}\n"; 1212 return tcu::StringTemplate(source).specialize(m_specializationMap); 1213 } 1214 1215 /** Prepare shader for current test case 1216 * 1217 * @return Source 1218 **/ 1219 std::string VertexBufferObjectsTest::getVertexShader() 1220 { 1221 const char* source = "${VERSION}\n" 1222 "layout (location = 0) in vec4 in_vs_position;\n" 1223 "void main()\n" 1224 "{\n" 1225 " gl_Position = in_vs_position;\n" 1226 "}\n"; 1227 1228 return tcu::StringTemplate(source).specialize(m_specializationMap); 1229 } 1230 1231 /** Fill texture with value 128 1232 * 1233 * @param texture_id Id of texture 1234 **/ 1235 void VertexBufferObjectsTest::cleanTexture(const Functions& gl, glw::GLuint texture_id) 1236 { 1237 static const GLuint height = 8; 1238 static const GLuint width = 8; 1239 1240 GLubyte pixels[width * height]; 1241 for (GLuint i = 0; i < width * height; ++i) 1242 { 1243 pixels[i] = 128; 1244 } 1245 1246 Texture::Bind(gl, texture_id, GL_TEXTURE_2D); 1247 1248 Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height, 0 /* depth */, 1249 GL_RED_INTEGER, GL_UNSIGNED_BYTE, pixels); 1250 1251 /* Unbind */ 1252 Texture::Bind(gl, 0, GL_TEXTURE_2D); 1253 } 1254 1255 /** Verifies that texutre is not filled with 1 1256 * 1257 * @param texture_id Id of texture 1258 * 1259 * @return false when image is filled with 1, true otherwise 1260 **/ 1261 bool VertexBufferObjectsTest::verifyInvalidResults(const Functions& gl, glw::GLuint texture_id) 1262 { 1263 // In OpenGL ES there is undefined out-of-bound behavior - no verification 1264 if (m_context_is_es) 1265 return true; 1266 return !verifyResults(gl, texture_id); 1267 } 1268 1269 /** Verifies that texutre is filled with 1 1270 * 1271 * @param texture_id Id of texture 1272 * 1273 * @return true when image is filled with 1, false otherwise 1274 **/ 1275 bool VertexBufferObjectsTest::verifyValidResults(const Functions& gl, glw::GLuint texture_id) 1276 { 1277 return verifyResults(gl, texture_id); 1278 } 1279 1280 /** Verifies that texutre is filled with 1 1281 * 1282 * @param texture_id Id of texture 1283 * 1284 * @return true when image is filled with 1, false otherwise 1285 **/ 1286 bool VertexBufferObjectsTest::verifyResults(const Functions& gl, glw::GLuint texture_id) 1287 { 1288 static const GLuint height = 8; 1289 static const GLuint width = 8; 1290 GLuint pixel_size = 4 * sizeof(GLuint); 1291 GLuint expected_value = 1; 1292 1293 std::vector<GLubyte> pixels(width * height * pixel_size, 0); 1294 Texture::Bind(gl, texture_id, GL_TEXTURE_2D); 1295 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]); 1296 Texture::Bind(gl, 0, GL_TEXTURE_2D); 1297 1298 /* Verify */ 1299 for (GLuint i = 0; i < pixels.size(); i += pixel_size) 1300 { 1301 if (expected_value != pixels[i]) 1302 return false; 1303 } 1304 1305 return true; 1306 } 1307 1308 /** Constructor 1309 * 1310 * @param testCtx Test context 1311 **/ 1312 TexelFetchTest::TexelFetchTest(tcu::TestContext& testCtx, glu::ApiType apiType) 1313 : RobustnessBase(testCtx, "texel_fetch", "Verifies that out-of-bound fetches from texture result in zero", apiType) 1314 , m_test_case(R8) 1315 { 1316 /* Nothing to be done */ 1317 } 1318 1319 /** Constructor 1320 * 1321 * @param testCtx Test context 1322 * @param name Test name 1323 * @param description Test description 1324 * @param apiType Api type 1325 **/ 1326 TexelFetchTest::TexelFetchTest(tcu::TestContext& testCtx, const char* name, const char* description, 1327 glu::ApiType apiType) 1328 : RobustnessBase(testCtx, name, description, apiType), m_test_case(R8) 1329 { 1330 /* Nothing to be done */ 1331 } 1332 1333 /** Execute test 1334 * 1335 * @return tcu::TestNode::STOP 1336 **/ 1337 tcu::TestNode::IterateResult TexelFetchTest::iterate() 1338 { 1339 de::SharedPtr<glu::RenderContext> robustContext(createRobustContext()); 1340 if (!robustContext.get()) 1341 return STOP; 1342 1343 /* Constants */ 1344 static const GLuint height = 16; 1345 static const GLuint width = 16; 1346 1347 /* GL entry points */ 1348 const Functions& gl = robustContext->getFunctions(); 1349 1350 /* Test result indicator */ 1351 bool test_result = true; 1352 1353 GLuint invalid_fetch_offsets[] = { 1354 16, // near fetch 1355 512, // medium fetch 1356 1008, // high fetch 1357 }; 1358 GLuint fetch_offsets_count = sizeof(invalid_fetch_offsets) / sizeof(GLuint); 1359 glu::ContextType contextType = robustContext->getType(); 1360 1361 /* Iterate over all cases */ 1362 for (; m_test_case < LAST; m_test_case = (TEST_CASES)((GLuint)m_test_case + 1)) 1363 { 1364 GLint level = 0; 1365 GLenum texture_target = GL_TEXTURE_2D; 1366 1367 if (R32UI_MULTISAMPLE == m_test_case || RG8_SNORM == m_test_case) 1368 { 1369 // 1. RG8_SNORM case: 1370 // Skip RG8_SNORM format case. 1371 // RG8_SNORM is not required to be used as a render target 1372 // OpenGL 4.5 Core Spec, Page 197 1373 // 1374 // 2. R32UI_MULTISAMPLE case 1375 // Skip test in multi sample case 1376 // texelFetch with invalid lod plane results undefined value 1377 // OpenGL 4.5 Core Spec, around page 377 1378 m_test_case = (TEST_CASES)((GLuint)m_test_case + 1); 1379 continue; 1380 } 1381 1382 /* */ 1383 Texture destination_texture(gl); 1384 Framebuffer framebuffer(gl); 1385 Texture source_texture(gl); 1386 Program program(gl); 1387 VertexArray vao(gl); 1388 1389 /* Prepare VAO */ 1390 VertexArray::Generate(gl, vao.m_id); 1391 VertexArray::Bind(gl, vao.m_id); 1392 1393 /* Prepare textures */ 1394 Texture::Generate(gl, destination_texture.m_id); 1395 Texture::Generate(gl, source_texture.m_id); 1396 1397 if (R32UI_MULTISAMPLE == m_test_case) 1398 { 1399 GLint max_integer_samples; 1400 gl.getIntegerv(GL_MAX_INTEGER_SAMPLES, &max_integer_samples); 1401 GLint max_image_samples; 1402 gl.getIntegerv(GL_MAX_IMAGE_SAMPLES, &max_image_samples); 1403 if (max_integer_samples < 4 || max_image_samples < 4) 1404 { 1405 /* prepareTexture() hard-codes 4 samples (n_levels) for 1406 * R32UI_MULTISAMPLE case. This value exceeds the required 1407 * min-max value (1 in OpenGL ES 3.2) and is not supported 1408 * by all implementations. 1409 * 1410 * Also, the test uses a compute shader with images 1411 * to upload the texture so max_image_samples >= 4 1412 * is also required. 1413 */ 1414 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << getTestCaseName() << " not supported" 1415 << tcu::TestLog::EndMessage; 1416 1417 continue; 1418 } 1419 } 1420 1421 prepareTexture(gl, false, destination_texture.m_id); 1422 prepareTexture(gl, true, source_texture.m_id); 1423 1424 /* Select FBO settings */ 1425 if (R32UI_MIPMAP == m_test_case) 1426 { 1427 level = 1; 1428 } 1429 else if (R32UI_MULTISAMPLE == m_test_case) 1430 { 1431 texture_target = GL_TEXTURE_2D_MULTISAMPLE; 1432 } 1433 1434 /* Prepare FBO */ 1435 Framebuffer::Generate(gl, framebuffer.m_id); 1436 Framebuffer::Bind(gl, GL_DRAW_FRAMEBUFFER, framebuffer.m_id); 1437 Framebuffer::AttachTexture(gl, GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, destination_texture.m_id, level, 1438 width, height); 1439 1440 /* Prepare valid program */ 1441 program.Init("" /* cs */, getFragmentShader(contextType, true), getGeometryShader(), "" /* tcs */, "" /* tes */, 1442 getVertexShader()); 1443 1444 /* Test valid case */ 1445 /* Set program */ 1446 Program::Use(gl, program.m_id); 1447 1448 /* Set texture */ 1449 gl.activeTexture(GL_TEXTURE0); /* location = 0 */ 1450 GLU_EXPECT_NO_ERROR(gl.getError(), "ActiveTexture"); 1451 Texture::Bind(gl, source_texture.m_id, texture_target); 1452 gl.uniform1i(0 /* location */, 0 /* texture unit */); 1453 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i"); 1454 1455 /* Check if setup is supported */ 1456 GLenum fbo_status = gl.checkFramebufferStatus(GL_DRAW_FRAMEBUFFER); 1457 GLU_EXPECT_NO_ERROR(gl.getError(), "CheckFramebufferStatus"); 1458 if (GL_FRAMEBUFFER_COMPLETE != fbo_status) 1459 { 1460 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << getTestCaseName() << " not supported" 1461 << tcu::TestLog::EndMessage; 1462 1463 continue; 1464 } 1465 1466 /* Enable multisampling */ 1467 if (R32UI_MULTISAMPLE == m_test_case) 1468 { 1469 gl.enable(GL_MULTISAMPLE); 1470 GLU_EXPECT_NO_ERROR(gl.getError(), "Enable"); 1471 } 1472 1473 /* Draw */ 1474 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */); 1475 { 1476 /* Get error from draw */ 1477 GLenum error = gl.getError(); 1478 1479 /* Disable multisampling */ 1480 if (R32UI_MULTISAMPLE == m_test_case) 1481 { 1482 gl.disable(GL_MULTISAMPLE); 1483 GLU_EXPECT_NO_ERROR(gl.getError(), "Disable"); 1484 } 1485 1486 /* Handle error from draw */ 1487 GLU_EXPECT_NO_ERROR(error, "DrawArrays"); 1488 } 1489 1490 /* Verification */ 1491 if (false == verifyValidResults(gl, destination_texture.m_id)) 1492 { 1493 test_result = false; 1494 } 1495 1496 /* Test invalid cases */ 1497 for (GLuint index = 0; index < fetch_offsets_count; ++index) 1498 { 1499 /* Prepare invalid program */ 1500 program.Init("" /* cs */, getFragmentShader(contextType, false, invalid_fetch_offsets[index]), 1501 getGeometryShader(), "" /* tcs */, "" /* tes */, getVertexShader()); 1502 Program::Use(gl, program.m_id); 1503 Framebuffer::Bind(gl, GL_DRAW_FRAMEBUFFER, framebuffer.m_id); 1504 1505 /* Set texture */ 1506 gl.activeTexture(GL_TEXTURE0); /* location = 0 */ 1507 GLU_EXPECT_NO_ERROR(gl.getError(), "ActiveTexture"); 1508 Texture::Bind(gl, source_texture.m_id, texture_target); 1509 gl.uniform1i(0 /* location */, 0 /* texture unit */); 1510 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i"); 1511 1512 /* Draw */ 1513 gl.clear(GL_COLOR_BUFFER_BIT); 1514 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */); 1515 GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays"); 1516 1517 /* Verification */ 1518 if (false == verifyInvalidResults(gl, destination_texture.m_id)) 1519 { 1520 test_result = false; 1521 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << getTestCaseName() << " failed for " 1522 << invalid_fetch_offsets[index] << " offset" << tcu::TestLog::EndMessage; 1523 } 1524 } 1525 } 1526 1527 /* Set result */ 1528 if (true == test_result) 1529 { 1530 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1531 } 1532 else 1533 { 1534 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 1535 } 1536 1537 /* Done */ 1538 return tcu::TestNode::STOP; 1539 } 1540 1541 /** Prepares source code for fragment shader 1542 * 1543 * @param is_case_valid Selects if valid or invalid case is tested 1544 * 1545 * @return string with prepared code 1546 **/ 1547 std::string TexelFetchTest::getFragmentShader(const glu::ContextType&, bool is_case_valid, GLuint fetch_offset) 1548 { 1549 const GLchar* source = "${VERSION}\n" 1550 "in lowp vec2 gs_fs_tex_coord;\n" 1551 "layout (location = 0) out lowp ${TYPE} out_fs_color;\n" 1552 "layout (location = 0) uniform lowp ${SAMPLER} uni_texture;\n" 1553 "\n" 1554 "void main()\n" 1555 "{\n" 1556 " ivec2 point = ivec2(gs_fs_tex_coord * 16.0 + float(${OFFSET}));\n" 1557 " out_fs_color = texelFetch(uni_texture, point, ${PLANE});\n" 1558 "}\n"; 1559 1560 m_specializationMap["PLANE"] = "0"; 1561 m_specializationMap["SAMPLER"] = "sampler2D"; 1562 m_specializationMap["TYPE"] = "vec4"; 1563 1564 if (R32UI_MIPMAP == m_test_case) 1565 { 1566 m_specializationMap["PLANE"] = "1"; 1567 m_specializationMap["SAMPLER"] = "usampler2D"; 1568 m_specializationMap["TYPE"] = "uvec4"; 1569 1570 if (false == is_case_valid) 1571 { 1572 fetch_offset = 0; 1573 m_specializationMap["PLANE"] = "2"; 1574 } 1575 } 1576 else if (R32UI_MULTISAMPLE == m_test_case) 1577 { 1578 m_specializationMap["PLANE"] = "9"; 1579 m_specializationMap["SAMPLER"] = "usampler2DMS"; 1580 m_specializationMap["TYPE"] = "uvec4"; 1581 1582 if (false == is_case_valid) 1583 { 1584 fetch_offset = 0; 1585 m_specializationMap["PLANE"] = "gl_SampleID"; 1586 } 1587 } 1588 1589 std::stringstream offset; 1590 offset << fetch_offset; 1591 m_specializationMap["OFFSET"] = offset.str(); 1592 1593 return tcu::StringTemplate(source).specialize(m_specializationMap); 1594 } 1595 1596 /** Prepare shader for current test case 1597 * 1598 * @return Source 1599 **/ 1600 std::string TexelFetchTest::getGeometryShader() 1601 { 1602 static const GLchar* source = "${VERSION}\n" 1603 "layout(points) in;\n" 1604 "layout(triangle_strip, max_vertices = 4) out;\n" 1605 "\n" 1606 "out vec2 gs_fs_tex_coord;\n" 1607 "\n" 1608 "void main()\n" 1609 "{\n" 1610 " gs_fs_tex_coord = vec2(0, 0);\n" 1611 " gl_Position = vec4(-1, -1, 0, 1);\n" 1612 " EmitVertex();\n" 1613 "\n" 1614 " gs_fs_tex_coord = vec2(0, 1);\n" 1615 " gl_Position = vec4(-1, 1, 0, 1);\n" 1616 " EmitVertex();\n" 1617 "\n" 1618 " gs_fs_tex_coord = vec2(1, 0);\n" 1619 " gl_Position = vec4(1, -1, 0, 1);\n" 1620 " EmitVertex();\n" 1621 "\n" 1622 " gs_fs_tex_coord = vec2(1, 1);\n" 1623 " gl_Position = vec4(1, 1, 0, 1);\n" 1624 " EmitVertex();\n" 1625 "}\n"; 1626 1627 return tcu::StringTemplate(source).specialize(m_specializationMap); 1628 } 1629 1630 /** Prepare shader for current test case 1631 * 1632 * @return Source 1633 **/ 1634 std::string TexelFetchTest::getVertexShader() 1635 { 1636 static const GLchar* source = "${VERSION}\n" 1637 "\n" 1638 "void main()\n" 1639 "{\n" 1640 " gl_Position = vec4(0, 0, 0, 1);\n" 1641 "}\n"; 1642 return tcu::StringTemplate(source).specialize(m_specializationMap); 1643 } 1644 1645 /** Returns name of current test case 1646 * 1647 * @return Name of test case 1648 **/ 1649 const glw::GLchar* TexelFetchTest::getTestCaseName() const 1650 { 1651 const GLchar* name = ""; 1652 1653 switch (m_test_case) 1654 { 1655 case R8: 1656 name = "Sampling GL_R8 texture"; 1657 break; 1658 case RG8_SNORM: 1659 name = "Sampling GL_RG8_SNORM texture"; 1660 break; 1661 case RGBA32F: 1662 name = "Sampling GL_RGBA32F texture"; 1663 break; 1664 case R32UI_MIPMAP: 1665 name = "Sampling mipmap of GL_32UI texture"; 1666 break; 1667 case R32UI_MULTISAMPLE: 1668 name = "Sampling GL_32UI multisampled texture"; 1669 break; 1670 default: 1671 TCU_FAIL("Invalid enum"); 1672 break; 1673 } 1674 1675 return name; 1676 } 1677 1678 /** Prepare a texture 1679 * 1680 * @param is_source Selects if texutre will be used as source or destination 1681 * @param texture_id Id of texutre 1682 **/ 1683 void TexelFetchTest::prepareTexture(const Functions& gl, bool is_source, glw::GLuint texture_id) 1684 { 1685 /* Image size */ 1686 static const GLuint image_height = 16; 1687 static const GLuint image_width = 16; 1688 1689 /* Texture storage parameters */ 1690 GLuint height = image_height; 1691 GLenum internal_format = 0; 1692 GLsizei n_levels = 1; 1693 GLenum target = GL_TEXTURE_2D; 1694 GLuint width = image_width; 1695 1696 /* Prepare texture storage parameters */ 1697 switch (m_test_case) 1698 { 1699 case R8: 1700 internal_format = GL_R8; 1701 break; 1702 case RG8_SNORM: 1703 internal_format = GL_RG8_SNORM; 1704 break; 1705 case RGBA32F: 1706 internal_format = GL_RGBA32F; 1707 break; 1708 case R32UI_MIPMAP: 1709 height = 2 * image_height; 1710 internal_format = GL_R32UI; 1711 n_levels = 2; 1712 width = 2 * image_width; 1713 break; 1714 case R32UI_MULTISAMPLE: 1715 internal_format = GL_R32UI; 1716 n_levels = 4; 1717 target = GL_TEXTURE_2D_MULTISAMPLE; 1718 break; 1719 default: 1720 TCU_FAIL("Invalid enum"); 1721 } 1722 1723 /* Prepare storage */ 1724 Texture::Bind(gl, texture_id, target); 1725 Texture::Storage(gl, target, n_levels, internal_format, width, height, 0); 1726 1727 /* Set samplers to NEAREST/NEAREST if required. The results of texelFetch builtins 1728 are undefined if the computed level of detail is not the texture's base level and 1729 the texture's minification filter is NEAREST or LINEAR. */ 1730 if (R32UI_MIPMAP == m_test_case) 1731 { 1732 gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); 1733 gl.texParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 1734 } 1735 else if (R32UI_MULTISAMPLE != m_test_case) 1736 { 1737 gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 1738 gl.texParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 1739 } 1740 1741 /* Destination image can be left empty */ 1742 if (false == is_source) 1743 { 1744 Texture::Bind(gl, 0, target); 1745 return; 1746 } 1747 1748 /* Prepare texture */ 1749 if (R8 == m_test_case) 1750 { 1751 GLubyte source_pixels[image_width * image_height]; 1752 for (GLuint i = 0; i < image_width * image_height; ++i) 1753 { 1754 source_pixels[i] = static_cast<GLubyte>(i); 1755 } 1756 1757 Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height, 1758 0 /* depth */, GL_RED, GL_UNSIGNED_BYTE, source_pixels); 1759 } 1760 else if (RG8_SNORM == m_test_case) 1761 { 1762 static const GLuint n_components = 2; 1763 1764 GLbyte source_pixels[image_width * image_height * n_components]; 1765 for (GLuint i = 0; i < image_width * image_height; ++i) 1766 { 1767 source_pixels[i * n_components + 0] = static_cast<GLubyte>((i % 16) - 8); 1768 source_pixels[i * n_components + 1] = static_cast<GLubyte>((i / 16) - 8); 1769 } 1770 1771 Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height, 1772 0 /* depth */, GL_RG, GL_BYTE, source_pixels); 1773 } 1774 else if (RGBA32F == m_test_case) 1775 { 1776 static const GLuint n_components = 4; 1777 1778 GLfloat source_pixels[image_width * image_height * n_components]; 1779 for (GLuint i = 0; i < image_width * image_height; ++i) 1780 { 1781 source_pixels[i * n_components + 0] = (GLfloat)(i % 16) / 16.0f; 1782 source_pixels[i * n_components + 1] = (GLfloat)(i / 16) / 16.0f; 1783 source_pixels[i * n_components + 2] = (GLfloat)i / 256.0f; 1784 source_pixels[i * n_components + 3] = 1.0f; 1785 } 1786 1787 Texture::SubImage(gl, GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, width, height, 1788 0 /* depth */, GL_RGBA, GL_FLOAT, source_pixels); 1789 } 1790 else if (R32UI_MIPMAP == m_test_case) 1791 { 1792 GLuint source_pixels[image_width * image_height]; 1793 for (GLuint i = 0; i < image_width * image_height; ++i) 1794 { 1795 source_pixels[i] = i; 1796 } 1797 1798 Texture::SubImage(gl, GL_TEXTURE_2D, 1 /* level */, 0 /* x */, 0 /* y */, 0 /* z */, image_width, image_height, 1799 0 /* depth */, GL_RED_INTEGER, GL_UNSIGNED_INT, source_pixels); 1800 } 1801 else if (R32UI_MULTISAMPLE == m_test_case) 1802 { 1803 /* Compute shader */ 1804 static const GLchar* source = 1805 "${VERSION}\n" 1806 "\n" 1807 "layout (local_size_x = ${LOCAL_SIZE}, local_size_y = ${LOCAL_SIZE}, local_size_z = 1) in;\n" 1808 "layout (${QUALIFIERS}) writeonly uniform highp uimage2DMS uni_image;\n" 1809 "\n" 1810 "void main()\n" 1811 "{\n" 1812 " const ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n" 1813 " const uint index = gl_WorkGroupID.y * 16U + gl_WorkGroupID.x;\n" 1814 "\n" 1815 " imageStore(uni_image, point, 0, uvec4(index + 0U, 0, 0, 0));\n" 1816 " imageStore(uni_image, point, 1, uvec4(index + 1U, 0, 0, 0));\n" 1817 " imageStore(uni_image, point, 2, uvec4(index + 2U, 0, 0, 0));\n" 1818 " imageStore(uni_image, point, 3, uvec4(index + 3U, 0, 0, 0));\n" 1819 "}\n" 1820 "\n"; 1821 1822 if (m_context_is_es) 1823 { 1824 m_specializationMap["LOCAL_SIZE"] = "16"; 1825 m_specializationMap["QUALIFIERS"] = "binding = 0, r32ui"; 1826 } 1827 else 1828 { 1829 m_specializationMap["LOCAL_SIZE"] = "1"; 1830 m_specializationMap["QUALIFIERS"] = "location = 0"; 1831 } 1832 1833 Program program(gl); 1834 std::string cs = tcu::StringTemplate(source).specialize(m_specializationMap); 1835 program.Init(cs, "", "", "", "", ""); 1836 program.Use(); 1837 1838 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */, 1839 GL_WRITE_ONLY, GL_R32UI); 1840 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture"); 1841 1842 if (!m_context_is_es) 1843 { 1844 gl.uniform1i(0 /* location */, 0 /* image unit*/); 1845 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i"); 1846 } 1847 1848 gl.dispatchCompute(16, 16, 1); 1849 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute"); 1850 } 1851 1852 Texture::Bind(gl, 0, target); 1853 } 1854 1855 /** Verifies that texutre is filled with 0 or with (0, 0, 0, x), 1856 * where x may be 0, 1 or the biggest representable integer value. 1857 * 1858 * @param texture_id Id of texture 1859 * 1860 * @return true when image is filled with 0, 1 or biggest represetable integer number, false otherwise 1861 **/ 1862 bool TexelFetchTest::verifyInvalidResults(const Functions& gl, glw::GLuint texture_id) 1863 { 1864 static const GLuint height = 16; 1865 static const GLuint width = 16; 1866 static const GLuint n_pixels = height * width; 1867 1868 // OpenGL ES has undefined out-of-bound behavior - no verification 1869 if (m_context_is_es) 1870 return true; 1871 1872 bool result = true; 1873 1874 if (R8 == m_test_case) 1875 { 1876 static const GLuint n_channels = 4; 1877 1878 std::vector<GLubyte> pixels(n_pixels * n_channels); 1879 initPixels(pixels, n_pixels, n_channels); 1880 1881 Texture::Bind(gl, texture_id, GL_TEXTURE_2D); 1882 1883 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]); 1884 1885 /* Unbind */ 1886 Texture::Bind(gl, 0, GL_TEXTURE_2D); 1887 1888 /* Verify */ 1889 for (GLuint i = 0; i < n_pixels; ++i) 1890 { 1891 const GLubyte expected_red = 0; 1892 const GLubyte drawn_red = pixels[i * n_channels]; 1893 1894 if (expected_red != drawn_red) 1895 { 1896 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLuint)drawn_red 1897 << ". Expected value: " << (GLuint)expected_red << " at offset: " << i 1898 << tcu::TestLog::EndMessage; 1899 1900 result = false; 1901 break; 1902 } 1903 } 1904 } 1905 else if (RG8_SNORM == m_test_case) 1906 { 1907 static const GLuint n_channels = 4; 1908 1909 std::vector<GLbyte> pixels(n_pixels * n_channels); 1910 initPixels(pixels, n_pixels, n_channels); 1911 1912 Texture::Bind(gl, texture_id, GL_TEXTURE_2D); 1913 1914 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RGBA, GL_BYTE, &pixels[0]); 1915 1916 /* Unbind */ 1917 Texture::Bind(gl, 0, GL_TEXTURE_2D); 1918 1919 /* Verify */ 1920 for (GLuint i = 0; i < n_pixels; ++i) 1921 { 1922 const GLbyte expected_red = 0; 1923 const GLbyte expected_green = 0; 1924 const GLbyte drawn_red = pixels[i * n_channels + 0]; 1925 const GLbyte drawn_green = pixels[i * n_channels + 1]; 1926 1927 if ((expected_red != drawn_red) || (expected_green != drawn_green)) 1928 { 1929 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLint)drawn_red << ", " 1930 << (GLint)drawn_green << ". Expected value: " << (GLint)expected_red << ", " 1931 << (GLint)expected_green << ". At offset: " << i << tcu::TestLog::EndMessage; 1932 1933 result = false; 1934 break; 1935 } 1936 } 1937 } 1938 else if (RGBA32F == m_test_case) 1939 { 1940 static const GLuint n_channels = 4; 1941 1942 std::vector<GLfloat> pixels(n_pixels * n_channels); 1943 for (GLuint i = 0; i < n_pixels; ++i) 1944 { 1945 const GLuint idx = i * n_channels; 1946 const GLfloat value = static_cast<GLfloat>(i) / n_pixels; 1947 pixels[idx + 0] = value; 1948 pixels[idx + 1] = value; 1949 pixels[idx + 2] = value; 1950 pixels[idx + 3] = value; 1951 } 1952 1953 Texture::Bind(gl, texture_id, GL_TEXTURE_2D); 1954 1955 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RGBA, GL_FLOAT, &pixels[0]); 1956 1957 /* Unbind */ 1958 Texture::Bind(gl, 0, GL_TEXTURE_2D); 1959 1960 /* Verify */ 1961 for (GLuint i = 0; i < n_pixels; ++i) 1962 { 1963 const GLfloat expected_red = 0.0f; 1964 const GLfloat expected_green = 0.0f; 1965 const GLfloat expected_blue = 0.0f; 1966 const GLfloat expected_alpha_0 = 1967 0.0f; /* OpenGL 4.5 (and ES) specifies two possiblities (0 or 1) for alpha channel (Chapter 11.1.3.12). */ 1968 const GLfloat expected_alpha_1 = 1.0f; 1969 const GLfloat drawn_red = pixels[i * n_channels + 0]; 1970 const GLfloat drawn_green = pixels[i * n_channels + 1]; 1971 const GLfloat drawn_blue = pixels[i * n_channels + 2]; 1972 const GLfloat drawn_alpha = pixels[i * n_channels + 3]; 1973 1974 const GLfloat precision = 0.0009765625; /* (1.f / 1024.f) */ 1975 1976 if ((de::abs(expected_red - drawn_red) > precision) || 1977 (de::abs(expected_green - drawn_green) > precision) || 1978 (de::abs(expected_blue - drawn_blue) > precision) || 1979 ((de::abs(expected_alpha_0 - drawn_alpha) > precision) && 1980 (de::abs(expected_alpha_1 - drawn_alpha) > precision))) 1981 { 1982 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red << ", " << drawn_green 1983 << ", " << drawn_blue << ", " << drawn_alpha << ". Expected value: " << expected_red 1984 << ", " << expected_green << ", " << expected_blue << ", " << expected_alpha_0 1985 << " or " << expected_alpha_1 << ". At offset: " << i << tcu::TestLog::EndMessage; 1986 1987 result = false; 1988 break; 1989 } 1990 } 1991 } 1992 else if (R32UI_MIPMAP == m_test_case) 1993 { 1994 static const GLuint n_channels = 4; 1995 1996 std::vector<GLuint> pixels(n_pixels * n_channels); 1997 initPixels(pixels, n_pixels, n_channels); 1998 1999 Texture::Bind(gl, texture_id, GL_TEXTURE_2D); 2000 2001 Texture::GetData(gl, texture_id, 1 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]); 2002 2003 /* Unbind */ 2004 Texture::Bind(gl, 0, GL_TEXTURE_2D); 2005 2006 /* Verify */ 2007 for (GLuint i = 0; i < n_pixels; ++i) 2008 { 2009 const GLuint expected_red = 0; 2010 const GLuint drawn_red = pixels[i * n_channels]; 2011 2012 if (expected_red != drawn_red) 2013 { 2014 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red 2015 << ". Expected value: " << expected_red << " at offset: " << i 2016 << tcu::TestLog::EndMessage; 2017 2018 result = false; 2019 break; 2020 } 2021 } 2022 } 2023 else if (R32UI_MULTISAMPLE == m_test_case) 2024 { 2025 static const GLuint n_channels = 4; 2026 2027 /* Compute shader */ 2028 static const GLchar* source = 2029 "${VERSION}\n" 2030 "\n" 2031 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" 2032 "\n" 2033 "layout (location = 1) writeonly uniform uimage2D uni_destination_image;\n" 2034 "layout (location = 0, r32ui) readonly uniform uimage2DMS uni_source_image;\n" 2035 "\n" 2036 "void main()\n" 2037 "{\n" 2038 " const ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n" 2039 "\n" 2040 " const uvec4 color_0 = imageLoad(uni_source_image, point, 0);\n" 2041 " const uvec4 color_1 = imageLoad(uni_source_image, point, 1);\n" 2042 " const uvec4 color_2 = imageLoad(uni_source_image, point, 2);\n" 2043 " const uvec4 color_3 = imageLoad(uni_source_image, point, 3);\n" 2044 "\n" 2045 " if (any(equal(uvec4(color_0.r, color_1.r, color_2.r, color_3.r), uvec4(0))))\n" 2046 " {\n" 2047 " imageStore(uni_destination_image, point, uvec4(1, 1, 1, 1));\n" 2048 " }\n" 2049 " else\n" 2050 " {\n" 2051 " imageStore(uni_destination_image, point, uvec4(0, 0, 0, 0));\n" 2052 " }\n" 2053 "}\n" 2054 "\n"; 2055 2056 Program program(gl); 2057 Texture destination_texture(gl); 2058 2059 Texture::Generate(gl, destination_texture.m_id); 2060 Texture::Bind(gl, destination_texture.m_id, GL_TEXTURE_2D); 2061 Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R32UI, width, height, 0 /* depth */); 2062 2063 std::string cs = tcu::StringTemplate(source).specialize(m_specializationMap); 2064 program.Init(cs, "", "", "", "", ""); 2065 program.Use(); 2066 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */, 2067 GL_READ_ONLY, GL_R32UI); 2068 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture"); 2069 gl.bindImageTexture(1 /* unit */, destination_texture.m_id, 0 /* level */, GL_FALSE /* layered */, 2070 0 /* layer */, GL_WRITE_ONLY, GL_R32UI); 2071 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture"); 2072 2073 gl.uniform1i(0 /* location */, 0 /* image unit*/); 2074 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i"); 2075 2076 gl.uniform1i(1 /* location */, 1 /* image unit*/); 2077 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i"); 2078 2079 gl.dispatchCompute(16, 16, 1); 2080 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute"); 2081 2082 /* Pixels buffer initialization */ 2083 std::vector<GLuint> pixels(n_pixels * n_channels); 2084 initPixels(pixels, n_pixels, n_channels); 2085 2086 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]); 2087 2088 /* Unbind */ 2089 Texture::Bind(gl, 0, GL_TEXTURE_2D); 2090 2091 /* Verify */ 2092 for (GLuint i = 0; i < n_pixels; ++i) 2093 { 2094 const GLuint expected_red = 1; 2095 const GLuint drawn_red = pixels[i * n_channels]; 2096 2097 if (expected_red != drawn_red) 2098 { 2099 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red 2100 << ". Expected value: " << expected_red << " at offset: " << i 2101 << tcu::TestLog::EndMessage; 2102 2103 result = false; 2104 break; 2105 } 2106 } 2107 } 2108 2109 return result; 2110 } 2111 2112 /** Verifies that texutre is filled with increasing values 2113 * 2114 * @param texture_id Id of texture 2115 * 2116 * @return true when image is filled with increasing values, false otherwise 2117 **/ 2118 bool TexelFetchTest::verifyValidResults(const Functions& gl, glw::GLuint texture_id) 2119 { 2120 static const GLuint height = 16; 2121 static const GLuint width = 16; 2122 static const GLuint n_pixels = height * width; 2123 2124 bool result = true; 2125 2126 if (R8 == m_test_case) 2127 { 2128 static const GLuint n_channels = 4; 2129 2130 Texture::Bind(gl, texture_id, GL_TEXTURE_2D); 2131 2132 std::vector<GLubyte> pixels(n_pixels * n_channels); 2133 initPixels(pixels, n_pixels, n_channels); 2134 2135 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]); 2136 2137 /* Unbind */ 2138 Texture::Bind(gl, 0, GL_TEXTURE_2D); 2139 2140 /* Verify */ 2141 for (GLuint i = 0; i < n_pixels; ++i) 2142 { 2143 const GLubyte expected_red = static_cast<GLubyte>(i); 2144 const GLubyte drawn_red = pixels[i * n_channels]; 2145 2146 if (expected_red != drawn_red) 2147 { 2148 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLuint)drawn_red 2149 << ". Expected value: " << (GLuint)expected_red << " at offset: " << i 2150 << tcu::TestLog::EndMessage; 2151 2152 result = false; 2153 break; 2154 } 2155 } 2156 } 2157 else if (RG8_SNORM == m_test_case) 2158 { 2159 static const GLuint n_channels = 4; 2160 2161 Texture::Bind(gl, texture_id, GL_TEXTURE_2D); 2162 2163 std::vector<GLbyte> pixels(n_pixels * n_channels); 2164 initPixels(pixels, n_pixels, n_channels); 2165 2166 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_BYTE, &pixels[0]); 2167 2168 /* Unbind */ 2169 Texture::Bind(gl, 0, GL_TEXTURE_2D); 2170 2171 /* Verify */ 2172 for (GLuint i = 0; i < n_pixels; ++i) 2173 { 2174 const GLbyte expected_red = static_cast<GLubyte>((i % 16) - 8); 2175 const GLbyte expected_green = static_cast<GLubyte>((i / 16) - 8); 2176 const GLbyte drawn_red = pixels[i * n_channels + 0]; 2177 const GLbyte drawn_green = pixels[i * n_channels + 1]; 2178 2179 if ((expected_red != drawn_red) || (expected_green != drawn_green)) 2180 { 2181 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLint)drawn_red << ", " 2182 << (GLint)drawn_green << ". Expected value: " << (GLint)expected_red << ", " 2183 << (GLint)expected_green << ". At offset: " << i << tcu::TestLog::EndMessage; 2184 2185 result = false; 2186 break; 2187 } 2188 } 2189 } 2190 else if (RGBA32F == m_test_case) 2191 { 2192 static const GLuint n_channels = 4; 2193 2194 Texture::Bind(gl, texture_id, GL_TEXTURE_2D); 2195 2196 std::vector<GLfloat> pixels(n_pixels * n_channels); 2197 for (GLuint i = 0; i < n_pixels; ++i) 2198 { 2199 const GLuint idx = i * n_channels; 2200 const GLfloat value = static_cast<GLfloat>(i) / n_pixels; 2201 pixels[idx + 0] = value; 2202 pixels[idx + 1] = value; 2203 pixels[idx + 2] = value; 2204 pixels[idx + 3] = value; 2205 } 2206 2207 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_FLOAT, &pixels[0]); 2208 2209 /* Unbind */ 2210 Texture::Bind(gl, 0, GL_TEXTURE_2D); 2211 2212 /* Verify */ 2213 for (GLuint i = 0; i < n_pixels; ++i) 2214 { 2215 const GLfloat expected_red = (GLfloat)(i % 16) / 16.0f; 2216 const GLfloat expected_green = (GLfloat)(i / 16) / 16.0f; 2217 const GLfloat expected_blue = (GLfloat)i / 256.0f; 2218 const GLfloat expected_alpha = 1.0f; 2219 const GLuint idx = i * n_channels; 2220 const GLfloat drawn_red = pixels[idx + 0]; 2221 const GLfloat drawn_green = pixels[idx + 1]; 2222 const GLfloat drawn_blue = pixels[idx + 2]; 2223 const GLfloat drawn_alpha = pixels[idx + 3]; 2224 2225 if ((expected_red != drawn_red) || (expected_green != drawn_green) || (expected_blue != drawn_blue) || 2226 (expected_alpha != drawn_alpha)) 2227 { 2228 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red << ", " << drawn_green 2229 << ", " << drawn_blue << ", " << drawn_alpha << ". Expected value: " << expected_red 2230 << ", " << expected_green << ", " << expected_blue << ", " << expected_alpha 2231 << ". At offset: " << i << tcu::TestLog::EndMessage; 2232 2233 result = false; 2234 break; 2235 } 2236 } 2237 } 2238 else if (R32UI_MIPMAP == m_test_case) 2239 { 2240 static const GLuint n_channels = 4; 2241 2242 Texture::Bind(gl, texture_id, GL_TEXTURE_2D); 2243 2244 std::vector<GLuint> pixels(n_pixels * n_channels, 0); 2245 2246 Texture::GetData(gl, texture_id, 1 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]); 2247 2248 /* Unbind */ 2249 Texture::Bind(gl, 0, GL_TEXTURE_2D); 2250 2251 /* Verify */ 2252 for (GLuint i = 0; i < n_pixels; ++i) 2253 { 2254 const GLuint expected_red = i; 2255 const GLuint drawn_red = pixels[i * n_channels]; 2256 2257 if (expected_red != drawn_red) 2258 { 2259 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red 2260 << ". Expected value: " << expected_red << " at offset: " << i 2261 << tcu::TestLog::EndMessage; 2262 2263 result = false; 2264 break; 2265 } 2266 } 2267 } 2268 else if (R32UI_MULTISAMPLE == m_test_case) 2269 { 2270 static const GLuint n_channels = 4; 2271 2272 /* Compute shader */ 2273 static const GLchar* source = 2274 "${VERSION}\n" 2275 "\n" 2276 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" 2277 "\n" 2278 "layout (location = 1, r32ui) writeonly uniform uimage2D uni_destination_image;\n" 2279 "layout (location = 0, r32ui) readonly uniform uimage2DMS uni_source_image;\n" 2280 "\n" 2281 "void main()\n" 2282 "{\n" 2283 " const ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n" 2284 " const uint index = gl_WorkGroupID.y * 16U + gl_WorkGroupID.x;\n" 2285 "\n" 2286 " const uvec4 color_0 = imageLoad(uni_source_image, point, 0);\n" 2287 " const uvec4 color_1 = imageLoad(uni_source_image, point, 1);\n" 2288 " const uvec4 color_2 = imageLoad(uni_source_image, point, 2);\n" 2289 " const uvec4 color_3 = imageLoad(uni_source_image, point, 3);\n" 2290 "\n" 2291 " if (any(equal(uvec4(color_0.r, color_1.r, color_2.r, color_3.r), uvec4(index + 3U))))\n" 2292 " {\n" 2293 " imageStore(uni_destination_image, point, uvec4(1U));\n" 2294 " }\n" 2295 " else\n" 2296 " {\n" 2297 " imageStore(uni_destination_image, point, uvec4(0U));\n" 2298 " }\n" 2299 "}\n" 2300 "\n"; 2301 2302 Program program(gl); 2303 Texture destination_texture(gl); 2304 2305 Texture::Generate(gl, destination_texture.m_id); 2306 Texture::Bind(gl, destination_texture.m_id, GL_TEXTURE_2D); 2307 Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R32UI, width, height, 0 /* depth */); 2308 2309 std::string cs = tcu::StringTemplate(source).specialize(m_specializationMap); 2310 program.Init(cs, "", "", "", "", ""); 2311 program.Use(); 2312 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */, 2313 GL_READ_ONLY, GL_R32UI); 2314 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture"); 2315 gl.bindImageTexture(1 /* unit */, destination_texture.m_id, 0 /* level */, GL_FALSE /* layered */, 2316 0 /* layer */, GL_WRITE_ONLY, GL_R32UI); 2317 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture"); 2318 2319 if (!m_context_is_es) 2320 { 2321 gl.uniform1i(0 /* location */, 0 /* image unit*/); 2322 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i"); 2323 2324 gl.uniform1i(1 /* location */, 1 /* image unit*/); 2325 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i"); 2326 } 2327 2328 gl.dispatchCompute(16, 16, 1); 2329 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute"); 2330 2331 /* Pixels buffer initialization */ 2332 std::vector<GLuint> pixels(n_pixels * n_channels); 2333 initPixels(pixels, n_pixels, n_channels); 2334 2335 Texture::GetData(gl, destination_texture.m_id, 0 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, 2336 &pixels[0]); 2337 2338 /* Unbind */ 2339 Texture::Bind(gl, 0, GL_TEXTURE_2D); 2340 2341 /* Verify */ 2342 for (GLuint i = 0; i < n_pixels; ++i) 2343 { 2344 const GLuint expected_red = 1; 2345 const GLuint drawn_red = pixels[i * n_channels]; 2346 2347 if (expected_red != drawn_red) 2348 { 2349 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red 2350 << ". Expected value: " << expected_red << " at offset: " << i 2351 << tcu::TestLog::EndMessage; 2352 2353 result = false; 2354 break; 2355 } 2356 } 2357 } 2358 2359 return result; 2360 } 2361 2362 /** Constructor 2363 * 2364 * @param testCtx Test context 2365 * @param apiType Api type 2366 **/ 2367 ImageLoadStoreTest::ImageLoadStoreTest(tcu::TestContext& testCtx, glu::ApiType apiType) 2368 : TexelFetchTest(testCtx, "image_load_store", "Verifies that out-of-bound to image result in zero or is discarded", 2369 apiType) 2370 { 2371 } 2372 2373 /** Execute test 2374 * 2375 * @return tcu::TestNode::STOP 2376 **/ 2377 tcu::TestNode::IterateResult ImageLoadStoreTest::iterate() 2378 { 2379 de::SharedPtr<glu::RenderContext> robustContext(createRobustContext()); 2380 if (!robustContext.get()) 2381 return STOP; 2382 2383 /* Constants */ 2384 static const GLuint height = 16; 2385 static const GLuint width = 16; 2386 2387 /* GL entry points */ 2388 const Functions& gl = robustContext->getFunctions(); 2389 2390 struct FetchingOffset 2391 { 2392 GLuint coord_offset; 2393 GLuint sample_offset; 2394 }; 2395 const FetchingOffset fetching_offsets[] = { 2396 { 16, 4 }, { 512, 4 }, { 1024, 8 }, { 2048, 8 }, 2397 }; 2398 2399 /* For ES start from RGBA32F as R8, R32UI_MULTISAMPLE and R8_SNORM are not supported */ 2400 if (m_context_is_es) 2401 m_test_case = RGBA32F; 2402 2403 /* Test result indicator */ 2404 bool test_result = true; 2405 2406 /* Iterate over all cases */ 2407 for (; m_test_case < LAST; m_test_case = (TEST_CASES)((GLuint)m_test_case + 1)) 2408 { 2409 /* Test case result indicator */ 2410 bool case_result = true; 2411 2412 if (R32UI_MULTISAMPLE == m_test_case) 2413 { 2414 // Skip invalid program test in multi sample case 2415 // texelFetch with invalid lod plane results undefined value 2416 // OpenGL 4.5 Core Spec, around page 377 2417 continue; 2418 } 2419 2420 /* Test case objects */ 2421 Texture destination_texture(gl); 2422 Texture source_texture(gl); 2423 Program program(gl); 2424 2425 /* Prepare textures */ 2426 Texture::Generate(gl, destination_texture.m_id); 2427 Texture::Generate(gl, source_texture.m_id); 2428 2429 if (R32UI_MULTISAMPLE == m_test_case) 2430 { 2431 GLint max_integer_samples; 2432 gl.getIntegerv(GL_MAX_INTEGER_SAMPLES, &max_integer_samples); 2433 GLint max_image_samples; 2434 gl.getIntegerv(GL_MAX_IMAGE_SAMPLES, &max_image_samples); 2435 if (max_integer_samples < 4 || max_image_samples < 4) 2436 { 2437 /* prepareTexture() hard-codes 4 samples (n_levels) for 2438 * R32UI_MULTISAMPLE case. This value exceeds the required 2439 * min-max value (1 in OpenGL ES 3.2) and is not supported 2440 * by all implementations. 2441 * 2442 * Also, the test uses a compute shader with images 2443 * to upload the texture so max_image_samples >= 4 2444 * is also required. 2445 */ 2446 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << getTestCaseName() << " not supported" 2447 << tcu::TestLog::EndMessage; 2448 continue; 2449 } 2450 } 2451 2452 prepareTexture(gl, false, destination_texture.m_id); 2453 prepareTexture(gl, true, source_texture.m_id); 2454 2455 /* Test invalid source cases */ 2456 for (GLuint i = 0; i < DE_LENGTH_OF_ARRAY(fetching_offsets); ++i) 2457 { 2458 const FetchingOffset& fo = fetching_offsets[i]; 2459 const std::string& cs = getComputeShader(SOURCE_INVALID, fo.coord_offset, fo.sample_offset); 2460 program.Init(cs, "", "", "", "", ""); 2461 program.Use(); 2462 2463 /* Set texture */ 2464 setTextures(gl, destination_texture.m_id, source_texture.m_id); 2465 2466 /* Dispatch */ 2467 gl.dispatchCompute(width, height, 1 /* depth */); 2468 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute"); 2469 2470 /* Verification */ 2471 if (false == verifyInvalidResults(gl, destination_texture.m_id)) 2472 { 2473 case_result = false; 2474 } 2475 } 2476 2477 /* Test valid case */ 2478 program.Init(getComputeShader(VALID), "", "", "", "", ""); 2479 program.Use(); 2480 2481 /* Set texture */ 2482 setTextures(gl, destination_texture.m_id, source_texture.m_id); 2483 2484 /* Set memory barrier with previous invalid tests */ 2485 gl.memoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); 2486 GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier"); 2487 2488 /* Dispatch */ 2489 gl.dispatchCompute(width, height, 1 /* depth */); 2490 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute"); 2491 2492 /* Verification */ 2493 if (false == verifyValidResults(gl, destination_texture.m_id)) 2494 { 2495 case_result = false; 2496 } 2497 2498 /* Test invalid destination cases */ 2499 for (GLuint i = 0; i < DE_LENGTH_OF_ARRAY(fetching_offsets); ++i) 2500 { 2501 const FetchingOffset& fo = fetching_offsets[i]; 2502 const std::string& cs = getComputeShader(DESTINATION_INVALID, fo.coord_offset, fo.sample_offset); 2503 program.Init(cs, "", "", "", "", ""); 2504 program.Use(); 2505 2506 /* Set texture */ 2507 setTextures(gl, destination_texture.m_id, source_texture.m_id); 2508 2509 /* Dispatch */ 2510 gl.dispatchCompute(width, height, 1 /* depth */); 2511 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute"); 2512 2513 /* Verification */ 2514 if (false == verifyValidResults(gl, destination_texture.m_id)) 2515 { 2516 case_result = false; 2517 } 2518 } 2519 2520 /* Set test result */ 2521 if (false == case_result) 2522 { 2523 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << getTestCaseName() << " failed" 2524 << tcu::TestLog::EndMessage; 2525 2526 test_result = false; 2527 } 2528 } 2529 2530 /* Set result */ 2531 if (true == test_result) 2532 { 2533 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 2534 } 2535 else 2536 { 2537 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 2538 } 2539 2540 /* Done */ 2541 return tcu::TestNode::STOP; 2542 } 2543 2544 /** Prepare shader for current test case 2545 * 2546 * @param version Specify which version should be prepared 2547 * 2548 * @return Source 2549 **/ 2550 std::string ImageLoadStoreTest::getComputeShader(VERSION version, GLuint coord_offset, GLuint sample_offset) 2551 { 2552 static const GLchar* source = 2553 "${VERSION}\n" 2554 "\n" 2555 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" 2556 "\n" 2557 "layout (${QUALIFIER} = 1, ${FORMAT}) writeonly uniform highp ${IMAGE} uni_destination_image;\n" 2558 "layout (${QUALIFIER} = 0, ${FORMAT}) readonly uniform highp ${IMAGE} uni_source_image;\n" 2559 "\n" 2560 "void main()\n" 2561 "{\n" 2562 " ivec2 point_destination = ivec2(gl_WorkGroupID.xy) + ivec2(${DST_COORD_OFFSET}U);\n" 2563 " ivec2 point_source = ivec2(gl_WorkGroupID.xy) + ivec2(${SRC_COORD_OFFSET}U);\n" 2564 "\n" 2565 "${COPY}" 2566 "}\n"; 2567 2568 static const GLchar* copy_multisampled = 2569 " ${TYPE} color_0 = imageLoad(uni_source_image, point_source, 0 + ${SRC_SAMPLE_OFFSET});\n" 2570 " ${TYPE} color_1 = imageLoad(uni_source_image, point_source, 1 + ${SRC_SAMPLE_OFFSET});\n" 2571 " ${TYPE} color_2 = imageLoad(uni_source_image, point_source, 2 + ${SRC_SAMPLE_OFFSET});\n" 2572 " ${TYPE} color_3 = imageLoad(uni_source_image, point_source, 3 + ${SRC_SAMPLE_OFFSET});\n" 2573 " imageStore(uni_destination_image, point_destination, 0 + ${DST_SAMPLE_OFFSET}, color_0);\n" 2574 " imageStore(uni_destination_image, point_destination, 1 + ${DST_SAMPLE_OFFSET}, color_1);\n" 2575 " imageStore(uni_destination_image, point_destination, 2 + ${DST_SAMPLE_OFFSET}, color_2);\n" 2576 " imageStore(uni_destination_image, point_destination, 3 + ${DST_SAMPLE_OFFSET}, color_3);\n"; 2577 2578 static const GLchar* copy_regular = " ${TYPE} color = imageLoad(uni_source_image, point_source);\n" 2579 " imageStore(uni_destination_image, point_destination, color);\n"; 2580 2581 std::string src_coord_offset_str("0"); 2582 std::string dst_coord_offset_str("0"); 2583 std::string src_sample_offset_str("0"); 2584 std::string dst_sample_offset_str("0"); 2585 2586 std::stringstream coord_offset_stream; 2587 coord_offset_stream << coord_offset; 2588 std::stringstream sample_offset_stream; 2589 sample_offset_stream << sample_offset; 2590 2591 m_specializationMap["QUALIFIER"] = m_context_is_es ? "binding" : "location"; 2592 m_specializationMap["IMAGE"] = "image2D"; 2593 m_specializationMap["TYPE"] = "vec4"; 2594 switch (m_test_case) 2595 { 2596 case R8: 2597 m_specializationMap["FORMAT"] = "r8"; 2598 break; 2599 case RG8_SNORM: 2600 m_specializationMap["FORMAT"] = "rg8_snorm"; 2601 break; 2602 case RGBA32F: 2603 m_specializationMap["FORMAT"] = "rgba32f"; 2604 break; 2605 case R32UI_MIPMAP: 2606 m_specializationMap["FORMAT"] = "r32ui"; 2607 m_specializationMap["IMAGE"] = "uimage2D"; 2608 m_specializationMap["TYPE"] = "uvec4"; 2609 break; 2610 case R32UI_MULTISAMPLE: 2611 m_specializationMap["FORMAT"] = "r32ui"; 2612 m_specializationMap["IMAGE"] = "uimage2DMS"; 2613 m_specializationMap["TYPE"] = "uvec4"; 2614 break; 2615 default: 2616 TCU_FAIL("Invalid enum"); 2617 }; 2618 2619 m_specializationMap["SRC_COORD_OFFSET"] = "0"; 2620 m_specializationMap["SRC_SAMPLE_OFFSET"] = "0"; 2621 m_specializationMap["DST_COORD_OFFSET"] = "0"; 2622 m_specializationMap["DST_SAMPLE_OFFSET"] = "0"; 2623 2624 if (version == SOURCE_INVALID) 2625 { 2626 m_specializationMap["SRC_COORD_OFFSET"] = coord_offset_stream.str(); 2627 m_specializationMap["SRC_SAMPLE_OFFSET"] = sample_offset_stream.str(); 2628 } 2629 else if (version == DESTINATION_INVALID) 2630 { 2631 m_specializationMap["DST_COORD_OFFSET"] = coord_offset_stream.str(); 2632 m_specializationMap["DST_SAMPLE_OFFSET"] = sample_offset_stream.str(); 2633 } 2634 2635 const GLchar* copy = (m_test_case == R32UI_MULTISAMPLE) ? copy_multisampled : copy_regular; 2636 m_specializationMap["COPY"] = tcu::StringTemplate(copy).specialize(m_specializationMap); 2637 2638 return tcu::StringTemplate(source).specialize(m_specializationMap); 2639 } 2640 2641 /** Set textures as images 2642 * 2643 * @param id_destination Id of texture used as destination 2644 * @param id_source Id of texture used as source 2645 **/ 2646 void ImageLoadStoreTest::setTextures(const Functions& gl, glw::GLuint id_destination, glw::GLuint id_source) 2647 { 2648 GLenum format = 0; 2649 GLint level = 0; 2650 2651 switch (m_test_case) 2652 { 2653 case R8: 2654 format = GL_R8; 2655 break; 2656 case RG8_SNORM: 2657 format = GL_RG8_SNORM; 2658 break; 2659 case RGBA32F: 2660 format = GL_RGBA32F; 2661 break; 2662 case R32UI_MIPMAP: 2663 format = GL_R32UI; 2664 level = 1; 2665 break; 2666 case R32UI_MULTISAMPLE: 2667 format = GL_R32UI; 2668 break; 2669 default: 2670 TCU_FAIL("Invalid enum"); 2671 } 2672 2673 gl.bindImageTexture(0 /* unit */, id_source, level, GL_FALSE /* layered */, 0 /* layer */, GL_READ_ONLY, format); 2674 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture"); 2675 2676 gl.bindImageTexture(1 /* unit */, id_destination, level, GL_FALSE /* layered */, 0 /* layer */, GL_WRITE_ONLY, 2677 format); 2678 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture"); 2679 2680 if (!m_context_is_es) 2681 { 2682 gl.uniform1i(0 /* location */, 0 /* image unit*/); 2683 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i"); 2684 2685 gl.uniform1i(1 /* location */, 1 /* image unit*/); 2686 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i"); 2687 } 2688 } 2689 2690 /** Verifies that texutre is filled with 0 2691 * 2692 * @param texture_id Id of texture 2693 * 2694 * @return true when image is filled with 0, false otherwise 2695 **/ 2696 bool ImageLoadStoreTest::verifyInvalidResults(const Functions& gl, glw::GLuint texture_id) 2697 { 2698 static const GLuint height = 16; 2699 static const GLuint width = 16; 2700 static const GLuint n_pixels = height * width; 2701 2702 // OpenGL ES has undefined out-of-bound behavior - no verification 2703 if (m_context_is_es) 2704 return true; 2705 2706 gl.memoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); 2707 GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier"); 2708 2709 bool result = true; 2710 2711 if (R8 == m_test_case) 2712 { 2713 static const GLuint n_channels = 1; 2714 2715 std::vector<GLubyte> pixels(n_pixels * n_channels); 2716 initPixels(pixels, n_pixels, n_channels); 2717 2718 Texture::Bind(gl, texture_id, GL_TEXTURE_2D); 2719 2720 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RED, GL_UNSIGNED_BYTE, &pixels[0]); 2721 2722 /* Unbind */ 2723 Texture::Bind(gl, 0, GL_TEXTURE_2D); 2724 2725 /* Verify */ 2726 for (GLuint i = 0; i < n_pixels; ++i) 2727 { 2728 const GLubyte expected_red = 0; 2729 const GLubyte drawn_red = pixels[i]; 2730 2731 if (expected_red != drawn_red) 2732 { 2733 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLuint)drawn_red 2734 << ". Expected value: " << (GLuint)expected_red << " at offset: " << i 2735 << tcu::TestLog::EndMessage; 2736 2737 result = false; 2738 break; 2739 } 2740 } 2741 } 2742 else if (RG8_SNORM == m_test_case) 2743 { 2744 static const GLuint n_channels = 2; 2745 2746 std::vector<GLbyte> pixels(n_pixels * n_channels); 2747 initPixels(pixels, n_pixels, n_channels); 2748 2749 Texture::Bind(gl, texture_id, GL_TEXTURE_2D); 2750 2751 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RG, GL_BYTE, &pixels[0]); 2752 2753 /* Unbind */ 2754 Texture::Bind(gl, 0, GL_TEXTURE_2D); 2755 2756 /* Verify */ 2757 for (GLuint i = 0; i < n_pixels; ++i) 2758 { 2759 const GLbyte expected_red = 0; 2760 const GLbyte expected_green = 0; 2761 const GLbyte drawn_red = pixels[i * n_channels + 0]; 2762 const GLbyte drawn_green = pixels[i * n_channels + 1]; 2763 2764 if ((expected_red != drawn_red) || (expected_green != drawn_green)) 2765 { 2766 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLint)drawn_red << ", " 2767 << (GLint)drawn_green << ". Expected value: " << (GLint)expected_red << ", " 2768 << (GLint)expected_green << ". At offset: " << i << tcu::TestLog::EndMessage; 2769 2770 result = false; 2771 break; 2772 } 2773 } 2774 } 2775 else if (RGBA32F == m_test_case) 2776 { 2777 static const GLuint n_channels = 4; 2778 2779 std::vector<GLfloat> pixels(n_pixels * n_channels); 2780 for (GLuint i = 0; i < n_pixels; ++i) 2781 { 2782 GLuint idx = i * n_channels; 2783 GLfloat value = static_cast<GLfloat>(i) / n_pixels; 2784 pixels[idx + 0] = value; 2785 pixels[idx + 1] = value; 2786 pixels[idx + 2] = value; 2787 pixels[idx + 3] = value; 2788 } 2789 2790 Texture::Bind(gl, texture_id, GL_TEXTURE_2D); 2791 2792 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RGBA, GL_FLOAT, &pixels[0]); 2793 2794 /* Unbind */ 2795 Texture::Bind(gl, 0, GL_TEXTURE_2D); 2796 2797 /* Verify */ 2798 for (GLuint i = 0; i < n_pixels; ++i) 2799 { 2800 const GLfloat expected_red = 0.0f; 2801 const GLfloat expected_green = 0.0f; 2802 const GLfloat expected_blue = 0.0f; 2803 const GLfloat expected_alpha = 0.0f; 2804 const GLuint idx = i * n_channels; 2805 const GLfloat drawn_red = pixels[idx + 0]; 2806 const GLfloat drawn_green = pixels[idx + 1]; 2807 const GLfloat drawn_blue = pixels[idx + 2]; 2808 const GLfloat drawn_alpha = pixels[idx + 3]; 2809 2810 if ((expected_red != drawn_red) || (expected_green != drawn_green) || (expected_blue != drawn_blue) || 2811 (expected_alpha != drawn_alpha)) 2812 { 2813 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red << ", " << drawn_green 2814 << ", " << drawn_blue << ", " << drawn_alpha << ". Expected value: " << expected_red 2815 << ", " << expected_green << ", " << expected_blue << ", " << expected_alpha 2816 << ". At offset: " << i << tcu::TestLog::EndMessage; 2817 2818 result = false; 2819 break; 2820 } 2821 } 2822 } 2823 else if (R32UI_MIPMAP == m_test_case) 2824 { 2825 static const GLuint n_channels = 1; 2826 2827 std::vector<GLuint> pixels(n_pixels * n_channels); 2828 initPixels(pixels, n_pixels, n_channels); 2829 2830 Texture::Bind(gl, texture_id, GL_TEXTURE_2D); 2831 2832 Texture::GetData(gl, 1 /* level */, GL_TEXTURE_2D, GL_RED_INTEGER, GL_UNSIGNED_INT, &pixels[0]); 2833 2834 /* Unbind */ 2835 Texture::Bind(gl, 0, GL_TEXTURE_2D); 2836 2837 /* Verify */ 2838 for (GLuint i = 0; i < n_pixels; ++i) 2839 { 2840 const GLuint expected_red = 0; 2841 const GLuint drawn_red = pixels[i]; 2842 2843 if (expected_red != drawn_red) 2844 { 2845 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red 2846 << ". Expected value: " << expected_red << " at offset: " << i 2847 << tcu::TestLog::EndMessage; 2848 2849 result = false; 2850 break; 2851 } 2852 } 2853 } 2854 else if (R32UI_MULTISAMPLE == m_test_case) 2855 { 2856 static const GLuint n_channels = 1; 2857 2858 /* Compute shader */ 2859 static const GLchar* cs = "${VERSION}\n" 2860 "\n" 2861 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" 2862 "\n" 2863 "layout (location = 1) writeonly uniform uimage2D uni_destination_image;\n" 2864 "layout (location = 0, r32ui) readonly uniform uimage2DMS uni_source_image;\n" 2865 "\n" 2866 "void main()\n" 2867 "{\n" 2868 " const ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n" 2869 "\n" 2870 " const uvec4 color_0 = imageLoad(uni_source_image, point, 0);\n" 2871 " const uvec4 color_1 = imageLoad(uni_source_image, point, 1);\n" 2872 " const uvec4 color_2 = imageLoad(uni_source_image, point, 2);\n" 2873 " const uvec4 color_3 = imageLoad(uni_source_image, point, 3);\n" 2874 "\n" 2875 " if (any(equal(uvec4(color_0.r, color_1.r, color_2.r, color_3.r), uvec4(0))))\n" 2876 " {\n" 2877 " imageStore(uni_destination_image, point, uvec4(1, 1, 1, 1));\n" 2878 " }\n" 2879 " else\n" 2880 " {\n" 2881 " imageStore(uni_destination_image, point, uvec4(0, 0, 0, 0));\n" 2882 " }\n" 2883 "}\n" 2884 "\n"; 2885 2886 Program program(gl); 2887 Texture destination_texture(gl); 2888 2889 Texture::Generate(gl, destination_texture.m_id); 2890 Texture::Bind(gl, destination_texture.m_id, GL_TEXTURE_2D); 2891 Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R32UI, width, height, 0 /* depth */); 2892 2893 program.Init(cs, "", "", "", "", ""); 2894 program.Use(); 2895 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */, 2896 GL_READ_ONLY, GL_R32UI); 2897 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture"); 2898 gl.bindImageTexture(1 /* unit */, destination_texture.m_id, 0 /* level */, GL_FALSE /* layered */, 2899 0 /* layer */, GL_WRITE_ONLY, GL_R32UI); 2900 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture"); 2901 2902 gl.uniform1i(0 /* location */, 0 /* image unit*/); 2903 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i"); 2904 2905 gl.uniform1i(1 /* location */, 1 /* image unit*/); 2906 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i"); 2907 2908 gl.dispatchCompute(16, 16, 1); 2909 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute"); 2910 2911 /* Pixels buffer initialization */ 2912 std::vector<GLuint> pixels(n_pixels * n_channels); 2913 initPixels(pixels, n_pixels, n_channels); 2914 2915 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RED_INTEGER, GL_UNSIGNED_INT, &pixels[0]); 2916 2917 /* Unbind */ 2918 Texture::Bind(gl, 0, GL_TEXTURE_2D); 2919 2920 /* Verify */ 2921 for (GLuint i = 0; i < n_pixels; ++i) 2922 { 2923 const GLuint expected_red = 1; 2924 const GLuint drawn_red = pixels[i]; 2925 2926 if (expected_red != drawn_red) 2927 { 2928 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red 2929 << ". Expected value: " << expected_red << " at offset: " << i 2930 << tcu::TestLog::EndMessage; 2931 2932 result = false; 2933 break; 2934 } 2935 } 2936 } 2937 2938 return result; 2939 } 2940 2941 /** Verifies that texutre is filled with increasing values 2942 * 2943 * @param texture_id Id of texture 2944 * 2945 * @return true when image is filled with increasing values, false otherwise 2946 **/ 2947 bool ImageLoadStoreTest::verifyValidResults(const glw::Functions& gl, glw::GLuint texture_id) 2948 { 2949 static const GLuint height = 16; 2950 static const GLuint width = 16; 2951 static const GLuint n_pixels = height * width; 2952 2953 gl.memoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); 2954 GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier"); 2955 2956 bool result = true; 2957 2958 if (R8 == m_test_case) 2959 { 2960 static const GLuint n_channels = 1; 2961 2962 Texture::Bind(gl, texture_id, GL_TEXTURE_2D); 2963 2964 std::vector<GLubyte> pixels(n_pixels * n_channels); 2965 initPixels(pixels, n_pixels, n_channels); 2966 2967 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RED, GL_UNSIGNED_BYTE, &pixels[0]); 2968 2969 /* Unbind */ 2970 Texture::Bind(gl, 0, GL_TEXTURE_2D); 2971 2972 /* Verify */ 2973 for (GLuint i = 0; i < n_pixels; ++i) 2974 { 2975 const GLubyte expected_red = static_cast<GLubyte>(i); 2976 const GLubyte drawn_red = pixels[i]; 2977 2978 if (expected_red != drawn_red) 2979 { 2980 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLuint)drawn_red 2981 << ". Expected value: " << (GLuint)expected_red << " at offset: " << i 2982 << tcu::TestLog::EndMessage; 2983 2984 result = false; 2985 break; 2986 } 2987 } 2988 } 2989 else if (RG8_SNORM == m_test_case) 2990 { 2991 static const GLuint n_channels = 2; 2992 2993 Texture::Bind(gl, texture_id, GL_TEXTURE_2D); 2994 2995 std::vector<GLbyte> pixels(n_pixels * n_channels); 2996 initPixels(pixels, n_pixels, n_channels); 2997 2998 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RG, GL_BYTE, &pixels[0]); 2999 3000 /* Unbind */ 3001 Texture::Bind(gl, 0, GL_TEXTURE_2D); 3002 3003 /* Verify */ 3004 for (GLuint i = 0; i < n_pixels; ++i) 3005 { 3006 const GLbyte expected_red = static_cast<GLubyte>((i % 16) - 8); 3007 const GLbyte expected_green = static_cast<GLubyte>((i / 16) - 8); 3008 const GLbyte drawn_red = pixels[i * n_channels + 0]; 3009 const GLbyte drawn_green = pixels[i * n_channels + 1]; 3010 3011 if ((expected_red != drawn_red) || (expected_green != drawn_green)) 3012 { 3013 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << (GLint)drawn_red << ", " 3014 << (GLint)drawn_green << ". Expected value: " << (GLint)expected_red << ", " 3015 << (GLint)expected_green << ". At offset: " << i << tcu::TestLog::EndMessage; 3016 3017 result = false; 3018 break; 3019 } 3020 } 3021 } 3022 else if (RGBA32F == m_test_case) 3023 { 3024 static const GLuint n_channels = 4; 3025 3026 Texture::Bind(gl, texture_id, GL_TEXTURE_2D); 3027 3028 std::vector<GLfloat> pixels(n_pixels * n_channels); 3029 for (GLuint i = 0; i < n_pixels; ++i) 3030 { 3031 GLfloat value = static_cast<GLfloat>(i) / n_pixels; 3032 pixels[i * n_channels + 0] = value; 3033 pixels[i * n_channels + 1] = value; 3034 pixels[i * n_channels + 2] = value; 3035 pixels[i * n_channels + 3] = value; 3036 } 3037 3038 Texture::GetData(gl, texture_id, 0 /* level */, width, height, GL_RGBA, GL_FLOAT, &pixels[0]); 3039 3040 /* Unbind */ 3041 Texture::Bind(gl, 0, GL_TEXTURE_2D); 3042 3043 /* Verify */ 3044 for (GLuint i = 0; i < n_pixels; ++i) 3045 { 3046 const GLfloat expected_red = (GLfloat)(i % 16) / 16.0f; 3047 const GLfloat expected_green = (GLfloat)(i / 16) / 16.0f; 3048 const GLfloat expected_blue = (GLfloat)i / 256.0f; 3049 const GLfloat expected_alpha = 1.0f; 3050 const GLuint idx = i * n_channels; 3051 const GLfloat drawn_red = pixels[idx + 0]; 3052 const GLfloat drawn_green = pixels[idx + 1]; 3053 const GLfloat drawn_blue = pixels[idx + 2]; 3054 const GLfloat drawn_alpha = pixels[idx + 3]; 3055 3056 if ((expected_red != drawn_red) || (expected_green != drawn_green) || (expected_blue != drawn_blue) || 3057 (expected_alpha != drawn_alpha)) 3058 { 3059 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red << ", " << drawn_green 3060 << ", " << drawn_blue << ", " << drawn_alpha << ". Expected value: " << expected_red 3061 << ", " << expected_green << ", " << expected_blue << ", " << expected_alpha 3062 << ". At offset: " << i << tcu::TestLog::EndMessage; 3063 3064 result = false; 3065 break; 3066 } 3067 } 3068 } 3069 else if (R32UI_MIPMAP == m_test_case) 3070 { 3071 static const GLuint n_channels = 4; 3072 3073 Texture::Bind(gl, texture_id, GL_TEXTURE_2D); 3074 3075 std::vector<GLuint> pixels(n_pixels * n_channels); 3076 initPixels(pixels, n_pixels, n_channels); 3077 3078 Texture::GetData(gl, texture_id, 1 /* level */, width, height, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &pixels[0]); 3079 3080 /* Unbind */ 3081 Texture::Bind(gl, 0, GL_TEXTURE_2D); 3082 3083 /* Verify */ 3084 for (GLuint i = 0; i < n_pixels; ++i) 3085 { 3086 const GLuint expected_red = i; 3087 const GLuint drawn_red = pixels[i * n_channels]; 3088 3089 if (expected_red != drawn_red) 3090 { 3091 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red 3092 << ". Expected value: " << expected_red << " at offset: " << i 3093 << tcu::TestLog::EndMessage; 3094 3095 result = false; 3096 break; 3097 } 3098 } 3099 } 3100 else if (R32UI_MULTISAMPLE == m_test_case) 3101 { 3102 static const GLuint n_channels = 1; 3103 3104 /* Compute shader */ 3105 static const GLchar* cs = 3106 "${VERSION}\n" 3107 "\n" 3108 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" 3109 "\n" 3110 "layout (location = 1) writeonly uniform uimage2D uni_destination_image;\n" 3111 "layout (location = 0, r32ui) readonly uniform uimage2DMS uni_source_image;\n" 3112 "\n" 3113 "void main()\n" 3114 "{\n" 3115 " const ivec2 point = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n" 3116 " const uint index = gl_WorkGroupID.y * 16 + gl_WorkGroupID.x;\n" 3117 "\n" 3118 " const uvec4 color_0 = imageLoad(uni_source_image, point, 0);\n" 3119 " const uvec4 color_1 = imageLoad(uni_source_image, point, 1);\n" 3120 " const uvec4 color_2 = imageLoad(uni_source_image, point, 2);\n" 3121 " const uvec4 color_3 = imageLoad(uni_source_image, point, 3);\n" 3122 "\n" 3123 " if (any(equal(uvec4(color_0.r, color_1.r, color_2.r, color_3.r), uvec4(index + 3))))\n" 3124 " {\n" 3125 " imageStore(uni_destination_image, point, uvec4(1, 1, 1, 1));\n" 3126 " }\n" 3127 " else\n" 3128 " {\n" 3129 " imageStore(uni_destination_image, point, uvec4(0, 0, 0, 0));\n" 3130 " }\n" 3131 "}\n" 3132 "\n"; 3133 3134 Program program(gl); 3135 Texture destination_texture(gl); 3136 3137 Texture::Generate(gl, destination_texture.m_id); 3138 Texture::Bind(gl, destination_texture.m_id, GL_TEXTURE_2D); 3139 Texture::Storage(gl, GL_TEXTURE_2D, 1, GL_R32UI, width, height, 0 /* depth */); 3140 3141 program.Init(cs, "", "", "", "", ""); 3142 program.Use(); 3143 gl.bindImageTexture(0 /* unit */, texture_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */, 3144 GL_READ_ONLY, GL_R32UI); 3145 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture"); 3146 gl.bindImageTexture(1 /* unit */, destination_texture.m_id, 0 /* level */, GL_FALSE /* layered */, 3147 0 /* layer */, GL_WRITE_ONLY, GL_R32UI); 3148 GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture"); 3149 3150 gl.uniform1i(0 /* location */, 0 /* image unit*/); 3151 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i"); 3152 3153 gl.uniform1i(1 /* location */, 1 /* image unit*/); 3154 GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i"); 3155 3156 gl.dispatchCompute(16, 16, 1); 3157 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute"); 3158 3159 /* Pixels buffer initialization */ 3160 std::vector<GLuint> pixels(n_pixels * n_channels); 3161 initPixels(pixels, n_pixels, n_channels); 3162 3163 Texture::GetData(gl, 0 /* level */, GL_TEXTURE_2D, GL_RED_INTEGER, GL_UNSIGNED_INT, &pixels[0]); 3164 3165 /* Unbind */ 3166 Texture::Bind(gl, 0, GL_TEXTURE_2D); 3167 3168 /* Verify */ 3169 for (GLuint i = 0; i < n_pixels; ++i) 3170 { 3171 const GLuint expected_red = 1; 3172 const GLuint drawn_red = pixels[i]; 3173 3174 if (expected_red != drawn_red) 3175 { 3176 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value: " << drawn_red 3177 << ". Expected value: " << expected_red << " at offset: " << i 3178 << tcu::TestLog::EndMessage; 3179 3180 result = false; 3181 break; 3182 } 3183 } 3184 } 3185 3186 return result; 3187 } 3188 3189 /* StorageBufferTest constants */ 3190 const GLfloat StorageBufferTest::m_destination_data[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; 3191 const GLfloat StorageBufferTest::m_source_data[4] = { 2.0f, 3.0f, 4.0f, 5.0f }; 3192 3193 /** Constructor 3194 * 3195 * @param testCtx Test context 3196 * @param apiType Api type 3197 **/ 3198 StorageBufferTest::StorageBufferTest(tcu::TestContext& testCtx, glu::ApiType apiType) 3199 : RobustnessBase(testCtx, "storage_buffer", "Verifies that out-of-bound access to SSBO is discared or resutls in 0", 3200 apiType) 3201 , m_test_case(VALID) 3202 { 3203 /* Nothing to be done here */ 3204 } 3205 3206 3207 /** Execute test 3208 * 3209 * @return tcu::TestNode::STOP 3210 **/ 3211 tcu::TestNode::IterateResult StorageBufferTest::iterate() 3212 { 3213 de::SharedPtr<glu::RenderContext> robustContext(createRobustContext()); 3214 if (!robustContext.get()) 3215 return STOP; 3216 3217 /* GL entry points */ 3218 const Functions& gl = robustContext->getFunctions(); 3219 3220 /* Test result indicator */ 3221 bool test_result = true; 3222 3223 GLuint test_offsets[] = { 3224 16, // close fetch 3225 4 * 1024, // near fetch (4K of the end of the object) 3226 1024 * 1024, // medium fetch (1MB past the end of the object) 3227 10 * 1024 * 1024 // high fetch (10MB beyond the end of the object) 3228 }; 3229 3230 /* Iterate over all cases */ 3231 while (LAST != m_test_case) 3232 { 3233 /* Test case objects */ 3234 Buffer destination_buffer(gl); 3235 Buffer source_buffer(gl); 3236 Program program(gl); 3237 3238 /* Buffers initialization */ 3239 destination_buffer.InitData(GL_SHADER_STORAGE_BUFFER, GL_DYNAMIC_COPY, sizeof(m_destination_data), 3240 m_destination_data); 3241 source_buffer.InitData(GL_SHADER_STORAGE_BUFFER, GL_DYNAMIC_COPY, sizeof(m_source_data), m_source_data); 3242 3243 destination_buffer.BindBase(0); 3244 source_buffer.BindBase(1); 3245 3246 for (GLuint i = 0; i < DE_LENGTH_OF_ARRAY(test_offsets); ++i) 3247 { 3248 /* Initialize shader */ 3249 const std::string& cs = getComputeShader(test_offsets[i]); 3250 program.Init(cs, "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */, "" /* vs */); 3251 program.Use(); 3252 3253 /* Dispatch compute */ 3254 gl.dispatchCompute(1 /* x */, 1 /* y */, 1 /* z */); 3255 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute"); 3256 3257 /* Set memory barrier */ 3258 gl.memoryBarrier(GL_ALL_BARRIER_BITS); 3259 GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier"); 3260 3261 /* Verify results */ 3262 destination_buffer.Bind(); 3263 GLfloat* buffer_data = 3264 (GLfloat*)gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(m_destination_data), GL_MAP_READ_BIT); 3265 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBufferRange"); 3266 3267 test_result &= verifyResults(buffer_data); 3268 3269 gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER); 3270 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer"); 3271 } 3272 3273 /* Increment */ 3274 m_test_case = (VERSION)((GLuint)m_test_case + 1); 3275 } 3276 3277 /* Set result */ 3278 if (true == test_result) 3279 { 3280 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 3281 } 3282 else 3283 { 3284 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 3285 } 3286 3287 /* Done */ 3288 return tcu::TestNode::STOP; 3289 } 3290 3291 /** Prepare shader for current test case 3292 * 3293 * @return Source 3294 **/ 3295 std::string StorageBufferTest::getComputeShader(GLuint offset) 3296 { 3297 static const GLchar* source = "${VERSION}\n" 3298 "\n" 3299 "layout (local_size_x = 4, local_size_y = 1, local_size_z = 1) in;\n" 3300 "\n" 3301 "layout (binding = 1, std430) buffer Source {\n" 3302 " float data[];\n" 3303 "} source;\n" 3304 "\n" 3305 "layout (binding = 0, std430) buffer Destination {\n" 3306 " float data[];\n" 3307 "} destination;\n" 3308 "\n" 3309 "void main()\n" 3310 "{\n" 3311 " uint index_destination = gl_LocalInvocationID.x + ${DST_OFFSET}U;\n" 3312 " uint index_source = gl_LocalInvocationID.x + ${SRC_OFFSET}U;\n" 3313 "\n" 3314 " destination.data[index_destination] = source.data[index_source];\n" 3315 "}\n" 3316 "\n"; 3317 3318 std::stringstream offset_stream; 3319 offset_stream << offset; 3320 3321 m_specializationMap["DST_OFFSET"] = "0"; 3322 m_specializationMap["SRC_OFFSET"] = "0"; 3323 if (m_test_case == SOURCE_INVALID) 3324 m_specializationMap["SRC_OFFSET"] = offset_stream.str(); 3325 else if (m_test_case == DESTINATION_INVALID) 3326 m_specializationMap["DST_OFFSET"] = offset_stream.str(); 3327 3328 return tcu::StringTemplate(source).specialize(m_specializationMap); 3329 } 3330 3331 /** Verify test case results 3332 * 3333 * @param buffer_data Buffer data to verify 3334 * 3335 * @return true if buffer_data is as expected, false othrewise 3336 **/ 3337 bool StorageBufferTest::verifyResults(GLfloat* buffer_data) 3338 { 3339 /* KHR_robust_buffer_access_behavior (and also GL 4.5 and later) states 3340 * which values can be expected when reading or writing outside of a 3341 * buffer's range. If supported, we will compare results against those 3342 * expectations. 3343 * 3344 * Otherwise, we will attempt to match results against previously observed 3345 * and valid behavior. 3346 */ 3347 static const GLfloat expected_data_valid[4] = { 2.0f, 3.0f, 4.0f, 5.0f }; 3348 static const GLfloat expected_data_invalid_source[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; 3349 static const GLfloat expected_data_invalid_destination[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; 3350 3351 /* OpenGL ES has undefined out-of-bound behavior - verify only valid result*/ 3352 if (m_context_is_es && (m_test_case != VALID)) 3353 return true; 3354 3355 /* Prepare expected data const for proper case*/ 3356 const GLchar* name = 0; 3357 bool check_expected_data = false; 3358 const GLfloat* expected_data = 0; 3359 switch (m_test_case) 3360 { 3361 case VALID: 3362 name = "valid indices"; 3363 check_expected_data = true; 3364 expected_data = expected_data_valid; 3365 break; 3366 case SOURCE_INVALID: 3367 name = "invalid source indices"; 3368 if (m_has_khr_robust_buffer_access) 3369 { 3370 for (int b = 0; b < 4; b++) 3371 { 3372 /* Each out-of-range read can either be 0 or any value within 3373 * the source buffer. 3374 * */ 3375 bool valid = false; 3376 if (buffer_data[b] == 0.0f) 3377 { 3378 valid = true; 3379 } 3380 else 3381 { 3382 for (int c = 0; c < 4 && !valid; c++) 3383 { 3384 if (buffer_data[b] == m_source_data[c]) 3385 { 3386 valid = true; 3387 } 3388 } 3389 } 3390 if (!valid) 3391 { 3392 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << name << " failed" 3393 << tcu::TestLog::EndMessage; 3394 } 3395 } 3396 } 3397 else 3398 { 3399 check_expected_data = true; 3400 expected_data = expected_data_invalid_source; 3401 } 3402 break; 3403 case DESTINATION_INVALID: 3404 name = "invalid destination indices"; 3405 if (m_has_khr_robust_buffer_access) 3406 { 3407 for (int b = 0; b < 4; b++) 3408 { 3409 bool valid = false; 3410 /* Each out-of-range write can either be discarded (in which 3411 * case it would have the original destination value) or it 3412 * could write any value within the buffer (so we need to check 3413 * against each possible source value). 3414 */ 3415 if (buffer_data[b] == m_destination_data[b]) 3416 { 3417 valid = true; 3418 } 3419 else 3420 { 3421 for (int c = 0; c < 4 && !valid; c++) 3422 { 3423 if (buffer_data[b] == m_source_data[c]) 3424 { 3425 valid = true; 3426 } 3427 } 3428 } 3429 if (!valid) 3430 { 3431 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << name << " failed" 3432 << tcu::TestLog::EndMessage; 3433 } 3434 } 3435 } 3436 else 3437 { 3438 check_expected_data = true; 3439 expected_data = expected_data_invalid_destination; 3440 } 3441 break; 3442 default: 3443 TCU_FAIL("Invalid enum"); 3444 } 3445 3446 if (check_expected_data) 3447 { 3448 /* Verify buffer data */ 3449 int size = static_cast<int>(sizeof(GLfloat) * 4); 3450 if (0 != memcmp(expected_data, buffer_data, size)) 3451 { 3452 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << name << " failed" 3453 << tcu::TestLog::EndMessage; 3454 return false; 3455 } 3456 } 3457 3458 return true; 3459 } 3460 3461 /** Constructor 3462 * 3463 * @param context Test context 3464 **/ 3465 UniformBufferTest::UniformBufferTest(tcu::TestContext& testCtx, glu::ApiType apiType) 3466 : RobustnessBase(testCtx, "uniform_buffer", "Verifies that out-of-bound access to UBO resutls in 0", apiType) 3467 , m_test_case(VALID) 3468 { 3469 /* Nothing to be done here */ 3470 } 3471 3472 /** Execute test 3473 * 3474 * @return tcu::TestNode::STOP 3475 **/ 3476 tcu::TestNode::IterateResult UniformBufferTest::iterate() 3477 { 3478 de::SharedPtr<glu::RenderContext> robustContext(createRobustContext()); 3479 if (!robustContext.get()) 3480 return STOP; 3481 3482 static const GLfloat destination_data[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; 3483 /* The source buffer is packed std140 so we need vec4s */ 3484 static const GLfloat source_data[16] = { 3485 2.0f, 0.0f, 0.0f, 0.0f, 3.0f, 0.0f, 0.0f, 0.0f, 4.0f, 0.0f, 0.0f, 0.0f, 5.0f, 0.0f, 0.0f, 0.0f, 3486 }; 3487 3488 GLuint test_offsets[] = { 3489 16, // close fetch 3490 4 * 1024, // near fetch (4K of the end of the object) 3491 1024 * 1024, // medium fetch (1MB past the end of the object) 3492 10 * 1024 * 1024 // high fetch (10MB beyond the end of the object) 3493 }; 3494 3495 /* GL entry points */ 3496 const Functions& gl = robustContext->getFunctions(); 3497 3498 /* Test result indicator */ 3499 bool test_result = true; 3500 3501 /* Iterate over all cases */ 3502 while (LAST != m_test_case) 3503 { 3504 /* Test case objects */ 3505 Buffer destination_buffer(gl); 3506 Buffer source_buffer(gl); 3507 Program program(gl); 3508 3509 /* Buffers initialization */ 3510 destination_buffer.InitData(GL_SHADER_STORAGE_BUFFER, GL_DYNAMIC_COPY, sizeof(destination_data), 3511 destination_data); 3512 source_buffer.InitData(GL_UNIFORM_BUFFER, GL_DYNAMIC_COPY, sizeof(source_data), source_data); 3513 3514 destination_buffer.BindBase(0); 3515 source_buffer.BindBase(0); 3516 3517 for (GLuint i = 0; i < DE_LENGTH_OF_ARRAY(test_offsets); ++i) 3518 { 3519 /* Initialize shader */ 3520 const std::string& cs = getComputeShader(test_offsets[i]); 3521 program.Init(cs, "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */, "" /* vs */); 3522 program.Use(); 3523 3524 /* Dispatch compute */ 3525 gl.dispatchCompute(1 /* x */, 1 /* y */, 1 /* z */); 3526 GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute"); 3527 3528 /* Set memory barrier */ 3529 gl.memoryBarrier(GL_ALL_BARRIER_BITS); 3530 GLU_EXPECT_NO_ERROR(gl.getError(), "MemoryBarrier"); 3531 3532 /* Verify results */ 3533 destination_buffer.Bind(); 3534 GLfloat* buffer_data = 3535 (GLfloat*)gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(destination_data), GL_MAP_READ_BIT); 3536 GLU_EXPECT_NO_ERROR(gl.getError(), "MapBufferRange"); 3537 3538 test_result &= verifyResults(buffer_data); 3539 3540 gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER); 3541 GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer"); 3542 } 3543 3544 /* Increment */ 3545 m_test_case = (VERSION)((GLuint)m_test_case + 1); 3546 } 3547 3548 /* Set result */ 3549 if (true == test_result) 3550 { 3551 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 3552 } 3553 else 3554 { 3555 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); 3556 } 3557 3558 /* Done */ 3559 return tcu::TestNode::STOP; 3560 } 3561 3562 /** Prepare shader for current test case 3563 * 3564 * @return Source 3565 **/ 3566 std::string UniformBufferTest::getComputeShader(GLuint offset) 3567 { 3568 static const GLchar* source = "${VERSION}\n" 3569 "\n" 3570 "layout (local_size_x = 4, local_size_y = 1, local_size_z = 1) in;\n" 3571 "\n" 3572 "layout (binding = 0, std140) uniform Source {\n" 3573 " float data[16];\n" 3574 "} source;\n" 3575 "\n" 3576 "layout (binding = 0, std430) buffer Destination {\n" 3577 " float data[];\n" 3578 "} destination;\n" 3579 "\n" 3580 "void main()\n" 3581 "{\n" 3582 " uint index_destination = gl_LocalInvocationID.x;\n" 3583 " uint index_source = gl_LocalInvocationID.x + ${OFFSET}U;\n" 3584 "\n" 3585 " destination.data[index_destination] = source.data[index_source];\n" 3586 "}\n" 3587 "\n"; 3588 3589 m_specializationMap["OFFSET"] = "0"; 3590 if (m_test_case == SOURCE_INVALID) 3591 { 3592 std::stringstream offset_stream; 3593 offset_stream << offset; 3594 m_specializationMap["OFFSET"] = offset_stream.str(); 3595 } 3596 3597 return tcu::StringTemplate(source).specialize(m_specializationMap); 3598 } 3599 3600 /** Verify test case results 3601 * 3602 * @param buffer_data Buffer data to verify 3603 * 3604 * @return true if buffer_data is as expected, false othrewise 3605 **/ 3606 bool UniformBufferTest::verifyResults(GLfloat* buffer_data) 3607 { 3608 static const GLfloat expected_data_valid[4] = { 2.0f, 3.0f, 4.0f, 5.0f }; 3609 static const GLfloat expected_data_invalid_source[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; 3610 3611 int size = static_cast<int>(sizeof(GLfloat) * 4); 3612 3613 /* Prepare expected data const for proper case*/ 3614 const GLfloat* expected_data = 0; 3615 const GLchar* name = 0; 3616 switch (m_test_case) 3617 { 3618 case VALID: 3619 expected_data = expected_data_valid; 3620 name = "valid indices"; 3621 break; 3622 case SOURCE_INVALID: 3623 expected_data = expected_data_invalid_source; 3624 name = "invalid source indices"; 3625 break; 3626 default: 3627 TCU_FAIL("Invalid enum"); 3628 } 3629 3630 /* Verify buffer data */ 3631 if (0 != memcmp(expected_data, buffer_data, size)) 3632 { 3633 m_testCtx.getLog() << tcu::TestLog::Message << "Test case: " << name << " failed" << tcu::TestLog::EndMessage; 3634 return false; 3635 } 3636 3637 return true; 3638 } 3639 } /* RobustBufferAccessBehavior */ 3640 3641 /** Constructor. 3642 * 3643 * @param context Rendering context. 3644 **/ 3645 RobustBufferAccessBehaviorTests::RobustBufferAccessBehaviorTests(tcu::TestContext& testCtx, glu::ApiType apiType) 3646 : tcu::TestCaseGroup(testCtx, "robust_buffer_access_behavior", 3647 "Verifies \"robust buffer access behavior\" functionality") 3648 , m_ApiType(apiType) 3649 { 3650 /* Left blank on purpose */ 3651 } 3652 3653 /** Initializes a multi_bind test group. 3654 * 3655 **/ 3656 void RobustBufferAccessBehaviorTests::init(void) 3657 { 3658 addChild(new RobustBufferAccessBehavior::VertexBufferObjectsTest(m_testCtx, m_ApiType)); 3659 addChild(new RobustBufferAccessBehavior::TexelFetchTest(m_testCtx, m_ApiType)); 3660 addChild(new RobustBufferAccessBehavior::ImageLoadStoreTest(m_testCtx, m_ApiType)); 3661 addChild(new RobustBufferAccessBehavior::StorageBufferTest(m_testCtx, m_ApiType)); 3662 addChild(new RobustBufferAccessBehavior::UniformBufferTest(m_testCtx, m_ApiType)); 3663 } 3664 3665 } /* glcts */ 3666