am 70413e6e: (-s ours) am e8efb729: Relax asin() precision requirements am: 1b358c43b7
[platform/upstream/VK-GL-CTS.git] / modules / gles3 / functional / es3fRandomFragmentOpTests.cpp
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 Randomized per-fragment operation tests.
22  *//*--------------------------------------------------------------------*/
23
24 #include "es3fRandomFragmentOpTests.hpp"
25 #include "glsFragmentOpUtil.hpp"
26 #include "glsInteractionTestUtil.hpp"
27 #include "tcuRenderTarget.hpp"
28 #include "tcuTestLog.hpp"
29 #include "tcuSurface.hpp"
30 #include "tcuCommandLine.hpp"
31 #include "tcuImageCompare.hpp"
32 #include "tcuVectorUtil.hpp"
33 #include "tcuTextureUtil.hpp"
34 #include "gluPixelTransfer.hpp"
35 #include "gluCallLogWrapper.hpp"
36 #include "gluRenderContext.hpp"
37 #include "deStringUtil.hpp"
38 #include "deRandom.hpp"
39 #include "deMath.h"
40 #include "glwEnums.hpp"
41 #include "glwFunctions.hpp"
42 #include "rrFragmentOperations.hpp"
43 #include "sglrReferenceUtils.hpp"
44
45 #include <algorithm>
46
47 namespace deqp
48 {
49 namespace gles3
50 {
51 namespace Functional
52 {
53
54 using std::vector;
55 using tcu::TestLog;
56 using tcu::Vec2;
57 using tcu::Vec4;
58 using tcu::IVec2;
59 using tcu::BVec4;
60
61 enum
62 {
63         VIEWPORT_WIDTH                          = 64,
64         VIEWPORT_HEIGHT                         = 64,
65         NUM_CALLS_PER_ITERATION         = 3,
66         NUM_ITERATIONS_PER_CASE         = 10
67 };
68
69 static const tcu::Vec4          CLEAR_COLOR                     (0.25f, 0.5f, 0.75f, 1.0f);
70 static const float                      CLEAR_DEPTH                     = 1.0f;
71 static const int                        CLEAR_STENCIL           = 0;
72 static const bool                       ENABLE_CALL_LOG         = true;
73
74 using namespace gls::FragmentOpUtil;
75 using namespace gls::InteractionTestUtil;
76
77 void translateStencilState (const StencilState& src, rr::StencilState& dst)
78 {
79         dst.func                = sglr::rr_util::mapGLTestFunc(src.function);
80         dst.ref                 = src.reference;
81         dst.compMask    = src.compareMask;
82         dst.sFail               = sglr::rr_util::mapGLStencilOp(src.stencilFailOp);
83         dst.dpFail              = sglr::rr_util::mapGLStencilOp(src.depthFailOp);
84         dst.dpPass              = sglr::rr_util::mapGLStencilOp(src.depthPassOp);
85         dst.writeMask   = src.writeMask;
86 }
87
88 void translateBlendState (const BlendState& src, rr::BlendState& dst)
89 {
90         dst.equation    = sglr::rr_util::mapGLBlendEquation(src.equation);
91         dst.srcFunc             = sglr::rr_util::mapGLBlendFunc(src.srcFunc);
92         dst.dstFunc             = sglr::rr_util::mapGLBlendFunc(src.dstFunc);
93 }
94
95 void translateState (const RenderState& src, rr::FragmentOperationState& dst, const tcu::RenderTarget& renderTarget)
96 {
97         bool hasDepth           = renderTarget.getDepthBits() > 0;
98         bool hasStencil         = renderTarget.getStencilBits() > 0;
99
100         dst.scissorTestEnabled          = src.scissorTestEnabled;
101         dst.scissorRectangle            = src.scissorRectangle;
102         dst.stencilTestEnabled          = hasStencil && src.stencilTestEnabled;
103         dst.depthTestEnabled            = hasDepth && src.depthTestEnabled;
104         dst.blendMode                           = src.blendEnabled ? rr::BLENDMODE_STANDARD : rr::BLENDMODE_NONE;
105         dst.numStencilBits                      = renderTarget.getStencilBits();
106
107         dst.colorMask = src.colorMask;
108
109         if (dst.depthTestEnabled)
110         {
111                 dst.depthFunc   = sglr::rr_util::mapGLTestFunc(src.depthFunc);
112                 dst.depthMask   = src.depthWriteMask;
113         }
114
115         if (dst.stencilTestEnabled)
116         {
117                 translateStencilState(src.stencil[rr::FACETYPE_BACK],   dst.stencilStates[rr::FACETYPE_BACK]);
118                 translateStencilState(src.stencil[rr::FACETYPE_FRONT],  dst.stencilStates[rr::FACETYPE_FRONT]);
119         }
120
121         if (src.blendEnabled)
122         {
123                 translateBlendState(src.blendRGBState, dst.blendRGBState);
124                 translateBlendState(src.blendAState, dst.blendAState);
125                 dst.blendColor = tcu::clamp(src.blendColor, Vec4(0.0f), Vec4(1.0f));
126         }
127 }
128
129 static void renderQuad (const glw::Functions& gl, gls::FragmentOpUtil::QuadRenderer& renderer, const gls::FragmentOpUtil::IntegerQuad& quad, int baseX, int baseY)
130 {
131         gls::FragmentOpUtil::Quad translated;
132
133         std::copy(DE_ARRAY_BEGIN(quad.color), DE_ARRAY_END(quad.color), DE_ARRAY_BEGIN(translated.color));
134
135         bool    flipX           = quad.posB.x() < quad.posA.x();
136         bool    flipY           = quad.posB.y() < quad.posA.y();
137         int             viewportX       = de::min(quad.posA.x(), quad.posB.x());
138         int             viewportY       = de::min(quad.posA.y(), quad.posB.y());
139         int             viewportW       = de::abs(quad.posA.x()-quad.posB.x())+1;
140         int             viewportH       = de::abs(quad.posA.y()-quad.posB.y())+1;
141
142         translated.posA = Vec2(flipX ? 1.0f : -1.0f, flipY ? 1.0f : -1.0f);
143         translated.posB = Vec2(flipX ? -1.0f : 1.0f, flipY ? -1.0f : 1.0f);
144
145         // \todo [2012-12-18 pyry] Pass in DepthRange parameters.
146         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(quad.depth); ndx++)
147                 translated.depth[ndx] = quad.depth[ndx]*2.0f - 1.0f;
148
149         gl.viewport(baseX+viewportX, baseY+viewportY, viewportW, viewportH);
150         renderer.render(translated);
151 }
152
153 static void setGLState (glu::CallLogWrapper& wrapper, const RenderState& state, int viewportX, int viewportY)
154 {
155         if (state.scissorTestEnabled)
156         {
157                 wrapper.glEnable(GL_SCISSOR_TEST);
158                 wrapper.glScissor(viewportX+state.scissorRectangle.left, viewportY+state.scissorRectangle.bottom,
159                                                   state.scissorRectangle.width, state.scissorRectangle.height);
160         }
161         else
162                 wrapper.glDisable(GL_SCISSOR_TEST);
163
164         if (state.stencilTestEnabled)
165         {
166                 wrapper.glEnable(GL_STENCIL_TEST);
167
168                 for (int face = 0; face < rr::FACETYPE_LAST; face++)
169                 {
170                         deUint32                                glFace  = face == rr::FACETYPE_BACK ? GL_BACK : GL_FRONT;
171                         const StencilState&             sParams = state.stencil[face];
172
173                         wrapper.glStencilFuncSeparate(glFace, sParams.function, sParams.reference, sParams.compareMask);
174                         wrapper.glStencilOpSeparate(glFace, sParams.stencilFailOp, sParams.depthFailOp, sParams.depthPassOp);
175                         wrapper.glStencilMaskSeparate(glFace, sParams.writeMask);
176                 }
177         }
178         else
179                 wrapper.glDisable(GL_STENCIL_TEST);
180
181         if (state.depthTestEnabled)
182         {
183                 wrapper.glEnable(GL_DEPTH_TEST);
184                 wrapper.glDepthFunc(state.depthFunc);
185                 wrapper.glDepthMask(state.depthWriteMask ? GL_TRUE : GL_FALSE);
186         }
187         else
188                 wrapper.glDisable(GL_DEPTH_TEST);
189
190         if (state.blendEnabled)
191         {
192                 wrapper.glEnable(GL_BLEND);
193                 wrapper.glBlendEquationSeparate(state.blendRGBState.equation, state.blendAState.equation);
194                 wrapper.glBlendFuncSeparate(state.blendRGBState.srcFunc, state.blendRGBState.dstFunc, state.blendAState.srcFunc, state.blendAState.dstFunc);
195                 wrapper.glBlendColor(state.blendColor.x(), state.blendColor.y(), state.blendColor.z(), state.blendColor.w());
196         }
197         else
198                 wrapper.glDisable(GL_BLEND);
199
200         if (state.ditherEnabled)
201                 wrapper.glEnable(GL_DITHER);
202         else
203                 wrapper.glDisable(GL_DITHER);
204
205         wrapper.glColorMask(state.colorMask[0] ? GL_TRUE : GL_FALSE,
206                                                 state.colorMask[1] ? GL_TRUE : GL_FALSE,
207                                                 state.colorMask[2] ? GL_TRUE : GL_FALSE,
208                                                 state.colorMask[3] ? GL_TRUE : GL_FALSE);
209 }
210
211 class RandomFragmentOpCase : public TestCase
212 {
213 public:
214                                                 RandomFragmentOpCase            (Context& context, const char* name, const char* desc, deUint32 seed);
215                                                 ~RandomFragmentOpCase           (void);
216
217         void                            init                                            (void);
218         void                            deinit                                          (void);
219         IterateResult           iterate                                         (void);
220
221 private:
222         tcu::UVec4                      getCompareThreshold                     (void) const;
223
224         deUint32                                                                                m_seed;
225
226         glu::CallLogWrapper                                                             m_callLogWrapper;
227
228         gls::FragmentOpUtil::QuadRenderer*                              m_renderer;
229         tcu::TextureLevel*                                                              m_refColorBuffer;
230         tcu::TextureLevel*                                                              m_refDepthBuffer;
231         tcu::TextureLevel*                                                              m_refStencilBuffer;
232         gls::FragmentOpUtil::ReferenceQuadRenderer*             m_refRenderer;
233
234         int                                                                                             m_iterNdx;
235 };
236
237 RandomFragmentOpCase::RandomFragmentOpCase (Context& context, const char* name, const char* desc, deUint32 seed)
238         : TestCase                              (context, name, desc)
239         , m_seed                                (seed)
240         , m_callLogWrapper              (context.getRenderContext().getFunctions(), context.getTestContext().getLog())
241         , m_renderer                    (DE_NULL)
242         , m_refColorBuffer              (DE_NULL)
243         , m_refDepthBuffer              (DE_NULL)
244         , m_refStencilBuffer    (DE_NULL)
245         , m_refRenderer                 (DE_NULL)
246         , m_iterNdx                             (0)
247 {
248         m_callLogWrapper.enableLogging(ENABLE_CALL_LOG);
249 }
250
251 RandomFragmentOpCase::~RandomFragmentOpCase (void)
252 {
253         delete m_renderer;
254         delete m_refColorBuffer;
255         delete m_refDepthBuffer;
256         delete m_refStencilBuffer;
257         delete m_refRenderer;
258 }
259
260 void RandomFragmentOpCase::init (void)
261 {
262         DE_ASSERT(!m_renderer && !m_refColorBuffer && !m_refDepthBuffer && !m_refStencilBuffer && !m_refRenderer);
263
264         int             width   = de::min<int>(m_context.getRenderTarget().getWidth(), VIEWPORT_WIDTH);
265         int             height  = de::min<int>(m_context.getRenderTarget().getHeight(), VIEWPORT_HEIGHT);
266         bool    useRGB  = m_context.getRenderTarget().getPixelFormat().alphaBits == 0;
267
268         m_renderer                      = new gls::FragmentOpUtil::QuadRenderer(m_context.getRenderContext(), glu::GLSL_VERSION_300_ES);
269         m_refColorBuffer        = new tcu::TextureLevel(tcu::TextureFormat(useRGB ? tcu::TextureFormat::RGB : tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), width, height);
270         m_refDepthBuffer        = new tcu::TextureLevel(tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::FLOAT),                   width, height);
271         m_refStencilBuffer      = new tcu::TextureLevel(tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT32),  width, height);
272         m_refRenderer           = new gls::FragmentOpUtil::ReferenceQuadRenderer();
273         m_iterNdx                       = 0;
274
275         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
276 }
277
278 void RandomFragmentOpCase::deinit (void)
279 {
280         delete m_renderer;
281         delete m_refColorBuffer;
282         delete m_refDepthBuffer;
283         delete m_refStencilBuffer;
284         delete m_refRenderer;
285
286         m_renderer                      = DE_NULL;
287         m_refColorBuffer        = DE_NULL;
288         m_refDepthBuffer        = DE_NULL;
289         m_refStencilBuffer      = DE_NULL;
290         m_refRenderer           = DE_NULL;
291 }
292
293 RandomFragmentOpCase::IterateResult RandomFragmentOpCase::iterate (void)
294 {
295         const glw::Functions&   gl                              = m_context.getRenderContext().getFunctions();
296         const bool                              isMSAA                  = m_context.getRenderTarget().getNumSamples() > 1;
297         const deUint32                  iterSeed                = deUint32Hash(m_seed) ^ deInt32Hash(m_iterNdx) ^ deInt32Hash(m_testCtx.getCommandLine().getBaseSeed());
298         de::Random                              rnd                             (iterSeed);
299
300         const int                               width                   = m_refColorBuffer->getWidth();
301         const int                               height                  = m_refColorBuffer->getHeight();
302         const int                               viewportX               = rnd.getInt(0, m_context.getRenderTarget().getWidth()-width);
303         const int                               viewportY               = rnd.getInt(0, m_context.getRenderTarget().getHeight()-height);
304
305         tcu::Surface                    renderedImg             (width, height);
306         tcu::Surface                    referenceImg    (width, height);
307
308         const Vec4                              clearColor              = CLEAR_COLOR;
309         const float                             clearDepth              = CLEAR_DEPTH;
310         const int                               clearStencil    = CLEAR_STENCIL;
311
312         bool                                    gotError                = false;
313
314         const tcu::ScopedLogSection     iterSection     (m_testCtx.getLog(), std::string("Iteration") + de::toString(m_iterNdx), std::string("Iteration ") + de::toString(m_iterNdx));
315
316         // Compute randomized rendering commands.
317         vector<RenderCommand> commands;
318         computeRandomRenderCommands(rnd, glu::ApiType::es(3,0), NUM_CALLS_PER_ITERATION, width, height, commands);
319
320         // Reset default fragment state.
321         gl.disable(GL_SCISSOR_TEST);
322         gl.colorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
323         gl.depthMask(GL_TRUE);
324         gl.stencilMask(~0u);
325
326         // Render using GL.
327         m_callLogWrapper.glClearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
328         m_callLogWrapper.glClearDepthf(clearDepth);
329         m_callLogWrapper.glClearStencil(clearStencil);
330         m_callLogWrapper.glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
331         m_callLogWrapper.glViewport(viewportX, viewportY, width, height);
332
333         for (vector<RenderCommand>::const_iterator cmd = commands.begin(); cmd != commands.end(); cmd++)
334         {
335                 setGLState(m_callLogWrapper, cmd->state, viewportX, viewportY);
336
337                 if (ENABLE_CALL_LOG)
338                         m_testCtx.getLog() << TestLog::Message << "// Quad: " << cmd->quad.posA << " -> " << cmd->quad.posB
339                                                                                                    << ", color: [" << cmd->quad.color[0] << ", " << cmd->quad.color[1] << ", " << cmd->quad.color[2] << ", " << cmd->quad.color[3] << "]"
340                                                                                                    << ", depth: [" << cmd->quad.depth[0] << ", " << cmd->quad.depth[1] << ", " << cmd->quad.depth[2] << ", " << cmd->quad.depth[3] << "]"
341                                                                 << TestLog::EndMessage;
342
343                 renderQuad(gl, *m_renderer, cmd->quad, viewportX, viewportY);
344         }
345
346         // Check error.
347         if (m_callLogWrapper.glGetError() != GL_NO_ERROR)
348                 gotError = true;
349
350         gl.flush();
351
352         // Render reference while GPU is doing work.
353         tcu::clear                      (m_refColorBuffer->getAccess(),         clearColor);
354         tcu::clearDepth         (m_refDepthBuffer->getAccess(),         clearDepth);
355         tcu::clearStencil       (m_refStencilBuffer->getAccess(),       clearStencil);
356
357         for (vector<RenderCommand>::const_iterator cmd = commands.begin(); cmd != commands.end(); cmd++)
358         {
359                 rr::FragmentOperationState refState;
360                 translateState(cmd->state, refState, m_context.getRenderTarget());
361                 m_refRenderer->render(gls::FragmentOpUtil::getMultisampleAccess(m_refColorBuffer->getAccess()),
362                                                           gls::FragmentOpUtil::getMultisampleAccess(m_refDepthBuffer->getAccess()),
363                                                           gls::FragmentOpUtil::getMultisampleAccess(m_refStencilBuffer->getAccess()),
364                                                           cmd->quad, refState);
365         }
366
367         // Expand reference color buffer to RGBA8
368         copy(referenceImg.getAccess(), m_refColorBuffer->getAccess());
369
370         // Read rendered image.
371         glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedImg.getAccess());
372
373         m_iterNdx += 1;
374
375         // Compare to reference.
376         const bool                      isLastIter      = m_iterNdx >= NUM_ITERATIONS_PER_CASE;
377         const tcu::UVec4        threshold       = getCompareThreshold();
378         bool                            compareOk;
379
380         if (isMSAA)
381         {
382                 // in MSAA cases, the sampling points could be anywhere in the pixel and we could
383                 // even have multiple samples that are combined in resolve. Allow arbitrary sample
384                 // positions by using bilinearCompare.
385                 compareOk = tcu::bilinearCompare(m_testCtx.getLog(),
386                                                                                  "CompareResult",
387                                                                                  "Image Comparison Result",
388                                                                                  referenceImg.getAccess(),
389                                                                                  renderedImg.getAccess(),
390                                                                                  tcu::RGBA(threshold.x(), threshold.y(), threshold.z(), threshold.w()),
391                                                                                  tcu::COMPARE_LOG_RESULT);
392         }
393         else
394                 compareOk = tcu::intThresholdCompare(m_testCtx.getLog(),
395                                                                                          "CompareResult",
396                                                                                          "Image Comparison Result",
397                                                                                          referenceImg.getAccess(),
398                                                                                          renderedImg.getAccess(),
399                                                                                          threshold,
400                                                                                          tcu::COMPARE_LOG_RESULT);
401
402         m_testCtx.getLog() << TestLog::Message << (compareOk ? "  Passed." : "  FAILED!") << TestLog::EndMessage;
403
404         if (!compareOk)
405                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
406         else if (gotError)
407                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "GL error");
408
409         if (compareOk && !gotError && !isLastIter)
410                 return CONTINUE;
411         else
412                 return STOP;
413 }
414
415 tcu::UVec4 RandomFragmentOpCase::getCompareThreshold (void) const
416 {
417         tcu::PixelFormat format = m_context.getRenderTarget().getPixelFormat();
418
419         if (format == tcu::PixelFormat(8, 8, 8, 8) || format == tcu::PixelFormat(8, 8, 8, 0))
420                 return format.getColorThreshold().toIVec().asUint() + tcu::UVec4(2); // Default threshold.
421         else
422                 return format.getColorThreshold().toIVec().asUint()
423                            * tcu::UVec4(5) + tcu::UVec4(2); // \note Non-scientific ad hoc formula. Need big threshold when few color bits; especially multiple blendings bring extra inaccuracy.
424 }
425
426 RandomFragmentOpTests::RandomFragmentOpTests (Context& context)
427         : TestCaseGroup(context, "random", "Randomized Per-Fragment Operation Tests")
428 {
429 }
430
431 RandomFragmentOpTests::~RandomFragmentOpTests (void)
432 {
433 }
434
435 void RandomFragmentOpTests::init (void)
436 {
437         for (int ndx = 0; ndx < 100; ndx++)
438                 addChild(new RandomFragmentOpCase(m_context, de::toString(ndx).c_str(), "", (deUint32)(ndx*NUM_ITERATIONS_PER_CASE)));
439 }
440
441 } // Functional
442 } // gles3
443 } // deqp