xref: /aosp_15_r20/external/deqp/modules/gles3/functional/es3fPolygonOffsetTests.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 Polygon offset tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es3fPolygonOffsetTests.hpp"
25 #include "deStringUtil.hpp"
26 #include "deRandom.hpp"
27 #include "gluContextInfo.hpp"
28 #include "gluRenderContext.hpp"
29 #include "gluShaderProgram.hpp"
30 #include "gluPixelTransfer.hpp"
31 #include "gluStrUtil.hpp"
32 #include "glwEnums.hpp"
33 #include "glwDefs.hpp"
34 #include "glwFunctions.hpp"
35 #include "tcuTestContext.hpp"
36 #include "tcuTestLog.hpp"
37 #include "tcuTextureUtil.hpp"
38 #include "tcuRenderTarget.hpp"
39 #include "tcuVectorUtil.hpp"
40 #include "rrRenderer.hpp"
41 #include "rrFragmentOperations.hpp"
42 
43 #include "sglrReferenceContext.hpp"
44 
45 #include <string>
46 #include <limits>
47 
48 using namespace glw; // GLint and other GL types
49 
50 namespace deqp
51 {
52 namespace gles3
53 {
54 namespace Functional
55 {
56 namespace
57 {
58 
59 const char *s_shaderSourceVertex   = "#version 300 es\n"
60                                      "in highp vec4 a_position;\n"
61                                      "in highp vec4 a_color;\n"
62                                      "out highp vec4 v_color;\n"
63                                      "void main (void)\n"
64                                      "{\n"
65                                      "    gl_Position = a_position;\n"
66                                      "    v_color = a_color;\n"
67                                      "}\n";
68 const char *s_shaderSourceFragment = "#version 300 es\n"
69                                      "in highp vec4 v_color;\n"
70                                      "layout(location = 0) out mediump vec4 fragColor;"
71                                      "void main (void)\n"
72                                      "{\n"
73                                      "    fragColor = v_color;\n"
74                                      "}\n";
75 
76 static const tcu::Vec4 MASK_COLOR_OK   = tcu::Vec4(0.0f, 0.1f, 0.0f, 1.0f);
77 static const tcu::Vec4 MASK_COLOR_DEV  = tcu::Vec4(0.8f, 0.5f, 0.0f, 1.0f);
78 static const tcu::Vec4 MASK_COLOR_FAIL = tcu::Vec4(1.0f, 0.0f, 1.0f, 1.0f);
79 
compareThreshold(const tcu::IVec4 & a,const tcu::IVec4 & b,const tcu::IVec4 & threshold)80 inline bool compareThreshold(const tcu::IVec4 &a, const tcu::IVec4 &b, const tcu::IVec4 &threshold)
81 {
82     return tcu::boolAll(tcu::lessThanEqual(tcu::abs(a - b), threshold));
83 }
84 
85 /*--------------------------------------------------------------------*//*!
86 * \brief Pixelwise comparison of two images.
87 * \note copied & modified from glsRasterizationTests
88 *
89 * Kernel radius defines maximum allowed distance. If radius is 0, only
90 * perfect match is allowed. Radius of 1 gives a 3x3 kernel.
91 *
92 * Return values: -1 = Perfect match
93 * 0 = Deviation within kernel
94 * >0 = Number of faulty pixels
95 *//*--------------------------------------------------------------------*/
compareImages(tcu::TestLog & log,glu::RenderContext & renderCtx,const tcu::ConstPixelBufferAccess & test,const tcu::ConstPixelBufferAccess & ref,const tcu::PixelBufferAccess & diffMask,int radius)96 int compareImages(tcu::TestLog &log, glu::RenderContext &renderCtx, const tcu::ConstPixelBufferAccess &test,
97                   const tcu::ConstPixelBufferAccess &ref, const tcu::PixelBufferAccess &diffMask, int radius)
98 {
99     const int height                = test.getHeight();
100     const int width                 = test.getWidth();
101     const int colorThreshold        = 128;
102     const tcu::RGBA formatThreshold = renderCtx.getRenderTarget().getPixelFormat().getColorThreshold();
103     const tcu::IVec4 threshold      = tcu::IVec4(colorThreshold, colorThreshold, colorThreshold,
104                                             formatThreshold.getAlpha() > 0 ? colorThreshold : 0) +
105                                  tcu::IVec4(formatThreshold.getRed(), formatThreshold.getGreen(),
106                                             formatThreshold.getBlue(), formatThreshold.getAlpha());
107 
108     int faultyPixels  = 0;
109     int compareFailed = -1;
110 
111     tcu::clear(diffMask, MASK_COLOR_OK);
112 
113     for (int y = 0; y < height; y++)
114     {
115         for (int x = 0; x < width; x++)
116         {
117             const tcu::IVec4 cRef = ref.getPixelInt(x, y);
118 
119             // Pixelwise match, no deviation or fault
120             {
121                 const tcu::IVec4 cTest = test.getPixelInt(x, y);
122                 if (compareThreshold(cRef, cTest, threshold))
123                     continue;
124             }
125 
126             // If not, search within kernel radius
127             {
128                 const int kYmin = deMax32(y - radius, 0);
129                 const int kYmax = deMin32(y + radius, height - 1);
130                 const int kXmin = deMax32(x - radius, 0);
131                 const int kXmax = deMin32(x + radius, width - 1);
132                 bool found      = false;
133 
134                 for (int kY = kYmin; kY <= kYmax; kY++)
135                     for (int kX = kXmin; kX <= kXmax; kX++)
136                     {
137                         const tcu::IVec4 cTest = test.getPixelInt(kX, kY);
138                         if (compareThreshold(cRef, cTest, threshold))
139                             found = true;
140                     }
141 
142                 if (found) // The pixel is deviating if the color is found inside the kernel
143                 {
144                     diffMask.setPixel(MASK_COLOR_DEV, x, y);
145                     if (compareFailed == -1)
146                         compareFailed = 0;
147                     continue;
148                 }
149             }
150 
151             diffMask.setPixel(MASK_COLOR_FAIL, x, y);
152             faultyPixels++; // The pixel is faulty if the color is not found
153             compareFailed = 1;
154         }
155     }
156 
157     log << tcu::TestLog::Message << faultyPixels << " faulty pixel(s) found." << tcu::TestLog::EndMessage;
158 
159     return (compareFailed == 1 ? faultyPixels : compareFailed);
160 }
161 
verifyImages(tcu::TestLog & log,tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const tcu::ConstPixelBufferAccess & testImage,const tcu::ConstPixelBufferAccess & referenceImage)162 void verifyImages(tcu::TestLog &log, tcu::TestContext &testCtx, glu::RenderContext &renderCtx,
163                   const tcu::ConstPixelBufferAccess &testImage, const tcu::ConstPixelBufferAccess &referenceImage)
164 {
165     using tcu::TestLog;
166 
167     const int kernelRadius     = 1;
168     const int faultyPixelLimit = 20;
169     int faultyPixels;
170     tcu::Surface diffMask(testImage.getWidth(), testImage.getHeight());
171 
172     faultyPixels = compareImages(log, renderCtx, referenceImage, testImage, diffMask.getAccess(), kernelRadius);
173 
174     if (faultyPixels > faultyPixelLimit)
175     {
176         log << TestLog::ImageSet("Images", "Image comparison");
177         log << TestLog::Image("Test image", "Test image", testImage);
178         log << TestLog::Image("Reference image", "Reference image", referenceImage);
179         log << TestLog::Image("Difference mask", "Difference mask", diffMask.getAccess());
180         log << TestLog::EndImageSet;
181 
182         log << tcu::TestLog::Message << "Got " << faultyPixels << " faulty pixel(s)." << tcu::TestLog::EndMessage;
183         testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got faulty pixels");
184     }
185 }
186 
verifyError(tcu::TestContext & testCtx,const glw::Functions & gl,GLenum expected)187 void verifyError(tcu::TestContext &testCtx, const glw::Functions &gl, GLenum expected)
188 {
189     uint32_t got = gl.getError();
190     if (got != expected)
191     {
192         testCtx.getLog() << tcu::TestLog::Message << "// ERROR: expected " << glu::getErrorStr(expected) << "; got "
193                          << glu::getErrorStr(got) << tcu::TestLog::EndMessage;
194         if (testCtx.getTestResult() == QP_TEST_RESULT_PASS)
195             testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got invalid error");
196     }
197 }
198 
checkCanvasSize(int width,int height,int minWidth,int minHeight)199 void checkCanvasSize(int width, int height, int minWidth, int minHeight)
200 {
201     if (width < minWidth || height < minHeight)
202         throw tcu::NotSupportedError(std::string("Render context size must be at least ") + de::toString(minWidth) +
203                                      "x" + de::toString(minWidth));
204 }
205 
206 class PositionColorShader : public sglr::ShaderProgram
207 {
208 public:
209     enum
210     {
211         VARYINGLOC_COLOR = 0
212     };
213 
214     PositionColorShader(void);
215     void shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets, const int numPackets) const;
216     void shadeFragments(rr::FragmentPacket *packets, const int numPackets,
217                         const rr::FragmentShadingContext &context) const;
218 };
219 
PositionColorShader(void)220 PositionColorShader::PositionColorShader(void)
221     : sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
222                           << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
223                           << sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT)
224                           << sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
225                           << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
226                           << sglr::pdec::VertexSource(s_shaderSourceVertex)
227                           << sglr::pdec::FragmentSource(s_shaderSourceFragment))
228 {
229 }
230 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const231 void PositionColorShader::shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets,
232                                         const int numPackets) const
233 {
234     for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
235     {
236         const int positionAttrLoc = 0;
237         const int colorAttrLoc    = 1;
238 
239         rr::VertexPacket &packet = *packets[packetNdx];
240 
241         // Transform to position
242         packet.position = rr::readVertexAttribFloat(inputs[positionAttrLoc], packet.instanceNdx, packet.vertexNdx);
243 
244         // Pass color to FS
245         packet.outputs[VARYINGLOC_COLOR] =
246             rr::readVertexAttribFloat(inputs[colorAttrLoc], packet.instanceNdx, packet.vertexNdx);
247     }
248 }
249 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const250 void PositionColorShader::shadeFragments(rr::FragmentPacket *packets, const int numPackets,
251                                          const rr::FragmentShadingContext &context) const
252 {
253     for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
254     {
255         rr::FragmentPacket &packet = packets[packetNdx];
256 
257         for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
258             rr::writeFragmentOutput(context, packetNdx, fragNdx, 0,
259                                     rr::readTriangleVarying<float>(packet, context, VARYINGLOC_COLOR, fragNdx));
260     }
261 }
262 
263 // PolygonOffsetTestCase
264 
265 class PolygonOffsetTestCase : public TestCase
266 {
267 public:
268     PolygonOffsetTestCase(Context &context, const char *name, const char *description, GLenum internalFormat,
269                           const char *internalFormatName, int canvasSize);
270 
271     virtual void testPolygonOffset(void) = DE_NULL;
272     IterateResult iterate(void);
273 
274 protected:
275     const GLenum m_internalFormat;
276     const char *m_internalFormatName;
277     const int m_targetSize;
278 };
279 
PolygonOffsetTestCase(Context & context,const char * name,const char * description,GLenum internalFormat,const char * internalFormatName,int canvasSize)280 PolygonOffsetTestCase::PolygonOffsetTestCase(Context &context, const char *name, const char *description,
281                                              GLenum internalFormat, const char *internalFormatName, int canvasSize)
282     : TestCase(context, name, description)
283     , m_internalFormat(internalFormat)
284     , m_internalFormatName(internalFormatName)
285     , m_targetSize(canvasSize)
286 {
287 }
288 
iterate(void)289 PolygonOffsetTestCase::IterateResult PolygonOffsetTestCase::iterate(void)
290 {
291     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
292     m_testCtx.getLog() << tcu::TestLog::Message << "Testing PolygonOffset with " << m_internalFormatName
293                        << " depth buffer." << tcu::TestLog::EndMessage;
294 
295     if (m_internalFormat == 0)
296     {
297         // default framebuffer
298         const int width  = m_context.getRenderTarget().getWidth();
299         const int height = m_context.getRenderTarget().getHeight();
300 
301         checkCanvasSize(width, height, m_targetSize, m_targetSize);
302 
303         if (m_context.getRenderTarget().getDepthBits() == 0)
304             throw tcu::NotSupportedError("polygon offset tests require depth buffer");
305 
306         testPolygonOffset();
307     }
308     else
309     {
310         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
311 
312         // framebuffer object
313         GLuint colorRboId = 0;
314         GLuint depthRboId = 0;
315         GLuint fboId      = 0;
316         bool fboComplete;
317 
318         gl.genRenderbuffers(1, &colorRboId);
319         gl.bindRenderbuffer(GL_RENDERBUFFER, colorRboId);
320         gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, m_targetSize, m_targetSize);
321         verifyError(m_testCtx, gl, GL_NO_ERROR);
322 
323         gl.genRenderbuffers(1, &depthRboId);
324         gl.bindRenderbuffer(GL_RENDERBUFFER, depthRboId);
325         gl.renderbufferStorage(GL_RENDERBUFFER, m_internalFormat, m_targetSize, m_targetSize);
326         verifyError(m_testCtx, gl, GL_NO_ERROR);
327 
328         gl.genFramebuffers(1, &fboId);
329         gl.bindFramebuffer(GL_FRAMEBUFFER, fboId);
330         gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRboId);
331         gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRboId);
332         verifyError(m_testCtx, gl, GL_NO_ERROR);
333 
334         fboComplete = gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
335 
336         if (fboComplete)
337             testPolygonOffset();
338 
339         gl.deleteFramebuffers(1, &fboId);
340         gl.deleteRenderbuffers(1, &depthRboId);
341         gl.deleteRenderbuffers(1, &colorRboId);
342 
343         if (!fboComplete)
344             throw tcu::NotSupportedError("could not create fbo for testing.");
345     }
346 
347     return STOP;
348 }
349 
350 // UsageTestCase
351 
352 class UsageTestCase : public PolygonOffsetTestCase
353 {
354 public:
355     UsageTestCase(Context &context, const char *name, const char *description, GLenum internalFormat,
356                   const char *internalFormatName);
357 
358     void testPolygonOffset(void);
359 };
360 
UsageTestCase(Context & context,const char * name,const char * description,GLenum internalFormat,const char * internalFormatName)361 UsageTestCase::UsageTestCase(Context &context, const char *name, const char *description, GLenum internalFormat,
362                              const char *internalFormatName)
363     : PolygonOffsetTestCase(context, name, description, internalFormat, internalFormatName, 200)
364 {
365 }
366 
testPolygonOffset(void)367 void UsageTestCase::testPolygonOffset(void)
368 {
369     using tcu::TestLog;
370 
371     const tcu::Vec4 triangle[] = {
372         tcu::Vec4(-1, 1, 0, 1),
373         tcu::Vec4(1, 1, 0, 1),
374         tcu::Vec4(1, -1, 0, 1),
375     };
376 
377     tcu::TestLog &log = m_testCtx.getLog();
378     tcu::Surface testImage(m_targetSize, m_targetSize);
379     tcu::Surface referenceImage(m_targetSize, m_targetSize);
380     int subpixelBits = 0;
381 
382     // render test image
383     {
384         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
385         const glu::ShaderProgram program(m_context.getRenderContext(),
386                                          glu::makeVtxFragSources(s_shaderSourceVertex, s_shaderSourceFragment));
387         const GLint positionLoc = gl.getAttribLocation(program.getProgram(), "a_position");
388         const GLint colorLoc    = gl.getAttribLocation(program.getProgram(), "a_color");
389 
390         if (!program.isOk())
391         {
392             log << program;
393             TCU_FAIL("Shader compile failed.");
394         }
395 
396         gl.clearColor(0, 0, 0, 1);
397         gl.clearDepthf(1.0f);
398         gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
399         gl.viewport(0, 0, m_targetSize, m_targetSize);
400         gl.useProgram(program.getProgram());
401         gl.enable(GL_DEPTH_TEST);
402         gl.depthFunc(
403             GL_LEQUAL); // make test pass if polygon offset doesn't do anything. It has its own test case. This test is only for to detect always-on cases.
404 
405         log << TestLog::Message << "DepthFunc = GL_LEQUAL" << TestLog::EndMessage;
406 
407         gl.enableVertexAttribArray(positionLoc);
408         gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, triangle);
409 
410         //draw back (offset disabled)
411 
412         log << TestLog::Message
413             << "Draw bottom-right. Color = White.\tState: PolygonOffset(0, -2), POLYGON_OFFSET_FILL disabled."
414             << TestLog::EndMessage;
415 
416         gl.polygonOffset(0, -2);
417         gl.disable(GL_POLYGON_OFFSET_FILL);
418         gl.vertexAttrib4f(colorLoc, 1.0f, 1.0f, 1.0f, 1.0f);
419         gl.drawArrays(GL_TRIANGLES, 0, 3);
420 
421         //draw front
422 
423         log << TestLog::Message
424             << "Draw bottom-right. Color = Red.\tState: PolygonOffset(0, -1), POLYGON_OFFSET_FILL enabled."
425             << TestLog::EndMessage;
426 
427         gl.polygonOffset(0, -1);
428         gl.enable(GL_POLYGON_OFFSET_FILL);
429         gl.vertexAttrib4f(colorLoc, 1.0f, 0.0f, 0.0f, 1.0f);
430         gl.drawArrays(GL_TRIANGLES, 0, 3);
431 
432         gl.disableVertexAttribArray(positionLoc);
433         gl.useProgram(0);
434         gl.finish();
435 
436         glu::readPixels(m_context.getRenderContext(), 0, 0, testImage.getAccess());
437 
438         gl.getIntegerv(GL_SUBPIXEL_BITS, &subpixelBits);
439     }
440 
441     // render reference image
442     {
443         rr::Renderer referenceRenderer;
444         rr::VertexAttrib attribs[2];
445         rr::RenderState state((rr::ViewportState)(rr::WindowRectangle(0, 0, m_targetSize, m_targetSize)), subpixelBits);
446 
447         PositionColorShader program;
448 
449         attribs[0].type            = rr::VERTEXATTRIBTYPE_FLOAT;
450         attribs[0].size            = 4;
451         attribs[0].stride          = 0;
452         attribs[0].instanceDivisor = 0;
453         attribs[0].pointer         = triangle;
454 
455         attribs[1].type    = rr::VERTEXATTRIBTYPE_DONT_CARE;
456         attribs[1].generic = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
457 
458         tcu::clear(referenceImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
459 
460         log << TestLog::Message << "Expecting: Bottom-right = Red." << TestLog::EndMessage;
461 
462         referenceRenderer.draw(rr::DrawCommand(
463             state,
464             rr::RenderTarget(rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(referenceImage.getAccess())),
465             rr::Program(program.getVertexShader(), program.getFragmentShader()), 2, attribs,
466             rr::PrimitiveList(rr::PRIMITIVETYPE_TRIANGLES, 3, 0)));
467     }
468 
469     // compare
470     verifyImages(log, m_testCtx, m_context.getRenderContext(), testImage.getAccess(), referenceImage.getAccess());
471 }
472 
473 // UsageDisplacementTestCase
474 
475 class UsageDisplacementTestCase : public PolygonOffsetTestCase
476 {
477 public:
478     UsageDisplacementTestCase(Context &context, const char *name, const char *description, GLenum internalFormat,
479                               const char *internalFormatName);
480 
481 private:
482     tcu::Vec4 genRandomVec4(de::Random &rnd) const;
483     void testPolygonOffset(void);
484 };
485 
UsageDisplacementTestCase(Context & context,const char * name,const char * description,GLenum internalFormat,const char * internalFormatName)486 UsageDisplacementTestCase::UsageDisplacementTestCase(Context &context, const char *name, const char *description,
487                                                      GLenum internalFormat, const char *internalFormatName)
488     : PolygonOffsetTestCase(context, name, description, internalFormat, internalFormatName, 200)
489 {
490 }
491 
genRandomVec4(de::Random & rnd) const492 tcu::Vec4 UsageDisplacementTestCase::genRandomVec4(de::Random &rnd) const
493 {
494     // generater triangle endpoint with following properties
495     //    1) it will not be clipped
496     //    2) it is not near either far or near plane to prevent possible problems related to depth clamping
497     // => w >= 1.0 and z in (-0.9, 0.9) range
498     tcu::Vec4 retVal;
499 
500     retVal.x() = rnd.getFloat(-1, 1);
501     retVal.y() = rnd.getFloat(-1, 1);
502     retVal.z() = 0.5f;
503     retVal.w() = 1.0f + rnd.getFloat();
504 
505     return retVal;
506 }
507 
testPolygonOffset(void)508 void UsageDisplacementTestCase::testPolygonOffset(void)
509 {
510     using tcu::TestLog;
511 
512     de::Random rnd(0xdec0de);
513     tcu::TestLog &log = m_testCtx.getLog();
514     tcu::Surface testImage(m_targetSize, m_targetSize);
515     tcu::Surface referenceImage(m_targetSize, m_targetSize);
516 
517     // render test image
518     {
519         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
520         const glu::ShaderProgram program(m_context.getRenderContext(),
521                                          glu::makeVtxFragSources(s_shaderSourceVertex, s_shaderSourceFragment));
522         const GLint positionLoc = gl.getAttribLocation(program.getProgram(), "a_position");
523         const GLint colorLoc    = gl.getAttribLocation(program.getProgram(), "a_color");
524         const int numIterations = 40;
525 
526         if (!program.isOk())
527         {
528             log << program;
529             TCU_FAIL("Shader compile failed.");
530         }
531 
532         gl.clearColor(0, 0, 0, 1);
533         gl.clearDepthf(1.0f);
534         gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
535         gl.viewport(0, 0, m_targetSize, m_targetSize);
536         gl.useProgram(program.getProgram());
537         gl.enable(GL_DEPTH_TEST);
538         gl.enable(GL_POLYGON_OFFSET_FILL);
539         gl.enableVertexAttribArray(positionLoc);
540         gl.vertexAttrib4f(colorLoc, 0.0f, 1.0f, 0.0f, 1.0f);
541 
542         log << TestLog::Message << "Framebuffer cleared, clear color = Black." << TestLog::EndMessage;
543         log << TestLog::Message << "POLYGON_OFFSET_FILL enabled." << TestLog::EndMessage;
544 
545         // draw colorless (mask = 0,0,0) triangle at random* location, set offset and render green triangle with depthfunc = equal
546         // *) w >= 1.0 and z in (-1, 1) range
547         for (int iterationNdx = 0; iterationNdx < numIterations; ++iterationNdx)
548         {
549             const bool offsetDirection = rnd.getBool();
550             const float offset         = offsetDirection ? -1.0f : 1.0f;
551             tcu::Vec4 triangle[3];
552 
553             for (int vertexNdx = 0; vertexNdx < DE_LENGTH_OF_ARRAY(triangle); ++vertexNdx)
554                 triangle[vertexNdx] = genRandomVec4(rnd);
555 
556             gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, triangle);
557 
558             log << TestLog::Message << "Setup triangle with random coordinates:" << TestLog::EndMessage;
559             for (size_t ndx = 0; ndx < DE_LENGTH_OF_ARRAY(triangle); ++ndx)
560                 log << TestLog::Message << "\tx=" << triangle[ndx].x() << "\ty=" << triangle[ndx].y()
561                     << "\tz=" << triangle[ndx].z() << "\tw=" << triangle[ndx].w() << TestLog::EndMessage;
562 
563             log << TestLog::Message << "Draw colorless triangle.\tState: DepthFunc = GL_ALWAYS, PolygonOffset(0, 0)."
564                 << TestLog::EndMessage;
565 
566             gl.depthFunc(GL_ALWAYS);
567             gl.polygonOffset(0, 0);
568             gl.colorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
569             gl.drawArrays(GL_TRIANGLES, 0, 3);
570 
571             // all fragments should have different Z => DepthFunc == GL_EQUAL fails with every fragment
572 
573             log << TestLog::Message << "Draw green triangle.\tState: DepthFunc = GL_EQUAL, PolygonOffset(0, " << offset
574                 << ")." << TestLog::EndMessage;
575 
576             gl.depthFunc(GL_EQUAL);
577             gl.polygonOffset(0, offset);
578             gl.colorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
579             gl.drawArrays(GL_TRIANGLES, 0, 3);
580 
581             log << TestLog::Message << TestLog::EndMessage; // empty line for clarity
582         }
583 
584         gl.disableVertexAttribArray(positionLoc);
585         gl.useProgram(0);
586         gl.finish();
587 
588         glu::readPixels(m_context.getRenderContext(), 0, 0, testImage.getAccess());
589     }
590 
591     // render reference image
592     log << TestLog::Message << "Expecting black framebuffer." << TestLog::EndMessage;
593     tcu::clear(referenceImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
594 
595     // compare
596     verifyImages(log, m_testCtx, m_context.getRenderContext(), testImage.getAccess(), referenceImage.getAccess());
597 }
598 
599 // UsagePositiveNegativeTestCase
600 
601 class UsagePositiveNegativeTestCase : public PolygonOffsetTestCase
602 {
603 public:
604     UsagePositiveNegativeTestCase(Context &context, const char *name, const char *description, GLenum internalFormat,
605                                   const char *internalFormatName);
606 
607     void testPolygonOffset(void);
608 };
609 
UsagePositiveNegativeTestCase(Context & context,const char * name,const char * description,GLenum internalFormat,const char * internalFormatName)610 UsagePositiveNegativeTestCase::UsagePositiveNegativeTestCase(Context &context, const char *name,
611                                                              const char *description, GLenum internalFormat,
612                                                              const char *internalFormatName)
613     : PolygonOffsetTestCase(context, name, description, internalFormat, internalFormatName, 200)
614 {
615 }
616 
testPolygonOffset(void)617 void UsagePositiveNegativeTestCase::testPolygonOffset(void)
618 {
619     using tcu::TestLog;
620 
621     const tcu::Vec4 triangleBottomRight[] = {
622         tcu::Vec4(-1, 1, 0, 1),
623         tcu::Vec4(1, 1, 0, 1),
624         tcu::Vec4(1, -1, 0, 1),
625     };
626     const tcu::Vec4 triangleTopLeft[] = {
627         tcu::Vec4(-1, -1, 0, 1),
628         tcu::Vec4(-1, 1, 0, 1),
629         tcu::Vec4(1, -1, 0, 1),
630     };
631 
632     tcu::TestLog &log = m_testCtx.getLog();
633     tcu::Surface testImage(m_targetSize, m_targetSize);
634     tcu::Surface referenceImage(m_targetSize, m_targetSize);
635     int subpixelBits = 0;
636     // render test image
637     {
638         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
639         const glu::ShaderProgram program(m_context.getRenderContext(),
640                                          glu::makeVtxFragSources(s_shaderSourceVertex, s_shaderSourceFragment));
641         const GLint positionLoc = gl.getAttribLocation(program.getProgram(), "a_position");
642         const GLint colorLoc    = gl.getAttribLocation(program.getProgram(), "a_color");
643 
644         if (!program.isOk())
645         {
646             log << program;
647             TCU_FAIL("Shader compile failed.");
648         }
649 
650         gl.clearColor(0, 0, 0, 1);
651         gl.clearDepthf(1.0f);
652         gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
653         gl.viewport(0, 0, m_targetSize, m_targetSize);
654         gl.depthFunc(GL_LESS);
655         gl.useProgram(program.getProgram());
656         gl.enable(GL_DEPTH_TEST);
657         gl.enable(GL_POLYGON_OFFSET_FILL);
658         gl.enableVertexAttribArray(positionLoc);
659 
660         log << TestLog::Message << "DepthFunc = GL_LESS." << TestLog::EndMessage;
661         log << TestLog::Message << "POLYGON_OFFSET_FILL enabled." << TestLog::EndMessage;
662 
663         //draw top left (negative offset test)
664         {
665             gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, triangleTopLeft);
666 
667             log << TestLog::Message << "Draw top-left. Color = White.\tState: PolygonOffset(0, 0)."
668                 << TestLog::EndMessage;
669 
670             gl.polygonOffset(0, 0);
671             gl.vertexAttrib4f(colorLoc, 1.0f, 1.0f, 1.0f, 1.0f);
672             gl.drawArrays(GL_TRIANGLES, 0, 3);
673 
674             log << TestLog::Message << "Draw top-left. Color = Green.\tState: PolygonOffset(0, -1)."
675                 << TestLog::EndMessage;
676 
677             gl.polygonOffset(0, -1);
678             gl.vertexAttrib4f(colorLoc, 0.0f, 1.0f, 0.0f, 1.0f);
679             gl.drawArrays(GL_TRIANGLES, 0, 3);
680         }
681 
682         //draw bottom right (positive offset test)
683         {
684             gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, triangleBottomRight);
685 
686             log << TestLog::Message << "Draw bottom-right. Color = White.\tState: PolygonOffset(0, 1)."
687                 << TestLog::EndMessage;
688 
689             gl.polygonOffset(0, 1);
690             gl.vertexAttrib4f(colorLoc, 1.0f, 1.0f, 1.0f, 1.0f);
691             gl.drawArrays(GL_TRIANGLES, 0, 3);
692 
693             log << TestLog::Message << "Draw bottom-right. Color = Yellow.\tState: PolygonOffset(0, 0)."
694                 << TestLog::EndMessage;
695 
696             gl.polygonOffset(0, 0);
697             gl.vertexAttrib4f(colorLoc, 1.0f, 1.0f, 0.0f, 1.0f);
698             gl.drawArrays(GL_TRIANGLES, 0, 3);
699         }
700 
701         gl.disableVertexAttribArray(positionLoc);
702         gl.useProgram(0);
703         gl.finish();
704 
705         glu::readPixels(m_context.getRenderContext(), 0, 0, testImage.getAccess());
706 
707         gl.getIntegerv(GL_SUBPIXEL_BITS, &subpixelBits);
708     }
709 
710     // render reference image
711     {
712         rr::Renderer referenceRenderer;
713         rr::VertexAttrib attribs[2];
714         rr::RenderState state((rr::ViewportState)(rr::WindowRectangle(0, 0, m_targetSize, m_targetSize)), subpixelBits);
715 
716         PositionColorShader program;
717 
718         attribs[0].type            = rr::VERTEXATTRIBTYPE_FLOAT;
719         attribs[0].size            = 4;
720         attribs[0].stride          = 0;
721         attribs[0].instanceDivisor = 0;
722         attribs[0].pointer         = triangleTopLeft;
723 
724         attribs[1].type    = rr::VERTEXATTRIBTYPE_DONT_CARE;
725         attribs[1].generic = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
726 
727         tcu::clear(referenceImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
728 
729         log << TestLog::Message << "Expecting: Top-left = Green, Bottom-right = Yellow." << TestLog::EndMessage;
730 
731         referenceRenderer.draw(rr::DrawCommand(
732             state,
733             rr::RenderTarget(rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(referenceImage.getAccess())),
734             rr::Program(program.getVertexShader(), program.getFragmentShader()), 2, attribs,
735             rr::PrimitiveList(rr::PRIMITIVETYPE_TRIANGLES, 3, 0)));
736 
737         attribs[0].pointer = triangleBottomRight;
738         attribs[1].generic = tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
739 
740         referenceRenderer.draw(rr::DrawCommand(
741             state,
742             rr::RenderTarget(rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(referenceImage.getAccess())),
743             rr::Program(program.getVertexShader(), program.getFragmentShader()), 2, attribs,
744             rr::PrimitiveList(rr::PRIMITIVETYPE_TRIANGLES, 3, 0)));
745     }
746 
747     // compare
748     verifyImages(log, m_testCtx, m_context.getRenderContext(), testImage.getAccess(), referenceImage.getAccess());
749 }
750 
751 // ResultClampingTestCase
752 
753 class ResultClampingTestCase : public PolygonOffsetTestCase
754 {
755 public:
756     ResultClampingTestCase(Context &context, const char *name, const char *description, GLenum internalFormat,
757                            const char *internalFormatName);
758 
759     void testPolygonOffset(void);
760 };
761 
ResultClampingTestCase(Context & context,const char * name,const char * description,GLenum internalFormat,const char * internalFormatName)762 ResultClampingTestCase::ResultClampingTestCase(Context &context, const char *name, const char *description,
763                                                GLenum internalFormat, const char *internalFormatName)
764     : PolygonOffsetTestCase(context, name, description, internalFormat, internalFormatName, 200)
765 {
766 }
767 
testPolygonOffset(void)768 void ResultClampingTestCase::testPolygonOffset(void)
769 {
770     using tcu::TestLog;
771 
772     const tcu::Vec4 triangleBottomRight[] = {
773         tcu::Vec4(-1, 1, 1, 1),
774         tcu::Vec4(1, 1, 1, 1),
775         tcu::Vec4(1, -1, 1, 1),
776     };
777     const tcu::Vec4 triangleTopLeft[] = {
778         tcu::Vec4(-1, -1, -1, 1),
779         tcu::Vec4(-1, 1, -1, 1),
780         tcu::Vec4(1, -1, -1, 1),
781     };
782 
783     tcu::TestLog &log = m_testCtx.getLog();
784     tcu::Surface testImage(m_targetSize, m_targetSize);
785     tcu::Surface referenceImage(m_targetSize, m_targetSize);
786 
787     // render test image
788     {
789         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
790         const glu::ShaderProgram program(m_context.getRenderContext(),
791                                          glu::makeVtxFragSources(s_shaderSourceVertex, s_shaderSourceFragment));
792         const GLint positionLoc = gl.getAttribLocation(program.getProgram(), "a_position");
793         const GLint colorLoc    = gl.getAttribLocation(program.getProgram(), "a_color");
794 
795         if (!program.isOk())
796         {
797             log << program;
798             TCU_FAIL("Shader compile failed.");
799         }
800 
801         gl.clearColor(0, 0, 0, 1);
802         gl.clearDepthf(1.0f);
803         gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
804         gl.viewport(0, 0, m_targetSize, m_targetSize);
805         gl.useProgram(program.getProgram());
806         gl.enable(GL_DEPTH_TEST);
807         gl.enable(GL_POLYGON_OFFSET_FILL);
808         gl.enableVertexAttribArray(positionLoc);
809 
810         log << TestLog::Message << "POLYGON_OFFSET_FILL enabled." << TestLog::EndMessage;
811 
812         //draw bottom right (far)
813         {
814             gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, triangleBottomRight);
815 
816             log << TestLog::Message
817                 << "Draw bottom-right. Color = White.\tState: DepthFunc = ALWAYS, PolygonOffset(0, 8), Polygon Z = "
818                    "1.0. (Result depth should clamp to 1.0)."
819                 << TestLog::EndMessage;
820 
821             gl.depthFunc(GL_ALWAYS);
822             gl.polygonOffset(0, 8);
823             gl.vertexAttrib4f(colorLoc, 1.0f, 1.0f, 1.0f, 1.0f);
824             gl.drawArrays(GL_TRIANGLES, 0, 3);
825 
826             log << TestLog::Message
827                 << "Draw bottom-right. Color = Red.\tState: DepthFunc = GREATER, PolygonOffset(0, 9), Polygon Z = 1.0. "
828                    "(Result depth should clamp to 1.0 too)"
829                 << TestLog::EndMessage;
830 
831             gl.depthFunc(GL_GREATER);
832             gl.polygonOffset(0, 9);
833             gl.vertexAttrib4f(colorLoc, 1.0f, 0.0f, 0.0f, 1.0f);
834             gl.drawArrays(GL_TRIANGLES, 0, 3);
835         }
836 
837         //draw top left (near)
838         {
839             gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, triangleTopLeft);
840 
841             log << TestLog::Message
842                 << "Draw top-left. Color = White.\tState: DepthFunc = ALWAYS, PolygonOffset(0, -8), Polygon Z = -1.0. "
843                    "(Result depth should clamp to -1.0)"
844                 << TestLog::EndMessage;
845 
846             gl.depthFunc(GL_ALWAYS);
847             gl.polygonOffset(0, -8);
848             gl.vertexAttrib4f(colorLoc, 1.0f, 1.0f, 1.0f, 1.0f);
849             gl.drawArrays(GL_TRIANGLES, 0, 3);
850 
851             log << TestLog::Message
852                 << "Draw top-left. Color = Yellow.\tState: DepthFunc = LESS, PolygonOffset(0, -9), Polygon Z = -1.0. "
853                    "(Result depth should clamp to -1.0 too)."
854                 << TestLog::EndMessage;
855 
856             gl.depthFunc(GL_LESS);
857             gl.polygonOffset(0, -9);
858             gl.vertexAttrib4f(colorLoc, 1.0f, 1.0f, 0.0f, 1.0f);
859             gl.drawArrays(GL_TRIANGLES, 0, 3);
860         }
861 
862         gl.disableVertexAttribArray(positionLoc);
863         gl.useProgram(0);
864         gl.finish();
865 
866         glu::readPixels(m_context.getRenderContext(), 0, 0, testImage.getAccess());
867     }
868 
869     // render reference image
870     log << TestLog::Message << "Expecting: Top-left = White, Bottom-right = White." << TestLog::EndMessage;
871     tcu::clear(referenceImage.getAccess(), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
872 
873     // compare
874     verifyImages(log, m_testCtx, m_context.getRenderContext(), testImage.getAccess(), referenceImage.getAccess());
875 }
876 
877 // UsageSlopeTestCase
878 
879 class UsageSlopeTestCase : public PolygonOffsetTestCase
880 {
881 public:
882     UsageSlopeTestCase(Context &context, const char *name, const char *description, GLenum internalFormat,
883                        const char *internalFormatName);
884 
885     void testPolygonOffset(void);
886 };
887 
UsageSlopeTestCase(Context & context,const char * name,const char * description,GLenum internalFormat,const char * internalFormatName)888 UsageSlopeTestCase::UsageSlopeTestCase(Context &context, const char *name, const char *description,
889                                        GLenum internalFormat, const char *internalFormatName)
890     : PolygonOffsetTestCase(context, name, description, internalFormat, internalFormatName, 200)
891 {
892 }
893 
testPolygonOffset(void)894 void UsageSlopeTestCase::testPolygonOffset(void)
895 {
896     using tcu::TestLog;
897 
898     const tcu::Vec4 triangleBottomRight[] = {
899         tcu::Vec4(-1, 1, 0.0f, 1),
900         tcu::Vec4(1, 1, 0.9f, 1),
901         tcu::Vec4(1, -1, 0.9f, 1),
902     };
903     const tcu::Vec4 triangleTopLeft[] = {
904         tcu::Vec4(-1, -1, -0.9f, 1),
905         tcu::Vec4(-1, 1, 0.9f, 1),
906         tcu::Vec4(1, -1, 0.0f, 1),
907     };
908 
909     tcu::TestLog &log = m_testCtx.getLog();
910     tcu::Surface testImage(m_targetSize, m_targetSize);
911     tcu::Surface referenceImage(m_targetSize, m_targetSize);
912 
913     // render test image
914     {
915         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
916         const glu::ShaderProgram program(m_context.getRenderContext(),
917                                          glu::makeVtxFragSources(s_shaderSourceVertex, s_shaderSourceFragment));
918         const GLint positionLoc = gl.getAttribLocation(program.getProgram(), "a_position");
919         const GLint colorLoc    = gl.getAttribLocation(program.getProgram(), "a_color");
920 
921         if (!program.isOk())
922         {
923             log << program;
924             TCU_FAIL("Shader compile failed.");
925         }
926 
927         gl.clearColor(0, 0, 0, 1);
928         gl.clearDepthf(1.0f);
929         gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
930         gl.viewport(0, 0, m_targetSize, m_targetSize);
931         gl.useProgram(program.getProgram());
932         gl.enable(GL_DEPTH_TEST);
933         gl.enable(GL_POLYGON_OFFSET_FILL);
934         gl.enableVertexAttribArray(positionLoc);
935 
936         log << TestLog::Message << "POLYGON_OFFSET_FILL enabled." << TestLog::EndMessage;
937 
938         //draw top left (negative offset test)
939         {
940             gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, triangleTopLeft);
941 
942             log << TestLog::Message << "Draw top-left. Color = White.\tState: DepthFunc = ALWAYS, PolygonOffset(0, 0)."
943                 << TestLog::EndMessage;
944 
945             gl.depthFunc(GL_ALWAYS);
946             gl.polygonOffset(0, 0);
947             gl.vertexAttrib4f(colorLoc, 1.0f, 1.0f, 1.0f, 1.0f);
948             gl.drawArrays(GL_TRIANGLES, 0, 3);
949 
950             log << TestLog::Message << "Draw top-left. Color = Green.\tState: DepthFunc = LESS, PolygonOffset(-1, 0)."
951                 << TestLog::EndMessage;
952 
953             gl.depthFunc(GL_LESS);
954             gl.polygonOffset(-1, 0);
955             gl.vertexAttrib4f(colorLoc, 0.0f, 1.0f, 0.0f, 1.0f);
956             gl.drawArrays(GL_TRIANGLES, 0, 3);
957         }
958 
959         //draw bottom right (positive offset test)
960         {
961             gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, triangleBottomRight);
962 
963             log << TestLog::Message
964                 << "Draw bottom-right. Color = White.\tState: DepthFunc = ALWAYS, PolygonOffset(0, 0)."
965                 << TestLog::EndMessage;
966 
967             gl.depthFunc(GL_ALWAYS);
968             gl.polygonOffset(0, 0);
969             gl.vertexAttrib4f(colorLoc, 1.0f, 1.0f, 1.0f, 1.0f);
970             gl.drawArrays(GL_TRIANGLES, 0, 3);
971 
972             log << TestLog::Message
973                 << "Draw bottom-right. Color = Green.\tState: DepthFunc = GREATER, PolygonOffset(1, 0)."
974                 << TestLog::EndMessage;
975 
976             gl.depthFunc(GL_GREATER);
977             gl.polygonOffset(1, 0);
978             gl.vertexAttrib4f(colorLoc, 0.0f, 1.0f, 0.0f, 1.0f);
979             gl.drawArrays(GL_TRIANGLES, 0, 3);
980         }
981 
982         gl.disableVertexAttribArray(positionLoc);
983         gl.useProgram(0);
984         gl.finish();
985 
986         glu::readPixels(m_context.getRenderContext(), 0, 0, testImage.getAccess());
987     }
988 
989     // render reference image
990     log << TestLog::Message << "Expecting: Top-left = Green, Bottom-right = Green." << TestLog::EndMessage;
991     tcu::clear(referenceImage.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
992 
993     // compare
994     verifyImages(log, m_testCtx, m_context.getRenderContext(), testImage.getAccess(), referenceImage.getAccess());
995 }
996 
997 // ZeroSlopeTestCase
998 
999 class ZeroSlopeTestCase : public PolygonOffsetTestCase
1000 {
1001 public:
1002     ZeroSlopeTestCase(Context &context, const char *name, const char *description, GLenum internalFormat,
1003                       const char *internalFormatName);
1004 
1005     void testPolygonOffset(void);
1006 };
1007 
ZeroSlopeTestCase(Context & context,const char * name,const char * description,GLenum internalFormat,const char * internalFormatName)1008 ZeroSlopeTestCase::ZeroSlopeTestCase(Context &context, const char *name, const char *description, GLenum internalFormat,
1009                                      const char *internalFormatName)
1010     : PolygonOffsetTestCase(context, name, description, internalFormat, internalFormatName, 200)
1011 {
1012 }
1013 
testPolygonOffset(void)1014 void ZeroSlopeTestCase::testPolygonOffset(void)
1015 {
1016     using tcu::TestLog;
1017 
1018     const tcu::Vec4 triangle[] = {
1019         tcu::Vec4(-0.4f, 0.4f, 0.0f, 1.0f),
1020         tcu::Vec4(-0.8f, -0.5f, 0.0f, 1.0f),
1021         tcu::Vec4(0.7f, 0.2f, 0.0f, 1.0f),
1022     };
1023 
1024     tcu::TestLog &log = m_testCtx.getLog();
1025     tcu::Surface testImage(m_targetSize, m_targetSize);
1026     tcu::Surface referenceImage(m_targetSize, m_targetSize);
1027 
1028     // log the triangle
1029     log << TestLog::Message << "Setup triangle with coordinates:" << TestLog::EndMessage;
1030     for (size_t ndx = 0; ndx < DE_LENGTH_OF_ARRAY(triangle); ++ndx)
1031         log << TestLog::Message << "\tx=" << triangle[ndx].x() << "\ty=" << triangle[ndx].y()
1032             << "\tz=" << triangle[ndx].z() << "\tw=" << triangle[ndx].w() << TestLog::EndMessage;
1033 
1034     // render test image
1035     {
1036         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1037         const glu::ShaderProgram program(m_context.getRenderContext(),
1038                                          glu::makeVtxFragSources(s_shaderSourceVertex, s_shaderSourceFragment));
1039         const GLint positionLoc = gl.getAttribLocation(program.getProgram(), "a_position");
1040         const GLint colorLoc    = gl.getAttribLocation(program.getProgram(), "a_color");
1041 
1042         if (!program.isOk())
1043         {
1044             log << program;
1045             TCU_FAIL("Shader compile failed.");
1046         }
1047 
1048         gl.clearColor(0, 0, 0, 1);
1049         gl.clearDepthf(1.0f);
1050         gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1051         gl.viewport(0, 0, m_targetSize, m_targetSize);
1052         gl.useProgram(program.getProgram());
1053         gl.enable(GL_DEPTH_TEST);
1054         gl.enable(GL_POLYGON_OFFSET_FILL);
1055         gl.enableVertexAttribArray(positionLoc);
1056 
1057         log << TestLog::Message << "POLYGON_OFFSET_FILL enabled." << TestLog::EndMessage;
1058 
1059         {
1060             gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, triangle);
1061 
1062             log << TestLog::Message << "Draw triangle. Color = Red.\tState: DepthFunc = ALWAYS, PolygonOffset(0, 0)."
1063                 << TestLog::EndMessage;
1064 
1065             gl.depthFunc(GL_ALWAYS);
1066             gl.polygonOffset(0, 0);
1067             gl.vertexAttrib4f(colorLoc, 1.0f, 0.0f, 0.0f, 1.0f);
1068             gl.drawArrays(GL_TRIANGLES, 0, 3);
1069 
1070             log << TestLog::Message << "Draw triangle. Color = Black.\tState: DepthFunc = EQUAL, PolygonOffset(4, 0)."
1071                 << TestLog::EndMessage;
1072 
1073             gl.depthFunc(GL_EQUAL);
1074             gl.polygonOffset(4, 0); // triangle slope == 0
1075             gl.vertexAttrib4f(colorLoc, 0.0f, 0.0f, 0.0f, 1.0f);
1076             gl.drawArrays(GL_TRIANGLES, 0, 3);
1077         }
1078 
1079         gl.disableVertexAttribArray(positionLoc);
1080         gl.useProgram(0);
1081         gl.finish();
1082 
1083         glu::readPixels(m_context.getRenderContext(), 0, 0, testImage.getAccess());
1084     }
1085 
1086     // render reference image
1087     log << TestLog::Message << "Expecting black triangle." << TestLog::EndMessage;
1088     tcu::clear(referenceImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1089 
1090     // compare
1091     verifyImages(log, m_testCtx, m_context.getRenderContext(), testImage.getAccess(), referenceImage.getAccess());
1092 }
1093 
1094 // OneSlopeTestCase
1095 
1096 class OneSlopeTestCase : public PolygonOffsetTestCase
1097 {
1098 public:
1099     OneSlopeTestCase(Context &context, const char *name, const char *description, GLenum internalFormat,
1100                      const char *internalFormatName);
1101 
1102     void testPolygonOffset(void);
1103 };
1104 
OneSlopeTestCase(Context & context,const char * name,const char * description,GLenum internalFormat,const char * internalFormatName)1105 OneSlopeTestCase::OneSlopeTestCase(Context &context, const char *name, const char *description, GLenum internalFormat,
1106                                    const char *internalFormatName)
1107     : PolygonOffsetTestCase(context, name, description, internalFormat, internalFormatName, 200)
1108 {
1109 }
1110 
testPolygonOffset(void)1111 void OneSlopeTestCase::testPolygonOffset(void)
1112 {
1113     using tcu::TestLog;
1114 
1115     /*
1116      * setup vertices subject to following properties
1117      *   dz_w / dx_w == 1
1118      *   dz_w / dy_w == 0
1119      * or
1120      *   dz_w / dx_w == 0
1121      *   dz_w / dy_w == 1
1122      * ==> m == 1
1123      */
1124     const float cornerDepth         = float(m_targetSize);
1125     const tcu::Vec4 triangles[2][3] = {
1126         {
1127             tcu::Vec4(-1, -1, -cornerDepth, 1),
1128             tcu::Vec4(-1, 1, -cornerDepth, 1),
1129             tcu::Vec4(1, -1, cornerDepth, 1),
1130         },
1131         {
1132             tcu::Vec4(-1, 1, cornerDepth, 1),
1133             tcu::Vec4(1, 1, cornerDepth, 1),
1134             tcu::Vec4(1, -1, -cornerDepth, 1),
1135         },
1136     };
1137 
1138     tcu::TestLog &log = m_testCtx.getLog();
1139     tcu::Surface testImage(m_targetSize, m_targetSize);
1140     tcu::Surface referenceImage(m_targetSize, m_targetSize);
1141 
1142     // log triangle info
1143     log << TestLog::Message << "Setup triangle0 coordinates: (slope in window coordinates = 1.0)"
1144         << TestLog::EndMessage;
1145     for (size_t ndx = 0; ndx < DE_LENGTH_OF_ARRAY(triangles[0]); ++ndx)
1146         log << TestLog::Message << "\tx=" << triangles[0][ndx].x() << "\ty=" << triangles[0][ndx].y()
1147             << "\tz=" << triangles[0][ndx].z() << "\tw=" << triangles[0][ndx].w() << TestLog::EndMessage;
1148     log << TestLog::Message << "Setup triangle1 coordinates: (slope in window coordinates = 1.0)"
1149         << TestLog::EndMessage;
1150     for (size_t ndx = 0; ndx < DE_LENGTH_OF_ARRAY(triangles[1]); ++ndx)
1151         log << TestLog::Message << "\tx=" << triangles[1][ndx].x() << "\ty=" << triangles[1][ndx].y()
1152             << "\tz=" << triangles[1][ndx].z() << "\tw=" << triangles[1][ndx].w() << TestLog::EndMessage;
1153 
1154     // render test image
1155     {
1156         const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1157         const glu::ShaderProgram program(m_context.getRenderContext(),
1158                                          glu::makeVtxFragSources(s_shaderSourceVertex, s_shaderSourceFragment));
1159         const GLint positionLoc = gl.getAttribLocation(program.getProgram(), "a_position");
1160         const GLint colorLoc    = gl.getAttribLocation(program.getProgram(), "a_color");
1161 
1162         if (!program.isOk())
1163         {
1164             log << program;
1165             TCU_FAIL("Shader compile failed.");
1166         }
1167 
1168         gl.clearColor(0, 0, 0, 1);
1169         gl.clear(GL_COLOR_BUFFER_BIT);
1170         gl.viewport(0, 0, m_targetSize, m_targetSize);
1171         gl.useProgram(program.getProgram());
1172         gl.enable(GL_DEPTH_TEST);
1173         gl.enable(GL_POLYGON_OFFSET_FILL);
1174         gl.enableVertexAttribArray(positionLoc);
1175 
1176         log << TestLog::Message << "Framebuffer cleared, clear color = Black." << TestLog::EndMessage;
1177         log << TestLog::Message << "POLYGON_OFFSET_FILL enabled." << TestLog::EndMessage;
1178 
1179         // top left (positive offset)
1180         {
1181             log << TestLog::Message << "Clear depth to 1.0." << TestLog::EndMessage;
1182 
1183             gl.clearDepthf(1.0f); // far
1184             gl.clear(GL_DEPTH_BUFFER_BIT);
1185 
1186             gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, triangles[0]);
1187 
1188             log << TestLog::Message
1189                 << "Draw triangle0. Color = Red.\tState: DepthFunc = NOTEQUAL, PolygonOffset(10, 0). (Result depth "
1190                    "should clamp to 1.0)."
1191                 << TestLog::EndMessage;
1192 
1193             gl.polygonOffset(10, 0); // clamps any depth on the triangle to 1
1194             gl.depthFunc(GL_NOTEQUAL);
1195             gl.vertexAttrib4f(colorLoc, 1.0f, 0.0f, 0.0f, 1.0f);
1196             gl.drawArrays(GL_TRIANGLES, 0, 3);
1197         }
1198         // bottom right (negative offset)
1199         {
1200             log << TestLog::Message << "Clear depth to 0.0." << TestLog::EndMessage;
1201 
1202             gl.clearDepthf(0.0f); // far
1203             gl.clear(GL_DEPTH_BUFFER_BIT);
1204 
1205             gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, triangles[1]);
1206 
1207             log << TestLog::Message
1208                 << "Draw triangle1. Color = Green.\tState: DepthFunc = NOTEQUAL, PolygonOffset(-10, 0). (Result depth "
1209                    "should clamp to 0.0)."
1210                 << TestLog::EndMessage;
1211 
1212             gl.polygonOffset(-10, 0); // clamps depth to 0
1213             gl.depthFunc(GL_NOTEQUAL);
1214             gl.vertexAttrib4f(colorLoc, 0.0f, 1.0f, 0.0f, 1.0f);
1215             gl.drawArrays(GL_TRIANGLES, 0, 3);
1216         }
1217 
1218         gl.disableVertexAttribArray(positionLoc);
1219         gl.useProgram(0);
1220         gl.finish();
1221 
1222         glu::readPixels(m_context.getRenderContext(), 0, 0, testImage.getAccess());
1223     }
1224 
1225     // render reference image
1226     log << TestLog::Message << "Expecting black framebuffer." << TestLog::EndMessage;
1227     tcu::clear(referenceImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1228 
1229     // compare
1230     verifyImages(log, m_testCtx, m_context.getRenderContext(), testImage.getAccess(), referenceImage.getAccess());
1231 }
1232 
1233 } // namespace
1234 
PolygonOffsetTests(Context & context)1235 PolygonOffsetTests::PolygonOffsetTests(Context &context)
1236     : TestCaseGroup(context, "polygon_offset", "Polygon offset tests")
1237 {
1238 }
1239 
~PolygonOffsetTests(void)1240 PolygonOffsetTests::~PolygonOffsetTests(void)
1241 {
1242 }
1243 
init(void)1244 void PolygonOffsetTests::init(void)
1245 {
1246     const struct DepthBufferFormat
1247     {
1248         enum BufferType
1249         {
1250             TYPE_FIXED_POINT,
1251             TYPE_FLOATING_POINT,
1252             TYPE_UNKNOWN
1253         };
1254 
1255         GLenum internalFormat;
1256         int bits;
1257         BufferType floatingPoint;
1258         const char *name;
1259     } depthFormats[] = {
1260         {0, 0, DepthBufferFormat::TYPE_UNKNOWN, "default"},
1261         {GL_DEPTH_COMPONENT16, 16, DepthBufferFormat::TYPE_FIXED_POINT, "fixed16"},
1262         {GL_DEPTH_COMPONENT24, 24, DepthBufferFormat::TYPE_FIXED_POINT, "fixed24"},
1263         {GL_DEPTH_COMPONENT32F, 32, DepthBufferFormat::TYPE_FLOATING_POINT, "float32"},
1264     };
1265 
1266     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(depthFormats); ++ndx)
1267     {
1268         const DepthBufferFormat &format = depthFormats[ndx];
1269 
1270         // enable works?
1271         addChild(new UsageTestCase(m_context, (std::string(format.name) + "_enable").c_str(),
1272                                    "test enable GL_POLYGON_OFFSET_FILL", format.internalFormat, format.name));
1273 
1274         // Really moves the polygons ?
1275         addChild(new UsageDisplacementTestCase(m_context,
1276                                                (std::string(format.name) + "_displacement_with_units").c_str(),
1277                                                "test polygon offset", format.internalFormat, format.name));
1278 
1279         // Really moves the polygons to right direction ?
1280         addChild(new UsagePositiveNegativeTestCase(m_context, (std::string(format.name) + "_render_with_units").c_str(),
1281                                                    "test polygon offset", format.internalFormat, format.name));
1282 
1283         // Is total result clamped to [0,1] like promised?
1284         addChild(new ResultClampingTestCase(m_context, (std::string(format.name) + "_result_depth_clamp").c_str(),
1285                                             "test polygon offset clamping", format.internalFormat, format.name));
1286 
1287         // Slope really moves the polygon?
1288         addChild(new UsageSlopeTestCase(m_context, (std::string(format.name) + "_render_with_factor").c_str(),
1289                                         "test polygon offset factor", format.internalFormat, format.name));
1290 
1291         // Factor with zero slope
1292         addChild(new ZeroSlopeTestCase(m_context, (std::string(format.name) + "_factor_0_slope").c_str(),
1293                                        "test polygon offset factor", format.internalFormat, format.name));
1294 
1295         // Factor with 1.0 slope
1296         addChild(new OneSlopeTestCase(m_context, (std::string(format.name) + "_factor_1_slope").c_str(),
1297                                       "test polygon offset factor", format.internalFormat, format.name));
1298     }
1299 }
1300 
1301 } // namespace Functional
1302 } // namespace gles3
1303 } // namespace deqp
1304