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