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