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