xref: /aosp_15_r20/external/deqp/modules/gles3/functional/es3fShaderMetamorphicTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2017 Hugues Evrard, Imperial College London
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 Shader metamorphic tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es3fShaderMetamorphicTests.hpp"
25 #include "glsShaderRenderCase.hpp"
26 #include "deUniquePtr.hpp"
27 #include "deFilePath.hpp"
28 #include "tcuTestContext.hpp"
29 #include "tcuTestLog.hpp"
30 #include "tcuRenderTarget.hpp"
31 #include "tcuImageCompare.hpp"
32 #include "tcuVectorUtil.hpp"
33 #include "tcuResource.hpp"
34 #include "gluPixelTransfer.hpp"
35 #include "gluDrawUtil.hpp"
36 
37 #include "glwFunctions.hpp"
38 
39 using std::vector;
40 using tcu::TestLog;
41 
42 namespace deqp
43 {
44 namespace gles3
45 {
46 namespace Functional
47 {
48 
49 static const int MAX_RENDER_WIDTH  = 256;
50 static const int MAX_RENDER_HEIGHT = 256;
51 
52 typedef bool (*SanityCheckFunc)(const tcu::ConstPixelBufferAccess &);
53 
54 /*--------------------------------------------------------------------*//*!
55  * \brief ShaderMetamorphicVariant
56  *
57  * ShaderMetamorphicVariant aims at rendering a recipient shader and a
58  * variant shader, and compare whether the resulting images are the
59  * approximately the same. It also checks non-deterministic renderings,
60  * by rendering each fragment shader a couple of times.
61  *//*--------------------------------------------------------------------*/
62 class ShaderMetamorphicVariant : public TestCase
63 {
64 public:
65     ShaderMetamorphicVariant(Context &context, const char *name, const std::string &vertexFilename,
66                              const std::string &recipientFilename, const std::string &variantFilename,
67                              SanityCheckFunc sanityCheck);
68     ~ShaderMetamorphicVariant(void);
69     IterateResult iterate(void);
70 
71 private:
72     const std::string m_vertexFilename;
73     const std::string m_recipientFilename;
74     const std::string m_variantFilename;
75     SanityCheckFunc m_sanityCheck;
76 
77     std::string fileContents(const std::string &filename);
78     void render(const tcu::PixelBufferAccess &img, const std::string &vertexSrc, const std::string &fragmentSrc);
79     void checkNondet(const tcu::Surface &refImg, const std::string &vertexSrc, const std::string &fragmentSrc);
80 };
81 
ShaderMetamorphicVariant(Context & context,const char * name,const std::string & vertexFilename,const std::string & recipientFilename,const std::string & variantFilename,SanityCheckFunc sanityCheck)82 ShaderMetamorphicVariant::ShaderMetamorphicVariant(Context &context, const char *name,
83                                                    const std::string &vertexFilename,
84                                                    const std::string &recipientFilename,
85                                                    const std::string &variantFilename, SanityCheckFunc sanityCheck)
86     : TestCase(context, name, "Test a given variant")
87     , m_vertexFilename(vertexFilename)
88     , m_recipientFilename(recipientFilename)
89     , m_variantFilename(variantFilename)
90     , m_sanityCheck(sanityCheck)
91 {
92 }
93 
~ShaderMetamorphicVariant(void)94 ShaderMetamorphicVariant::~ShaderMetamorphicVariant(void)
95 {
96 }
97 
fileContents(const std::string & filename)98 std::string ShaderMetamorphicVariant::fileContents(const std::string &filename)
99 {
100     de::UniquePtr<tcu::Resource> resource(m_testCtx.getArchive().getResource(filename.c_str()));
101     int size = resource->getSize();
102     std::vector<uint8_t> data;
103 
104     data.resize(size + 1);
105     resource->read(&data[0], size);
106     data[size]           = '\0';
107     std::string contents = std::string((const char *)(&data[0]));
108     return contents;
109 }
110 
render(const tcu::PixelBufferAccess & img,const std::string & vertexSrc,const std::string & fragmentSrc)111 void ShaderMetamorphicVariant::render(const tcu::PixelBufferAccess &img, const std::string &vertexSrc,
112                                       const std::string &fragmentSrc)
113 {
114     TestLog &log             = m_testCtx.getLog();
115     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
116 
117     // Positions, shared between shaders
118     const float positions[] = {
119         -1.0f, 1.0f,  // top-left
120         -1.0f, -1.0f, // bottom-left
121         1.0f,  -1.0f, // bottom-right
122         1.0f,  1.0f,  // top-right
123     };
124 
125     const uint16_t indices[] = {
126         0, 1, 2, // bottom-left triangle
127         0, 3, 2, // top-right triangle
128     };
129 
130     glu::VertexArrayBinding posBinding = glu::va::Float("coord2d", 2, 6, 0, &positions[0]);
131 
132     const glu::ShaderProgram program(m_context.getRenderContext(), glu::makeVtxFragSources(vertexSrc, fragmentSrc));
133     log << program;
134 
135     if (!program.isOk())
136         throw tcu::TestError("Compile failed");
137 
138     // Set uniforms expected in GraphicsFuzz generated programs
139     gl.useProgram(program.getProgram());
140     // Uniform: injectionSwitch
141     int uniformLoc = gl.getUniformLocation(program.getProgram(), "injectionSwitch");
142     if (uniformLoc != -1)
143         gl.uniform2f(uniformLoc, 0.0f, 1.0f);
144     // Uniform: resolution
145     uniformLoc = gl.getUniformLocation(program.getProgram(), "resolution");
146     if (uniformLoc != -1)
147         gl.uniform2f(uniformLoc, glw::GLfloat(img.getWidth()), glw::GLfloat(img.getHeight()));
148     // Uniform: mouse
149     uniformLoc = gl.getUniformLocation(program.getProgram(), "mouse");
150     if (uniformLoc != -1)
151         gl.uniform2f(uniformLoc, 0.0f, 0.0f);
152     // Uniform: time
153     uniformLoc = gl.getUniformLocation(program.getProgram(), "time");
154     if (uniformLoc != -1)
155         gl.uniform1f(uniformLoc, 0.0f);
156 
157     // Render two times to check nondeterministic renderings
158     glu::draw(m_context.getRenderContext(), program.getProgram(), 1, &posBinding,
159               glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0]));
160     glu::readPixels(m_context.getRenderContext(), 0, 0, img);
161     GLU_EXPECT_NO_ERROR(gl.getError(), "Draw");
162 }
163 
checkNondet(const tcu::Surface & refImg,const std::string & vertexSrc,const std::string & fragmentSrc)164 void ShaderMetamorphicVariant::checkNondet(const tcu::Surface &refImg, const std::string &vertexSrc,
165                                            const std::string &fragmentSrc)
166 {
167     TestLog &log     = m_testCtx.getLog();
168     tcu::Surface img = tcu::Surface(refImg.getWidth(), refImg.getHeight());
169 
170     render(img.getAccess(), vertexSrc, fragmentSrc);
171     bool same = tcu::pixelThresholdCompare(log, "Result", "Image comparison result", img, refImg, tcu::RGBA(0, 0, 0, 0),
172                                            tcu::COMPARE_LOG_RESULT);
173     if (!same)
174         throw tcu::TestError("Nondeterministic rendering");
175 }
176 
iterate(void)177 ShaderMetamorphicVariant::IterateResult ShaderMetamorphicVariant::iterate(void)
178 {
179     TestLog &log = m_testCtx.getLog();
180     const tcu::RGBA threshold =
181         tcu::RGBA(1, 1, 1, 1) + m_context.getRenderTarget().getPixelFormat().getColorThreshold();
182     std::string vertexSrc     = fileContents(m_vertexFilename);
183     std::string recipientSrc  = fileContents(m_recipientFilename);
184     std::string variantSrc    = fileContents(m_variantFilename);
185     const int width           = deMin32(m_context.getRenderTarget().getWidth(), MAX_RENDER_WIDTH);
186     const int height          = deMin32(m_context.getRenderTarget().getHeight(), MAX_RENDER_HEIGHT);
187     tcu::Surface recipientImg = tcu::Surface(width, height);
188     tcu::Surface variantImg   = tcu::Surface(width, height);
189 
190     render(recipientImg.getAccess(), vertexSrc, recipientSrc);
191     render(variantImg.getAccess(), vertexSrc, variantSrc);
192 
193     checkNondet(recipientImg, vertexSrc, recipientSrc);
194     checkNondet(variantImg, vertexSrc, variantSrc);
195 
196     if (m_sanityCheck != DE_NULL)
197     {
198         bool isSane = m_sanityCheck(recipientImg.getAccess());
199         if (!isSane)
200             throw tcu::TestError("Quick check fails on recipient");
201     }
202 
203     bool isOk = tcu::pixelThresholdCompare(log, "Result", "Image comparison result", recipientImg, variantImg,
204                                            threshold, tcu::COMPARE_LOG_RESULT);
205 
206     m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
207                             isOk ? "Pass" : "Image comparison failed");
208 
209     return STOP;
210 }
211 
212 /*--------------------------------------------------------------------*//*!
213  * \brief ShaderMetamorphicShaderset
214  *
215  * ShaderMetamorphicShaderset gathers a set of ShaderMetamorphicVariant
216  * for a similar recipient.
217  *//*--------------------------------------------------------------------*/
218 class ShaderMetamorphicShaderset : public TestCaseGroup
219 {
220 public:
221     ShaderMetamorphicShaderset(Context &context, const char *name, const std::string &vertexFilename,
222                                const std::string &recipientFilename, std::vector<std::string> variantFilenames,
223                                SanityCheckFunc sanityCheck);
224     ~ShaderMetamorphicShaderset(void);
225     virtual void init(void);
226 
227 private:
228     const std::string m_vertexFilename;
229     const std::string m_recipientFilename;
230     std::vector<std::string> m_variantFilenames;
231     SanityCheckFunc m_sanityCheck;
232 
233     ShaderMetamorphicShaderset(const ShaderMetamorphicShaderset &);            // Not allowed!
234     ShaderMetamorphicShaderset &operator=(const ShaderMetamorphicShaderset &); // Not allowed!
235 };
236 
ShaderMetamorphicShaderset(Context & context,const char * name,const std::string & vertexFilename,const std::string & recipientFilename,std::vector<std::string> variantFilenames,SanityCheckFunc sanityCheck)237 ShaderMetamorphicShaderset::ShaderMetamorphicShaderset(Context &context, const char *name,
238                                                        const std::string &vertexFilename,
239                                                        const std::string &recipientFilename,
240                                                        std::vector<std::string> variantFilenames,
241                                                        SanityCheckFunc sanityCheck)
242     : TestCaseGroup(context, name, "Metamorphic Shader Set")
243     , m_vertexFilename(vertexFilename)
244     , m_recipientFilename(recipientFilename)
245     , m_variantFilenames(variantFilenames)
246     , m_sanityCheck(sanityCheck)
247 {
248 }
249 
~ShaderMetamorphicShaderset(void)250 ShaderMetamorphicShaderset::~ShaderMetamorphicShaderset(void)
251 {
252 }
253 
init(void)254 void ShaderMetamorphicShaderset::init(void)
255 {
256     for (size_t variantNdx = 0; variantNdx < m_variantFilenames.size(); variantNdx++)
257     {
258         std::string variantName = de::FilePath(m_variantFilenames[variantNdx]).getBaseName();
259         // Remove extension
260         size_t pos  = variantName.find_last_of(".");
261         variantName = variantName.substr(0, pos);
262 
263         addChild(new ShaderMetamorphicVariant(m_context, variantName.c_str(), m_vertexFilename, m_recipientFilename,
264                                               m_variantFilenames[variantNdx], m_sanityCheck));
265     }
266 }
267 
268 /*--------------------------------------------------------------------*//*!
269  * \brief SanityPixel
270  *
271  * A place holder to store info on reference pixel for quick checking.
272  *//*--------------------------------------------------------------------*/
273 class SanityPixel
274 {
275 public:
276     float m_xRelative;
277     float m_yRelative;
278     tcu::Vec4 m_RGBA;
279 
280     SanityPixel(float xRelative, float yRelative, tcu::Vec4 RGBA);
281 };
282 
SanityPixel(float xRelative,float yRelative,tcu::Vec4 RGBA)283 SanityPixel::SanityPixel(float xRelative, float yRelative, tcu::Vec4 RGBA)
284     : m_xRelative(xRelative)
285     , m_yRelative(yRelative)
286     , m_RGBA(RGBA)
287 {
288 }
289 
sanityComparePixels(const tcu::ConstPixelBufferAccess & img,std::vector<SanityPixel> sanityPixels)290 static bool sanityComparePixels(const tcu::ConstPixelBufferAccess &img, std::vector<SanityPixel> sanityPixels)
291 {
292     const int depth           = 0;
293     const tcu::Vec4 threshold = tcu::Vec4(0.01f, 0.01f, 0.01f, 0.01f);
294 
295     for (uint32_t i = 0; i < sanityPixels.size(); i++)
296     {
297         SanityPixel sanPix = sanityPixels[i];
298         int x              = (int)((float)img.getWidth() * sanPix.m_xRelative);
299         int y              = (int)((float)img.getHeight() * sanPix.m_yRelative);
300         tcu::Vec4 RGBA     = img.getPixel(x, y, depth);
301         tcu::Vec4 diff     = abs(RGBA - sanPix.m_RGBA);
302         for (int j = 0; j < 4; j++)
303             if (diff[j] >= threshold[j])
304                 return false;
305     }
306     return true;
307 }
308 
sanityCheck_synthetic(const tcu::ConstPixelBufferAccess & img)309 static bool sanityCheck_synthetic(const tcu::ConstPixelBufferAccess &img)
310 {
311     std::vector<SanityPixel> sanityPixels;
312     bool isOK;
313 
314     sanityPixels.push_back(SanityPixel(0.5f, 0.5f, tcu::Vec4(0.0f, 1.0f, 1.0f, 1.0f)));
315 
316     isOK = sanityComparePixels(img, sanityPixels);
317     return isOK;
318 }
319 
sanityCheck_bubblesort_flag(const tcu::ConstPixelBufferAccess & img)320 static bool sanityCheck_bubblesort_flag(const tcu::ConstPixelBufferAccess &img)
321 {
322     std::vector<SanityPixel> sanityPixels;
323     bool isOK;
324 
325     sanityPixels.push_back(SanityPixel(0.25f, 0.25f, tcu::Vec4(0.1f, 0.6f, 1.0f, 1.0f)));
326     sanityPixels.push_back(SanityPixel(0.25f, 0.75f, tcu::Vec4(1.0f, 0.5f, 0.1f, 1.0f)));
327     sanityPixels.push_back(SanityPixel(0.75f, 0.25f, tcu::Vec4(0.6f, 1.0f, 0.1f, 1.0f)));
328     sanityPixels.push_back(SanityPixel(0.75f, 0.75f, tcu::Vec4(0.5f, 0.1f, 1.0f, 1.0f)));
329 
330     isOK = sanityComparePixels(img, sanityPixels);
331     return isOK;
332 }
333 
334 /*--------------------------------------------------------------------*//*!
335  * \brief ShaderMetamorphicTests
336  *
337  * ShaderMetamorphicTests regroups metamorphic shadersets.
338  *//*--------------------------------------------------------------------*/
ShaderMetamorphicTests(Context & context)339 ShaderMetamorphicTests::ShaderMetamorphicTests(Context &context)
340     : TestCaseGroup(context, "metamorphic", "Shader Metamorphic Tests")
341 {
342 }
343 
~ShaderMetamorphicTests(void)344 ShaderMetamorphicTests::~ShaderMetamorphicTests(void)
345 {
346 }
347 
init(void)348 void ShaderMetamorphicTests::init(void)
349 {
350     std::vector<std::string> fragNames;
351     std::string vertexFilename = "graphicsfuzz/vertexShader.glsl";
352 
353     // synthetic
354     fragNames.clear();
355     fragNames.push_back("graphicsfuzz/synthetic/variant_1.frag");
356     fragNames.push_back("graphicsfuzz/synthetic/variant_2.frag");
357     fragNames.push_back("graphicsfuzz/synthetic/variant_3.frag");
358     fragNames.push_back("graphicsfuzz/synthetic/variant_4.frag");
359     addChild(new ShaderMetamorphicShaderset(m_context, "synthetic", vertexFilename,
360                                             "graphicsfuzz/synthetic/recipient.frag", fragNames, sanityCheck_synthetic));
361 
362     // bubblesort_flag
363     fragNames.clear();
364     fragNames.push_back("graphicsfuzz/bubblesort_flag/variant_1.frag");
365     fragNames.push_back("graphicsfuzz/bubblesort_flag/variant_2.frag");
366     addChild(new ShaderMetamorphicShaderset(m_context, "bubblesort_flag", vertexFilename,
367                                             "graphicsfuzz/bubblesort_flag/recipient.frag", fragNames,
368                                             sanityCheck_bubblesort_flag));
369 }
370 
371 } // namespace Functional
372 } // namespace gles3
373 } // namespace deqp
374