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 esextcFragmentShadingRateAttachmentTests.hpp
22 * \brief FragmentShadingRateEXT Attachment related tests
23 */ /*-------------------------------------------------------------------*/
24
25 #include "esextcFragmentShadingRateAttachmentTests.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
37 namespace glcts
38 {
39
40 /// Constructor
41 ///
42 /// @param context Test context
43 /// @param extParams extension params
44 /// @param testcaseParam Test case params
45 /// @param name Test case's name
46 /// @param description Test case's description
FragmentShadingRateAttachment(Context & context,const ExtParameters & extParams,const FragmentShadingRateAttachment::TestcaseParam & testcaseParam,const char * name,const char * description)47 FragmentShadingRateAttachment::FragmentShadingRateAttachment(
48 Context &context, const ExtParameters &extParams, const FragmentShadingRateAttachment::TestcaseParam &testcaseParam,
49 const char *name, const char *description)
50 : TestCaseBase(context, extParams, name, description)
51 , m_tcParam(testcaseParam)
52 , m_program(nullptr)
53 {
54 }
55
56 /// Initialize test
init(void)57 void FragmentShadingRateAttachment::init(void)
58 {
59 TestCaseBase::init();
60
61 // Skip if required extensions are not supported.
62 if (!m_is_fragment_shading_rate_supported)
63 {
64 throw tcu::NotSupportedError(FRAGMENT_SHADING_RATE_NOT_SUPPORTED, "", __FILE__, __LINE__);
65 }
66
67 if (!m_is_fragment_shading_rate_attachment_supported)
68 {
69 if (m_tcParam.attachmentShadingRate)
70 {
71 throw tcu::NotSupportedError(FRAGMENT_SHADING_RATE_NOT_SUPPORTED, "", __FILE__, __LINE__);
72 }
73
74 if (m_tcParam.multiShadingRate)
75 {
76 throw tcu::NotSupportedError(FRAGMENT_SHADING_RATE_NOT_SUPPORTED, "", __FILE__, __LINE__);
77 }
78 }
79
80 if (!m_is_multiview_ovr_supported)
81 {
82 throw tcu::NotSupportedError(MULTIVIEW_OVR_NOT_SUPPORTED, "", __FILE__, __LINE__);
83 }
84 }
85
86 /// Deinitializes all GLES objects created for the test.
deinit(void)87 void FragmentShadingRateAttachment::deinit(void)
88 {
89 // Retrieve GLES entry points.
90 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
91
92 // Reset GLES state
93 gl.bindTexture(GL_TEXTURE_2D, 0);
94 gl.bindBuffer(GL_ARRAY_BUFFER, 0);
95 gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
96
97 gl.deleteTextures(1, &m_to_id);
98 gl.deleteFramebuffers(1, &m_fbo_id);
99 gl.deleteBuffers(1, &m_vbo_id);
100
101 delete m_program;
102
103 // Deinitialize base class
104 TestCaseBase::deinit();
105 }
106
107 /// Generate Vertex Shader string
genVS() const108 std::string FragmentShadingRateAttachment::genVS() const
109 {
110 std::ostringstream os;
111 os << "#version 310 es\n";
112
113 if (m_tcParam.testKind == TestKind::MultiView)
114 {
115 os << "#extension GL_OVR_multiview: enable\n"
116 "layout(num_views = 2) in;\n";
117 }
118
119 os << "precision highp float;\n"
120 << "precision highp int;\n"
121 << "uniform int drawID;\n"
122 << "layout(location = 0) in vec4 position;\n"
123 << "void main() {\n"
124 << " gl_Position = position;\n";
125 if (m_tcParam.testKind == TestKind::MultiView)
126 {
127 os << "if (gl_ViewID_OVR == 1u) {\n"
128 << "gl_Position.x += 0.1;\n"
129 << "}\n";
130 }
131 os << "}";
132 return os.str();
133 }
134
135 /// Generate Fragment Shader string
genFS() const136 std::string FragmentShadingRateAttachment::genFS() const
137 {
138 std::ostringstream os;
139 os << "#version 310 es\n"
140 << "#extension GL_EXT_fragment_shading_rate : enable\n"
141 << "precision highp float;\n"
142 << "precision highp int;\n"
143 << "layout(location = 0) out ivec4 color0;\n"
144 << "uniform int drawID;\n"
145 << "void main() {\n"
146 << " color0.x = gl_ShadingRateEXT;\n"
147 << " color0.y = drawID;\n"
148 << " color0.z = 0;\n"
149 << " color0.w = 0;\n"
150 << "}";
151
152 return os.str();
153 }
154
155 /// Initializes all GLES objects and reference values for the test.
setupTest(void)156 void FragmentShadingRateAttachment::setupTest(void)
157 {
158 m_program =
159 new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(genVS().c_str(), genFS().c_str()));
160
161 if (!m_program->isOk())
162 {
163 m_testCtx.getLog() << tcu::TestLog::Message << "" << tcu::TestLog::EndMessage
164 << tcu::TestLog::ShaderProgram(false, "")
165 << tcu::TestLog::Shader(QP_SHADER_TYPE_VERTEX,
166 m_program->getShaderInfo(glu::SHADERTYPE_VERTEX, 0).source, false,
167 m_program->getShaderInfo(glu::SHADERTYPE_VERTEX, 0).infoLog)
168
169 << tcu::TestLog::Shader(QP_SHADER_TYPE_FRAGMENT,
170 m_program->getShaderInfo(glu::SHADERTYPE_FRAGMENT, 0).source, false,
171 m_program->getShaderInfo(glu::SHADERTYPE_FRAGMENT, 0).infoLog)
172 << tcu::TestLog::EndShaderProgram;
173 TCU_FAIL("Shader creation failed");
174 }
175
176 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
177
178 // Generate framebuffer objects
179 gl.genFramebuffers(1, &m_fbo_id);
180 GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting up framebuffer objects");
181
182 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
183 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding frame buffer object!");
184
185 // Generate a new texture name
186 gl.genTextures(1, &m_to_id);
187 GLU_EXPECT_NO_ERROR(gl.getError(), "Error generating texture objects");
188
189 if (m_tcParam.layerCount > 1)
190 {
191 // Allocate unsigned integer storage
192 gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_to_id);
193 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding texture object!");
194
195 gl.texStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA32UI, m_tcParam.framebufferSize, m_tcParam.framebufferSize,
196 m_tcParam.layerCount);
197 GLU_EXPECT_NO_ERROR(gl.getError(), "Error allocating texture object!");
198 }
199 else
200 {
201 // Allocate unsigned integer storage
202 gl.bindTexture(GL_TEXTURE_2D, m_to_id);
203 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding texture object!");
204
205 gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32UI, m_tcParam.framebufferSize, m_tcParam.framebufferSize);
206 GLU_EXPECT_NO_ERROR(gl.getError(), "Error allocating texture object!");
207 }
208
209 // Attach it to the framebuffer
210 if (m_tcParam.testKind == TestKind::MultiView)
211 {
212 gl.framebufferTextureMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_to_id, 0, 0,
213 m_tcParam.layerCount);
214 GLU_EXPECT_NO_ERROR(gl.getError(), "Error attaching texture to frame buffer");
215 }
216 else
217 {
218 gl.framebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_to_id, 0);
219 GLU_EXPECT_NO_ERROR(gl.getError(), "Error attaching texture to frame buffer");
220 }
221
222 // Generate a shading rate texture name
223 if (m_tcParam.attachmentShadingRate)
224 {
225 // generate shading rate texture
226 gl.getIntegerv(GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT, &m_srTexelWidth);
227 GLU_EXPECT_NO_ERROR(gl.getError(),
228 "Error getIntegerv GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT!");
229 gl.getIntegerv(GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_HEIGHT_EXT, &m_srTexelHeight);
230 GLU_EXPECT_NO_ERROR(gl.getError(),
231 "Error getIntegerv GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_HEIGHT_EXT!");
232
233 const uint32_t srWidth = (m_tcParam.framebufferSize + m_srTexelWidth - 1) / m_srTexelWidth;
234 const uint32_t srHeight = (m_tcParam.framebufferSize + m_srTexelHeight - 1) / m_srTexelHeight;
235
236 std::vector<uint8_t> attachmentShadingRateData;
237 const uint32_t srLayerCount = m_tcParam.multiShadingRate ? 2 : 1;
238 attachmentShadingRateData.reserve(srWidth * srHeight * srLayerCount);
239 for (uint32_t srLayer = 0; srLayer < srLayerCount; srLayer++)
240 {
241 for (uint32_t y = 0; y < srHeight; y++)
242 {
243 for (uint32_t x = 0; x < srWidth; x++)
244 {
245 uint8_t packedShadingRate = static_cast<unsigned char>(
246 fsrutils::packShadingRate(translateCoordsToShadingRate(srLayer, x, y)));
247 attachmentShadingRateData.push_back(packedShadingRate);
248 }
249 }
250 }
251
252 gl.genTextures(1, &m_sr_to_id);
253 GLU_EXPECT_NO_ERROR(gl.getError(), "Error generating texture objects");
254 gl.pixelStorei(GL_UNPACK_ALIGNMENT, 1);
255 GLU_EXPECT_NO_ERROR(gl.getError(), "Error set pixelStorei for unpack alignment");
256
257 if (m_tcParam.multiShadingRate)
258 {
259 DE_ASSERT(m_tcParam.layerCount > 1);
260 // Allocate unsigned integer storage
261 gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_sr_to_id);
262 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding texture object!");
263
264 gl.texStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R8UI, srWidth, srHeight, m_tcParam.layerCount);
265 GLU_EXPECT_NO_ERROR(gl.getError(), "Error allocating texture object!");
266
267 gl.texSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, srWidth, srHeight, m_tcParam.layerCount, GL_RED_INTEGER,
268 GL_UNSIGNED_BYTE, attachmentShadingRateData.data());
269 GLU_EXPECT_NO_ERROR(gl.getError(), "Error updating shading rate data to texture");
270
271 // Attach it to the framebuffer
272 gl.framebufferShadingRateEXT(GL_FRAMEBUFFER, GL_SHADING_RATE_ATTACHMENT_EXT, m_sr_to_id, 0,
273 m_tcParam.layerCount, m_srTexelWidth, m_srTexelHeight);
274 GLU_EXPECT_NO_ERROR(gl.getError(), "Error framebufferShadingRate");
275 }
276 else
277 {
278 // Allocate unsigned integer storage
279 gl.bindTexture(GL_TEXTURE_2D, m_sr_to_id);
280 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding texture object!");
281
282 gl.texStorage2D(GL_TEXTURE_2D, 1, GL_R8UI, srWidth, srHeight);
283 GLU_EXPECT_NO_ERROR(gl.getError(), "Error allocating texture object!");
284
285 gl.texSubImage2D(GL_TEXTURE_2D, 0, 0, 0, srWidth, srHeight, GL_RED_INTEGER, GL_UNSIGNED_BYTE,
286 attachmentShadingRateData.data());
287 GLU_EXPECT_NO_ERROR(gl.getError(), "Error updating shading rate data to texture");
288
289 // Attach it to the framebuffer
290 gl.framebufferShadingRateEXT(GL_FRAMEBUFFER, GL_SHADING_RATE_ATTACHMENT_EXT, m_sr_to_id, 0, 1,
291 m_srTexelWidth, m_srTexelHeight);
292 GLU_EXPECT_NO_ERROR(gl.getError(), "Error framebufferShadingRate");
293 }
294 }
295
296 constexpr uint32_t kVerticesCount = (TRIANGLE_COUNT * 3 * 2);
297 std::vector<float> randomVertices;
298 randomVertices.reserve(kVerticesCount);
299
300 // 1st draw triangle is huge to fill all rect.
301 randomVertices.push_back(-3.0);
302 randomVertices.push_back(-3.0);
303 randomVertices.push_back(-3.0);
304 randomVertices.push_back(3.0);
305 randomVertices.push_back(3.0);
306 randomVertices.push_back(-3.0);
307
308 deRandom rnd;
309 deRandom_init(&rnd, 0);
310 for (uint32_t i = 0; i < kVerticesCount; i++)
311 {
312 randomVertices.push_back((deRandom_getFloat(&rnd) * 2.0f - 1.0f));
313 }
314
315 gl.genBuffers(1, &m_vbo_id);
316 GLU_EXPECT_NO_ERROR(gl.getError(), "Error generate buffer objects");
317
318 gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo_id);
319 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding buffer objects");
320
321 gl.bufferData(GL_ARRAY_BUFFER, randomVertices.size() * sizeof(float), randomVertices.data(), GL_STATIC_DRAW);
322 GLU_EXPECT_NO_ERROR(gl.getError(), "Error uploading buffer data");
323
324 if (m_tcParam.testKind == TestKind::Scissor)
325 {
326 m_scissorBox = {m_tcParam.framebufferSize / 3, m_tcParam.framebufferSize / 3, m_tcParam.framebufferSize / 3,
327 m_tcParam.framebufferSize / 3};
328 }
329 }
330
331 /// Executes the test.
332 /// Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
333 /// Note the function throws exception should an error occur!
334 ///
335 /// @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
336 ///
iterate(void)337 tcu::TestNode::IterateResult FragmentShadingRateAttachment::iterate(void)
338 {
339 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
340
341 // Initialization
342 constexpr uint32_t kMaxRateCount =
343 16; // SHADING_RATE_1X1_PIXELS_EXT ~ SHADING_RATE_4X4_PIXELS_EXT, actually 9 is enough
344 glw::GLenum shadingRates[kMaxRateCount];
345 glw::GLsizei count = 0;
346
347 gl.getFragmentShadingRatesEXT(1, kMaxRateCount, &count, shadingRates);
348 GLU_EXPECT_NO_ERROR(gl.getError(), "Error to get shading rate getFragmentShadingRatesEXT");
349 DE_ASSERT(count > 0);
350
351 for (glw::GLsizei i = 0; i < count; i++)
352 {
353 m_availableShadingRates.push_back(shadingRates[i]);
354 }
355
356 setupTest();
357
358 gl.disable(GL_DEPTH_TEST);
359
360 gl.shadingRateEXT(GL_SHADING_RATE_1X1_PIXELS_EXT);
361 GLU_EXPECT_NO_ERROR(gl.getError(), "Error to set shadingRateEXT as default");
362
363 gl.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
364 GLU_EXPECT_NO_ERROR(gl.getError(), "Error clear Color");
365
366 gl.clear(GL_COLOR_BUFFER_BIT);
367 GLU_EXPECT_NO_ERROR(gl.getError(), "Error clear");
368
369 gl.useProgram(m_program->getProgram());
370 GLU_EXPECT_NO_ERROR(gl.getError(), "Error use program");
371
372 gl.bindBuffer(GL_ARRAY_BUFFER, m_vbo_id);
373 GLU_EXPECT_NO_ERROR(gl.getError(), "Error bind buffer vertex data");
374
375 gl.enableVertexAttribArray(0);
376 GLU_EXPECT_NO_ERROR(gl.getError(), "Error enabling vertex attrib pointer 0");
377
378 gl.vertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, nullptr);
379 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex attrib pointer 0");
380
381 if (m_tcParam.attachmentShadingRate)
382 {
383 gl.shadingRateCombinerOpsEXT(GL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_EXT,
384 GL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_EXT);
385 }
386 else
387 {
388 gl.shadingRateCombinerOpsEXT(GL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_EXT,
389 GL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_EXT);
390 }
391
392 if (m_tcParam.testKind == TestKind::Scissor)
393 {
394 gl.scissor(m_scissorBox.x, m_scissorBox.y, m_scissorBox.width, m_scissorBox.height);
395 gl.enable(GL_SCISSOR_TEST);
396 }
397
398 // draw ID start from 1
399 for (uint32_t drawID = 1; drawID < TRIANGLE_COUNT; drawID++)
400 {
401 gl.uniform1i(gl.getUniformLocation(m_program->getProgram(), "drawID"), drawID);
402 GLU_EXPECT_NO_ERROR(gl.getError(), "Error set uniform drawID value");
403
404 if (!m_tcParam.attachmentShadingRate)
405 {
406 gl.shadingRateEXT(translateDrawIDToShadingRate(drawID));
407 GLU_EXPECT_NO_ERROR(gl.getError(), "Error set shading rate");
408 }
409
410 const uint32_t startVertex = (drawID - 1) * 2; // to use first vertices "-1" because drawID start from 1
411 gl.drawArrays(GL_TRIANGLES, startVertex, 3);
412 GLU_EXPECT_NO_ERROR(gl.getError(), "Error draw a triangle");
413 }
414
415 for (uint32_t layer = 0; layer < m_tcParam.layerCount; layer++)
416 {
417 if (m_tcParam.layerCount > 1)
418 {
419 gl.framebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_to_id, 0, layer);
420 }
421 const uint32_t dataSize = m_tcParam.framebufferSize * m_tcParam.framebufferSize * 4;
422 std::vector<uint32_t> resultData(dataSize);
423 gl.readPixels(0, 0, m_tcParam.framebufferSize, m_tcParam.framebufferSize, GL_RGBA_INTEGER, GL_UNSIGNED_INT,
424 resultData.data());
425 GLU_EXPECT_NO_ERROR(gl.getError(), "Error reading pixels from frame buffer!");
426
427 for (uint32_t y = 0; y < m_tcParam.framebufferSize; y++)
428 {
429 for (uint32_t x = 0; x < m_tcParam.framebufferSize; x++)
430 {
431 const uint32_t *sample = &resultData[((y * m_tcParam.framebufferSize) + x) * 4];
432
433 if (m_tcParam.testKind == TestKind::Scissor)
434 {
435 if (!m_scissorBox.in(x, y)) // out of scissor box
436 {
437 if (sample[1] != 0) // should be cleared to 0
438 {
439 std::stringstream error_sstream;
440 error_sstream << "out of scissor box should be 0"
441 << "scissor: " << m_scissorBox.x << " " << m_scissorBox.width << " "
442 << m_scissorBox.y << " " << m_scissorBox.height;
443 }
444 else
445 {
446 // success. outside scissor is always 0
447 continue;
448 }
449 }
450 else
451 {
452 if (sample[1] == 0) // if it is cleared to 0, error. All cleared by 1st big triangle
453 {
454 std::stringstream error_sstream;
455 error_sstream << "inside of scissor box should not be 0"
456 << "scissor: " << m_scissorBox.x << " " << m_scissorBox.width << " "
457 << m_scissorBox.y << " " << m_scissorBox.height;
458 }
459 }
460 }
461 else if (sample[1] == 0) // nothing rendered for the other case except scissor test
462 {
463 continue;
464 }
465
466 const uint32_t shadingRate = sample[0];
467 const uint32_t drawID = sample[1];
468
469 uint32_t expectedShadingRate = 0;
470 if (m_tcParam.attachmentShadingRate)
471 {
472 uint32_t srLayer = m_tcParam.multiShadingRate ? layer : 0;
473 expectedShadingRate = fsrutils::packShadingRate(
474 translateCoordsToShadingRate(srLayer, x / m_srTexelWidth, y / m_srTexelHeight));
475 }
476 else
477 {
478 expectedShadingRate = fsrutils::packShadingRate(translateDrawIDToShadingRate(drawID));
479 }
480
481 if (expectedShadingRate != shadingRate)
482 {
483 std::stringstream error_sstream;
484
485 error_sstream << "The draw ID is " << drawID << "Shading Rate is" << shadingRate
486 << ", But we expect " << expectedShadingRate;
487
488 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, error_sstream.str().c_str());
489
490 return STOP;
491 }
492 }
493 }
494 }
495
496 // All done
497 if (m_testCtx.getTestResult() != QP_TEST_RESULT_FAIL)
498 {
499 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
500 }
501
502 return STOP;
503 }
504
505 /// Translate draw ID to ShadingRate enumeration
506 ///
507 /// @param drawID draw ID to translate shading rate
508 ///
509 /// @return shading rate enumeration
translateDrawIDToShadingRate(uint32_t drawID) const510 glw::GLenum FragmentShadingRateAttachment::translateDrawIDToShadingRate(uint32_t drawID) const
511 {
512 return m_availableShadingRates[drawID % m_availableShadingRates.size()];
513 }
514
515 /// translate draw ID to View ID
516 ///
517 /// @param drawID ID to translate to View ID
518 ///
519 /// @return translated ViewID
drawIDToViewID(uint32_t drawID) const520 uint32_t FragmentShadingRateAttachment::drawIDToViewID(uint32_t drawID) const
521 {
522 return drawID & 1;
523 }
524
525 /// Translate Coordinates ID to ShadingRate enumeration
526 ///
527 ///@param srLayer shading rate layer index
528 ///@param srx x coord in the shading rate attachment to translate shading rate
529 ///@param sry y coord in the shading rate attachment to translate shading rate
530 ///
531 ///@return shading rate enumeration
translateCoordsToShadingRate(uint32_t srLayer,uint32_t srx,uint32_t sry) const532 glw::GLenum FragmentShadingRateAttachment::translateCoordsToShadingRate(uint32_t srLayer, uint32_t srx,
533 uint32_t sry) const
534 {
535 DE_ASSERT(m_tcParam.multiShadingRate || srLayer == 0);
536 return m_availableShadingRates[(srLayer + srx + sry) % m_availableShadingRates.size()];
537 }
538
539 } // namespace glcts
540