Merge "DO NOT MERGE: Add cube gather tests that avoid corners; remove D32F from...
[platform/upstream/VK-GL-CTS.git] / modules / glshared / glsScissorTests.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL (ES) 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 GLES Scissor tests
22  *//*--------------------------------------------------------------------*/
23
24 #include "glsScissorTests.hpp"
25 #include "glsTextureTestUtil.hpp"
26
27 #include "deMath.h"
28 #include "deRandom.hpp"
29 #include "deUniquePtr.hpp"
30
31 #include "tcuTestCase.hpp"
32 #include "tcuImageCompare.hpp"
33 #include "tcuVector.hpp"
34 #include "tcuVectorUtil.hpp"
35 #include "tcuTexture.hpp"
36 #include "tcuStringTemplate.hpp"
37
38 #include "gluStrUtil.hpp"
39 #include "gluDrawUtil.hpp"
40 #include "gluPixelTransfer.hpp"
41 #include "gluObjectWrapper.hpp"
42
43 #include "glwEnums.hpp"
44 #include "glwFunctions.hpp"
45
46 #include <map>
47
48 namespace deqp
49 {
50 namespace gls
51 {
52 namespace Functional
53 {
54 namespace
55 {
56
57 using namespace ScissorTestInternal;
58 using namespace glw; // GL types
59
60 using tcu::ConstPixelBufferAccess;
61 using tcu::PixelBufferAccess;
62 using tcu::TestLog;
63
64 using std::vector;
65 using std::string;
66 using std::map;
67 using tcu::Vec3;
68 using tcu::Vec4;
69 using tcu::IVec4;
70 using tcu::UVec4;
71
72 void drawQuad (const glw::Functions& gl, deUint32 program, const Vec3& p0, const Vec3& p1)
73 {
74         // Vertex data.
75         const float hz = (p0.z() + p1.z()) * 0.5f;
76         const float position[] =
77         {
78                 p0.x(), p0.y(), p0.z(), 1.0f,
79                 p0.x(), p1.y(), hz,             1.0f,
80                 p1.x(), p0.y(), hz,             1.0f,
81                 p1.x(), p1.y(), p1.z(), 1.0f
82         };
83
84         const deUint16  indices[]       = { 0, 1, 2, 2, 1, 3 };
85
86         const deInt32   posLoc          = gl.getAttribLocation(program, "a_position");
87
88         gl.useProgram(program);
89         gl.enableVertexAttribArray(posLoc);
90         gl.vertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
91
92         gl.drawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_SHORT, &indices[0]);
93
94         gl.disableVertexAttribArray(posLoc);
95
96 }
97
98 void drawPrimitives (const glw::Functions& gl, deUint32 program, const deUint32 type, const vector<float>& vertices, const vector<deUint16>& indices)
99 {
100         const deInt32 posLoc = gl.getAttribLocation(program, "a_position");
101
102         TCU_CHECK(posLoc >= 0);
103
104         gl.useProgram(program);
105         gl.enableVertexAttribArray(posLoc);
106         gl.vertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &vertices[0]);
107
108         gl.drawElements(type, GLsizei(indices.size()), GL_UNSIGNED_SHORT, &indices[0]);
109
110         gl.disableVertexAttribArray(posLoc);
111 }
112
113 template<typename T>
114 void clearEdges (const tcu::PixelBufferAccess& access, const T& color, const IVec4& scissorArea)
115 {
116         for (int y = 0; y < access.getHeight(); y++)
117         for (int x = 0; x < access.getWidth(); x++)
118         {
119                 if (y < scissorArea.y() ||
120                         y >= scissorArea.y() + scissorArea.w() ||
121                         x < scissorArea.x() ||
122                         x >= scissorArea.x()+ scissorArea.z())
123                         access.setPixel(color, x, y);
124         }
125 }
126
127 glu::ProgramSources genShaders(glu::GLSLVersion version)
128 {
129         const string vtxSource = "${VERSION}\n"
130                                                          "${IN} highp vec4 a_position;\n"
131                                                          "void main(){\n"
132                                                          "      gl_Position = a_position;\n"
133                                                          "}\n";
134
135         const string frgSource = "${VERSION}\n"
136                                                          "${OUT_DECL}"
137                                                          "uniform highp vec4 u_color;\n"
138                                                          "void main(){\n"
139                                                          "      ${OUTPUT} = u_color;\n"
140                                                          "}\n";
141
142         map<string, string>     params;
143
144         switch(version)
145         {
146                 case glu::GLSL_VERSION_100_ES:
147                         params["VERSION"] = "#version 100";
148                         params["IN"] = "attribute";
149                         params["OUT_DECL"] = "";
150                         params["OUTPUT"] = "gl_FragColor";
151                         break;
152
153                 case glu::GLSL_VERSION_300_ES:
154                 case glu::GLSL_VERSION_310_ES: // Assumed to support 3.0
155                         params["VERSION"] = "#version 300 es";
156                         params["IN"] = "in";
157                         params["OUT_DECL"] = "out mediump vec4 f_color;\n";
158                         params["OUTPUT"] = "f_color";
159                         break;
160
161                 default:
162                         DE_FATAL("Unsupported version");
163         }
164
165         return glu::makeVtxFragSources(tcu::StringTemplate(vtxSource).specialize(params), tcu::StringTemplate(frgSource).specialize(params));
166 }
167
168 // Wrapper class, provides iterator & reporting logic
169 class ScissorCase : public tcu::TestCase
170 {
171 public:
172                                                         ScissorCase             (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char *name, const char* desc, const Vec4& scissorArea);
173         virtual                                 ~ScissorCase    (void) {}
174
175         virtual IterateResult   iterate                 (void);
176
177 protected:
178         virtual void                    render                  (GLuint program, const IVec4& viewport) const = 0;
179
180         glu::RenderContext&             m_renderCtx;
181         const Vec4                              m_scissorArea;
182 };
183
184 ScissorCase::ScissorCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char *name, const char* desc, const Vec4& scissorArea)
185         : TestCase              (testCtx, name, desc)
186         , m_renderCtx   (renderCtx)
187         , m_scissorArea (scissorArea)
188 {
189 }
190
191 ScissorCase::IterateResult ScissorCase::iterate (void)
192 {
193         using TextureTestUtil::RandomViewport;
194
195         const glw::Functions&           gl                              = m_renderCtx.getFunctions();
196         TestLog&                                        log                             = m_testCtx.getLog();
197         const tcu::PixelFormat          renderFormat    = m_renderCtx.getRenderTarget().getPixelFormat();
198         const tcu::Vec4                         threshold               = 0.02f * UVec4(1u << de::max(0, 8 - renderFormat.redBits),
199                                                                                                                                 1u << de::max(0, 8 - renderFormat.greenBits),
200                                                                                                                                 1u << de::max(0, 8 - renderFormat.blueBits),
201                                                                                                                                 1u << de::max(0, 8 - renderFormat.alphaBits)).asFloat();
202         const glu::ShaderProgram        shader                  (m_renderCtx, genShaders(glu::getContextTypeGLSLVersion(m_renderCtx.getType())));
203
204         const RandomViewport            viewport                (m_renderCtx.getRenderTarget(), 256, 256, deStringHash(getName()));
205         const IVec4                                     relScissorArea  (int(m_scissorArea.x() * (float)viewport.width),
206                                                                                                  int(m_scissorArea.y() * (float)viewport.height),
207                                                                                                  int(m_scissorArea.z() * (float)viewport.width),
208                                                                                                  int(m_scissorArea.w() * (float)viewport.height));
209         const IVec4                                     absScissorArea  (relScissorArea.x() + viewport.x,
210                                                                                                  relScissorArea.y() + viewport.y,
211                                                                                                  relScissorArea.z(),
212                                                                                                  relScissorArea.w());
213
214         tcu::Surface                            refImage                (viewport.width, viewport.height);
215         tcu::Surface                            resImage                (viewport.width, viewport.height);
216
217         if (!shader.isOk())
218         {
219                 log << shader;
220                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader compile/link failed");
221                 return STOP;
222         }
223
224         log << TestLog::Message << "Viewport area is " << IVec4(viewport.x, viewport.y, viewport.width, viewport.height) << TestLog::EndMessage;
225         log << TestLog::Message << "Scissor area is " << absScissorArea << TestLog::EndMessage;
226
227         // Render reference (no scissors)
228         {
229                 log << TestLog::Message << "Rendering reference (scissors disabled)" << TestLog::EndMessage;
230
231                 gl.useProgram(shader.getProgram());
232                 gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
233
234                 gl.clearColor(0.125f, 0.25f, 0.5f, 1.0f);
235                 gl.clearDepthf(1.0f);
236                 gl.clearStencil(0);
237                 gl.disable(GL_DEPTH_TEST);
238                 gl.disable(GL_STENCIL_TEST);
239                 gl.disable(GL_SCISSOR_TEST);
240                 gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
241
242                 render(shader.getProgram(), IVec4(viewport.x, viewport.y, viewport.width, viewport.height));
243
244                 glu::readPixels(m_renderCtx, viewport.x, viewport.y, refImage.getAccess());
245                 GLU_CHECK_ERROR(gl.getError());
246         }
247
248         // Render result (scissors)
249         {
250                 log << TestLog::Message << "Rendering result (scissors enabled)" << TestLog::EndMessage;
251
252                 gl.useProgram(shader.getProgram());
253                 gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
254
255                 gl.clearColor(0.125f, 0.25f, 0.5f, 1.0f);
256                 gl.clearDepthf(1.0f);
257                 gl.clearStencil(0);
258                 gl.disable(GL_DEPTH_TEST);
259                 gl.disable(GL_STENCIL_TEST);
260                 gl.disable(GL_SCISSOR_TEST);
261                 gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
262
263                 gl.scissor(absScissorArea.x(), absScissorArea.y(), absScissorArea.z(), absScissorArea.w());
264                 gl.enable(GL_SCISSOR_TEST);
265
266                 render(shader.getProgram(), IVec4(viewport.x, viewport.y, viewport.width, viewport.height));
267
268                 glu::readPixels(m_renderCtx, viewport.x, viewport.y, resImage.getAccess());
269                 GLU_CHECK_ERROR(gl.getError());
270         }
271
272         // Manual 'scissors' for reference image
273         log << TestLog::Message << "Clearing area outside scissor area from reference" << TestLog::EndMessage;
274         clearEdges(refImage.getAccess(), IVec4(32, 64, 128, 255), relScissorArea);
275
276         if (tcu::floatThresholdCompare(log, "ComparisonResult", "Image comparison result", refImage.getAccess(), resImage.getAccess(), threshold, tcu::COMPARE_LOG_RESULT))
277                 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
278         else
279                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
280
281         return STOP;
282 }
283
284 // Tests scissoring with multiple primitive types
285 class ScissorPrimitiveCase : public ScissorCase
286 {
287 public:
288                                                                 ScissorPrimitiveCase    (tcu::TestContext&              testCtx,
289                                                                                                                  glu::RenderContext&    renderCtx,
290                                                                                                                  const char*                    name,
291                                                                                                                  const char*                    desc,
292                                                                                                                  const Vec4&                    scissorArea,
293                                                                                                                  const Vec4&                    renderArea,
294                                                                                                                  PrimitiveType                  type,
295                                                                                                                  int                                    primitiveCount);
296         virtual                                         ~ScissorPrimitiveCase   (void){}
297
298 protected:
299         virtual void                            render                                  (GLuint program, const IVec4& viewport) const;
300
301 private:
302         const Vec4                                      m_renderArea;
303         const PrimitiveType                     m_primitiveType;
304         const int                                       m_primitiveCount;
305 };
306
307 ScissorPrimitiveCase::ScissorPrimitiveCase      (tcu::TestContext&              testCtx,
308                                                                                          glu::RenderContext&    renderCtx,
309                                                                                          const char*                    name,
310                                                                                          const char*                    desc,
311                                                                                          const Vec4&                    scissorArea,
312                                                                                          const Vec4&                    renderArea,
313                                                                                          PrimitiveType                  type,
314                                                                                          int                                    primitiveCount)
315         : ScissorCase           (testCtx, renderCtx, name, desc, scissorArea)
316         , m_renderArea          (renderArea)
317         , m_primitiveType       (type)
318         , m_primitiveCount      (primitiveCount)
319 {
320 }
321
322 void ScissorPrimitiveCase::render (GLuint program, const IVec4&) const
323 {
324         const glw::Functions&           gl                              = m_renderCtx.getFunctions();
325         const Vec4                                      white                   (1.0f, 1.0f, 1.0f, 1.0);
326         const Vec4                                      primitiveArea   (m_renderArea.x()*2.0f-1.0f,
327                                                                                                  m_renderArea.x()*2.0f-1.0f,
328                                                                                                  m_renderArea.z()*2.0f,
329                                                                                                  m_renderArea.w()*2.0f);
330
331         static const float quadPositions[] =
332         {
333                  0.0f,  1.0f,
334                  0.0f,  0.0f,
335                  1.0f,  1.0f,
336                  1.0f,  0.0f
337         };
338         static const float triPositions[] =
339         {
340                  0.0f,  0.0f,
341                  1.0f,  0.0f,
342                  0.5f,  1.0f,
343         };
344         static const float linePositions[] =
345         {
346                  0.0f,  0.0f,
347                  1.0f,  1.0f
348         };
349         static const float pointPosition[] =
350         {
351                  0.5f,  0.5f
352         };
353
354         const float*            positionSet[]   = { pointPosition, linePositions, triPositions, quadPositions };
355         const int                       vertexCountSet[]= { 1, 2, 3, 4 };
356         const int                       indexCountSet[] = { 1, 2, 3, 6 };
357
358         const deUint16          baseIndices[]   = { 0, 1, 2, 2, 1, 3 };
359         const float*            basePositions   = positionSet[m_primitiveType];
360         const int                       vertexCount             = vertexCountSet[m_primitiveType];
361         const int                       indexCount              = indexCountSet[m_primitiveType];
362
363         const float                     scale                   = 1.44f/deFloatSqrt(float(m_primitiveCount)*2.0f); // Magic value to roughly fill the render area with primitives at a readable density
364         vector<float>           positions               (4*vertexCount*m_primitiveCount);
365         vector<deUint16>        indices                 (indexCount*m_primitiveCount);
366         de::Random                      rng                             (1234);
367
368         for (int primNdx = 0; primNdx < m_primitiveCount; primNdx++)
369         {
370                 const float dx = m_primitiveCount>1 ? rng.getFloat() : 0.0f;
371                 const float dy = m_primitiveCount>1 ? rng.getFloat() : 0.0f;
372
373                 for (int vertNdx = 0; vertNdx < vertexCount; vertNdx++)
374                 {
375                         const int ndx = primNdx*4*vertexCount + vertNdx*4;
376                         positions[ndx+0] = (basePositions[vertNdx*2 + 0]*scale + dx)*primitiveArea.z() + primitiveArea.x();
377                         positions[ndx+1] = (basePositions[vertNdx*2 + 1]*scale + dy)*primitiveArea.w() + primitiveArea.y();
378                         positions[ndx+2] = 0.2f;
379                         positions[ndx+3] = 1.0f;
380                 }
381
382                 for (int ndx = 0; ndx < indexCount; ndx++)
383                         indices[primNdx*indexCount + ndx] = (deUint16)(baseIndices[ndx] + primNdx*vertexCount);
384         }
385
386         gl.uniform4fv(gl.getUniformLocation(program, "u_color"), 1, white.m_data);
387
388         switch (m_primitiveType)
389         {
390                 case TRIANGLE:  drawPrimitives(gl, program, GL_TRIANGLES,       positions, indices);    break;
391                 case LINE:              drawPrimitives(gl, program, GL_LINES,           positions, indices);    break;
392                 case POINT:             drawPrimitives(gl, program, GL_POINTS,          positions, indices);    break;
393                 default:                DE_ASSERT(false);                                                                                                       break;
394         }
395 }
396
397 // Test effect of scissor on default framebuffer clears
398 class ScissorClearCase : public ScissorCase
399 {
400 public:
401                                         ScissorClearCase        (tcu::TestContext&              testCtx,
402                                                                                  glu::RenderContext&    renderCtx,
403                                                                                  const char*                    name,
404                                                                                  const char*                    desc,
405                                                                                  const Vec4&                    scissorArea,
406                                                                                  deUint32                               clearMode);
407         virtual                 ~ScissorClearCase       (void) {}
408
409         virtual void    init                            (void);
410
411 protected:
412         virtual void    render                          (GLuint program, const IVec4& viewport) const;
413
414 private:
415         const deUint32  m_clearMode; //!< Combination of the flags accepted by glClear
416 };
417
418 ScissorClearCase::ScissorClearCase      (tcu::TestContext&              testCtx,
419                                                                          glu::RenderContext&    renderCtx,
420                                                                          const char*                    name,
421                                                                          const char*                    desc,
422                                                                          const Vec4&                    scissorArea,
423                                                                          deUint32                               clearMode)
424         : ScissorCase   (testCtx, renderCtx, name, desc, scissorArea)
425         , m_clearMode   (clearMode)
426 {
427 }
428
429 void ScissorClearCase::init (void)
430 {
431         if ((m_clearMode & GL_DEPTH_BUFFER_BIT) && m_renderCtx.getRenderTarget().getDepthBits() == 0)
432                 throw tcu::NotSupportedError("Cannot clear depth; no depth buffer present", "", __FILE__, __LINE__);
433         else if ((m_clearMode & GL_STENCIL_BUFFER_BIT) && m_renderCtx.getRenderTarget().getStencilBits() == 0)
434                 throw tcu::NotSupportedError("Cannot clear stencil; no stencil buffer present", "", __FILE__, __LINE__);
435 }
436
437 void ScissorClearCase::render (GLuint program, const IVec4&) const
438 {
439         const glw::Functions&   gl              = m_renderCtx.getFunctions();
440         const Vec4                              white   (1.0f, 1.0f, 1.0f, 1.0);
441
442         gl.clearColor(0.6f, 0.1f, 0.1f, 1.0);
443         gl.clearDepthf(0.0f);
444
445         if (m_clearMode & GL_DEPTH_BUFFER_BIT)
446         {
447                 gl.enable(GL_DEPTH_TEST);
448                 gl.depthFunc(GL_GREATER);
449         }
450
451         if (m_clearMode & GL_STENCIL_BUFFER_BIT)
452         {
453                 gl.clearStencil(123);
454                 gl.enable(GL_STENCIL_TEST);
455                 gl.stencilFunc(GL_EQUAL, 123, ~0u);
456         }
457
458         if (m_clearMode & GL_COLOR_BUFFER_BIT)
459                 gl.clearColor(0.1f, 0.6f, 0.1f, 1.0);
460
461         gl.clear(m_clearMode);
462         gl.disable(GL_SCISSOR_TEST);
463
464         gl.uniform4fv(gl.getUniformLocation(program, "u_color"), 1, white.getPtr());
465
466         if (!(m_clearMode & GL_COLOR_BUFFER_BIT))
467                 drawQuad(gl, program, Vec3(-1.0f, -1.0f, 0.5f), Vec3(1.0f, 1.0f, 0.5f));
468
469         gl.disable(GL_DEPTH_TEST);
470         gl.disable(GL_STENCIL_TEST);
471 }
472
473 class FramebufferBlitCase : public ScissorCase
474 {
475 public:
476                                         FramebufferBlitCase             (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, const Vec4& scissorArea);
477         virtual                 ~FramebufferBlitCase    (void) {}
478
479         virtual void    init                                    (void);
480         virtual void    deinit                                  (void);
481
482 protected:
483         typedef de::MovePtr<glu::Framebuffer> FramebufferP;
484
485         enum {SIZE = 64};
486
487         virtual void    render                                  (GLuint program, const IVec4& viewport) const;
488
489         FramebufferP    m_fbo;
490 };
491
492 FramebufferBlitCase::FramebufferBlitCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, const Vec4& scissorArea)
493         : ScissorCase(testCtx, renderCtx, name, desc, scissorArea)
494 {
495 }
496
497 void FramebufferBlitCase::init (void)
498 {
499         if (m_renderCtx.getRenderTarget().getNumSamples())
500                 throw tcu::NotSupportedError("Cannot blit to multisampled framebuffer", "", __FILE__, __LINE__);
501
502         const glw::Functions&   gl                      = m_renderCtx.getFunctions();
503         const glu::Renderbuffer colorbuf        (gl);
504         const tcu::Vec4                 clearColor      (1.0f, 0.5, 0.125f, 1.0f);
505
506         m_fbo = FramebufferP(new glu::Framebuffer(gl));
507
508         gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, **m_fbo);
509
510         gl.bindRenderbuffer(GL_RENDERBUFFER, *colorbuf);
511         gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, SIZE, SIZE);
512         gl.framebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *colorbuf);
513
514         gl.clearBufferfv(GL_COLOR, 0, clearColor.getPtr());
515         gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_renderCtx.getDefaultFramebuffer());
516 }
517
518 void FramebufferBlitCase::deinit (void)
519 {
520         m_fbo.clear();
521 }
522
523 void FramebufferBlitCase::render(GLuint program, const IVec4& viewport) const
524 {
525         const glw::Functions&   gl                                      = m_renderCtx.getFunctions();
526
527         const int                               width                           = viewport.z();
528         const int                               height                          = viewport.w();
529         const deInt32                   defaultFramebuffer      = m_renderCtx.getDefaultFramebuffer();
530
531         DE_UNREF(program);
532
533         // blit to default framebuffer
534         gl.bindFramebuffer(GL_READ_FRAMEBUFFER, **m_fbo);
535         gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, defaultFramebuffer);
536
537         gl.blitFramebuffer(0, 0, SIZE, SIZE, viewport.x(), viewport.y(), viewport.x() + width, viewport.y() + height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
538
539         gl.bindFramebuffer(GL_READ_FRAMEBUFFER, defaultFramebuffer);
540 }
541
542 struct BufferFmtDesc
543 {
544         tcu::TextureFormat      texFmt;
545         GLenum                          colorFmt;
546 };
547
548 struct Color
549 {
550         enum Type {FLOAT, INT, UINT};
551
552         Type type;
553
554         union
555         {
556                 float           f[4];
557                 deInt32         i[4];
558                 deUint32        u[4];
559         };
560
561         Color(const float f_[4])    : type(FLOAT) { f[0] = f_[0]; f[1] = f_[1]; f[2] = f_[2]; f[3] = f_[3]; }
562         Color(const deInt32 i_[4])  : type(INT)   { i[0] = i_[0]; i[1] = i_[1]; i[2] = i_[2]; i[3] = i_[3]; }
563         Color(const deUint32 u_[4]) : type(UINT)  { u[0] = u_[0]; u[1] = u_[1]; u[2] = u_[2]; u[3] = u_[3]; }
564 };
565
566 class FramebufferClearCase : public tcu::TestCase
567 {
568 public:
569                                                         FramebufferClearCase    (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, ClearType clearType);
570         virtual                                 ~FramebufferClearCase   (void) {}
571
572         virtual IterateResult   iterate                                 (void);
573
574 private:
575         static void                             clearBuffers                    (const glw::Functions& gl, Color color, float depth, int stencil);
576         static Color                    getBaseColor                    (const BufferFmtDesc& bufferFmt);
577         static Color                    getMainColor                    (const BufferFmtDesc& bufferFmt);
578         static BufferFmtDesc    getBufferFormat                 (ClearType type);
579
580         virtual void                    render                                  (GLuint program) const;
581
582         glu::RenderContext&             m_renderCtx;
583         const ClearType                 m_clearType;
584 };
585
586 FramebufferClearCase::FramebufferClearCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, ClearType clearType)
587         : tcu::TestCase (testCtx, name, desc)
588         , m_renderCtx   (renderCtx)
589         , m_clearType   (clearType)
590 {
591 }
592
593 void FramebufferClearCase::clearBuffers (const glw::Functions& gl, Color color, float depth, int stencil)
594 {
595         switch(color.type)
596         {
597                 case Color::FLOAT:      gl.clearBufferfv (GL_COLOR, 0, color.f); break;
598                 case Color::INT:        gl.clearBufferiv (GL_COLOR, 0, color.i); break;
599                 case Color::UINT:       gl.clearBufferuiv(GL_COLOR, 0, color.u); break;
600                 default:
601                         DE_ASSERT(false);
602         }
603
604         gl.clearBufferfv(GL_DEPTH, 0, &depth);
605         gl.clearBufferiv(GL_STENCIL, 0, &stencil);
606 }
607
608 FramebufferClearCase::IterateResult FramebufferClearCase::iterate (void)
609 {
610         TestLog&                                        log                             = m_testCtx.getLog();
611         const glw::Functions&           gl                              = m_renderCtx.getFunctions();
612         const glu::ShaderProgram        shader                  (m_renderCtx, genShaders(glu::getContextTypeGLSLVersion(m_renderCtx.getType())));
613
614         const glu::Framebuffer          fbo                             (gl);
615         const glu::Renderbuffer         colorbuf                (gl);
616         const glu::Renderbuffer         depthbuf                (gl);
617
618         const BufferFmtDesc                     bufferFmt               = getBufferFormat(m_clearType);
619         const Color                                     baseColor               = getBaseColor(bufferFmt);
620
621         const int                                       width                   = 64;
622         const int                                       height                  = 64;
623
624         const IVec4                                     scissorArea             (8, 8, 48, 48);
625
626         vector<deUint8>                         refData                 (width*height*bufferFmt.texFmt.getPixelSize());
627         vector<deUint8>                         resData                 (width*height*bufferFmt.texFmt.getPixelSize());
628
629         tcu::PixelBufferAccess          refAccess               (bufferFmt.texFmt, width, height, 1, &refData[0]);
630         tcu::PixelBufferAccess          resAccess               (bufferFmt.texFmt, width, height, 1, &resData[0]);
631
632         if (!shader.isOk())
633         {
634                 log << shader;
635                 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader compile/link failed");
636                 return STOP;
637         }
638
639         gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, *fbo);
640         gl.bindFramebuffer(GL_READ_FRAMEBUFFER, *fbo);
641
642         // Color
643         gl.bindRenderbuffer(GL_RENDERBUFFER, *colorbuf);
644         gl.renderbufferStorage(GL_RENDERBUFFER, bufferFmt.colorFmt, width, height);
645         gl.framebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *colorbuf);
646
647         // Depth/stencil
648         gl.bindRenderbuffer(GL_RENDERBUFFER, *depthbuf);
649         gl.renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
650         gl.framebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, *depthbuf);
651
652         log << TestLog::Message << "Scissor area is " << scissorArea << TestLog::EndMessage;
653
654         // Render reference
655         {
656                 log << TestLog::Message << "Rendering reference (scissors disabled)" << TestLog::EndMessage;
657
658                 gl.useProgram(shader.getProgram());
659                 gl.viewport(0, 0, width, height);
660
661                 gl.disable(GL_DEPTH_TEST);
662                 gl.disable(GL_STENCIL_TEST);
663                 gl.disable(GL_SCISSOR_TEST);
664
665                 clearBuffers(gl, baseColor, 1.0f, 0);
666
667                 render(shader.getProgram());
668
669                 glu::readPixels(m_renderCtx, 0, 0, refAccess);
670                 GLU_CHECK_ERROR(gl.getError());
671         }
672
673         // Render result
674         {
675                 log << TestLog::Message << "Rendering result (scissors enabled)" << TestLog::EndMessage;
676
677                 gl.useProgram(shader.getProgram());
678                 gl.viewport(0, 0, width, height);
679
680                 gl.disable(GL_DEPTH_TEST);
681                 gl.disable(GL_STENCIL_TEST);
682                 gl.disable(GL_SCISSOR_TEST);
683
684                 clearBuffers(gl, baseColor, 1.0f, 0);
685
686                 gl.enable(GL_SCISSOR_TEST);
687                 gl.scissor(scissorArea.x(), scissorArea.y(), scissorArea.z(), scissorArea.w());
688
689                 render(shader.getProgram());
690
691                 glu::readPixels(m_renderCtx, 0, 0, resAccess);
692                 GLU_CHECK_ERROR(gl.getError());
693         }
694
695         {
696                 bool resultOk = false;
697
698                 switch (baseColor.type)
699                 {
700                         case Color::FLOAT:
701                                 clearEdges(refAccess, Vec4(baseColor.f[0], baseColor.f[1], baseColor.f[2], baseColor.f[3]), scissorArea);
702                                 resultOk = tcu::floatThresholdCompare(log, "ComparisonResult", "Image comparison result", refAccess, resAccess, Vec4(0.02f, 0.02f, 0.02f, 0.02f), tcu::COMPARE_LOG_RESULT);
703                                 break;
704
705                         case Color::INT:
706                                 clearEdges(refAccess, IVec4(baseColor.i[0], baseColor.i[1], baseColor.i[2], baseColor.i[3]), scissorArea);
707                                 resultOk = tcu::intThresholdCompare(log, "ComparisonResult", "Image comparison result", refAccess, resAccess, UVec4(2, 2, 2, 2), tcu::COMPARE_LOG_RESULT);
708                                 break;
709
710                         case Color::UINT:
711                                 clearEdges(refAccess, UVec4(baseColor.u[0], baseColor.u[1], baseColor.u[2], baseColor.u[3]), scissorArea);
712                                 resultOk = tcu::intThresholdCompare(log, "ComparisonResult", "Image comparison result", refAccess, resAccess, UVec4(2, 2, 2, 2), tcu::COMPARE_LOG_RESULT);
713                                 break;
714                 }
715
716                 if (resultOk)
717                         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
718                 else
719                         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
720         }
721
722         return STOP;
723 }
724
725 Color FramebufferClearCase::getBaseColor (const BufferFmtDesc& bufferFmt)
726 {
727         const float             f[4] = {0.125f, 0.25f, 0.5f, 1.0f};
728         const deInt32   i[4] = {0, 0, 0, 0};
729         const deUint32  u[4] = {0, 0, 0, 0};
730
731         switch(bufferFmt.colorFmt)
732         {
733                 case GL_RGBA8:          return Color(f);
734                 case GL_RGBA8I:         return Color(i);
735                 case GL_RGBA8UI:        return Color(u);
736                 default:
737                         DE_ASSERT(false);
738         }
739
740         return Color(f);
741 }
742
743 Color FramebufferClearCase::getMainColor (const BufferFmtDesc& bufferFmt)
744 {
745         const float             f[4] = {1.0f, 1.0f, 0.5f, 1.0f};
746         const deInt32   i[4] = {127, -127, 0, 127};
747         const deUint32  u[4] = {255, 255, 0, 255};
748
749         switch(bufferFmt.colorFmt)
750         {
751                 case GL_RGBA8:          return Color(f);
752                 case GL_RGBA8I:         return Color(i);
753                 case GL_RGBA8UI:        return Color(u);
754                 default:
755                         DE_ASSERT(false);
756         }
757
758         return Color(f);
759 }
760
761 BufferFmtDesc FramebufferClearCase::getBufferFormat (ClearType type)
762 {
763         BufferFmtDesc retval;
764
765         switch (type)
766         {
767                 case CLEAR_COLOR_FLOAT:
768                         retval.colorFmt = GL_RGBA16F;
769                         retval.texFmt   = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::HALF_FLOAT);
770                         DE_FATAL("Floating point clear not implemented");// \todo [2014-1-23 otto] pixel read format & type, nothing guaranteed, need extension...
771                         break;
772
773                 case CLEAR_COLOR_INT:
774                         retval.colorFmt = GL_RGBA8I;
775                         retval.texFmt   = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT32);
776                         break;
777
778                 case CLEAR_COLOR_UINT:
779                         retval.colorFmt = GL_RGBA8UI;
780                         retval.texFmt   = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT32);
781                         break;
782
783                 default:
784                         retval.colorFmt = GL_RGBA8;
785                         retval.texFmt   = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
786                         break;
787         }
788
789         return retval;
790 }
791
792 void FramebufferClearCase::render (GLuint program) const
793 {
794         const glw::Functions&   gl                                      = m_renderCtx.getFunctions();
795
796         const BufferFmtDesc             bufferFmt                       = getBufferFormat(m_clearType);
797         const Color                             clearColor                      = getMainColor(bufferFmt);
798
799         const int                               clearStencil            = 123;
800         const float                             clearDepth                      = 0.5f;
801
802         switch (m_clearType)
803         {
804                 case CLEAR_COLOR_FIXED:         gl.clearBufferfv (GL_COLOR, 0, clearColor.f);                                           break;
805                 case CLEAR_COLOR_FLOAT:         gl.clearBufferfv (GL_COLOR, 0, clearColor.f);                                           break;
806                 case CLEAR_COLOR_INT:           gl.clearBufferiv (GL_COLOR, 0, clearColor.i);                                           break;
807                 case CLEAR_COLOR_UINT:          gl.clearBufferuiv(GL_COLOR, 0, clearColor.u);                                           break;
808                 case CLEAR_DEPTH:                       gl.clearBufferfv (GL_DEPTH, 0, &clearDepth);                                            break;
809                 case CLEAR_STENCIL:                     gl.clearBufferiv (GL_STENCIL, 0, &clearStencil);                                        break;
810                 case CLEAR_DEPTH_STENCIL:       gl.clearBufferfi (GL_DEPTH_STENCIL, 0, clearDepth, clearStencil);       break;
811
812                 default:
813                         DE_ASSERT(false);
814         }
815
816         const bool useDepth             = (m_clearType == CLEAR_DEPTH   || m_clearType == CLEAR_DEPTH_STENCIL);
817         const bool useStencil   = (m_clearType == CLEAR_STENCIL || m_clearType == CLEAR_DEPTH_STENCIL);
818
819         // Render something to expose changes to depth/stencil buffer
820         if (useDepth || useStencil)
821         {
822                 if (useDepth)
823                         gl.enable(GL_DEPTH_TEST);
824
825                 if (useStencil)
826                         gl.enable(GL_STENCIL_TEST);
827
828                 gl.stencilFunc(GL_EQUAL, clearStencil, ~0u);
829                 gl.depthFunc(GL_GREATER);
830                 gl.disable(GL_SCISSOR_TEST);
831
832                 gl.uniform4fv(gl.getUniformLocation(program, "u_color"), 1, clearColor.f);
833                 drawQuad(gl, program, tcu::Vec3(-1.0f, -1.0f, 0.6f), tcu::Vec3(1.0f, 1.0f, 0.6f));
834         }
835 }
836
837 } // Anonymous
838
839 namespace ScissorTestInternal
840 {
841
842 tcu::TestNode* createPrimitiveTest (tcu::TestContext&   testCtx,
843                                                                         glu::RenderContext&     renderCtx,
844                                                                         const char*                     name,
845                                                                         const char*                     desc,
846                                                                         const Vec4&                     scissorArea,
847                                                                         const Vec4&                     renderArea,
848                                                                         PrimitiveType           type,
849                                                                         int                                     primitiveCount)
850 {
851         return new ScissorPrimitiveCase(testCtx, renderCtx, name, desc, scissorArea, renderArea, type, primitiveCount);
852 }
853
854 tcu::TestNode* createClearTest (tcu::TestContext&       testCtx,
855                                                                 glu::RenderContext&     renderCtx,
856                                                                 const char*                     name,
857                                                                 const char*                     desc,
858                                                                 const Vec4&                     scissorArea,
859                                                                 deUint32                        clearMode)
860 {
861         return new ScissorClearCase(testCtx, renderCtx, name, desc, scissorArea, clearMode);
862 }
863
864 tcu::TestNode* createFramebufferClearTest (tcu::TestContext&    testCtx,
865                                                                                    glu::RenderContext&  renderCtx,
866                                                                                    const char*                  name,
867                                                                                    const char*                  desc,
868                                                                                    ClearType                    clearType)
869 {
870         return new FramebufferClearCase(testCtx, renderCtx, name, desc, clearType);
871 }
872
873 tcu::TestNode* createFramebufferBlitTest (tcu::TestContext&             testCtx,
874                                                                                   glu::RenderContext&   renderCtx,
875                                                                                   const char*                   name,
876                                                                                   const char*                   desc,
877                                                                                   const Vec4&                   scissorArea)
878 {
879         return new FramebufferBlitCase(testCtx, renderCtx, name, desc, scissorArea);
880 }
881
882 } // ScissorTestInternal
883 } // Functional
884 } // gls
885 } // deqp