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