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 /*!
22  * \file  esextcFragmentShadingRateErrors.hpp
23  * \brief FragmentShadingRateEXT errors
24  */ /*-------------------------------------------------------------------*/
25 
26 #include "esextcFragmentShadingRateErrors.hpp"
27 #include "gluContextInfo.hpp"
28 #include "gluDefs.hpp"
29 #include "glwEnums.hpp"
30 #include "glwFunctions.hpp"
31 #include "tcuTestLog.hpp"
32 #include <cstddef>
33 
34 namespace glcts
35 {
36 
37 /// Constructor
38 ///
39 /// @param context     Test context
40 /// @param name        Test case's name
41 /// @param description Test case's description
FragmentShadingRateErrors(Context & context,const ExtParameters & extParams,const char * name,const char * description)42 FragmentShadingRateErrors::FragmentShadingRateErrors(Context &context, const ExtParameters &extParams, const char *name,
43                                                      const char *description)
44     : TestCaseBase(context, extParams, name, description)
45 {
46 }
47 
48 /// Initialize the test.
init(void)49 void FragmentShadingRateErrors::init(void)
50 {
51     TestCaseBase::init();
52 
53     // Skip if required extensions are not supported.
54     if (!m_is_fragment_shading_rate_supported)
55     {
56         throw tcu::NotSupportedError(FRAGMENT_SHADING_RATE_NOT_SUPPORTED, "", __FILE__, __LINE__);
57     }
58 }
59 
60 /// Deinitializes all GLES objects created for the test.
deinit(void)61 void FragmentShadingRateErrors::deinit(void)
62 {
63     // Deinitialize base class
64     TestCaseBase::deinit();
65 }
66 
67 /// Test if the error code returned by glGetError is the same as expected.
68 ///  If the error is different from expected description is logged.
69 ///
70 /// @param expected_error    GLenum error which is expected
71 /// @param description       Log message in the case of failure.
72 ///
73 /// @return true if error is equal to expected, false otherwise.
verifyError(const glw::GLenum expected_error,const char * description) const74 glw::GLboolean FragmentShadingRateErrors::verifyError(const glw::GLenum expected_error, const char *description) const
75 {
76     /* Retrieve GLES entry points. */
77     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
78 
79     glw::GLboolean test_passed = true;
80     glw::GLenum error_code     = gl.getError();
81 
82     if (error_code != expected_error)
83     {
84         test_passed = false;
85 
86         m_testCtx.getLog() << tcu::TestLog::Message << description << tcu::TestLog::EndMessage;
87     }
88 
89     return test_passed;
90 }
91 
92 /// Executes the test.
93 /// Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
94 /// Note the function throws exception should an error occur!
95 ///
96 ///  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
iterate(void)97 tcu::TestNode::IterateResult FragmentShadingRateErrors::iterate(void)
98 {
99     bool testPassed = true;
100 
101     /* Retrieve GLES entry points. */
102     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
103 
104     // Shading Rate                   Size
105     // ----------------------------   -----
106     // SHADING_RATE_1X1_PIXELS_EXT    1x1
107     // SHADING_RATE_1X2_PIXELS_EXT    1x2
108     // SHADING_RATE_1X4_PIXELS_EXT    1x4
109     // SHADING_RATE_2X1_PIXELS_EXT    2x1
110     // SHADING_RATE_2X2_PIXELS_EXT    2x2
111     // SHADING_RATE_2X4_PIXELS_EXT    2x4
112     // SHADING_RATE_4X1_PIXELS_EXT    4x1
113     // SHADING_RATE_4X2_PIXELS_EXT    4x2
114     // SHADING_RATE_4X4_PIXELS_EXT    4x4
115     // INVALID_ENUM is generated by ShadingRateEXT if <rate> is not a valid shading rate from table
116     gl.shadingRateEXT(GL_SAMPLE_SHADING);
117     testPassed = testPassed && verifyError(GL_INVALID_ENUM, "glShadingRateEXT <rate> is not valid");
118 
119     if (m_is_fragment_shading_rate_attachment_supported)
120     {
121         // void FramebufferShadingRateEXT(enum target, enum attachment, uint texture, GLint baseLayer, GLsizei numLayers, GLsizei texelWidth, GLsizei texelHeight);
122         constexpr uint32_t kBaseLayer     = 0;
123         constexpr uint32_t kNumLayer      = 1;
124         constexpr uint32_t kTextureWidth  = 256;
125         constexpr uint32_t kTextureHeight = 256;
126         constexpr uint32_t kTexelWidth    = 16;
127         constexpr uint32_t kTexelHeight   = 16;
128 
129         glw::GLuint fbo_id;
130         /* Generate framebuffer objects */
131         gl.genFramebuffers(1, &fbo_id);
132         GLU_EXPECT_NO_ERROR(gl.getError(), "Error setting up framebuffer objects");
133 
134         gl.bindFramebuffer(GL_FRAMEBUFFER, fbo_id);
135         GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding frame buffer object!");
136 
137         glw::GLuint to_id;
138         glw::GLuint mutable_to_id;
139         /* Generate texture objects */
140         gl.genTextures(1, &to_id);
141         GLU_EXPECT_NO_ERROR(gl.getError(), "Error generating texture objects");
142 
143         gl.genTextures(1, &mutable_to_id);
144         GLU_EXPECT_NO_ERROR(gl.getError(), "Error generating texture objects");
145 
146         gl.bindTexture(GL_TEXTURE_2D, to_id);
147         GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding texture object!");
148         gl.texStorage2D(GL_TEXTURE_2D, 1, GL_R8UI, kTextureWidth, kTextureHeight);
149         GLU_EXPECT_NO_ERROR(gl.getError(), "Error allocating texture object!");
150 
151         gl.bindTexture(GL_TEXTURE_2D, mutable_to_id);
152         GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding texture object!");
153         gl.texImage2D(GL_TEXTURE_2D, 0, GL_R8, kTextureWidth, kTextureHeight, 0, GL_RED, GL_UNSIGNED_BYTE, nullptr);
154         GLU_EXPECT_NO_ERROR(gl.getError(), "Error allocating texture object!");
155 
156         glw::GLint minTexelWidth        = 0;
157         glw::GLint maxTexelWidth        = 0;
158         glw::GLint minTexelHeight       = 0;
159         glw::GLint maxTexelHeight       = 0;
160         glw::GLint maxAttachAspectRatio = 0;
161         glw::GLint maxAttachLayerCount  = 0;
162         gl.getIntegerv(GL_MIN_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT, &minTexelWidth);
163         GLU_EXPECT_NO_ERROR(gl.getError(),
164                             "Error getIntegerv GL_MIN_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT!");
165         gl.getIntegerv(GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT, &maxTexelWidth);
166         GLU_EXPECT_NO_ERROR(gl.getError(),
167                             "Error getIntegerv GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT!");
168         gl.getIntegerv(GL_MIN_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_HEIGHT_EXT, &minTexelHeight);
169         GLU_EXPECT_NO_ERROR(gl.getError(),
170                             "Error getIntegerv GL_MIN_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_HEIGHT_EXT!");
171         gl.getIntegerv(GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_HEIGHT_EXT, &maxTexelHeight);
172         GLU_EXPECT_NO_ERROR(gl.getError(),
173                             "Error getIntegerv GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_HEIGHT_EXT!");
174         gl.getIntegerv(GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_ASPECT_RATIO_EXT, &maxAttachAspectRatio);
175         GLU_EXPECT_NO_ERROR(gl.getError(),
176                             "Error getIntegerv GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_ASPECT_RATIO_EXT!");
177         gl.getIntegerv(GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_LAYERS_EXT, &maxAttachLayerCount);
178         GLU_EXPECT_NO_ERROR(gl.getError(), "Error getIntegerv GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_LAYERS_EXT!");
179 
180         // An INVALID_ENUM error is generated if <target> is not DRAW_FRAMEBUFFER, READ_FRAMEBUFFER, or FRAMEBUFFER.
181         gl.framebufferShadingRateEXT(GL_RENDERBUFFER, GL_SHADING_RATE_ATTACHMENT_EXT, to_id, kBaseLayer, kNumLayer,
182                                      kTexelWidth, kTexelHeight);
183         testPassed = testPassed && verifyError(GL_INVALID_ENUM, "framebufferShadingRateEXT <target> is not valid");
184 
185         // An INVALID_ENUM error is generated if <attachment> is not SHADING_RATE_ATTACHMENT_EXT.
186         gl.framebufferShadingRateEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, to_id, kBaseLayer, kNumLayer, kTexelWidth,
187                                      kTexelHeight);
188         testPassed = testPassed && verifyError(GL_INVALID_ENUM, "framebufferShadingRateEXT <attachment> is not valid");
189 
190         // An INVALID_VALUE error is generated if <texture> is not zero and is not the name of an immutable texture object.
191         gl.framebufferShadingRateEXT(GL_FRAMEBUFFER, GL_SHADING_RATE_ATTACHMENT_EXT, mutable_to_id, kBaseLayer,
192                                      kNumLayer, kTexelWidth, kTexelHeight);
193         testPassed = testPassed && verifyError(GL_INVALID_VALUE, "framebufferShadingRateEXT <texture> is not valid");
194 
195         // An INVALID_VALUE error is generated if <baseLayer> is greater than or equal to the value of MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_LAYERS_EXT.
196         gl.framebufferShadingRateEXT(GL_FRAMEBUFFER, GL_SHADING_RATE_ATTACHMENT_EXT, to_id,
197                                      GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_LAYERS_EXT, kNumLayer, kTexelWidth,
198                                      kTexelHeight);
199         testPassed = testPassed && verifyError(GL_INVALID_VALUE, "framebufferShadingRateEXT <baseLayer> is not valid");
200 
201         // An INVALID_VALUE error is generated if <numLayers> is greater than the value of MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_LAYERS_EXT.
202         gl.framebufferShadingRateEXT(GL_FRAMEBUFFER, GL_SHADING_RATE_ATTACHMENT_EXT, to_id, 0,
203                                      GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_LAYERS_EXT + 1, kTexelWidth, kTexelHeight);
204         testPassed = testPassed && verifyError(GL_INVALID_VALUE, "framebufferShadingRateEXT <numLayers> is not valid");
205 
206         // An INVALID_VALUE error is generated if <texelWidth> / <texelHeight> is larger than MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_ASPECT_RATIO_EXT.
207         gl.framebufferShadingRateEXT(GL_FRAMEBUFFER, GL_SHADING_RATE_ATTACHMENT_EXT, to_id, 0,
208                                      GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_LAYERS_EXT + 1, minTexelWidth,
209                                      (minTexelWidth * GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_ASPECT_RATIO_EXT)
210                                          << 1);
211         testPassed = testPassed &&
212                      verifyError(GL_INVALID_VALUE, "framebufferShadingRateEXT <texelWidth, texelHeight> is not valid");
213 
214         // An INVALID_VALUE error is generated if <texelHeight> / <texelWidth> is larger than MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_ASPECT_RATIO_EXT.
215         gl.framebufferShadingRateEXT(
216             GL_FRAMEBUFFER, GL_SHADING_RATE_ATTACHMENT_EXT, to_id, 0,
217             GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_LAYERS_EXT + 1,
218             (minTexelHeight * GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_ASPECT_RATIO_EXT) << 1, minTexelHeight);
219         testPassed = testPassed &&
220                      verifyError(GL_INVALID_VALUE, "framebufferShadingRateEXT <texelWidth, texelHeight> is not valid");
221 
222         gl.deleteFramebuffers(1, &fbo_id);
223         gl.deleteFramebuffers(1, &to_id);
224         gl.deleteFramebuffers(1, &mutable_to_id);
225     }
226 
227     // void ShadingRateCombinerOpsEXT(enum combinerOp0, enum combinerOp1)
228     //
229     // An INVALID_ENUM error is generated if <combinerOp0> is not
230     // An INVALID_ENUM error is generated if <combinerOp1> is not
231     // FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_EXT,
232     // FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_EXT,
233     // FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_EXT,
234     // FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_EXT, or
235     // FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_EXT
236     gl.shadingRateCombinerOpsEXT(GL_SHADING_RATE_EXT, GL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_EXT);
237     testPassed = testPassed && verifyError(GL_INVALID_ENUM, "shadingRateCombinerOpsEXT <combinerOp0> is not valid");
238     gl.shadingRateCombinerOpsEXT(GL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_EXT,
239                                  GL_MIN_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT);
240     testPassed = testPassed && verifyError(GL_INVALID_ENUM, "shadingRateCombinerOpsEXT <combinerOp1> is not valid");
241 
242     glw::GLboolean supportNonTrivialCombiner = false;
243     gl.getBooleanv(GL_FRAGMENT_SHADING_RATE_NON_TRIVIAL_COMBINERS_SUPPORTED_EXT, &supportNonTrivialCombiner);
244     GLU_EXPECT_NO_ERROR(gl.getError(), "Error getBooleanv non trivial combiner");
245 
246     // An INVALID_OPERATION error is generated if the value of FRAGMENT_SHADING_RATE_NON_TRIVIAL_COMBINERS_SUPPORTED_EXT
247     // is FALSE and <combinerOp0> is not
248     // FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_EXT or FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_EXT
249     // is FALSE and <combinerOp1> is not
250     // FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_EXT or FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_EXT
251     if (!supportNonTrivialCombiner)
252     {
253         gl.shadingRateCombinerOpsEXT(GL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_EXT,
254                                      GL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_EXT);
255         testPassed = testPassed && verifyError(GL_INVALID_OPERATION, "<combinerOp0> combiner is non trivial combiner");
256 
257         gl.shadingRateCombinerOpsEXT(GL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_EXT,
258                                      GL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_EXT);
259         testPassed = testPassed && verifyError(GL_INVALID_OPERATION, "<combinerOp1> combiner is non trivial combiner");
260     }
261     // [[If GL_EXT_fragment_shading_rate_primitive is not supported]]
262     // An INVALID_OPERATION error is generated if <combinerOp0> is not
263     // FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_EXT
264     if (!m_is_fragment_shading_rate_primitive_supported)
265     {
266         gl.shadingRateCombinerOpsEXT(GL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_EXT,
267                                      GL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_EXT);
268         testPassed = testPassed && verifyError(GL_INVALID_ENUM, "shadingRateCombinerOpsEXT <combinerOp0> is not valid");
269     }
270 
271     // [[If GL_EXT_fragment_shading_rate_attachment is not supported]]
272     // An INVALID_OPERATION error is generated if <combinerOp1> is not
273     // FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_EXT
274     if (!m_is_fragment_shading_rate_attachment_supported)
275     {
276         gl.shadingRateCombinerOpsEXT(GL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_EXT,
277                                      GL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_EXT);
278         testPassed = testPassed && verifyError(GL_INVALID_ENUM, "shadingRateCombinerOpsEXT <combinerOp0> is not valid");
279     }
280 
281     /* All done */
282     if (testPassed)
283     {
284         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
285     }
286     else
287     {
288         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
289     }
290 
291     return STOP;
292 }
293 
294 } // namespace glcts
295