1e5c31af7Sopenharmony_ci/*------------------------------------------------------------------------- 2e5c31af7Sopenharmony_ci * OpenGL Conformance Test Suite 3e5c31af7Sopenharmony_ci * ----------------------------- 4e5c31af7Sopenharmony_ci * 5e5c31af7Sopenharmony_ci * Copyright (c) 2014-2016 The Khronos Group Inc. 6e5c31af7Sopenharmony_ci * 7e5c31af7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 8e5c31af7Sopenharmony_ci * you may not use this file except in compliance with the License. 9e5c31af7Sopenharmony_ci * You may obtain a copy of the License at 10e5c31af7Sopenharmony_ci * 11e5c31af7Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 12e5c31af7Sopenharmony_ci * 13e5c31af7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 14e5c31af7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 15e5c31af7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16e5c31af7Sopenharmony_ci * See the License for the specific language governing permissions and 17e5c31af7Sopenharmony_ci * limitations under the License. 18e5c31af7Sopenharmony_ci * 19e5c31af7Sopenharmony_ci */ /*! 20e5c31af7Sopenharmony_ci * \file 21e5c31af7Sopenharmony_ci * \brief 22e5c31af7Sopenharmony_ci */ /*-------------------------------------------------------------------*/ 23e5c31af7Sopenharmony_ci 24e5c31af7Sopenharmony_ci/** 25e5c31af7Sopenharmony_ci * \file gl4cTextureBarrierTests.cpp 26e5c31af7Sopenharmony_ci * \brief Implements conformance tests for "Texture Barrier" functionality. 27e5c31af7Sopenharmony_ci */ /*-------------------------------------------------------------------*/ 28e5c31af7Sopenharmony_ci 29e5c31af7Sopenharmony_ci#include "gl4cTextureBarrierTests.hpp" 30e5c31af7Sopenharmony_ci 31e5c31af7Sopenharmony_ci#include "deMath.h" 32e5c31af7Sopenharmony_ci#include "deSharedPtr.hpp" 33e5c31af7Sopenharmony_ci 34e5c31af7Sopenharmony_ci#include "gluContextInfo.hpp" 35e5c31af7Sopenharmony_ci#include "gluDefs.hpp" 36e5c31af7Sopenharmony_ci#include "gluPixelTransfer.hpp" 37e5c31af7Sopenharmony_ci#include "gluShaderProgram.hpp" 38e5c31af7Sopenharmony_ci 39e5c31af7Sopenharmony_ci#include "tcuFuzzyImageCompare.hpp" 40e5c31af7Sopenharmony_ci#include "tcuImageCompare.hpp" 41e5c31af7Sopenharmony_ci#include "tcuRenderTarget.hpp" 42e5c31af7Sopenharmony_ci#include "tcuSurface.hpp" 43e5c31af7Sopenharmony_ci#include "tcuTestLog.hpp" 44e5c31af7Sopenharmony_ci 45e5c31af7Sopenharmony_ci#include "glw.h" 46e5c31af7Sopenharmony_ci#include "glwFunctions.hpp" 47e5c31af7Sopenharmony_ci 48e5c31af7Sopenharmony_ci#include "glcWaiver.hpp" 49e5c31af7Sopenharmony_ci 50e5c31af7Sopenharmony_cinamespace gl4cts 51e5c31af7Sopenharmony_ci{ 52e5c31af7Sopenharmony_ci 53e5c31af7Sopenharmony_ci/* 54e5c31af7Sopenharmony_ci Base class of all test cases of the feature. Enforces the requirements below: 55e5c31af7Sopenharmony_ci 56e5c31af7Sopenharmony_ci * Check that the extension string or GL 4.5 is available. 57e5c31af7Sopenharmony_ci */ 58e5c31af7Sopenharmony_ciclass TextureBarrierBaseTest : public deqp::TestCase 59e5c31af7Sopenharmony_ci{ 60e5c31af7Sopenharmony_ciprotected: 61e5c31af7Sopenharmony_ci TextureBarrierBaseTest(deqp::Context& context, TextureBarrierTests::API api, const char* name, 62e5c31af7Sopenharmony_ci const char* description) 63e5c31af7Sopenharmony_ci : TestCase(context, name, description), m_api(api) 64e5c31af7Sopenharmony_ci { 65e5c31af7Sopenharmony_ci } 66e5c31af7Sopenharmony_ci 67e5c31af7Sopenharmony_ci /* Checks whether the feature is supported. */ 68e5c31af7Sopenharmony_ci bool featureSupported() 69e5c31af7Sopenharmony_ci { 70e5c31af7Sopenharmony_ci return (m_api == TextureBarrierTests::API_GL_ARB_texture_barrier && 71e5c31af7Sopenharmony_ci m_context.getContextInfo().isExtensionSupported("GL_ARB_texture_barrier")) || 72e5c31af7Sopenharmony_ci m_api == TextureBarrierTests::API_GL_45core; 73e5c31af7Sopenharmony_ci } 74e5c31af7Sopenharmony_ci 75e5c31af7Sopenharmony_ci /* Basic test init, child classes must call it. */ 76e5c31af7Sopenharmony_ci virtual void init() 77e5c31af7Sopenharmony_ci { 78e5c31af7Sopenharmony_ci if (!featureSupported()) 79e5c31af7Sopenharmony_ci { 80e5c31af7Sopenharmony_ci throw tcu::NotSupportedError("Required texture_barrier extension is not supported"); 81e5c31af7Sopenharmony_ci } 82e5c31af7Sopenharmony_ci } 83e5c31af7Sopenharmony_ci 84e5c31af7Sopenharmony_ciprotected: 85e5c31af7Sopenharmony_ci const TextureBarrierTests::API m_api; 86e5c31af7Sopenharmony_ci}; 87e5c31af7Sopenharmony_ci 88e5c31af7Sopenharmony_ci/* 89e5c31af7Sopenharmony_ci Base class of all rendering test cases of the feature. Implements the basic outline below: 90e5c31af7Sopenharmony_ci 91e5c31af7Sopenharmony_ci This basic outline provides a simple tutorial on how to implement and 92e5c31af7Sopenharmony_ci what to check in the test cases of this feature. 93e5c31af7Sopenharmony_ci 94e5c31af7Sopenharmony_ci * Create a set of color textures and fill each of their texels with unique 95e5c31af7Sopenharmony_ci values using an arbitrary method. Set the minification and magnification 96e5c31af7Sopenharmony_ci filtering modes of the textures to NEAREST. Bind all of them for 97e5c31af7Sopenharmony_ci texturing to subsequent texture units starting from texture unit zero. 98e5c31af7Sopenharmony_ci 99e5c31af7Sopenharmony_ci * Create a framebuffer object and attach the set of textures so that 100e5c31af7Sopenharmony_ci texture #i is attached as color attachment #i. Set the draw buffers so 101e5c31af7Sopenharmony_ci that draw buffer #i is set to color attachment #i. Bind the framebuffer 102e5c31af7Sopenharmony_ci for rendering. 103e5c31af7Sopenharmony_ci 104e5c31af7Sopenharmony_ci * Render a set of primitives that cover each pixel of the framebuffer 105e5c31af7Sopenharmony_ci exactly once using the fragment shader described in the particular 106e5c31af7Sopenharmony_ci test case. 107e5c31af7Sopenharmony_ci 108e5c31af7Sopenharmony_ci * Expect all texels written by the draw command to have well defined 109e5c31af7Sopenharmony_ci values in accordance with the used fragment shader's functionality. 110e5c31af7Sopenharmony_ci */ 111e5c31af7Sopenharmony_ciclass TextureBarrierBasicOutline : public TextureBarrierBaseTest 112e5c31af7Sopenharmony_ci{ 113e5c31af7Sopenharmony_ciprotected: 114e5c31af7Sopenharmony_ci TextureBarrierBasicOutline(deqp::Context& context, TextureBarrierTests::API api, const char* name, 115e5c31af7Sopenharmony_ci const char* description) 116e5c31af7Sopenharmony_ci : TextureBarrierBaseTest(context, api, name, description) 117e5c31af7Sopenharmony_ci , m_program(0) 118e5c31af7Sopenharmony_ci , m_vao(0) 119e5c31af7Sopenharmony_ci , m_vbo(0) 120e5c31af7Sopenharmony_ci , m_fbo(0) 121e5c31af7Sopenharmony_ci , m_width(0) 122e5c31af7Sopenharmony_ci , m_height(0) 123e5c31af7Sopenharmony_ci , m_actual(DE_NULL) 124e5c31af7Sopenharmony_ci { 125e5c31af7Sopenharmony_ci for (size_t i = 0; i < NUM_TEXTURES; ++i) 126e5c31af7Sopenharmony_ci { 127e5c31af7Sopenharmony_ci m_tex[i] = 0; 128e5c31af7Sopenharmony_ci m_reference[i] = DE_NULL; 129e5c31af7Sopenharmony_ci } 130e5c31af7Sopenharmony_ci } 131e5c31af7Sopenharmony_ci 132e5c31af7Sopenharmony_ci /* Actual test cases may override it to provide an alternative vertex shader. */ 133e5c31af7Sopenharmony_ci virtual const char* vsh() 134e5c31af7Sopenharmony_ci { 135e5c31af7Sopenharmony_ci return "#version 400 core\n" 136e5c31af7Sopenharmony_ci "in vec2 Position;\n" 137e5c31af7Sopenharmony_ci "void main() {\n" 138e5c31af7Sopenharmony_ci " gl_Position = vec4(Position, 0.0, 1.0);\n" 139e5c31af7Sopenharmony_ci "}"; 140e5c31af7Sopenharmony_ci } 141e5c31af7Sopenharmony_ci 142e5c31af7Sopenharmony_ci /* Actual test cases must override it to provide the fragment shader. */ 143e5c31af7Sopenharmony_ci virtual const char* fsh() = 0; 144e5c31af7Sopenharmony_ci 145e5c31af7Sopenharmony_ci /* Rendering test init. */ 146e5c31af7Sopenharmony_ci virtual void init() 147e5c31af7Sopenharmony_ci { 148e5c31af7Sopenharmony_ci // Call parent init (takes care of API requirements) 149e5c31af7Sopenharmony_ci TextureBarrierBaseTest::init(); 150e5c31af7Sopenharmony_ci 151e5c31af7Sopenharmony_ci const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget(); 152e5c31af7Sopenharmony_ci m_width = renderTarget.getWidth(); 153e5c31af7Sopenharmony_ci m_height = renderTarget.getHeight(); 154e5c31af7Sopenharmony_ci 155e5c31af7Sopenharmony_ci#ifdef WAIVER_WITH_BUG_13788 156e5c31af7Sopenharmony_ci m_width = m_width >= 16383 ? 16382 : m_width; 157e5c31af7Sopenharmony_ci#endif 158e5c31af7Sopenharmony_ci 159e5c31af7Sopenharmony_ci const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 160e5c31af7Sopenharmony_ci 161e5c31af7Sopenharmony_ci // Create textures 162e5c31af7Sopenharmony_ci gl.genTextures(NUM_TEXTURES, m_tex); 163e5c31af7Sopenharmony_ci for (GLuint i = 0; i < NUM_TEXTURES; ++i) 164e5c31af7Sopenharmony_ci { 165e5c31af7Sopenharmony_ci gl.activeTexture(GL_TEXTURE0 + i); 166e5c31af7Sopenharmony_ci gl.bindTexture(GL_TEXTURE_2D, m_tex[i]); 167e5c31af7Sopenharmony_ci gl.texStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, m_width, m_height); 168e5c31af7Sopenharmony_ci gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 169e5c31af7Sopenharmony_ci gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 170e5c31af7Sopenharmony_ci m_reference[i] = new GLuint[m_width * m_height]; 171e5c31af7Sopenharmony_ci } 172e5c31af7Sopenharmony_ci m_actual = new GLuint[m_width * m_height]; 173e5c31af7Sopenharmony_ci 174e5c31af7Sopenharmony_ci // Create framebuffer 175e5c31af7Sopenharmony_ci gl.genFramebuffers(1, &m_fbo); 176e5c31af7Sopenharmony_ci gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo); 177e5c31af7Sopenharmony_ci GLenum drawBuffers[NUM_TEXTURES]; 178e5c31af7Sopenharmony_ci for (GLuint i = 0; i < NUM_TEXTURES; ++i) 179e5c31af7Sopenharmony_ci { 180e5c31af7Sopenharmony_ci gl.framebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, m_tex[i], 0); 181e5c31af7Sopenharmony_ci drawBuffers[i] = GL_COLOR_ATTACHMENT0 + i; 182e5c31af7Sopenharmony_ci } 183e5c31af7Sopenharmony_ci gl.drawBuffers(NUM_TEXTURES, drawBuffers); 184e5c31af7Sopenharmony_ci 185e5c31af7Sopenharmony_ci // Create vertex array and buffer 186e5c31af7Sopenharmony_ci gl.genVertexArrays(1, &m_vao); 187e5c31af7Sopenharmony_ci gl.bindVertexArray(m_vao); 188e5c31af7Sopenharmony_ci 189e5c31af7Sopenharmony_ci gl.genBuffers(1, &m_vbo); 190e5c31af7Sopenharmony_ci gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo); 191e5c31af7Sopenharmony_ci gl.bufferData(GL_ARRAY_BUFFER, GRID_SIZE * GRID_SIZE * sizeof(float) * 12, NULL, GL_STATIC_DRAW); 192e5c31af7Sopenharmony_ci 193e5c31af7Sopenharmony_ci generateVertexData((float*)gl.mapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY)); 194e5c31af7Sopenharmony_ci gl.unmapBuffer(GL_ARRAY_BUFFER); 195e5c31af7Sopenharmony_ci 196e5c31af7Sopenharmony_ci gl.vertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL); 197e5c31af7Sopenharmony_ci gl.enableVertexAttribArray(0); 198e5c31af7Sopenharmony_ci 199e5c31af7Sopenharmony_ci // Setup state 200e5c31af7Sopenharmony_ci gl.pixelStorei(GL_PACK_ALIGNMENT, 1); 201e5c31af7Sopenharmony_ci gl.pixelStorei(GL_UNPACK_ALIGNMENT, 1); 202e5c31af7Sopenharmony_ci } 203e5c31af7Sopenharmony_ci 204e5c31af7Sopenharmony_ci /* Rendering test deinit. */ 205e5c31af7Sopenharmony_ci virtual void deinit() 206e5c31af7Sopenharmony_ci { 207e5c31af7Sopenharmony_ci const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 208e5c31af7Sopenharmony_ci 209e5c31af7Sopenharmony_ci // Cleanup textures 210e5c31af7Sopenharmony_ci gl.activeTexture(GL_TEXTURE0); 211e5c31af7Sopenharmony_ci gl.deleteTextures(NUM_TEXTURES, m_tex); 212e5c31af7Sopenharmony_ci for (GLuint i = 0; i < NUM_TEXTURES; ++i) 213e5c31af7Sopenharmony_ci { 214e5c31af7Sopenharmony_ci if (DE_NULL != m_reference[i]) 215e5c31af7Sopenharmony_ci { 216e5c31af7Sopenharmony_ci delete[] m_reference[i]; 217e5c31af7Sopenharmony_ci m_reference[i] = DE_NULL; 218e5c31af7Sopenharmony_ci } 219e5c31af7Sopenharmony_ci } 220e5c31af7Sopenharmony_ci 221e5c31af7Sopenharmony_ci if (DE_NULL != m_actual) 222e5c31af7Sopenharmony_ci { 223e5c31af7Sopenharmony_ci delete[] m_actual; 224e5c31af7Sopenharmony_ci m_actual = DE_NULL; 225e5c31af7Sopenharmony_ci } 226e5c31af7Sopenharmony_ci 227e5c31af7Sopenharmony_ci // Cleanup framebuffer 228e5c31af7Sopenharmony_ci gl.bindFramebuffer(GL_FRAMEBUFFER, 0); 229e5c31af7Sopenharmony_ci gl.deleteFramebuffers(1, &m_fbo); 230e5c31af7Sopenharmony_ci 231e5c31af7Sopenharmony_ci // Cleanup vertex array and buffer 232e5c31af7Sopenharmony_ci gl.bindBuffer(GL_ARRAY_BUFFER, 0); 233e5c31af7Sopenharmony_ci gl.bindVertexArray(0); 234e5c31af7Sopenharmony_ci gl.deleteBuffers(1, &m_vbo); 235e5c31af7Sopenharmony_ci gl.deleteVertexArrays(1, &m_vao); 236e5c31af7Sopenharmony_ci 237e5c31af7Sopenharmony_ci // Cleanup state 238e5c31af7Sopenharmony_ci gl.pixelStorei(GL_PACK_ALIGNMENT, 4); 239e5c31af7Sopenharmony_ci gl.pixelStorei(GL_UNPACK_ALIGNMENT, 4); 240e5c31af7Sopenharmony_ci } 241e5c31af7Sopenharmony_ci 242e5c31af7Sopenharmony_ci /* Generate vertex data using the following steps: 243e5c31af7Sopenharmony_ci (1) Generate an irregular grid covering the whole screen (i.e. (-1,-1) to (1,1)); 244e5c31af7Sopenharmony_ci (2) Generate a list of triangles covering the grid; 245e5c31af7Sopenharmony_ci (3) Shuffle the generated triangle list; 246e5c31af7Sopenharmony_ci (4) Write the vertices of the shuffled triangle list to the destination address. */ 247e5c31af7Sopenharmony_ci void generateVertexData(float* destAddr) 248e5c31af7Sopenharmony_ci { 249e5c31af7Sopenharmony_ci DE_ASSERT(destAddr != NULL); 250e5c31af7Sopenharmony_ci 251e5c31af7Sopenharmony_ci typedef struct 252e5c31af7Sopenharmony_ci { 253e5c31af7Sopenharmony_ci float x, y; 254e5c31af7Sopenharmony_ci } Vertex; 255e5c31af7Sopenharmony_ci 256e5c31af7Sopenharmony_ci typedef struct 257e5c31af7Sopenharmony_ci { 258e5c31af7Sopenharmony_ci Vertex v0, v1, v2; 259e5c31af7Sopenharmony_ci } Triangle; 260e5c31af7Sopenharmony_ci 261e5c31af7Sopenharmony_ci static Vertex grid[GRID_SIZE + 1][GRID_SIZE + 1]; 262e5c31af7Sopenharmony_ci 263e5c31af7Sopenharmony_ci // Generate grid vertices 264e5c31af7Sopenharmony_ci for (int x = 0; x < GRID_SIZE + 1; ++x) 265e5c31af7Sopenharmony_ci for (int y = 0; y < GRID_SIZE + 1; ++y) 266e5c31af7Sopenharmony_ci { 267e5c31af7Sopenharmony_ci // Calculate normalized coordinates 268e5c31af7Sopenharmony_ci float normx = (((float)x) / GRID_SIZE); 269e5c31af7Sopenharmony_ci float normy = (((float)y) / GRID_SIZE); 270e5c31af7Sopenharmony_ci 271e5c31af7Sopenharmony_ci // Pseudo-random grid vertex coordinate with scale & bias 272e5c31af7Sopenharmony_ci grid[x][y].x = normx * 2.f - 1.f + deFloatSin(normx * DE_PI * 13.f) * 0.3f / GRID_SIZE; 273e5c31af7Sopenharmony_ci grid[x][y].y = normy * 2.f - 1.f + deFloatSin(normy * DE_PI * 13.f) * 0.3f / GRID_SIZE; 274e5c31af7Sopenharmony_ci } 275e5c31af7Sopenharmony_ci 276e5c31af7Sopenharmony_ci Triangle list[TRIANGLE_COUNT]; 277e5c31af7Sopenharmony_ci 278e5c31af7Sopenharmony_ci // Generate triangle list 279e5c31af7Sopenharmony_ci for (int x = 0; x < GRID_SIZE; ++x) 280e5c31af7Sopenharmony_ci for (int y = 0; y < GRID_SIZE; ++y) 281e5c31af7Sopenharmony_ci { 282e5c31af7Sopenharmony_ci // Generate first triangle of grid block 283e5c31af7Sopenharmony_ci list[(x + y * GRID_SIZE) * 2 + 0].v0 = grid[x][y]; 284e5c31af7Sopenharmony_ci list[(x + y * GRID_SIZE) * 2 + 0].v1 = grid[x + 1][y]; 285e5c31af7Sopenharmony_ci list[(x + y * GRID_SIZE) * 2 + 0].v2 = grid[x + 1][y + 1]; 286e5c31af7Sopenharmony_ci 287e5c31af7Sopenharmony_ci // Generate second triangle of grid block 288e5c31af7Sopenharmony_ci list[(x + y * GRID_SIZE) * 2 + 1].v0 = grid[x + 1][y + 1]; 289e5c31af7Sopenharmony_ci list[(x + y * GRID_SIZE) * 2 + 1].v1 = grid[x][y + 1]; 290e5c31af7Sopenharmony_ci list[(x + y * GRID_SIZE) * 2 + 1].v2 = grid[x][y]; 291e5c31af7Sopenharmony_ci } 292e5c31af7Sopenharmony_ci 293e5c31af7Sopenharmony_ci // Shuffle triangle list 294e5c31af7Sopenharmony_ci for (int i = TRIANGLE_COUNT - 2; i > 0; --i) 295e5c31af7Sopenharmony_ci { 296e5c31af7Sopenharmony_ci // Pseudo-random triangle index as one operand of the exchange 297e5c31af7Sopenharmony_ci int j = (int)((list[i].v1.y + list[i].v2.x + 13.f) * 1345.13f) % i; 298e5c31af7Sopenharmony_ci 299e5c31af7Sopenharmony_ci Triangle xchg = list[j]; 300e5c31af7Sopenharmony_ci list[j] = list[i]; 301e5c31af7Sopenharmony_ci list[i] = xchg; 302e5c31af7Sopenharmony_ci } 303e5c31af7Sopenharmony_ci 304e5c31af7Sopenharmony_ci // Write triange list vertices to destination address 305e5c31af7Sopenharmony_ci for (int i = 0; i < TRIANGLE_COUNT; ++i) 306e5c31af7Sopenharmony_ci { 307e5c31af7Sopenharmony_ci // Write first vertex of triangle 308e5c31af7Sopenharmony_ci destAddr[i * 6 + 0] = list[i].v0.x; 309e5c31af7Sopenharmony_ci destAddr[i * 6 + 1] = list[i].v0.y; 310e5c31af7Sopenharmony_ci 311e5c31af7Sopenharmony_ci // Write second vertex of triangle 312e5c31af7Sopenharmony_ci destAddr[i * 6 + 2] = list[i].v1.x; 313e5c31af7Sopenharmony_ci destAddr[i * 6 + 3] = list[i].v1.y; 314e5c31af7Sopenharmony_ci 315e5c31af7Sopenharmony_ci // Write third vertex of triangle 316e5c31af7Sopenharmony_ci destAddr[i * 6 + 4] = list[i].v2.x; 317e5c31af7Sopenharmony_ci destAddr[i * 6 + 5] = list[i].v2.y; 318e5c31af7Sopenharmony_ci } 319e5c31af7Sopenharmony_ci } 320e5c31af7Sopenharmony_ci 321e5c31af7Sopenharmony_ci /* Renders a set of primitives that cover each pixel of the framebuffer exactly once. */ 322e5c31af7Sopenharmony_ci void render() 323e5c31af7Sopenharmony_ci { 324e5c31af7Sopenharmony_ci const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 325e5c31af7Sopenharmony_ci 326e5c31af7Sopenharmony_ci // Issue the whole grid using multiple separate draw commands 327e5c31af7Sopenharmony_ci int minTriCountPerDraw = TRIANGLE_COUNT / 7; 328e5c31af7Sopenharmony_ci int first = 0, count = 0; 329e5c31af7Sopenharmony_ci while (first < VERTEX_COUNT) 330e5c31af7Sopenharmony_ci { 331e5c31af7Sopenharmony_ci // Pseudo-random number of vertices per draw 332e5c31af7Sopenharmony_ci count = deMin32(VERTEX_COUNT - first, (first % 23 + minTriCountPerDraw) * 3); 333e5c31af7Sopenharmony_ci 334e5c31af7Sopenharmony_ci gl.drawArrays(GL_TRIANGLES, first, count); 335e5c31af7Sopenharmony_ci 336e5c31af7Sopenharmony_ci first += count; 337e5c31af7Sopenharmony_ci } 338e5c31af7Sopenharmony_ci } 339e5c31af7Sopenharmony_ci 340e5c31af7Sopenharmony_ci /* Returns a reference to the texel value of the specified image at the specified location. */ 341e5c31af7Sopenharmony_ci GLuint& texel(GLuint* image, GLuint x, GLuint y) 342e5c31af7Sopenharmony_ci { 343e5c31af7Sopenharmony_ci // If out-of-bounds reads should return zero, writes should be ignored 344e5c31af7Sopenharmony_ci if ((static_cast<GLint>(x) < 0) || (x >= m_width) || (static_cast<GLint>(y) < 0) || (y >= m_height)) 345e5c31af7Sopenharmony_ci { 346e5c31af7Sopenharmony_ci static GLuint zero; 347e5c31af7Sopenharmony_ci return (zero = 0); 348e5c31af7Sopenharmony_ci } 349e5c31af7Sopenharmony_ci 350e5c31af7Sopenharmony_ci return image[x + y * m_width]; 351e5c31af7Sopenharmony_ci } 352e5c31af7Sopenharmony_ci 353e5c31af7Sopenharmony_ci /* Initializes the reference images and uploads them to their corresponding textures. */ 354e5c31af7Sopenharmony_ci void initTextureData() 355e5c31af7Sopenharmony_ci { 356e5c31af7Sopenharmony_ci const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 357e5c31af7Sopenharmony_ci 358e5c31af7Sopenharmony_ci for (GLuint i = 0; i < NUM_TEXTURES; ++i) 359e5c31af7Sopenharmony_ci { 360e5c31af7Sopenharmony_ci for (GLuint x = 0; x < m_width; ++x) 361e5c31af7Sopenharmony_ci for (GLuint y = 0; y < m_height; ++y) 362e5c31af7Sopenharmony_ci { 363e5c31af7Sopenharmony_ci texel(m_reference[i], x, y) = (i << 24) + (y << 12) + x; 364e5c31af7Sopenharmony_ci } 365e5c31af7Sopenharmony_ci 366e5c31af7Sopenharmony_ci gl.activeTexture(GL_TEXTURE0 + i); 367e5c31af7Sopenharmony_ci gl.texSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_width, m_height, GL_RED_INTEGER, GL_UNSIGNED_INT, 368e5c31af7Sopenharmony_ci m_reference[i]); 369e5c31af7Sopenharmony_ci } 370e5c31af7Sopenharmony_ci } 371e5c31af7Sopenharmony_ci 372e5c31af7Sopenharmony_ci /* Updates the reference images according to a single execution of the fragment shader for each pixel. */ 373e5c31af7Sopenharmony_ci virtual void updateTextureData() = 0; 374e5c31af7Sopenharmony_ci 375e5c31af7Sopenharmony_ci /* Verifies whether the reference images matches those of the textures we rendered to. */ 376e5c31af7Sopenharmony_ci bool verifyTextureData() 377e5c31af7Sopenharmony_ci { 378e5c31af7Sopenharmony_ci const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 379e5c31af7Sopenharmony_ci 380e5c31af7Sopenharmony_ci for (GLuint i = 0; i < NUM_TEXTURES; ++i) 381e5c31af7Sopenharmony_ci { 382e5c31af7Sopenharmony_ci gl.activeTexture(GL_TEXTURE0 + i); 383e5c31af7Sopenharmony_ci gl.getTexImage(GL_TEXTURE_2D, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, m_actual); 384e5c31af7Sopenharmony_ci 385e5c31af7Sopenharmony_ci for (GLuint x = 0; x < m_width; ++x) 386e5c31af7Sopenharmony_ci for (GLuint y = 0; y < m_height; ++y) 387e5c31af7Sopenharmony_ci { 388e5c31af7Sopenharmony_ci if (texel(m_reference[i], x, y) != texel(m_actual, x, y)) 389e5c31af7Sopenharmony_ci { 390e5c31af7Sopenharmony_ci return false; 391e5c31af7Sopenharmony_ci } 392e5c31af7Sopenharmony_ci } 393e5c31af7Sopenharmony_ci } 394e5c31af7Sopenharmony_ci 395e5c31af7Sopenharmony_ci return true; 396e5c31af7Sopenharmony_ci } 397e5c31af7Sopenharmony_ci 398e5c31af7Sopenharmony_ci /* Should return the number of separate test passes. */ 399e5c31af7Sopenharmony_ci virtual int numTestPasses() = 0; 400e5c31af7Sopenharmony_ci 401e5c31af7Sopenharmony_ci /* Should return the number of rendering passes to perform. */ 402e5c31af7Sopenharmony_ci virtual int numRenderPasses() = 0; 403e5c31af7Sopenharmony_ci 404e5c31af7Sopenharmony_ci /* Should set up configuration for a particular render pass (e.g. setting uniforms). */ 405e5c31af7Sopenharmony_ci virtual void setupRenderPass(int testPass, int renderPass) = 0; 406e5c31af7Sopenharmony_ci 407e5c31af7Sopenharmony_ci /* Should return whether there is need for a TextureBarrier between subsequent render passes. */ 408e5c31af7Sopenharmony_ci virtual bool needsBarrier() = 0; 409e5c31af7Sopenharmony_ci 410e5c31af7Sopenharmony_ci /* Test case iterate function. Contains the actual test case logic. */ 411e5c31af7Sopenharmony_ci IterateResult iterate() 412e5c31af7Sopenharmony_ci { 413e5c31af7Sopenharmony_ci tcu::TestLog& log = m_testCtx.getLog(); 414e5c31af7Sopenharmony_ci const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 415e5c31af7Sopenharmony_ci 416e5c31af7Sopenharmony_ci // Compile & link the program to use 417e5c31af7Sopenharmony_ci de::SharedPtr<glu::ShaderProgram> program( 418e5c31af7Sopenharmony_ci new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vsh(), fsh()))); 419e5c31af7Sopenharmony_ci log << (*program); 420e5c31af7Sopenharmony_ci if (!program->isOk()) 421e5c31af7Sopenharmony_ci { 422e5c31af7Sopenharmony_ci TCU_FAIL("Program compilation failed"); 423e5c31af7Sopenharmony_ci } 424e5c31af7Sopenharmony_ci m_program = program->getProgram(); 425e5c31af7Sopenharmony_ci 426e5c31af7Sopenharmony_ci gl.useProgram(m_program); 427e5c31af7Sopenharmony_ci 428e5c31af7Sopenharmony_ci for (GLuint i = 0; i < NUM_TEXTURES; ++i) 429e5c31af7Sopenharmony_ci { 430e5c31af7Sopenharmony_ci GLchar samplerName[] = "texInput[0]"; 431e5c31af7Sopenharmony_ci samplerName[9] = static_cast<GLchar>('0' + i); 432e5c31af7Sopenharmony_ci GLint loc = gl.getUniformLocation(m_program, samplerName); 433e5c31af7Sopenharmony_ci gl.uniform1i(loc, i); 434e5c31af7Sopenharmony_ci } 435e5c31af7Sopenharmony_ci 436e5c31af7Sopenharmony_ci for (int testPass = 0; testPass < numTestPasses(); ++testPass) 437e5c31af7Sopenharmony_ci { 438e5c31af7Sopenharmony_ci // Initialize texture data at the beginning of each test pass 439e5c31af7Sopenharmony_ci initTextureData(); 440e5c31af7Sopenharmony_ci 441e5c31af7Sopenharmony_ci // Perform rendering passes 442e5c31af7Sopenharmony_ci for (int renderPass = 0; renderPass < numRenderPasses(); ++renderPass) 443e5c31af7Sopenharmony_ci { 444e5c31af7Sopenharmony_ci // Setup render pass 445e5c31af7Sopenharmony_ci setupRenderPass(testPass, renderPass); 446e5c31af7Sopenharmony_ci 447e5c31af7Sopenharmony_ci // Render a set of primitives that cover each pixel of the framebuffer exactly once 448e5c31af7Sopenharmony_ci render(); 449e5c31af7Sopenharmony_ci 450e5c31af7Sopenharmony_ci // If a TextureBarrier is needed insert it here 451e5c31af7Sopenharmony_ci if (needsBarrier()) 452e5c31af7Sopenharmony_ci gl.textureBarrier(); 453e5c31af7Sopenharmony_ci } 454e5c31af7Sopenharmony_ci 455e5c31af7Sopenharmony_ci // Update reference data after actual rendering to avoid bubbles 456e5c31af7Sopenharmony_ci for (int renderPass = 0; renderPass < numRenderPasses(); ++renderPass) 457e5c31af7Sopenharmony_ci { 458e5c31af7Sopenharmony_ci // Setup render pass 459e5c31af7Sopenharmony_ci setupRenderPass(testPass, renderPass); 460e5c31af7Sopenharmony_ci 461e5c31af7Sopenharmony_ci // Update reference data 462e5c31af7Sopenharmony_ci updateTextureData(); 463e5c31af7Sopenharmony_ci } 464e5c31af7Sopenharmony_ci 465e5c31af7Sopenharmony_ci // Verify results at the end of each test pass 466e5c31af7Sopenharmony_ci if (!verifyTextureData()) 467e5c31af7Sopenharmony_ci { 468e5c31af7Sopenharmony_ci TCU_FAIL("Failed to validate rendering results"); 469e5c31af7Sopenharmony_ci } 470e5c31af7Sopenharmony_ci } 471e5c31af7Sopenharmony_ci 472e5c31af7Sopenharmony_ci gl.useProgram(0); 473e5c31af7Sopenharmony_ci 474e5c31af7Sopenharmony_ci // Test case passed 475e5c31af7Sopenharmony_ci m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 476e5c31af7Sopenharmony_ci 477e5c31af7Sopenharmony_ci return STOP; 478e5c31af7Sopenharmony_ci } 479e5c31af7Sopenharmony_ci 480e5c31af7Sopenharmony_ciprotected: 481e5c31af7Sopenharmony_ci enum 482e5c31af7Sopenharmony_ci { 483e5c31af7Sopenharmony_ci NUM_TEXTURES = 8, 484e5c31af7Sopenharmony_ci 485e5c31af7Sopenharmony_ci GRID_SIZE = 64, 486e5c31af7Sopenharmony_ci TRIANGLE_COUNT = GRID_SIZE * GRID_SIZE * 2, 487e5c31af7Sopenharmony_ci VERTEX_COUNT = TRIANGLE_COUNT * 3, 488e5c31af7Sopenharmony_ci }; 489e5c31af7Sopenharmony_ci 490e5c31af7Sopenharmony_ci GLuint m_program; 491e5c31af7Sopenharmony_ci GLuint m_vao; 492e5c31af7Sopenharmony_ci GLuint m_vbo; 493e5c31af7Sopenharmony_ci GLuint m_fbo; 494e5c31af7Sopenharmony_ci GLuint m_tex[NUM_TEXTURES]; 495e5c31af7Sopenharmony_ci GLuint m_width, m_height; 496e5c31af7Sopenharmony_ci GLuint* m_reference[NUM_TEXTURES]; 497e5c31af7Sopenharmony_ci GLuint* m_actual; 498e5c31af7Sopenharmony_ci}; 499e5c31af7Sopenharmony_ci 500e5c31af7Sopenharmony_ci/* 501e5c31af7Sopenharmony_ci Base class of the rendering tests which use a fragment shader performing 502e5c31af7Sopenharmony_ci reads and writes from/to disjoint blocks of texels within a single rendering 503e5c31af7Sopenharmony_ci pass. The skeleton of these tests is as follows: 504e5c31af7Sopenharmony_ci 505e5c31af7Sopenharmony_ci * Using the basic outline above test that reads and writes from/to 506e5c31af7Sopenharmony_ci disjoint sets of texels work as expected. Use the following fragment 507e5c31af7Sopenharmony_ci shader as a template: 508e5c31af7Sopenharmony_ci 509e5c31af7Sopenharmony_ci uniform int blockSize; 510e5c31af7Sopenharmony_ci uniform int modulo; 511e5c31af7Sopenharmony_ci uniform sampler2D texture[N]; 512e5c31af7Sopenharmony_ci out vec4 output[N]; 513e5c31af7Sopenharmony_ci 514e5c31af7Sopenharmony_ci void main() { 515e5c31af7Sopenharmony_ci ivec2 texelCoord = ivec2(gl_FragCoord.xy); 516e5c31af7Sopenharmony_ci ivec2 blockCoord = texelCoord / blockSize; 517e5c31af7Sopenharmony_ci ivec2 xOffset = ivec2(blockSize, 0); 518e5c31af7Sopenharmony_ci ivec2 yOffset = ivec2(0, blockSize); 519e5c31af7Sopenharmony_ci 520e5c31af7Sopenharmony_ci if (((blockCoord.x + blockCoord.y) % 2) == modulo) { 521e5c31af7Sopenharmony_ci for (int i = 0; i < N; ++i) { 522e5c31af7Sopenharmony_ci output[i] = function( 523e5c31af7Sopenharmony_ci texelFetch(texture[i], texelCoord + xOffset, 0), 524e5c31af7Sopenharmony_ci texelFetch(texture[i], texelCoord - xOffset, 0), 525e5c31af7Sopenharmony_ci texelFetch(texture[i], texelCoord + yOffset, 0), 526e5c31af7Sopenharmony_ci texelFetch(texture[i], texelCoord - yOffset, 0) 527e5c31af7Sopenharmony_ci ); 528e5c31af7Sopenharmony_ci } 529e5c31af7Sopenharmony_ci } else { 530e5c31af7Sopenharmony_ci discard; 531e5c31af7Sopenharmony_ci } 532e5c31af7Sopenharmony_ci } 533e5c31af7Sopenharmony_ci 534e5c31af7Sopenharmony_ci Where "blockSize" is the size of the disjoint rectangular sets of texels, 535e5c31af7Sopenharmony_ci "modulo" should be either zero or one (depending whether even or odd 536e5c31af7Sopenharmony_ci blocks should be fetched/written), and "function" is an arbitrary 537e5c31af7Sopenharmony_ci function of its parameters. 538e5c31af7Sopenharmony_ci */ 539e5c31af7Sopenharmony_ciclass TextureBarrierTexelBlocksBase : public TextureBarrierBasicOutline 540e5c31af7Sopenharmony_ci{ 541e5c31af7Sopenharmony_ciprotected: 542e5c31af7Sopenharmony_ci TextureBarrierTexelBlocksBase(deqp::Context& context, TextureBarrierTests::API api, const char* name, 543e5c31af7Sopenharmony_ci const char* description) 544e5c31af7Sopenharmony_ci : TextureBarrierBasicOutline(context, api, name, description) 545e5c31af7Sopenharmony_ci , m_blockSize(-1) 546e5c31af7Sopenharmony_ci , m_modulo(-1) 547e5c31af7Sopenharmony_ci , m_blockSizeLoc(0) 548e5c31af7Sopenharmony_ci , m_moduloLoc(0) 549e5c31af7Sopenharmony_ci { 550e5c31af7Sopenharmony_ci } 551e5c31af7Sopenharmony_ci 552e5c31af7Sopenharmony_ci /* Actual fragment shader source based on the provided template. */ 553e5c31af7Sopenharmony_ci virtual const char* fsh() 554e5c31af7Sopenharmony_ci { 555e5c31af7Sopenharmony_ci return "#version 400 core\n" 556e5c31af7Sopenharmony_ci "#define NUM_TEXTURES 8\n" 557e5c31af7Sopenharmony_ci "uniform int blockSize;\n" 558e5c31af7Sopenharmony_ci "uniform int modulo;\n" 559e5c31af7Sopenharmony_ci "uniform usampler2D texInput[NUM_TEXTURES];\n" 560e5c31af7Sopenharmony_ci "out uvec4 fragOutput[NUM_TEXTURES];\n" 561e5c31af7Sopenharmony_ci "uvec4 func(uvec4 t0, uvec4 t1, uvec4 t2, uvec4 t3) {\n" 562e5c31af7Sopenharmony_ci " return t0 + t1 + t2 + t3;\n" 563e5c31af7Sopenharmony_ci "}\n" 564e5c31af7Sopenharmony_ci "void main() {\n" 565e5c31af7Sopenharmony_ci " ivec2 texelCoord = ivec2(gl_FragCoord.xy);\n" 566e5c31af7Sopenharmony_ci " ivec2 blockCoord = texelCoord / blockSize;\n" 567e5c31af7Sopenharmony_ci " ivec2 xOffset = ivec2(blockSize, 0);\n" 568e5c31af7Sopenharmony_ci " ivec2 yOffset = ivec2(0, blockSize);\n" 569e5c31af7Sopenharmony_ci " if (((blockCoord.x + blockCoord.y) % 2) == modulo) {\n" 570e5c31af7Sopenharmony_ci " for (int i = 0; i < NUM_TEXTURES; ++i) {\n" 571e5c31af7Sopenharmony_ci " fragOutput[i] = func(texelFetch(texInput[i], texelCoord + xOffset, 0),\n" 572e5c31af7Sopenharmony_ci " texelFetch(texInput[i], texelCoord - xOffset, 0),\n" 573e5c31af7Sopenharmony_ci " texelFetch(texInput[i], texelCoord + yOffset, 0),\n" 574e5c31af7Sopenharmony_ci " texelFetch(texInput[i], texelCoord - yOffset, 0));\n" 575e5c31af7Sopenharmony_ci " }\n" 576e5c31af7Sopenharmony_ci " } else {\n" 577e5c31af7Sopenharmony_ci " discard;\n" 578e5c31af7Sopenharmony_ci " }\n" 579e5c31af7Sopenharmony_ci "}"; 580e5c31af7Sopenharmony_ci } 581e5c31af7Sopenharmony_ci 582e5c31af7Sopenharmony_ci /* CPU code equivalent to the fragment shader to update reference data. */ 583e5c31af7Sopenharmony_ci virtual void updateTextureData() 584e5c31af7Sopenharmony_ci { 585e5c31af7Sopenharmony_ci for (GLuint x = 0; x < m_width; ++x) 586e5c31af7Sopenharmony_ci for (GLuint y = 0; y < m_height; ++y) 587e5c31af7Sopenharmony_ci { 588e5c31af7Sopenharmony_ci GLuint blockX = x / m_blockSize; 589e5c31af7Sopenharmony_ci GLuint blockY = y / m_blockSize; 590e5c31af7Sopenharmony_ci 591e5c31af7Sopenharmony_ci if ((static_cast<int>((blockX + blockY) % 2)) == m_modulo) 592e5c31af7Sopenharmony_ci { 593e5c31af7Sopenharmony_ci for (GLuint i = 0; i < NUM_TEXTURES; ++i) 594e5c31af7Sopenharmony_ci { 595e5c31af7Sopenharmony_ci texel(m_reference[i], x, y) = 596e5c31af7Sopenharmony_ci texel(m_reference[i], x + m_blockSize, y) + texel(m_reference[i], x - m_blockSize, y) + 597e5c31af7Sopenharmony_ci texel(m_reference[i], x, y + m_blockSize) + texel(m_reference[i], x, y - m_blockSize); 598e5c31af7Sopenharmony_ci } 599e5c31af7Sopenharmony_ci } 600e5c31af7Sopenharmony_ci } 601e5c31af7Sopenharmony_ci } 602e5c31af7Sopenharmony_ci 603e5c31af7Sopenharmony_ci /* Render pass setup code. Updates uniforms used by the fragment shader and 604e5c31af7Sopenharmony_ci member variables used by the reference data update code. */ 605e5c31af7Sopenharmony_ci virtual void setupRenderPass(int testPass, int renderPass) 606e5c31af7Sopenharmony_ci { 607e5c31af7Sopenharmony_ci const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 608e5c31af7Sopenharmony_ci 609e5c31af7Sopenharmony_ci if ((testPass == 0) && (renderPass == 0)) 610e5c31af7Sopenharmony_ci { 611e5c31af7Sopenharmony_ci // Get the uniform locations in the first pass, reuse it afterwards 612e5c31af7Sopenharmony_ci m_blockSizeLoc = gl.getUniformLocation(m_program, "blockSize"); 613e5c31af7Sopenharmony_ci m_moduloLoc = gl.getUniformLocation(m_program, "modulo"); 614e5c31af7Sopenharmony_ci } 615e5c31af7Sopenharmony_ci 616e5c31af7Sopenharmony_ci // Update block size if changed 617e5c31af7Sopenharmony_ci int newBlockSize = getBlockSize(testPass, renderPass); 618e5c31af7Sopenharmony_ci if (newBlockSize != m_blockSize) 619e5c31af7Sopenharmony_ci { 620e5c31af7Sopenharmony_ci m_blockSize = newBlockSize; 621e5c31af7Sopenharmony_ci gl.uniform1i(m_blockSizeLoc, m_blockSize); 622e5c31af7Sopenharmony_ci } 623e5c31af7Sopenharmony_ci 624e5c31af7Sopenharmony_ci // Update modulo if changed 625e5c31af7Sopenharmony_ci int newModulo = getModulo(testPass, renderPass); 626e5c31af7Sopenharmony_ci if (newModulo != m_modulo) 627e5c31af7Sopenharmony_ci { 628e5c31af7Sopenharmony_ci m_modulo = newModulo; 629e5c31af7Sopenharmony_ci gl.uniform1i(m_moduloLoc, m_modulo); 630e5c31af7Sopenharmony_ci } 631e5c31af7Sopenharmony_ci } 632e5c31af7Sopenharmony_ci 633e5c31af7Sopenharmony_ci /* Returns the block size to be used in the specified pass. */ 634e5c31af7Sopenharmony_ci virtual int getBlockSize(int testPass, int renderPass) = 0; 635e5c31af7Sopenharmony_ci 636e5c31af7Sopenharmony_ci /* Returns the modulo value to be used in the specified pass. */ 637e5c31af7Sopenharmony_ci virtual int getModulo(int testPass, int renderPass) = 0; 638e5c31af7Sopenharmony_ci 639e5c31af7Sopenharmony_ciprivate: 640e5c31af7Sopenharmony_ci int m_blockSize; 641e5c31af7Sopenharmony_ci int m_modulo; 642e5c31af7Sopenharmony_ci GLint m_blockSizeLoc; 643e5c31af7Sopenharmony_ci GLint m_moduloLoc; 644e5c31af7Sopenharmony_ci}; 645e5c31af7Sopenharmony_ci 646e5c31af7Sopenharmony_ci/* 647e5c31af7Sopenharmony_ci Test case #1: Disjoint texels 648e5c31af7Sopenharmony_ci 649e5c31af7Sopenharmony_ci * Using the basic outline above test that reads and writes from/to 650e5c31af7Sopenharmony_ci disjoint sets of texels work as expected. 651e5c31af7Sopenharmony_ci 652e5c31af7Sopenharmony_ci * Repeat the above test case with various values for blockSize (including a 653e5c31af7Sopenharmony_ci block size of one). 654e5c31af7Sopenharmony_ci 655e5c31af7Sopenharmony_ci * Repeat the actual rendering pass multiple times within a single test 656e5c31af7Sopenharmony_ci using a fixed value for "blockSize" and "modulo". Because the set of 657e5c31af7Sopenharmony_ci read and written texels stays disjoint the results should still be well 658e5c31af7Sopenharmony_ci defined even without the use of any synchronization primitive. 659e5c31af7Sopenharmony_ci */ 660e5c31af7Sopenharmony_ciclass TextureBarrierDisjointTexels : public TextureBarrierTexelBlocksBase 661e5c31af7Sopenharmony_ci{ 662e5c31af7Sopenharmony_cipublic: 663e5c31af7Sopenharmony_ci TextureBarrierDisjointTexels(deqp::Context& context, TextureBarrierTests::API api, const char* name) 664e5c31af7Sopenharmony_ci : TextureBarrierTexelBlocksBase( 665e5c31af7Sopenharmony_ci context, api, name, 666e5c31af7Sopenharmony_ci "Using the basic outline test that reads and writes from/to disjoint sets of texels work as expected. " 667e5c31af7Sopenharmony_ci "Repeat the test with multiple different block size values (including a block size of one). " 668e5c31af7Sopenharmony_ci "Repeat the actual rendering pass multiple times within a single test using a fixed value for " 669e5c31af7Sopenharmony_ci "blockSize and modulo. Because the set of read and written texels stays disjoint the result " 670e5c31af7Sopenharmony_ci "should still be well defined even without the use of any synchronization primitive.") 671e5c31af7Sopenharmony_ci { 672e5c31af7Sopenharmony_ci } 673e5c31af7Sopenharmony_ci 674e5c31af7Sopenharmony_ci /* Perform multiple test passes, one for each blockSize value. */ 675e5c31af7Sopenharmony_ci virtual int numTestPasses() 676e5c31af7Sopenharmony_ci { 677e5c31af7Sopenharmony_ci return 16; 678e5c31af7Sopenharmony_ci } 679e5c31af7Sopenharmony_ci 680e5c31af7Sopenharmony_ci /* Perform multiple render passes. As the same blockSize and modulo value is used between render passes the rendering 681e5c31af7Sopenharmony_ci results should still stay well defined. */ 682e5c31af7Sopenharmony_ci virtual int numRenderPasses() 683e5c31af7Sopenharmony_ci { 684e5c31af7Sopenharmony_ci return 5; 685e5c31af7Sopenharmony_ci } 686e5c31af7Sopenharmony_ci 687e5c31af7Sopenharmony_ci /* No need for a texture barrier as reads and writes happen from/to disjoint set of texels within a single test pass. */ 688e5c31af7Sopenharmony_ci virtual bool needsBarrier() 689e5c31af7Sopenharmony_ci { 690e5c31af7Sopenharmony_ci return false; 691e5c31af7Sopenharmony_ci } 692e5c31af7Sopenharmony_ci 693e5c31af7Sopenharmony_ci /* Try different values for blockSize, but the value must stay constant within a single test pass. */ 694e5c31af7Sopenharmony_ci virtual int getBlockSize(int testPass, int renderPass) 695e5c31af7Sopenharmony_ci { 696e5c31af7Sopenharmony_ci (void)renderPass; 697e5c31af7Sopenharmony_ci return testPass + 1; 698e5c31af7Sopenharmony_ci } 699e5c31af7Sopenharmony_ci 700e5c31af7Sopenharmony_ci /* Use a fixed value for modulo. */ 701e5c31af7Sopenharmony_ci virtual int getModulo(int testPass, int renderPass) 702e5c31af7Sopenharmony_ci { 703e5c31af7Sopenharmony_ci (void)testPass; 704e5c31af7Sopenharmony_ci (void)renderPass; 705e5c31af7Sopenharmony_ci return 0; 706e5c31af7Sopenharmony_ci } 707e5c31af7Sopenharmony_ci}; 708e5c31af7Sopenharmony_ci 709e5c31af7Sopenharmony_ci/* 710e5c31af7Sopenharmony_ci Test case #2: Overlapping texels (with texture barrier) 711e5c31af7Sopenharmony_ci 712e5c31af7Sopenharmony_ci * Using the basic outline above test that reads and writes from/to 713e5c31af7Sopenharmony_ci disjoint sets of texels work as expected. 714e5c31af7Sopenharmony_ci 715e5c31af7Sopenharmony_ci * Repeat the actual rendering pass multiple times within a single test, 716e5c31af7Sopenharmony_ci but this time use different values for "blockSize" and "modulo" and 717e5c31af7Sopenharmony_ci call TextureBarrier between subsequent rendering passes to ensure 718e5c31af7Sopenharmony_ci well defined results. 719e5c31af7Sopenharmony_ci */ 720e5c31af7Sopenharmony_ciclass TextureBarrierOverlappingTexels : public TextureBarrierTexelBlocksBase 721e5c31af7Sopenharmony_ci{ 722e5c31af7Sopenharmony_cipublic: 723e5c31af7Sopenharmony_ci TextureBarrierOverlappingTexels(deqp::Context& context, TextureBarrierTests::API api, const char* name) 724e5c31af7Sopenharmony_ci : TextureBarrierTexelBlocksBase( 725e5c31af7Sopenharmony_ci context, api, name, 726e5c31af7Sopenharmony_ci "Using the basic outline test that reads and writes from/to overlapping sets of texels work " 727e5c31af7Sopenharmony_ci "as expected if there is a call to TextureBarrier between subsequent rendering passes. Test " 728e5c31af7Sopenharmony_ci "this by using different values for blockSize and modulo for each rendering pass.") 729e5c31af7Sopenharmony_ci { 730e5c31af7Sopenharmony_ci } 731e5c31af7Sopenharmony_ci 732e5c31af7Sopenharmony_ci /* A single test pass is sufficient. */ 733e5c31af7Sopenharmony_ci virtual int numTestPasses() 734e5c31af7Sopenharmony_ci { 735e5c31af7Sopenharmony_ci return 1; 736e5c31af7Sopenharmony_ci } 737e5c31af7Sopenharmony_ci 738e5c31af7Sopenharmony_ci /* Perform several render passes to provoke a lot of overlap between read and written texel blocks. */ 739e5c31af7Sopenharmony_ci virtual int numRenderPasses() 740e5c31af7Sopenharmony_ci { 741e5c31af7Sopenharmony_ci return 42; 742e5c31af7Sopenharmony_ci } 743e5c31af7Sopenharmony_ci 744e5c31af7Sopenharmony_ci /* We need texture barriers between render passes as reads and writes in different render passes do overlap. */ 745e5c31af7Sopenharmony_ci virtual bool needsBarrier() 746e5c31af7Sopenharmony_ci { 747e5c31af7Sopenharmony_ci return true; 748e5c31af7Sopenharmony_ci } 749e5c31af7Sopenharmony_ci 750e5c31af7Sopenharmony_ci /* Use a pseudo-random blockSize for each render pass. */ 751e5c31af7Sopenharmony_ci virtual int getBlockSize(int testPass, int renderPass) 752e5c31af7Sopenharmony_ci { 753e5c31af7Sopenharmony_ci (void)testPass; 754e5c31af7Sopenharmony_ci return (5 + renderPass * 3) % 7 + 1; 755e5c31af7Sopenharmony_ci } 756e5c31af7Sopenharmony_ci 757e5c31af7Sopenharmony_ci /* Use a pseudo-random modulo for each render pass. */ 758e5c31af7Sopenharmony_ci virtual int getModulo(int testPass, int renderPass) 759e5c31af7Sopenharmony_ci { 760e5c31af7Sopenharmony_ci (void)testPass; 761e5c31af7Sopenharmony_ci return (renderPass * 3) % 2; 762e5c31af7Sopenharmony_ci } 763e5c31af7Sopenharmony_ci}; 764e5c31af7Sopenharmony_ci 765e5c31af7Sopenharmony_ci/* 766e5c31af7Sopenharmony_ci Base class of the rendering tests which use a fragment shader performing a 767e5c31af7Sopenharmony_ci single read and write of each texel. The skeleton of these tests is as follows: 768e5c31af7Sopenharmony_ci 769e5c31af7Sopenharmony_ci * Using the basic outline above test that a single read and write of each 770e5c31af7Sopenharmony_ci texel, where the read is in the fragment shader invocation that writes 771e5c31af7Sopenharmony_ci the same texel, works as expected. Use the following fragment shader as 772e5c31af7Sopenharmony_ci a template: 773e5c31af7Sopenharmony_ci 774e5c31af7Sopenharmony_ci uniform sampler2D texture[N]; 775e5c31af7Sopenharmony_ci out vec4 output[N]; 776e5c31af7Sopenharmony_ci 777e5c31af7Sopenharmony_ci void main() { 778e5c31af7Sopenharmony_ci ivec2 texelCoord = ivec2(gl_FragCoord.xy); 779e5c31af7Sopenharmony_ci 780e5c31af7Sopenharmony_ci for (int i = 0; i < N; ++i) { 781e5c31af7Sopenharmony_ci output[i] = function(texelFetch(texture[i], texelCoord, 0); 782e5c31af7Sopenharmony_ci } 783e5c31af7Sopenharmony_ci } 784e5c31af7Sopenharmony_ci 785e5c31af7Sopenharmony_ci Where "function" is an arbitrary function of its parameter. 786e5c31af7Sopenharmony_ci */ 787e5c31af7Sopenharmony_ciclass TextureBarrierSameTexelRWBase : public TextureBarrierBasicOutline 788e5c31af7Sopenharmony_ci{ 789e5c31af7Sopenharmony_ciprotected: 790e5c31af7Sopenharmony_ci TextureBarrierSameTexelRWBase(deqp::Context& context, TextureBarrierTests::API api, const char* name, 791e5c31af7Sopenharmony_ci const char* description) 792e5c31af7Sopenharmony_ci : TextureBarrierBasicOutline(context, api, name, description) 793e5c31af7Sopenharmony_ci { 794e5c31af7Sopenharmony_ci } 795e5c31af7Sopenharmony_ci 796e5c31af7Sopenharmony_ci /* Actual fragment shader source based on the provided template. */ 797e5c31af7Sopenharmony_ci virtual const char* fsh() 798e5c31af7Sopenharmony_ci { 799e5c31af7Sopenharmony_ci return "#version 400 core\n" 800e5c31af7Sopenharmony_ci "#define NUM_TEXTURES 8\n" 801e5c31af7Sopenharmony_ci "uniform usampler2D texInput[NUM_TEXTURES];\n" 802e5c31af7Sopenharmony_ci "out uvec4 fragOutput[NUM_TEXTURES];\n" 803e5c31af7Sopenharmony_ci "uvec4 func(uvec4 t) {\n" 804e5c31af7Sopenharmony_ci " return t + 1;\n" 805e5c31af7Sopenharmony_ci "}\n" 806e5c31af7Sopenharmony_ci "void main() {\n" 807e5c31af7Sopenharmony_ci " ivec2 texelCoord = ivec2(gl_FragCoord.xy);\n" 808e5c31af7Sopenharmony_ci " for (int i = 0; i < NUM_TEXTURES; ++i) {\n" 809e5c31af7Sopenharmony_ci " fragOutput[i] = func(texelFetch(texInput[i], texelCoord, 0));\n" 810e5c31af7Sopenharmony_ci " }\n" 811e5c31af7Sopenharmony_ci "}"; 812e5c31af7Sopenharmony_ci } 813e5c31af7Sopenharmony_ci 814e5c31af7Sopenharmony_ci /* CPU code equivalent to the fragment shader to update reference data. */ 815e5c31af7Sopenharmony_ci virtual void updateTextureData() 816e5c31af7Sopenharmony_ci { 817e5c31af7Sopenharmony_ci for (GLuint x = 0; x < m_width; ++x) 818e5c31af7Sopenharmony_ci for (GLuint y = 0; y < m_height; ++y) 819e5c31af7Sopenharmony_ci { 820e5c31af7Sopenharmony_ci for (GLuint i = 0; i < NUM_TEXTURES; ++i) 821e5c31af7Sopenharmony_ci { 822e5c31af7Sopenharmony_ci texel(m_reference[i], x, y)++; 823e5c31af7Sopenharmony_ci } 824e5c31af7Sopenharmony_ci } 825e5c31af7Sopenharmony_ci } 826e5c31af7Sopenharmony_ci 827e5c31af7Sopenharmony_ci /* The fragment shader used by these tests doesn't have any parameters, thus no need for render pass setup code. */ 828e5c31af7Sopenharmony_ci virtual void setupRenderPass(int testPass, int renderPass) 829e5c31af7Sopenharmony_ci { 830e5c31af7Sopenharmony_ci (void)testPass; 831e5c31af7Sopenharmony_ci (void)renderPass; 832e5c31af7Sopenharmony_ci } 833e5c31af7Sopenharmony_ci}; 834e5c31af7Sopenharmony_ci 835e5c31af7Sopenharmony_ci/* 836e5c31af7Sopenharmony_ci Test case #3: Single read and write of the same texel 837e5c31af7Sopenharmony_ci 838e5c31af7Sopenharmony_ci * Using the basic outline above test that a single read and write of each 839e5c31af7Sopenharmony_ci texel, where the read is in the fragment shader invocation that writes 840e5c31af7Sopenharmony_ci the same texel, works as expected. 841e5c31af7Sopenharmony_ci */ 842e5c31af7Sopenharmony_ciclass TextureBarrierSameTexelRW : public TextureBarrierSameTexelRWBase 843e5c31af7Sopenharmony_ci{ 844e5c31af7Sopenharmony_cipublic: 845e5c31af7Sopenharmony_ci TextureBarrierSameTexelRW(deqp::Context& context, TextureBarrierTests::API api, const char* name) 846e5c31af7Sopenharmony_ci : TextureBarrierSameTexelRWBase( 847e5c31af7Sopenharmony_ci context, api, name, 848e5c31af7Sopenharmony_ci "Using the basic outline tests that a single read and write of each texel, where the read " 849e5c31af7Sopenharmony_ci "is in the fragment shader invocation that writes the same texel, works as expected.") 850e5c31af7Sopenharmony_ci { 851e5c31af7Sopenharmony_ci } 852e5c31af7Sopenharmony_ci 853e5c31af7Sopenharmony_ci /* A single test pass is sufficient. */ 854e5c31af7Sopenharmony_ci virtual int numTestPasses() 855e5c31af7Sopenharmony_ci { 856e5c31af7Sopenharmony_ci return 1; 857e5c31af7Sopenharmony_ci } 858e5c31af7Sopenharmony_ci 859e5c31af7Sopenharmony_ci /* Well defined behavior is guaranteed only in case of a single pass. */ 860e5c31af7Sopenharmony_ci virtual int numRenderPasses() 861e5c31af7Sopenharmony_ci { 862e5c31af7Sopenharmony_ci return 1; 863e5c31af7Sopenharmony_ci } 864e5c31af7Sopenharmony_ci 865e5c31af7Sopenharmony_ci /* A single read and write of the same texel doesn't require a texture barrier. */ 866e5c31af7Sopenharmony_ci virtual bool needsBarrier() 867e5c31af7Sopenharmony_ci { 868e5c31af7Sopenharmony_ci return false; 869e5c31af7Sopenharmony_ci } 870e5c31af7Sopenharmony_ci}; 871e5c31af7Sopenharmony_ci 872e5c31af7Sopenharmony_ci/* 873e5c31af7Sopenharmony_ci Test case #4: Multipass read and write of the same texel (with texture barrier) 874e5c31af7Sopenharmony_ci 875e5c31af7Sopenharmony_ci * Using the basic outline above test that a single read and write of each 876e5c31af7Sopenharmony_ci texel, where the read is in the fragment shader invocation that writes 877e5c31af7Sopenharmony_ci the same texel, works as expected. 878e5c31af7Sopenharmony_ci 879e5c31af7Sopenharmony_ci * Repeat the above test case but this time perform multiple iterations 880e5c31af7Sopenharmony_ci of the actual rendering pass and use a call to TextureBarrier between 881e5c31af7Sopenharmony_ci them to ensure consistency. 882e5c31af7Sopenharmony_ci */ 883e5c31af7Sopenharmony_ciclass TextureBarrierSameTexelRWMultipass : public TextureBarrierSameTexelRWBase 884e5c31af7Sopenharmony_ci{ 885e5c31af7Sopenharmony_cipublic: 886e5c31af7Sopenharmony_ci TextureBarrierSameTexelRWMultipass(deqp::Context& context, TextureBarrierTests::API api, const char* name) 887e5c31af7Sopenharmony_ci : TextureBarrierSameTexelRWBase( 888e5c31af7Sopenharmony_ci context, api, name, 889e5c31af7Sopenharmony_ci "Using the basic outline tests that multiple reads and writes of each texel, where the read " 890e5c31af7Sopenharmony_ci "is in the fragment shader invocation that writes the same texel, works as expected if there " 891e5c31af7Sopenharmony_ci "is a call to TextureBarrier between each subsequent read-after-write.") 892e5c31af7Sopenharmony_ci { 893e5c31af7Sopenharmony_ci } 894e5c31af7Sopenharmony_ci 895e5c31af7Sopenharmony_ci /* A single test pass is sufficient. */ 896e5c31af7Sopenharmony_ci virtual int numTestPasses() 897e5c31af7Sopenharmony_ci { 898e5c31af7Sopenharmony_ci return 1; 899e5c31af7Sopenharmony_ci } 900e5c31af7Sopenharmony_ci 901e5c31af7Sopenharmony_ci /* Perform several render passes to provoke read-after-write hazards. */ 902e5c31af7Sopenharmony_ci virtual int numRenderPasses() 903e5c31af7Sopenharmony_ci { 904e5c31af7Sopenharmony_ci return 42; 905e5c31af7Sopenharmony_ci } 906e5c31af7Sopenharmony_ci 907e5c31af7Sopenharmony_ci /* We need to use texture barriers in between rendering passes to avoid read-after-write hazards. */ 908e5c31af7Sopenharmony_ci virtual bool needsBarrier() 909e5c31af7Sopenharmony_ci { 910e5c31af7Sopenharmony_ci return true; 911e5c31af7Sopenharmony_ci } 912e5c31af7Sopenharmony_ci}; 913e5c31af7Sopenharmony_ci 914e5c31af7Sopenharmony_ciconst char* apiToTestName(TextureBarrierTests::API api) 915e5c31af7Sopenharmony_ci{ 916e5c31af7Sopenharmony_ci switch (api) 917e5c31af7Sopenharmony_ci { 918e5c31af7Sopenharmony_ci case TextureBarrierTests::API_GL_45core: 919e5c31af7Sopenharmony_ci return "texture_barrier"; 920e5c31af7Sopenharmony_ci case TextureBarrierTests::API_GL_ARB_texture_barrier: 921e5c31af7Sopenharmony_ci return "texture_barrier_ARB"; 922e5c31af7Sopenharmony_ci } 923e5c31af7Sopenharmony_ci DE_ASSERT(0); 924e5c31af7Sopenharmony_ci return ""; 925e5c31af7Sopenharmony_ci} 926e5c31af7Sopenharmony_ci 927e5c31af7Sopenharmony_ci/** Constructor. 928e5c31af7Sopenharmony_ci * 929e5c31af7Sopenharmony_ci * @param context Rendering context. 930e5c31af7Sopenharmony_ci * @param api API to test (core vs ARB extension) 931e5c31af7Sopenharmony_ci **/ 932e5c31af7Sopenharmony_ciTextureBarrierTests::TextureBarrierTests(deqp::Context& context, API api) 933e5c31af7Sopenharmony_ci : TestCaseGroup(context, apiToTestName(api), "Verifies \"texture_barrier\" functionality"), m_api(api) 934e5c31af7Sopenharmony_ci{ 935e5c31af7Sopenharmony_ci /* Left blank on purpose */ 936e5c31af7Sopenharmony_ci} 937e5c31af7Sopenharmony_ci 938e5c31af7Sopenharmony_ci/** Destructor. 939e5c31af7Sopenharmony_ci * 940e5c31af7Sopenharmony_ci **/ 941e5c31af7Sopenharmony_ciTextureBarrierTests::~TextureBarrierTests() 942e5c31af7Sopenharmony_ci{ 943e5c31af7Sopenharmony_ci} 944e5c31af7Sopenharmony_ci 945e5c31af7Sopenharmony_ci/** Initializes the texture_barrier test group. 946e5c31af7Sopenharmony_ci * 947e5c31af7Sopenharmony_ci **/ 948e5c31af7Sopenharmony_civoid TextureBarrierTests::init(void) 949e5c31af7Sopenharmony_ci{ 950e5c31af7Sopenharmony_ci addChild(new TextureBarrierDisjointTexels(m_context, m_api, "disjoint-texels")); 951e5c31af7Sopenharmony_ci addChild(new TextureBarrierOverlappingTexels(m_context, m_api, "overlapping-texels")); 952e5c31af7Sopenharmony_ci addChild(new TextureBarrierSameTexelRW(m_context, m_api, "same-texel-rw")); 953e5c31af7Sopenharmony_ci addChild(new TextureBarrierSameTexelRWMultipass(m_context, m_api, "same-texel-rw-multipass")); 954e5c31af7Sopenharmony_ci} 955e5c31af7Sopenharmony_ci} /* glcts namespace */ 956