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