• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2022-2022 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 /*!
21  * \file  esextcesextcFragmentShadingRateCombinedTests.hpp
22  * \brief FragmentShadingRateEXT combined tests
23  */ /*-------------------------------------------------------------------*/
24 
25 #include "esextcFragmentShadingRateCombinedTests.hpp"
26 #include "deRandom.h"
27 #include "esextcFragmentShadingRateTests.hpp"
28 #include "gluContextInfo.hpp"
29 #include "gluDefs.hpp"
30 #include "gluShaderProgram.hpp"
31 #include "glwEnums.hpp"
32 #include "glwFunctions.hpp"
33 #include "tcuTestLog.hpp"
34 
35 #define TRIANGLE_COUNT 100
36 constexpr deUint32 kShadingRateCount = 16;
37 
38 namespace glcts
39 {
40 
41 /// check combiner is trivial operation or not
42 ///
43 /// @param combineOp combiner which want to check
44 ///
45 /// @return true for trivial combiner
isTrivialCombiner(glw::GLenum combineOp)46 bool isTrivialCombiner(glw::GLenum combineOp)
47 {
48 	return ((combineOp == GL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_EXT) ||
49 			(combineOp == GL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_EXT)) ?
50 			   true :
51 			   false;
52 }
53 
54 /// Constructor
55 ///
56 /// @param context     Test context
57 /// @param extParams   Extension Parameter
58 /// @param testcaseParam Test case Parameter
59 /// @param name        Test case's name
60 /// @param description Test case's description
FragmentShadingRateCombined(Context & context,const ExtParameters & extParams,const FragmentShadingRateCombined::TestcaseParam & testcaseParam,const char * name,const char * description)61 FragmentShadingRateCombined::FragmentShadingRateCombined(
62 	Context& context, const ExtParameters& extParams, const FragmentShadingRateCombined::TestcaseParam& testcaseParam,
63 	const char* name, const char* description)
64 	: TestCaseBase(context, extParams, name, description)
65 	, m_tcParam(testcaseParam)
66 	, m_renderProgram(nullptr)
67 	, m_computeProgram(nullptr)
68 	, m_to_id(0)
69 	, m_sr_to_id(0)
70 	, m_fbo_id(0)
71 	, m_vbo_id(0)
72 	, m_simulationCache(kShadingRateCount * kShadingRateCount * kShadingRateCount, 0xFFFFFFFF)
73 {
74 }
75 
76 /// Initialize test
init(void)77 void FragmentShadingRateCombined::init(void)
78 {
79 	TestCaseBase::init();
80 
81 	// Skip if required extensions are not supported.
82 	if (!m_is_fragment_shading_rate_supported)
83 	{
84 		throw tcu::NotSupportedError(FRAGMENT_SHADING_RATE_NOT_SUPPORTED, "", __FILE__, __LINE__);
85 	}
86 
87 	if (!m_is_fragment_shading_rate_primitive_supported)
88 	{
89 		if (m_tcParam.useShadingRatePrimitive)
90 		{
91 			throw tcu::NotSupportedError(FRAGMENT_SHADING_RATE_NOT_SUPPORTED, "", __FILE__, __LINE__);
92 		}
93 
94 		if (m_tcParam.combinerOp0 != GL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_EXT)
95 		{
96 			throw tcu::NotSupportedError(FRAGMENT_SHADING_RATE_NOT_SUPPORTED, "", __FILE__, __LINE__);
97 		}
98 	}
99 
100 	if (!m_is_fragment_shading_rate_attachment_supported)
101 	{
102 		if (m_tcParam.useShadingRateAttachment)
103 		{
104 			throw tcu::NotSupportedError(FRAGMENT_SHADING_RATE_NOT_SUPPORTED, "", __FILE__, __LINE__);
105 		}
106 
107 		if (m_tcParam.combinerOp1 != GL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_EXT)
108 		{
109 			throw tcu::NotSupportedError(FRAGMENT_SHADING_RATE_NOT_SUPPORTED, "", __FILE__, __LINE__);
110 		}
111 	}
112 
113 	if (!isTrivialCombiner(m_tcParam.combinerOp0) || !isTrivialCombiner(m_tcParam.combinerOp1))
114 	{
115 		const glw::Functions& gl						= m_context.getRenderContext().getFunctions();
116 		glw::GLboolean		  supportNonTrivialCombiner = false;
117 		gl.getBooleanv(GL_FRAGMENT_SHADING_RATE_NON_TRIVIAL_COMBINERS_SUPPORTED_EXT, &supportNonTrivialCombiner);
118 		GLU_EXPECT_NO_ERROR(gl.getError(), "Error getBooleanv non trivial combiner");
119 
120 		if (!supportNonTrivialCombiner)
121 		{
122 			throw tcu::NotSupportedError("Non trivial combiner is not supported", "", __FILE__, __LINE__);
123 		}
124 	}
125 }
126 
127 /// Deinitializes all GLES objects created for the test.
deinit(void)128 void FragmentShadingRateCombined::deinit(void)
129 {
130 	// Retrieve GLES entry points.
131 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
132 
133 	// Reset GLES state
134 	gl.bindTexture(GL_TEXTURE_2D, 0);
135 	gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
136 	gl.bindBuffer(GL_ARRAY_BUFFER, 0);
137 	gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
138 
139 	gl.deleteTextures(1, &m_to_id);
140 	gl.deleteFramebuffers(1, &m_fbo_id);
141 	gl.deleteBuffers(1, &m_vbo_id);
142 
143 	if (m_tcParam.useShadingRateAttachment)
144 	{
145 		gl.deleteTextures(1, &m_sr_to_id);
146 	}
147 
148 	delete m_renderProgram;
149 	delete m_computeProgram;
150 
151 	// Deinitialize base class
152 	TestCaseBase::deinit();
153 }
154 
155 /// Generate Vertex Shader string
genVS()156 std::string FragmentShadingRateCombined::genVS()
157 {
158 	std::ostringstream os;
159 	os << "#version 310 es                        \n"
160 	   << "#extension GL_EXT_fragment_shading_rate : enable\n"
161 	   << "precision highp float;                 \n"
162 	   << "precision highp int;                   \n"
163 	   << "layout(location = 0) in vec4 position; \n"
164 	   << "uniform int primShadingRate;           \n"
165 	   << "void main() {                          \n"
166 	   << "    gl_Position = position;            \n";
167 
168 	if (m_tcParam.useShadingRatePrimitive)
169 	{
170 		os << "    gl_PrimitiveShadingRateEXT = primShadingRate;\n";
171 	}
172 	os << "}";
173 	return os.str();
174 }
175 
176 /// Generate Fragment Shader string
genFS()177 std::string FragmentShadingRateCombined::genFS()
178 {
179 	std::ostringstream os;
180 	os << "#version 310 es\n"
181 	   << "#extension GL_EXT_fragment_shading_rate : enable\n"
182 	   << "precision highp float;\n"
183 	   << "precision highp int;\n"
184 	   << "layout(location = 0) out vec4 color0;\n"
185 	   << "uniform int primID;\n"
186 	   << "uniform int drawID;\n"
187 	   << "void main() {\n"
188 	   << "    color0.x = float(gl_ShadingRateEXT);\n"
189 	   << "    color0.y = float(drawID);\n";
190 
191 	if (m_tcParam.useShadingRatePrimitive)
192 	{
193 		os << "    color0.z = float(primID);\n";
194 	};
195 
196 	os << "    color0.w = 0.0;\n"
197 	   << "}";
198 
199 	return os.str();
200 }
201 
202 /// Generate Compute Shader string for copy
genCS()203 std::string FragmentShadingRateCombined::genCS()
204 {
205 	deUint32		   samples = m_tcParam.msaa ? 4 : 1;
206 	std::ostringstream os;
207 	os << "#version 310 es\n"
208 	   << "precision highp float;\n"
209 	   << "precision highp int;\n"
210 	   << (m_tcParam.msaa ? "uniform highp sampler2DMS colorTex;\n" : "uniform highp sampler2D colorTex;\n")
211 	   << "layout (binding = 0, std430) buffer ColorBuf {\n"
212 	   << "    uvec4 values[];\n"
213 	   << "} colorbuf;\n"
214 	   << "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
215 	   << "void main()\n"
216 	   << "{\n"
217 	   << "    for (uint i = 0u; i < " << samples << "u; ++i) \n"
218 	   << "    {\n"
219 	   << "        uint index = ((gl_GlobalInvocationID.y * " << m_tcParam.framebufferSize
220 	   << "u) + gl_GlobalInvocationID.x) * " << samples << "u + i;\n"
221 	   << "        colorbuf.values[index] = uvec4(round(texelFetch(colorTex, ivec2(gl_GlobalInvocationID.xy), "
222 	   << "int(i))));\n"
223 	   << "    }\n"
224 	   << "}";
225 	return os.str();
226 }
227 
228 /// Initializes all GLES objects and reference values for the test.
setupTest(void)229 void FragmentShadingRateCombined::setupTest(void)
230 {
231 	m_renderProgram =
232 		new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(genVS().c_str(), genFS().c_str()));
233 
234 	if (!m_renderProgram->isOk())
235 	{
236 		m_testCtx.getLog() << tcu::TestLog::Message << "" << tcu::TestLog::EndMessage
237 						   << tcu::TestLog::ShaderProgram(false, "")
238 						   << tcu::TestLog::Shader(QP_SHADER_TYPE_VERTEX,
239 												   m_renderProgram->getShaderInfo(glu::SHADERTYPE_VERTEX, 0).source,
240 												   false,
241 												   m_renderProgram->getShaderInfo(glu::SHADERTYPE_VERTEX, 0).infoLog)
242 
243 						   << tcu::TestLog::Shader(QP_SHADER_TYPE_FRAGMENT,
244 												   m_renderProgram->getShaderInfo(glu::SHADERTYPE_FRAGMENT, 0).source,
245 												   false,
246 												   m_renderProgram->getShaderInfo(glu::SHADERTYPE_FRAGMENT, 0).infoLog)
247 						   << tcu::TestLog::EndShaderProgram;
248 		TCU_FAIL("Shader creation failed");
249 	}
250 
251 	glu::ProgramSources sourcesCompute;
252 	sourcesCompute.sources[glu::SHADERTYPE_COMPUTE].push_back(genCS());
253 	m_computeProgram = new glu::ShaderProgram(m_context.getRenderContext(), sourcesCompute);
254 	if (!m_computeProgram->isOk())
255 	{
256 		m_testCtx.getLog() << tcu::TestLog::Message << "" << tcu::TestLog::EndMessage
257 						   << tcu::TestLog::ShaderProgram(false, "")
258 						   << tcu::TestLog::Shader(QP_SHADER_TYPE_COMPUTE,
259 												   m_computeProgram->getShaderInfo(glu::SHADERTYPE_COMPUTE, 0).source,
260 												   false,
261 												   m_computeProgram->getShaderInfo(glu::SHADERTYPE_COMPUTE, 0).infoLog);
262 		TCU_FAIL("Shader creation failed");
263 	}
264 
265 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
266 
267 	// Generate framebuffer objects
268 	gl.genFramebuffers(1, &m_fbo_id);
269 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting up framebuffer objects");
270 
271 	gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
272 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding frame buffer object!");
273 
274 	// Generate texture objects
275 	gl.genTextures(1, &m_to_id);
276 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error generating texture objects");
277 
278 	gl.pixelStorei(GL_UNPACK_ALIGNMENT, 1);
279 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error set pixelStorei for unpack alignment");
280 
281 	// Allocate unsigned integer storage
282 	glw::GLenum textureTarget = GL_TEXTURE_2D;
283 	if (m_tcParam.msaa)
284 	{
285 		textureTarget = GL_TEXTURE_2D_MULTISAMPLE;
286 		gl.bindTexture(textureTarget, m_to_id);
287 		GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding texture object!");
288 		gl.texStorage2DMultisample(textureTarget, 4, GL_RGBA32F, m_tcParam.framebufferSize, m_tcParam.framebufferSize,
289 								   true);
290 		GLU_EXPECT_NO_ERROR(gl.getError(), "Error allocating texture object!");
291 	}
292 	else
293 	{
294 		gl.bindTexture(textureTarget, m_to_id);
295 		GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding texture object!");
296 		gl.texStorage2D(textureTarget, 1, GL_RGBA32F, m_tcParam.framebufferSize, m_tcParam.framebufferSize);
297 		GLU_EXPECT_NO_ERROR(gl.getError(), "Error allocating texture object!");
298 	}
299 
300 	// Attach it to the framebuffer
301 	gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureTarget, m_to_id, 0); /* level */
302 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error attaching texture to frame buffer");
303 
304 	if (m_tcParam.useShadingRateAttachment)
305 	{
306 		// generate shading rate texture
307 		gl.getIntegerv(GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT, &m_srTexelWidth);
308 		GLU_EXPECT_NO_ERROR(gl.getError(),
309 							"Error getIntegerv GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT!");
310 		gl.getIntegerv(GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_HEIGHT_EXT, &m_srTexelHeight);
311 		GLU_EXPECT_NO_ERROR(gl.getError(),
312 							"Error getIntegerv GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_HEIGHT_EXT!");
313 
314 		const deUint32 srWidth	= (m_tcParam.framebufferSize + m_srTexelWidth - 1) / m_srTexelWidth;
315 		const deUint32 srHeight = (m_tcParam.framebufferSize + m_srTexelHeight - 1) / m_srTexelHeight;
316 
317 		gl.genTextures(1, &m_sr_to_id);
318 		GLU_EXPECT_NO_ERROR(gl.getError(), "Error generating texture objects");
319 
320 		// Allocate unsigned integer storage
321 		gl.bindTexture(GL_TEXTURE_2D, m_sr_to_id);
322 		GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding texture object!");
323 
324 		gl.texStorage2D(GL_TEXTURE_2D, 1, GL_R8UI, srWidth, srHeight);
325 		GLU_EXPECT_NO_ERROR(gl.getError(), "Error allocating texture object!");
326 
327 		std::vector<deUint8> attachmentShadingRateData;
328 		attachmentShadingRateData.reserve(srWidth * srHeight);
329 		for (deUint32 sry = 0; sry < srHeight; sry++)
330 		{
331 			for (deUint32 srx = 0; srx < srWidth; srx++)
332 			{
333 				deUint8 packedShadingRate =
334 					static_cast<unsigned char>(fsrutils::packShadingRate(translateCoordsToShadingRate(srx, sry)));
335 				attachmentShadingRateData.push_back(packedShadingRate);
336 			}
337 		}
338 
339 		gl.texSubImage2D(GL_TEXTURE_2D, 0, 0, 0, srWidth, srHeight, GL_RED_INTEGER, GL_UNSIGNED_BYTE,
340 						 attachmentShadingRateData.data());
341 		GLU_EXPECT_NO_ERROR(gl.getError(), "Error updating shading rate data to texture");
342 
343 		// Attach it to the framebuffer
344 		gl.framebufferShadingRateEXT(GL_FRAMEBUFFER, GL_SHADING_RATE_ATTACHMENT_EXT, m_sr_to_id, 0, 1, m_srTexelWidth,
345 									 m_srTexelHeight);
346 		GLU_EXPECT_NO_ERROR(gl.getError(), "Error attaching shading rate attachment to frame buffer");
347 	}
348 
349 	constexpr deUint32 kVerticesCount = (TRIANGLE_COUNT * 3 * 2);
350 	float			   randomVertices[kVerticesCount];
351 
352 	deRandom rnd;
353 	deRandom_init(&rnd, 0);
354 	for (deUint32 i = 0; i < kVerticesCount; i++)
355 	{
356 		randomVertices[i] = deRandom_getFloat(&rnd) * 2.0f - 1.0f;
357 	}
358 
359 	gl.genBuffers(1, &m_vbo_id);
360 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting up buffer objects");
361 
362 	gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo_id);
363 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding buffer objects");
364 
365 	gl.bufferData(GL_ARRAY_BUFFER, sizeof(randomVertices), randomVertices, GL_STATIC_DRAW);
366 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error uploading buffer data");
367 }
368 
369 /// Executes the test.
370 /// Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
371 /// Note the function throws exception should an error occur!
372 ///
373 /// @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
iterate(void)374 tcu::TestNode::IterateResult FragmentShadingRateCombined::iterate(void)
375 {
376 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
377 
378 	// Initialization
379 	const deUint32	   sampleCount = m_tcParam.msaa ? 4 : 1;
380 	constexpr deUint32 kMaxRateCount =
381 		16; // SHADING_RATE_1X1_PIXELS_EXT ~ SHADING_RATE_4X4_PIXELS_EXT, actually 9 is enough
382 	glw::GLenum	 shadingRates[kMaxRateCount];
383 	glw::GLsizei count = 0;
384 
385 	gl.getFragmentShadingRatesEXT(sampleCount, kMaxRateCount, &count, shadingRates);
386 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error to get shading rate getFragmentShadingRatesEXT");
387 	DE_ASSERT(count > 0);
388 
389 	for (glw::GLsizei i = 0; i < count; i++)
390 	{
391 		m_availableShadingRates.push_back(shadingRates[i]);
392 	}
393 
394 	setupTest();
395 
396 	gl.shadingRateEXT(GL_SHADING_RATE_1X1_PIXELS_EXT);
397 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error to set shadingRateEXT as default");
398 
399 	gl.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
400 	gl.clear(GL_COLOR_BUFFER_BIT);
401 
402 	gl.useProgram(m_renderProgram->getProgram());
403 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error use program");
404 
405 	gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo_id);
406 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error bind buffer vertex data");
407 
408 	gl.enableVertexAttribArray(0);
409 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error enabling vertex attrib pointer 0");
410 
411 	gl.vertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, nullptr);
412 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex attrib pointer 0");
413 
414 	// primitive ID start from 1
415 	for (deUint32 drawID = 1; drawID < TRIANGLE_COUNT; drawID++)
416 	{
417 		const deUint32 primID			 = getPrimitiveID(drawID);
418 		const deUint32 packedShadingRate = fsrutils::packShadingRate(translatePrimIDToShadingRate(primID));
419 		gl.uniform1i(gl.getUniformLocation(m_renderProgram->getProgram(), "primShadingRate"), packedShadingRate);
420 		GLU_EXPECT_NO_ERROR(gl.getError(), "Error set uniform shadingRate value");
421 
422 		gl.uniform1i(gl.getUniformLocation(m_renderProgram->getProgram(), "primID"), primID);
423 		GLU_EXPECT_NO_ERROR(gl.getError(), "Error set uniform primID value");
424 
425 		gl.uniform1i(gl.getUniformLocation(m_renderProgram->getProgram(), "drawID"), drawID);
426 		GLU_EXPECT_NO_ERROR(gl.getError(), "Error set uniform drawID value");
427 
428 		if (m_tcParam.useShadingRateAPI)
429 		{
430 			gl.shadingRateEXT(translateDrawIDToShadingRate(drawID));
431 			GLU_EXPECT_NO_ERROR(gl.getError(), "Error set shading rate");
432 		}
433 
434 		gl.shadingRateCombinerOpsEXT(m_tcParam.combinerOp0, m_tcParam.combinerOp1);
435 		GLU_EXPECT_NO_ERROR(gl.getError(), "Error set Shading Rate combiner operations");
436 
437 		gl.drawArrays(GL_TRIANGLES, drawID * 2, 3);
438 		GLU_EXPECT_NO_ERROR(gl.getError(), "Error draw a triangle");
439 	}
440 
441 	constexpr deUint32 kChannels = 4;
442 	const deUint32	   dataSize =
443 		m_tcParam.framebufferSize * m_tcParam.framebufferSize * sampleCount * sizeof(deUint32) * kChannels;
444 
445 	// Copy the result color buffer to shader storage buffer to access for the msaa case
446 	glw::GLuint ssbo_id;
447 	gl.genBuffers(1, &ssbo_id);
448 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error generate buffer object");
449 
450 	gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_id);
451 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error bind buffer object");
452 
453 	gl.bufferData(GL_SHADER_STORAGE_BUFFER, dataSize, nullptr, GL_DYNAMIC_COPY);
454 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error allocate buffer object");
455 
456 	gl.useProgram(m_computeProgram->getProgram());
457 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error use compute object");
458 
459 	gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo_id);
460 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error bind buffer object to program");
461 
462 	gl.uniform1i(gl.getUniformLocation(m_renderProgram->getProgram(), "colorTex"), 0);
463 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error bind set colorTex uniform value");
464 
465 	glw::GLenum textureTarget = GL_TEXTURE_2D;
466 	if (m_tcParam.msaa)
467 	{
468 		textureTarget = GL_TEXTURE_2D_MULTISAMPLE;
469 	}
470 
471 	gl.bindTexture(textureTarget, m_to_id);
472 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error bind texture");
473 
474 	gl.dispatchCompute(m_tcParam.framebufferSize, m_tcParam.framebufferSize, 1);
475 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error dispatching copy compute program");
476 
477 	gl.flush();
478 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error for flushing");
479 
480 	const deUint32* resPtr =
481 		static_cast<const deUint32*>(gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, dataSize, GL_MAP_READ_BIT));
482 	for (deInt32 y = 0; y < m_tcParam.framebufferSize; y++)
483 	{
484 		for (deInt32 x = 0; x < m_tcParam.framebufferSize; x++)
485 		{
486 			for (deUint32 s = 0; s < sampleCount; s++)
487 			{
488 				const deUint32	index  = ((y * m_tcParam.framebufferSize + x) * sampleCount + s) * kChannels;
489 				const deUint32* sample = &resPtr[index];
490 				if (sample[1] == 0) // nothing rendered
491 				{
492 					continue;
493 				}
494 
495 				const deUint32 shadingRate			   = sample[0];
496 				const deUint32 drawID				   = sample[1];
497 				const deUint32 primID				   = sample[2];
498 				const deUint32 expectedShadingRateMask = simulate(drawID, primID, x, y);
499 				if (!(expectedShadingRateMask & (1 << shadingRate)))
500 				{
501 					std::stringstream error_sstream;
502 
503 					error_sstream << "The draw ID is " << drawID << "The primitive ID is " << primID
504 								  << "Shading Rate is" << shadingRate << ", But we expect one mask of "
505 								  << expectedShadingRateMask;
506 
507 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, error_sstream.str().c_str());
508 
509 					gl.deleteBuffers(1, &ssbo_id);
510 					return STOP;
511 				}
512 			}
513 		}
514 	}
515 
516 	gl.deleteBuffers(1, &ssbo_id);
517 
518 	/* All done */
519 	if (m_testCtx.getTestResult() != QP_TEST_RESULT_FAIL)
520 	{
521 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
522 	}
523 
524 	return STOP;
525 }
526 
527 /// Translate Primitive ID to ShadingRate enumeration
528 ///
529 /// @param primID primitive ID to translate shading rate
530 ///
531 /// @return shading rate enumeration
translateDrawIDToShadingRate(deUint32 drawID) const532 glw::GLenum FragmentShadingRateCombined::translateDrawIDToShadingRate(deUint32 drawID) const
533 {
534 	return m_availableShadingRates[drawID % m_availableShadingRates.size()];
535 }
536 
537 /// Translate Primitive ID to ShadingRate enumeration
538 ///
539 /// @param primID primitive ID to translate shading rate
540 ///
541 /// @return shading rate enumeration
translatePrimIDToShadingRate(deUint32 primID) const542 glw::GLenum FragmentShadingRateCombined::translatePrimIDToShadingRate(deUint32 primID) const
543 {
544 	return m_availableShadingRates[(primID * 7) % m_availableShadingRates.size()];
545 }
546 
547 /// Translate Coordinates ID to ShadingRate enumeration
548 ///
549 ///@param srx x coord in the shading rate attachment to translate shading rate
550 ///@param sry y coord in the shading rate attachment to translate shading rate
551 ///
552 ///@return shading rate enumeration
translateCoordsToShadingRate(deUint32 srx,deUint32 sry) const553 glw::GLenum FragmentShadingRateCombined::translateCoordsToShadingRate(deUint32 srx, deUint32 sry) const
554 {
555 	return m_availableShadingRates[(srx + sry) % m_availableShadingRates.size()];
556 }
557 
558 /// getPrimitiveID from drawID
559 ///
560 /// @param drawID draw ID to translate
561 ///
562 /// @return primitive ID
getPrimitiveID(deUint32 drawID) const563 deUint32 FragmentShadingRateCombined::getPrimitiveID(deUint32 drawID) const
564 {
565 	return drawID + 1;
566 }
567 
568 /// Map an extent to a mask of all modes smaller than or equal to it in either dimension
569 ///
570 /// @param ext extent to get available shading rate mask
571 /// @param allowSwap swap allowable between width and height
572 ///
573 /// @return shifted mask which is shifted from all candidate rates
shadingRateExtentToClampedMask(Extent2D ext,bool allowSwap) const574 deUint32 FragmentShadingRateCombined::shadingRateExtentToClampedMask(Extent2D ext, bool allowSwap) const
575 {
576 	deUint32 desiredSize = ext.width * ext.height;
577 
578 	deUint32 mask = 0;
579 
580 	while (desiredSize > 0)
581 	{
582 		// First, find modes that maximize the area
583 		for (deUint32 i = 0; i < m_availableShadingRates.size(); ++i)
584 		{
585 			deUint32 packedShadingRate = fsrutils::packShadingRate(m_availableShadingRates[i]);
586 			Extent2D fragmentSize	   = packedShadingRateToExtent(packedShadingRate);
587 
588 			if (fragmentSize.width * fragmentSize.height == desiredSize &&
589 				((fragmentSize.width <= ext.width && fragmentSize.height <= ext.height) ||
590 				 (fragmentSize.height <= ext.width && fragmentSize.width <= ext.height && allowSwap)))
591 			{
592 				deUint32 candidate = (deCtz32(fragmentSize.width) << 2) | deCtz32(fragmentSize.height);
593 				mask |= 1 << candidate;
594 			}
595 		}
596 		if (mask)
597 		{
598 			// Amongst the modes that maximize the area, pick the ones that
599 			// minimize the aspect ratio. Prefer ratio of 1, then 2, then 4.
600 			// 1x1 = 0, 2x2 = 5, 4x4 = 10
601 			static const deUint32 aspectMaskRatio1 = 0x421;
602 			// 2x1 = 4, 1x2 = 1, 4x2 = 9, 2x4 = 6
603 			static const deUint32 aspectMaskRatio2 = 0x252;
604 			// 4x1 = 8, 1x4 = 2,
605 			static const deUint32 aspectMaskRatio4 = 0x104;
606 
607 			if (mask & aspectMaskRatio1)
608 			{
609 				mask &= aspectMaskRatio1;
610 				break;
611 			}
612 			if (mask & aspectMaskRatio2)
613 			{
614 				mask &= aspectMaskRatio2;
615 				break;
616 			}
617 			if (mask & aspectMaskRatio4)
618 			{
619 				mask &= aspectMaskRatio4;
620 				break;
621 			}
622 			DE_ASSERT(0);
623 		}
624 		desiredSize /= 2;
625 	}
626 
627 	return mask;
628 }
629 
630 /// Software simulate to compare with GPU result
631 ///
632 /// @param drawID draw ID
633 /// @param primID primitive ID
634 /// @param x fragment coordinates X
635 /// @param y fragment coordinates Y
636 ///
637 /// @return shifted mask which is shifted from all candidate rates
simulate(deUint32 drawID,deUint32 primID,deUint32 x,deUint32 y)638 deUint32 FragmentShadingRateCombined::simulate(deUint32 drawID, deUint32 primID, deUint32 x, deUint32 y)
639 {
640 
641 	const deUint32 rate0 =
642 		m_tcParam.useShadingRateAPI ? fsrutils::packShadingRate(translateDrawIDToShadingRate(drawID)) : 0;
643 	const deUint32 rate1 =
644 		m_tcParam.useShadingRatePrimitive ? fsrutils::packShadingRate(translatePrimIDToShadingRate(primID)) : 0;
645 	const deUint32 rate2 =
646 		m_tcParam.useShadingRateAttachment ?
647 			fsrutils::packShadingRate(translateCoordsToShadingRate(x / m_srTexelWidth, y / m_srTexelWidth)) :
648 			0;
649 
650 	deUint32& cachedRate = m_simulationCache[(rate2 * kShadingRateCount + rate1) * kShadingRateCount + rate0];
651 	if (cachedRate != 0xFFFFFFFF)
652 	{
653 		return cachedRate;
654 	}
655 
656 	const Extent2D extent0 = packedShadingRateToExtent(rate0);
657 	const Extent2D extent1 = packedShadingRateToExtent(rate1);
658 	const Extent2D extent2 = packedShadingRateToExtent(rate2);
659 
660 	deUint32		  finalMask = 0;
661 	std::vector<bool> allowSwaps{ false, true };
662 	// Simulate once for implementations that don't allow swapping rate xy,
663 	// and once for those that do. Any of those results is allowed.
664 	for (bool allowSwap : allowSwaps)
665 	{
666 		// Combine rate 0 and 1, get a mask of possible clamped rates
667 		Extent2D intermediate	  = combine(extent0, extent1, m_tcParam.combinerOp0);
668 		deUint32 intermediateMask = shadingRateExtentToClampedMask(intermediate, allowSwap);
669 
670 		// For each clamped rate, combine that with rate 2 and accumulate the possible clamped rates
671 		for (deUint32 i = 0; i < kShadingRateCount; ++i)
672 		{
673 			if (intermediateMask & (1 << i))
674 			{
675 				Extent2D final = combine(packedShadingRateToExtent(i), extent2, m_tcParam.combinerOp1);
676 				finalMask |= shadingRateExtentToClampedMask(final, allowSwap);
677 			}
678 		}
679 		{
680 			// unclamped intermediate value is also permitted
681 			Extent2D final = combine(intermediate, extent2, m_tcParam.combinerOp1);
682 			finalMask |= shadingRateExtentToClampedMask(final, allowSwap);
683 		}
684 	}
685 
686 	cachedRate = finalMask;
687 
688 	return finalMask;
689 }
690 
691 /// translate packed rate to Extent
692 ///
693 /// @param packedRate packed with (log(width) << 2 | log(height))
694 ///
695 /// @return shading rate Extent
packedShadingRateToExtent(deUint32 packedRate) const696 FragmentShadingRateCombined::Extent2D FragmentShadingRateCombined::packedShadingRateToExtent(deUint32 packedRate) const
697 {
698 	Extent2D ret = { static_cast<deUint32>(1 << ((packedRate / 4) & 3)), static_cast<deUint32>(1 << (packedRate & 3)) };
699 
700 	return ret;
701 }
702 
703 /// combine the two extent with given combine operation
704 ///
705 /// @param extent0 extent0
706 /// @param extent1 extent1
707 /// @param combineOp combination operation
708 ///
709 /// @return combined extent
combine(Extent2D extent0,Extent2D extent1,glw::GLenum combineOp) const710 FragmentShadingRateCombined::Extent2D FragmentShadingRateCombined::combine(Extent2D extent0, Extent2D extent1,
711 																		   glw::GLenum combineOp) const
712 {
713 	Extent2D resultExtent;
714 
715 	switch (combineOp)
716 	{
717 	case GL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_EXT:
718 		return extent0;
719 	case GL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_EXT:
720 		return extent1;
721 	case GL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_EXT:
722 		resultExtent.width	= std::min(extent0.width, extent1.width);
723 		resultExtent.height = std::min(extent0.height, extent1.height);
724 		break;
725 	case GL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_EXT:
726 		resultExtent.width	= std::max(extent0.width, extent1.width);
727 		resultExtent.height = std::max(extent0.height, extent1.height);
728 		break;
729 	case GL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_EXT:
730 		resultExtent.width	= extent0.width * extent1.width;
731 		resultExtent.height = extent0.height * extent1.height;
732 		break;
733 	}
734 
735 	return resultExtent;
736 }
737 
738 } // namespace glcts
739