xref: /aosp_15_r20/external/deqp/modules/gles3/functional/es3fShaderFragDataTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
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  * \file
21  * \brief GLSL ES 1.0 gl_FragData[] tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es3fShaderFragDataTests.hpp"
25 
26 #include "glsShaderLibrary.hpp"
27 
28 #include "gluRenderContext.hpp"
29 #include "gluShaderProgram.hpp"
30 #include "gluDrawUtil.hpp"
31 #include "gluPixelTransfer.hpp"
32 #include "gluObjectWrapper.hpp"
33 
34 #include "tcuRenderTarget.hpp"
35 #include "tcuStringTemplate.hpp"
36 #include "tcuTestLog.hpp"
37 #include "tcuSurface.hpp"
38 
39 #include "glwFunctions.hpp"
40 #include "glwEnums.hpp"
41 
42 namespace deqp
43 {
44 namespace gles3
45 {
46 namespace Functional
47 {
48 
49 using std::string;
50 using tcu::TestLog;
51 
52 namespace
53 {
54 
55 enum IndexExprType
56 {
57     INDEX_EXPR_STATIC = 0,
58     INDEX_EXPR_UNIFORM,
59     INDEX_EXPR_DYNAMIC,
60 
61     INDEX_EXPR_TYPE_LAST
62 };
63 
isExtensionSupported(const glu::RenderContext & renderCtx,const std::string & extension)64 static bool isExtensionSupported(const glu::RenderContext &renderCtx, const std::string &extension)
65 {
66     const glw::Functions &gl = renderCtx.getFunctions();
67     int numExts              = 0;
68 
69     gl.getIntegerv(GL_NUM_EXTENSIONS, &numExts);
70 
71     for (int ndx = 0; ndx < numExts; ndx++)
72     {
73         const char *curExt = (const char *)gl.getStringi(GL_EXTENSIONS, ndx);
74 
75         if (extension == curExt)
76             return true;
77     }
78 
79     return false;
80 }
81 
compareSingleColor(tcu::TestLog & log,const tcu::Surface & surface,tcu::RGBA expectedColor,tcu::RGBA threshold)82 static bool compareSingleColor(tcu::TestLog &log, const tcu::Surface &surface, tcu::RGBA expectedColor,
83                                tcu::RGBA threshold)
84 {
85     const int maxPrints = 10;
86     int numFailedPixels = 0;
87 
88     log << TestLog::Message << "Expecting " << expectedColor << " with threshold " << threshold << TestLog::EndMessage;
89 
90     for (int y = 0; y < surface.getHeight(); y++)
91     {
92         for (int x = 0; x < surface.getWidth(); x++)
93         {
94             const tcu::RGBA resultColor = surface.getPixel(x, y);
95             const bool isOk             = compareThreshold(resultColor, expectedColor, threshold);
96 
97             if (!isOk)
98             {
99                 if (numFailedPixels < maxPrints)
100                     log << TestLog::Message << "ERROR: Got " << resultColor << " at (" << x << ", " << y << ")!"
101                         << TestLog::EndMessage;
102                 else if (numFailedPixels == maxPrints)
103                     log << TestLog::Message << "..." << TestLog::EndMessage;
104 
105                 numFailedPixels += 1;
106             }
107         }
108     }
109 
110     if (numFailedPixels > 0)
111     {
112         log << TestLog::Message << "Found " << numFailedPixels << " invalid pixels, comparison FAILED!"
113             << TestLog::EndMessage;
114         log << TestLog::Image("ResultImage", "Result Image", surface);
115         return false;
116     }
117     else
118     {
119         log << TestLog::Message << "Image comparison passed." << TestLog::EndMessage;
120         return true;
121     }
122 }
123 
124 class FragDataIndexingCase : public TestCase
125 {
126 public:
FragDataIndexingCase(Context & context,const char * name,const char * description,IndexExprType indexExprType)127     FragDataIndexingCase(Context &context, const char *name, const char *description, IndexExprType indexExprType)
128         : TestCase(context, name, description)
129         , m_indexExprType(indexExprType)
130     {
131     }
132 
genSources(const IndexExprType indexExprType)133     static glu::ProgramSources genSources(const IndexExprType indexExprType)
134     {
135         const char *const fragIndexExpr = indexExprType == INDEX_EXPR_STATIC  ? "0" :
136                                           indexExprType == INDEX_EXPR_UNIFORM ? "u_index" :
137                                           indexExprType == INDEX_EXPR_DYNAMIC ? "int(v_index)" :
138                                                                                 DE_NULL;
139         glu::ProgramSources sources;
140 
141         DE_ASSERT(fragIndexExpr);
142 
143         sources << glu::VertexSource("attribute highp vec4 a_position;\n"
144                                      "attribute highp float a_index;\n"
145                                      "attribute highp vec4 a_color;\n"
146                                      "varying mediump float v_index;\n"
147                                      "varying mediump vec4 v_color;\n"
148                                      "void main (void)\n"
149                                      "{\n"
150                                      "    gl_Position = a_position;\n"
151                                      "    v_color = a_color;\n"
152                                      "    v_index = a_index;\n"
153                                      "}\n");
154 
155         sources << glu::FragmentSource(string("varying mediump vec4 v_color;\n"
156                                               "varying mediump float v_index;\n"
157                                               "uniform mediump int u_index;\n"
158                                               "void main (void)\n"
159                                               "{\n"
160                                               "    gl_FragData[") +
161                                        fragIndexExpr +
162                                        "] = v_color;\n"
163                                        "}\n");
164 
165         return sources;
166     }
167 
iterate(void)168     IterateResult iterate(void)
169     {
170         const glu::RenderContext &renderCtx = m_context.getRenderContext();
171         const glw::Functions &gl            = renderCtx.getFunctions();
172         const glu::ShaderProgram program(renderCtx, genSources(m_indexExprType));
173         const int viewportW = de::min(renderCtx.getRenderTarget().getWidth(), 128);
174         const int viewportH = de::min(renderCtx.getRenderTarget().getHeight(), 128);
175 
176         const float positions[]   = {-1.0f, -1.0f, +1.0f, -1.0f, -1.0f, +1.0f, +1.0f, +1.0f};
177         const float colors[]      = {0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f,
178                                      0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f};
179         const float indexValues[] = {0.0f, 0.0f, 0.0f, 0.0f};
180         const uint8_t indices[]   = {0, 1, 2, 2, 1, 3};
181 
182         const glu::VertexArrayBinding vertexArrays[] = {glu::va::Float("a_position", 2, 4, 0, &positions[0]),
183                                                         glu::va::Float("a_color", 4, 4, 0, &colors[0]),
184                                                         glu::va::Float("a_index", 1, 4, 0, &indexValues[0])};
185 
186         m_testCtx.getLog() << program;
187 
188         if (!program.isOk())
189         {
190             if (m_indexExprType == INDEX_EXPR_STATIC)
191                 TCU_FAIL("Compile failed");
192             else
193                 throw tcu::NotSupportedError("Dynamic indexing of gl_FragData[] not supported");
194         }
195 
196         gl.clearColor(1.0f, 0.0f, 0.0f, 1.0f);
197         gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
198 
199         gl.viewport(0, 0, viewportW, viewportH);
200         gl.useProgram(program.getProgram());
201         gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_index"), 0);
202 
203         glu::draw(renderCtx, program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0],
204                   glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
205         GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering failed");
206 
207         {
208             tcu::Surface result(viewportW, viewportH);
209             const tcu::RGBA threshold =
210                 renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(1, 1, 1, 1);
211             bool isOk;
212 
213             glu::readPixels(renderCtx, 0, 0, result.getAccess());
214             GLU_EXPECT_NO_ERROR(gl.getError(), "Reading pixels failed");
215 
216             isOk = compareSingleColor(m_testCtx.getLog(), result, tcu::RGBA::green(), threshold);
217 
218             m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
219                                     isOk ? "Pass" : "Image comparison failed");
220         }
221 
222         return STOP;
223     }
224 
225 private:
226     const IndexExprType m_indexExprType;
227 };
228 
229 class FragDataDrawBuffersCase : public TestCase
230 {
231 public:
FragDataDrawBuffersCase(Context & context)232     FragDataDrawBuffersCase(Context &context)
233         : TestCase(context, "draw_buffers", "gl_FragData[] and glDrawBuffers() interaction")
234     {
235     }
236 
iterate(void)237     IterateResult iterate(void)
238     {
239         const glu::RenderContext &renderCtx = m_context.getRenderContext();
240 
241         int num_test_attachment = 2;
242         if (!isExtensionSupported(renderCtx, "GL_EXT_draw_buffers") &&
243             !isExtensionSupported(renderCtx, "GL_NV_draw_buffers"))
244             num_test_attachment = 1;
245 
246         std::string extensionString;
247         if (isExtensionSupported(renderCtx, "GL_EXT_draw_buffers"))
248             extensionString = "#extension GL_EXT_draw_buffers : require\n";
249         else if (isExtensionSupported(renderCtx, "GL_NV_draw_buffers"))
250             extensionString = "#extension GL_NV_draw_buffers : require\n";
251 
252         const glu::ShaderProgram program(renderCtx, glu::ProgramSources()
253                                                         << glu::VertexSource("attribute highp vec4 a_position;\n"
254                                                                              "attribute highp vec4 a_color;\n"
255                                                                              "varying mediump vec4 v_color;\n"
256                                                                              "void main (void)\n"
257                                                                              "{\n"
258                                                                              "    gl_Position = a_position;\n"
259                                                                              "    v_color = a_color;\n"
260                                                                              "}\n")
261                                                         << glu::FragmentSource(extensionString +
262                                                                                "varying mediump vec4 v_color;\n"
263                                                                                "uniform mediump int u_index;\n"
264                                                                                "void main (void)\n"
265                                                                                "{\n"
266                                                                                "    gl_FragData[u_index] = v_color;\n"
267                                                                                "}\n"));
268         const glw::Functions &gl = renderCtx.getFunctions();
269         const int width          = 128;
270         const int height         = 128;
271         const int indexLoc       = program.isOk() ? gl.getUniformLocation(program.getProgram(), "u_index") : -1;
272         const glu::Framebuffer fbo(renderCtx);
273         const glu::Renderbuffer colorBuf0(renderCtx);
274         const glu::Renderbuffer colorBuf1(renderCtx);
275 
276         const float positions[] = {-1.0f, -1.0f, +1.0f, -1.0f, -1.0f, +1.0f, +1.0f, +1.0f};
277         const float colors[]    = {0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f,
278                                    0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f};
279         const uint8_t indices[] = {0, 1, 2, 2, 1, 3};
280 
281         const glu::VertexArrayBinding vertexArrays[] = {glu::va::Float("a_position", 2, 4, 0, &positions[0]),
282                                                         glu::va::Float("a_color", 4, 4, 0, &colors[0])};
283 
284         m_testCtx.getLog() << program;
285 
286         if (!program.isOk())
287             throw tcu::NotSupportedError("Dynamic indexing of gl_FragData[] not supported");
288 
289         gl.bindFramebuffer(GL_FRAMEBUFFER, *fbo);
290         for (int ndx = 0; ndx < num_test_attachment; ndx++)
291         {
292             const uint32_t rbo = ndx == 0 ? *colorBuf0 : *colorBuf1;
293 
294             gl.bindRenderbuffer(GL_RENDERBUFFER, rbo);
295             gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);
296             gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + ndx, GL_RENDERBUFFER, rbo);
297         }
298         TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
299 
300         {
301             const uint32_t drawBuffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
302             gl.drawBuffers(DE_LENGTH_OF_ARRAY(drawBuffers), &drawBuffers[0]);
303         }
304 
305         gl.viewport(0, 0, width, height);
306         gl.useProgram(program.getProgram());
307 
308         GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed");
309 
310         bool allOk = true;
311         const tcu::RGBA threshold =
312             renderCtx.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(1, 1, 1, 1);
313 
314         for (int ndx = 0; ndx < num_test_attachment; ndx++)
315         {
316             gl.clearBufferfv(GL_COLOR, 0, tcu::RGBA::red().toVec().getPtr());
317             gl.clearBufferfv(GL_COLOR, 1, tcu::RGBA::red().toVec().getPtr());
318 
319             m_testCtx.getLog() << TestLog::Message << "Drawing to attachments " << ndx << TestLog::EndMessage;
320 
321             gl.uniform1i(indexLoc, ndx);
322             glu::draw(renderCtx, program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), &vertexArrays[0],
323                       glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
324 
325             GLU_EXPECT_NO_ERROR(gl.getError(), "Rendering failed");
326 
327             {
328                 tcu::Surface result(width, height);
329 
330                 m_testCtx.getLog() << TestLog::Message << "Verifying attachment " << ndx << "..."
331                                    << TestLog::EndMessage;
332 
333                 gl.readBuffer(GL_COLOR_ATTACHMENT0 + ndx);
334                 glu::readPixels(renderCtx, 0, 0, result.getAccess());
335                 GLU_EXPECT_NO_ERROR(gl.getError(), "Reading pixels failed");
336 
337                 if (!compareSingleColor(m_testCtx.getLog(), result, tcu::RGBA::green(), threshold))
338                     allOk = false;
339             }
340         }
341 
342         m_testCtx.setTestResult(allOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
343                                 allOk ? "Pass" : "Image comparison failed");
344 
345         return STOP;
346     }
347 };
348 
349 } // namespace
350 
ShaderFragDataTests(Context & context)351 ShaderFragDataTests::ShaderFragDataTests(Context &context) : TestCaseGroup(context, "fragdata", "gl_FragData[] Tests")
352 {
353 }
354 
~ShaderFragDataTests(void)355 ShaderFragDataTests::~ShaderFragDataTests(void)
356 {
357 }
358 
init(void)359 void ShaderFragDataTests::init(void)
360 {
361     addChild(new FragDataIndexingCase(m_context, "valid_static_index",
362                                       "Valid gl_FragData[] assignment using static index", INDEX_EXPR_STATIC));
363     addChild(new FragDataIndexingCase(m_context, "valid_uniform_index",
364                                       "Valid gl_FragData[] assignment using uniform index", INDEX_EXPR_UNIFORM));
365     addChild(new FragDataIndexingCase(m_context, "valid_dynamic_index",
366                                       "Valid gl_FragData[] assignment using dynamic index", INDEX_EXPR_DYNAMIC));
367     addChild(new FragDataDrawBuffersCase(m_context));
368 
369     // Negative cases.
370     {
371         gls::ShaderLibrary library(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
372         std::vector<tcu::TestNode *> negativeCases = library.loadShaderFile("shaders/fragdata.test");
373 
374         for (std::vector<tcu::TestNode *>::iterator i = negativeCases.begin(); i != negativeCases.end(); i++)
375             addChild(*i);
376     }
377 }
378 
379 } // namespace Functional
380 } // namespace gles3
381 } // namespace deqp
382