xref: /aosp_15_r20/external/deqp/modules/gles3/functional/es3fFramebufferBlitTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief FBO stencilbuffer tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es3fFramebufferBlitTests.hpp"
25 #include "es3fFboTestCase.hpp"
26 #include "es3fFboTestUtil.hpp"
27 #include "gluTextureUtil.hpp"
28 #include "gluContextInfo.hpp"
29 #include "tcuTextureUtil.hpp"
30 #include "tcuVectorUtil.hpp"
31 #include "tcuTestLog.hpp"
32 #include "tcuImageCompare.hpp"
33 #include "tcuRenderTarget.hpp"
34 #include "sglrContextUtil.hpp"
35 #include "glwEnums.hpp"
36 #include "deStringUtil.hpp"
37 
38 namespace deqp
39 {
40 namespace gles3
41 {
42 namespace Functional
43 {
44 
45 using std::string;
46 using tcu::IVec2;
47 using tcu::IVec3;
48 using tcu::IVec4;
49 using tcu::TestLog;
50 using tcu::UVec4;
51 using tcu::Vec2;
52 using tcu::Vec3;
53 using tcu::Vec4;
54 using namespace FboTestUtil;
55 
56 class BlitRectCase : public FboTestCase
57 {
58 public:
BlitRectCase(Context & context,const char * name,const char * desc,uint32_t filter,const IVec2 & srcSize,const IVec4 & srcRect,const IVec2 & dstSize,const IVec4 & dstRect,int cellSize=8)59     BlitRectCase(Context &context, const char *name, const char *desc, uint32_t filter, const IVec2 &srcSize,
60                  const IVec4 &srcRect, const IVec2 &dstSize, const IVec4 &dstRect, int cellSize = 8)
61         : FboTestCase(context, name, desc)
62         , m_filter(filter)
63         , m_srcSize(srcSize)
64         , m_srcRect(srcRect)
65         , m_dstSize(dstSize)
66         , m_dstRect(dstRect)
67         , m_cellSize(cellSize)
68         , m_gridCellColorA(0.2f, 0.7f, 0.1f, 1.0f)
69         , m_gridCellColorB(0.7f, 0.1f, 0.5f, 0.8f)
70     {
71     }
72 
render(tcu::Surface & dst)73     void render(tcu::Surface &dst)
74     {
75         const uint32_t colorFormat = GL_RGBA8;
76 
77         GradientShader gradShader(glu::TYPE_FLOAT_VEC4);
78         Texture2DShader texShader(DataTypes() << glu::TYPE_SAMPLER_2D, glu::TYPE_FLOAT_VEC4);
79         uint32_t gradShaderID = getCurrentContext()->createProgram(&gradShader);
80         uint32_t texShaderID  = getCurrentContext()->createProgram(&texShader);
81 
82         uint32_t srcFbo = 0;
83         uint32_t dstFbo = 0;
84         uint32_t srcRbo = 0;
85         uint32_t dstRbo = 0;
86 
87         // Setup shaders
88         gradShader.setGradient(*getCurrentContext(), gradShaderID, Vec4(0.0f), Vec4(1.0f));
89         texShader.setUniforms(*getCurrentContext(), texShaderID);
90 
91         // Create framebuffers.
92         for (int ndx = 0; ndx < 2; ndx++)
93         {
94             uint32_t &fbo     = ndx ? dstFbo : srcFbo;
95             uint32_t &rbo     = ndx ? dstRbo : srcRbo;
96             const IVec2 &size = ndx ? m_dstSize : m_srcSize;
97 
98             glGenFramebuffers(1, &fbo);
99             glGenRenderbuffers(1, &rbo);
100 
101             glBindRenderbuffer(GL_RENDERBUFFER, rbo);
102             glRenderbufferStorage(GL_RENDERBUFFER, colorFormat, size.x(), size.y());
103 
104             glBindFramebuffer(GL_FRAMEBUFFER, fbo);
105             glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
106             checkError();
107             checkFramebufferStatus(GL_FRAMEBUFFER);
108         }
109 
110         // Fill destination with gradient.
111         glBindFramebuffer(GL_FRAMEBUFFER, dstFbo);
112         glViewport(0, 0, m_dstSize.x(), m_dstSize.y());
113 
114         sglr::drawQuad(*getCurrentContext(), gradShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
115 
116         // Fill source with grid pattern.
117         {
118             const uint32_t format   = GL_RGBA;
119             const uint32_t dataType = GL_UNSIGNED_BYTE;
120             const int texW          = m_srcSize.x();
121             const int texH          = m_srcSize.y();
122             uint32_t gridTex        = 0;
123             tcu::TextureLevel data(glu::mapGLTransferFormat(format, dataType), texW, texH, 1);
124 
125             tcu::fillWithGrid(data.getAccess(), m_cellSize, m_gridCellColorA, m_gridCellColorB);
126 
127             glGenTextures(1, &gridTex);
128             glBindTexture(GL_TEXTURE_2D, gridTex);
129             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
130             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
131             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
132             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
133             glTexImage2D(GL_TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr());
134 
135             glBindFramebuffer(GL_FRAMEBUFFER, srcFbo);
136             glViewport(0, 0, m_srcSize.x(), m_srcSize.y());
137             sglr::drawQuad(*getCurrentContext(), texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
138         }
139 
140         // Perform copy.
141         glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFbo);
142         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFbo);
143         glBlitFramebuffer(m_srcRect.x(), m_srcRect.y(), m_srcRect.z(), m_srcRect.w(), m_dstRect.x(), m_dstRect.y(),
144                           m_dstRect.z(), m_dstRect.w(), GL_COLOR_BUFFER_BIT, m_filter);
145 
146         // Read back results.
147         glBindFramebuffer(GL_READ_FRAMEBUFFER, dstFbo);
148         readPixels(dst, 0, 0, m_dstSize.x(), m_dstSize.y(), glu::mapGLInternalFormat(colorFormat), Vec4(1.0f),
149                    Vec4(0.0f));
150     }
151 
compare(const tcu::Surface & reference,const tcu::Surface & result)152     virtual bool compare(const tcu::Surface &reference, const tcu::Surface &result)
153     {
154         // Use pixel-threshold compare for rect cases since 1px off will mean failure.
155         tcu::RGBA threshold =
156             TestCase::m_context.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(7, 7, 7, 7);
157         return tcu::pixelThresholdCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference, result,
158                                           threshold, tcu::COMPARE_LOG_RESULT);
159     }
160 
161 protected:
162     const uint32_t m_filter;
163     const IVec2 m_srcSize;
164     const IVec4 m_srcRect;
165     const IVec2 m_dstSize;
166     const IVec4 m_dstRect;
167     const int m_cellSize;
168     const Vec4 m_gridCellColorA;
169     const Vec4 m_gridCellColorB;
170 };
171 
172 class BlitNearestFilterConsistencyCase : public BlitRectCase
173 {
174 public:
175     BlitNearestFilterConsistencyCase(Context &context, const char *name, const char *desc, const IVec2 &srcSize,
176                                      const IVec4 &srcRect, const IVec2 &dstSize, const IVec4 &dstRect);
177 
178     bool compare(const tcu::Surface &reference, const tcu::Surface &result);
179 };
180 
BlitNearestFilterConsistencyCase(Context & context,const char * name,const char * desc,const IVec2 & srcSize,const IVec4 & srcRect,const IVec2 & dstSize,const IVec4 & dstRect)181 BlitNearestFilterConsistencyCase::BlitNearestFilterConsistencyCase(Context &context, const char *name, const char *desc,
182                                                                    const IVec2 &srcSize, const IVec4 &srcRect,
183                                                                    const IVec2 &dstSize, const IVec4 &dstRect)
184     : BlitRectCase(context, name, desc, GL_NEAREST, srcSize, srcRect, dstSize, dstRect, 1)
185 {
186 }
187 
compare(const tcu::Surface & reference,const tcu::Surface & result)188 bool BlitNearestFilterConsistencyCase::compare(const tcu::Surface &reference, const tcu::Surface &result)
189 {
190     DE_ASSERT(reference.getWidth() == result.getWidth());
191     DE_ASSERT(reference.getHeight() == result.getHeight());
192     DE_UNREF(reference);
193 
194     // Image origin must be visible (for baseColor)
195     DE_ASSERT(de::min(m_dstRect.x(), m_dstRect.z()) >= 0);
196     DE_ASSERT(de::min(m_dstRect.y(), m_dstRect.w()) >= 0);
197 
198     const tcu::RGBA cellColorA(m_gridCellColorA);
199     const tcu::RGBA cellColorB(m_gridCellColorB);
200     const tcu::RGBA threshold =
201         TestCase::m_context.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(7, 7, 7, 7);
202     const tcu::IVec4 destinationArea =
203         tcu::IVec4(de::clamp(de::min(m_dstRect.x(), m_dstRect.z()), 0, result.getWidth()),
204                    de::clamp(de::min(m_dstRect.y(), m_dstRect.w()), 0, result.getHeight()),
205                    de::clamp(de::max(m_dstRect.x(), m_dstRect.z()), 0, result.getWidth()),
206                    de::clamp(de::max(m_dstRect.y(), m_dstRect.w()), 0, result.getHeight()));
207     const tcu::RGBA baseColor = result.getPixel(destinationArea.x(), destinationArea.y());
208     const bool signConfig     = tcu::compareThreshold(baseColor, cellColorA, threshold);
209 
210     bool error = false;
211     tcu::Surface errorMask(result.getWidth(), result.getHeight());
212     std::vector<bool> horisontalSign(destinationArea.z() - destinationArea.x());
213     std::vector<bool> verticalSign(destinationArea.w() - destinationArea.y());
214 
215     tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
216 
217     // Checking only area in our destination rect
218 
219     m_testCtx.getLog()
220         << tcu::TestLog::Message << "Verifying consistency of NEAREST filtering. Verifying rect " << m_dstRect << ".\n"
221         << "Rounding direction of the NEAREST filter at the horisontal texel edge (x = n + 0.5) should not depend on "
222            "the y-coordinate.\n"
223         << "Rounding direction of the NEAREST filter at the vertical texel edge (y = n + 0.5) should not depend on the "
224            "x-coordinate.\n"
225         << "Blitting a grid (with uniform sized cells) should result in a grid (with non-uniform sized cells)."
226         << tcu::TestLog::EndMessage;
227 
228     // Verify that destination only contains valid colors
229 
230     for (int dy = 0; dy < destinationArea.w() - destinationArea.y(); ++dy)
231         for (int dx = 0; dx < destinationArea.z() - destinationArea.x(); ++dx)
232         {
233             const tcu::RGBA color   = result.getPixel(destinationArea.x() + dx, destinationArea.y() + dy);
234             const bool isValidColor = tcu::compareThreshold(color, cellColorA, threshold) ||
235                                       tcu::compareThreshold(color, cellColorB, threshold);
236 
237             if (!isValidColor)
238             {
239                 errorMask.setPixel(destinationArea.x() + dx, destinationArea.y() + dy, tcu::RGBA::red());
240                 error = true;
241             }
242         }
243     if (error)
244     {
245         m_testCtx.getLog() << tcu::TestLog::Message
246                            << "Image verification failed, destination rect contains unexpected values. "
247                            << "Expected either " << cellColorA << " or " << cellColorB << "."
248                            << tcu::TestLog::EndMessage << tcu::TestLog::ImageSet("Result", "Image verification result")
249                            << tcu::TestLog::Image("Result", "Result", result)
250                            << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask) << tcu::TestLog::EndImageSet;
251         return false;
252     }
253 
254     // Detect result edges by reading the first row and first column of the blitted area.
255     // Blitting a grid should result in a grid-like image. ("sign changes" should be consistent)
256 
257     for (int dx = 0; dx < destinationArea.z() - destinationArea.x(); ++dx)
258     {
259         const tcu::RGBA color = result.getPixel(destinationArea.x() + dx, destinationArea.y());
260 
261         if (tcu::compareThreshold(color, cellColorA, threshold))
262             horisontalSign[dx] = true;
263         else if (tcu::compareThreshold(color, cellColorB, threshold))
264             horisontalSign[dx] = false;
265         else
266             DE_ASSERT(false);
267     }
268     for (int dy = 0; dy < destinationArea.w() - destinationArea.y(); ++dy)
269     {
270         const tcu::RGBA color = result.getPixel(destinationArea.x(), destinationArea.y() + dy);
271 
272         if (tcu::compareThreshold(color, cellColorA, threshold))
273             verticalSign[dy] = true;
274         else if (tcu::compareThreshold(color, cellColorB, threshold))
275             verticalSign[dy] = false;
276         else
277             DE_ASSERT(false);
278     }
279 
280     // Verify grid-like image
281 
282     for (int dy = 0; dy < destinationArea.w() - destinationArea.y(); ++dy)
283         for (int dx = 0; dx < destinationArea.z() - destinationArea.x(); ++dx)
284         {
285             const tcu::RGBA color  = result.getPixel(destinationArea.x() + dx, destinationArea.y() + dy);
286             const bool resultSign  = tcu::compareThreshold(cellColorA, color, threshold);
287             const bool correctSign = (horisontalSign[dx] == verticalSign[dy]) == signConfig;
288 
289             if (resultSign != correctSign)
290             {
291                 errorMask.setPixel(destinationArea.x() + dx, destinationArea.y() + dy, tcu::RGBA::red());
292                 error = true;
293             }
294         }
295 
296     // Report result
297 
298     if (error)
299     {
300         m_testCtx.getLog() << tcu::TestLog::Message << "Image verification failed, nearest filter is not consistent."
301                            << tcu::TestLog::EndMessage << tcu::TestLog::ImageSet("Result", "Image verification result")
302                            << tcu::TestLog::Image("Result", "Result", result)
303                            << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask) << tcu::TestLog::EndImageSet;
304     }
305     else
306     {
307         m_testCtx.getLog() << tcu::TestLog::Message << "Image verification passed." << tcu::TestLog::EndMessage
308                            << tcu::TestLog::ImageSet("Result", "Image verification result")
309                            << tcu::TestLog::Image("Result", "Result", result) << tcu::TestLog::EndImageSet;
310     }
311 
312     return !error;
313 }
314 
getChannelMask(tcu::TextureFormat::ChannelOrder order)315 static tcu::BVec4 getChannelMask(tcu::TextureFormat::ChannelOrder order)
316 {
317     switch (order)
318     {
319     case tcu::TextureFormat::R:
320         return tcu::BVec4(true, false, false, false);
321     case tcu::TextureFormat::RG:
322         return tcu::BVec4(true, true, false, false);
323     case tcu::TextureFormat::RGB:
324         return tcu::BVec4(true, true, true, false);
325     case tcu::TextureFormat::RGBA:
326         return tcu::BVec4(true, true, true, true);
327     case tcu::TextureFormat::sRGB:
328         return tcu::BVec4(true, true, true, false);
329     case tcu::TextureFormat::sRGBA:
330         return tcu::BVec4(true, true, true, true);
331     default:
332         DE_ASSERT(false);
333         return tcu::BVec4(false);
334     }
335 }
336 
337 class BlitColorConversionCase : public FboTestCase
338 {
339 public:
BlitColorConversionCase(Context & context,const char * name,const char * desc,uint32_t srcFormat,uint32_t dstFormat,const IVec2 & size)340     BlitColorConversionCase(Context &context, const char *name, const char *desc, uint32_t srcFormat,
341                             uint32_t dstFormat, const IVec2 &size)
342         : FboTestCase(context, name, desc)
343         , m_srcFormat(srcFormat)
344         , m_dstFormat(dstFormat)
345         , m_size(size)
346     {
347     }
348 
349 protected:
preCheck(void)350     void preCheck(void)
351     {
352         checkFormatSupport(m_srcFormat);
353         checkFormatSupport(m_dstFormat);
354     }
355 
render(tcu::Surface & dst)356     void render(tcu::Surface &dst)
357     {
358         tcu::TextureFormat srcFormat = glu::mapGLInternalFormat(m_srcFormat);
359         tcu::TextureFormat dstFormat = glu::mapGLInternalFormat(m_dstFormat);
360         glu::DataType srcOutputType  = getFragmentOutputType(srcFormat);
361         glu::DataType dstOutputType  = getFragmentOutputType(dstFormat);
362 
363         // Compute ranges \note Doesn't handle case where src or dest is not subset of the another!
364         tcu::TextureFormatInfo srcFmtRangeInfo = tcu::getTextureFormatInfo(srcFormat);
365         tcu::TextureFormatInfo dstFmtRangeInfo = tcu::getTextureFormatInfo(dstFormat);
366         tcu::BVec4 copyMask     = tcu::logicalAnd(getChannelMask(srcFormat.order), getChannelMask(dstFormat.order));
367         tcu::BVec4 srcIsGreater = tcu::greaterThan(srcFmtRangeInfo.valueMax - srcFmtRangeInfo.valueMin,
368                                                    dstFmtRangeInfo.valueMax - dstFmtRangeInfo.valueMin);
369         tcu::TextureFormatInfo srcRangeInfo(
370             tcu::select(dstFmtRangeInfo.valueMin, srcFmtRangeInfo.valueMin, tcu::logicalAnd(copyMask, srcIsGreater)),
371             tcu::select(dstFmtRangeInfo.valueMax, srcFmtRangeInfo.valueMax, tcu::logicalAnd(copyMask, srcIsGreater)),
372             tcu::select(dstFmtRangeInfo.lookupScale, srcFmtRangeInfo.lookupScale,
373                         tcu::logicalAnd(copyMask, srcIsGreater)),
374             tcu::select(dstFmtRangeInfo.lookupBias, srcFmtRangeInfo.lookupBias,
375                         tcu::logicalAnd(copyMask, srcIsGreater)));
376         tcu::TextureFormatInfo dstRangeInfo(tcu::select(dstFmtRangeInfo.valueMin, srcFmtRangeInfo.valueMin,
377                                                         tcu::logicalOr(tcu::logicalNot(copyMask), srcIsGreater)),
378                                             tcu::select(dstFmtRangeInfo.valueMax, srcFmtRangeInfo.valueMax,
379                                                         tcu::logicalOr(tcu::logicalNot(copyMask), srcIsGreater)),
380                                             tcu::select(dstFmtRangeInfo.lookupScale, srcFmtRangeInfo.lookupScale,
381                                                         tcu::logicalOr(tcu::logicalNot(copyMask), srcIsGreater)),
382                                             tcu::select(dstFmtRangeInfo.lookupBias, srcFmtRangeInfo.lookupBias,
383                                                         tcu::logicalOr(tcu::logicalNot(copyMask), srcIsGreater)));
384 
385         // Shaders.
386         GradientShader gradientToSrcShader(srcOutputType);
387         GradientShader gradientToDstShader(dstOutputType);
388 
389         uint32_t gradShaderSrcID = getCurrentContext()->createProgram(&gradientToSrcShader);
390         uint32_t gradShaderDstID = getCurrentContext()->createProgram(&gradientToDstShader);
391 
392         uint32_t srcFbo, dstFbo;
393         uint32_t srcRbo, dstRbo;
394 
395         // Create framebuffers.
396         for (int ndx = 0; ndx < 2; ndx++)
397         {
398             uint32_t &fbo   = ndx ? dstFbo : srcFbo;
399             uint32_t &rbo   = ndx ? dstRbo : srcRbo;
400             uint32_t format = ndx ? m_dstFormat : m_srcFormat;
401 
402             glGenFramebuffers(1, &fbo);
403             glGenRenderbuffers(1, &rbo);
404 
405             glBindRenderbuffer(GL_RENDERBUFFER, rbo);
406             glRenderbufferStorage(GL_RENDERBUFFER, format, m_size.x(), m_size.y());
407 
408             glBindFramebuffer(GL_FRAMEBUFFER, fbo);
409             glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
410             checkError();
411             checkFramebufferStatus(GL_FRAMEBUFFER);
412         }
413 
414         glViewport(0, 0, m_size.x(), m_size.y());
415 
416         // Render gradients.
417         for (int ndx = 0; ndx < 2; ndx++)
418         {
419             glBindFramebuffer(GL_FRAMEBUFFER, ndx ? dstFbo : srcFbo);
420 
421             if (ndx)
422             {
423                 gradientToDstShader.setGradient(*getCurrentContext(), gradShaderDstID, dstRangeInfo.valueMax,
424                                                 dstRangeInfo.valueMin);
425                 sglr::drawQuad(*getCurrentContext(), gradShaderDstID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
426             }
427             else
428             {
429                 gradientToSrcShader.setGradient(*getCurrentContext(), gradShaderSrcID, srcRangeInfo.valueMin,
430                                                 dstRangeInfo.valueMax);
431                 sglr::drawQuad(*getCurrentContext(), gradShaderSrcID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
432             }
433         }
434 
435         // Execute copy.
436         glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFbo);
437         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFbo);
438         glBlitFramebuffer(0, 0, m_size.x(), m_size.y(), 0, 0, m_size.x(), m_size.y(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
439         checkError();
440 
441         // Read results.
442         glBindFramebuffer(GL_READ_FRAMEBUFFER, dstFbo);
443         readPixels(dst, 0, 0, m_size.x(), m_size.y(), dstFormat, dstRangeInfo.lookupScale, dstRangeInfo.lookupBias);
444     }
445 
compare(const tcu::Surface & reference,const tcu::Surface & result)446     bool compare(const tcu::Surface &reference, const tcu::Surface &result)
447     {
448         const tcu::TextureFormat srcFormat = glu::mapGLInternalFormat(m_srcFormat);
449         const tcu::TextureFormat dstFormat = glu::mapGLInternalFormat(m_dstFormat);
450         const bool srcIsSRGB               = tcu::isSRGB(srcFormat);
451         const bool dstIsSRGB               = tcu::isSRGB(dstFormat);
452 
453         tcu::RGBA threshold;
454 
455         if (dstIsSRGB)
456         {
457             threshold = getToSRGBConversionThreshold(srcFormat, dstFormat);
458         }
459         else
460         {
461             const tcu::RGBA srcMaxDiff = getFormatThreshold(srcFormat) * (srcIsSRGB ? 2 : 1);
462             const tcu::RGBA dstMaxDiff = getFormatThreshold(dstFormat);
463 
464             threshold = tcu::max(srcMaxDiff, dstMaxDiff);
465         }
466 
467         m_testCtx.getLog() << tcu::TestLog::Message << "threshold = " << threshold << tcu::TestLog::EndMessage;
468         return tcu::pixelThresholdCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference, result,
469                                           threshold, tcu::COMPARE_LOG_RESULT);
470     }
471 
472 private:
473     uint32_t m_srcFormat;
474     uint32_t m_dstFormat;
475     IVec2 m_size;
476 };
477 
478 class BlitDepthStencilCase : public FboTestCase
479 {
480 public:
BlitDepthStencilCase(Context & context,const char * name,const char * desc,uint32_t depthFormat,uint32_t stencilFormat,uint32_t srcBuffers,const IVec2 & srcSize,const IVec4 & srcRect,uint32_t dstBuffers,const IVec2 & dstSize,const IVec4 & dstRect,uint32_t copyBuffers)481     BlitDepthStencilCase(Context &context, const char *name, const char *desc, uint32_t depthFormat,
482                          uint32_t stencilFormat, uint32_t srcBuffers, const IVec2 &srcSize, const IVec4 &srcRect,
483                          uint32_t dstBuffers, const IVec2 &dstSize, const IVec4 &dstRect, uint32_t copyBuffers)
484         : FboTestCase(context, name, desc)
485         , m_depthFormat(depthFormat)
486         , m_stencilFormat(stencilFormat)
487         , m_srcBuffers(srcBuffers)
488         , m_srcSize(srcSize)
489         , m_srcRect(srcRect)
490         , m_dstBuffers(dstBuffers)
491         , m_dstSize(dstSize)
492         , m_dstRect(dstRect)
493         , m_copyBuffers(copyBuffers)
494     {
495     }
496 
497 protected:
preCheck(void)498     void preCheck(void)
499     {
500         if (m_depthFormat != GL_NONE)
501             checkFormatSupport(m_depthFormat);
502         if (m_stencilFormat != GL_NONE)
503             checkFormatSupport(m_stencilFormat);
504         if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_separate_depth_stencil") &&
505             m_depthFormat != GL_NONE && m_stencilFormat != GL_NONE)
506             throw tcu::NotSupportedError("Separate depth and stencil buffers not supported");
507     }
508 
render(tcu::Surface & dst)509     void render(tcu::Surface &dst)
510     {
511         const uint32_t colorFormat = GL_RGBA8;
512 
513         GradientShader gradShader(glu::TYPE_FLOAT_VEC4);
514         Texture2DShader texShader(DataTypes() << glu::TYPE_SAMPLER_2D, glu::TYPE_FLOAT_VEC4);
515         FlatColorShader flatShader(glu::TYPE_FLOAT_VEC4);
516 
517         uint32_t flatShaderID = getCurrentContext()->createProgram(&flatShader);
518         uint32_t texShaderID  = getCurrentContext()->createProgram(&texShader);
519         uint32_t gradShaderID = getCurrentContext()->createProgram(&gradShader);
520 
521         uint32_t srcFbo        = 0;
522         uint32_t dstFbo        = 0;
523         uint32_t srcColorRbo   = 0;
524         uint32_t dstColorRbo   = 0;
525         uint32_t srcDepthRbo   = 0;
526         uint32_t srcStencilRbo = 0;
527         uint32_t dstDepthRbo   = 0;
528         uint32_t dstStencilRbo = 0;
529 
530         // setup shaders
531         gradShader.setGradient(*getCurrentContext(), gradShaderID, Vec4(0.0f), Vec4(1.0f));
532         texShader.setUniforms(*getCurrentContext(), texShaderID);
533 
534         // Create framebuffers.
535         for (int ndx = 0; ndx < 2; ndx++)
536         {
537             uint32_t &fbo        = ndx ? dstFbo : srcFbo;
538             uint32_t &colorRbo   = ndx ? dstColorRbo : srcColorRbo;
539             uint32_t &depthRbo   = ndx ? dstDepthRbo : srcDepthRbo;
540             uint32_t &stencilRbo = ndx ? dstStencilRbo : srcStencilRbo;
541             uint32_t bufs        = ndx ? m_dstBuffers : m_srcBuffers;
542             const IVec2 &size    = ndx ? m_dstSize : m_srcSize;
543 
544             glGenFramebuffers(1, &fbo);
545             glGenRenderbuffers(1, &colorRbo);
546 
547             glBindRenderbuffer(GL_RENDERBUFFER, colorRbo);
548             glRenderbufferStorage(GL_RENDERBUFFER, colorFormat, size.x(), size.y());
549 
550             if (m_depthFormat != GL_NONE)
551             {
552                 glGenRenderbuffers(1, &depthRbo);
553                 glBindRenderbuffer(GL_RENDERBUFFER, depthRbo);
554                 glRenderbufferStorage(GL_RENDERBUFFER, m_depthFormat, size.x(), size.y());
555             }
556 
557             if (m_stencilFormat != GL_NONE)
558             {
559                 glGenRenderbuffers(1, &stencilRbo);
560                 glBindRenderbuffer(GL_RENDERBUFFER, stencilRbo);
561                 glRenderbufferStorage(GL_RENDERBUFFER, m_stencilFormat, size.x(), size.y());
562             }
563 
564             glBindFramebuffer(GL_FRAMEBUFFER, fbo);
565             glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRbo);
566 
567             if (bufs & GL_DEPTH_BUFFER_BIT)
568                 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRbo);
569             if (bufs & GL_STENCIL_BUFFER_BIT)
570                 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
571                                           m_stencilFormat == GL_NONE ? depthRbo : stencilRbo);
572 
573             checkError();
574             checkFramebufferStatus(GL_FRAMEBUFFER);
575 
576             // Clear depth to 1 and stencil to 0.
577             glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0f, 0);
578         }
579 
580         // Fill source with gradient, depth = [-1..1], stencil = 7
581         glBindFramebuffer(GL_FRAMEBUFFER, srcFbo);
582         glViewport(0, 0, m_srcSize.x(), m_srcSize.y());
583         glEnable(GL_DEPTH_TEST);
584         glEnable(GL_STENCIL_TEST);
585         glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
586         glStencilFunc(GL_ALWAYS, 7, 0xffu);
587 
588         sglr::drawQuad(*getCurrentContext(), gradShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(1.0f, 1.0f, 1.0f));
589 
590         // Fill destination with grid pattern, depth = 0 and stencil = 1
591         {
592             const uint32_t format   = GL_RGBA;
593             const uint32_t dataType = GL_UNSIGNED_BYTE;
594             const int texW          = m_srcSize.x();
595             const int texH          = m_srcSize.y();
596             uint32_t gridTex        = 0;
597             tcu::TextureLevel data(glu::mapGLTransferFormat(format, dataType), texW, texH, 1);
598 
599             tcu::fillWithGrid(data.getAccess(), 8, Vec4(0.2f, 0.7f, 0.1f, 1.0f), Vec4(0.7f, 0.1f, 0.5f, 0.8f));
600 
601             glGenTextures(1, &gridTex);
602             glBindTexture(GL_TEXTURE_2D, gridTex);
603             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
604             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
605             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
606             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
607             glTexImage2D(GL_TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr());
608 
609             glBindFramebuffer(GL_FRAMEBUFFER, dstFbo);
610             glViewport(0, 0, m_dstSize.x(), m_dstSize.y());
611             glStencilFunc(GL_ALWAYS, 1, 0xffu);
612             sglr::drawQuad(*getCurrentContext(), texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
613         }
614 
615         // Perform copy.
616         glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFbo);
617         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFbo);
618         glBlitFramebuffer(m_srcRect.x(), m_srcRect.y(), m_srcRect.z(), m_srcRect.w(), m_dstRect.x(), m_dstRect.y(),
619                           m_dstRect.z(), m_dstRect.w(), m_copyBuffers, GL_NEAREST);
620 
621         // Render blue color where depth < 0, decrement on depth failure.
622         glBindFramebuffer(GL_FRAMEBUFFER, dstFbo);
623         glViewport(0, 0, m_dstSize.x(), m_dstSize.y());
624         glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
625         glStencilFunc(GL_ALWAYS, 0, 0xffu);
626 
627         flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, 0.0f, 1.0f, 1.0f));
628         sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
629 
630         if (m_dstBuffers & GL_STENCIL_BUFFER_BIT)
631         {
632             // Render green color where stencil == 6.
633             glDisable(GL_DEPTH_TEST);
634             glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
635             glStencilFunc(GL_EQUAL, 6, 0xffu);
636 
637             flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, 1.0f, 0.0f, 1.0f));
638             sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
639         }
640 
641         readPixels(dst, 0, 0, m_dstSize.x(), m_dstSize.y(), glu::mapGLInternalFormat(colorFormat), Vec4(1.0f),
642                    Vec4(0.0f));
643     }
644 
645 private:
646     uint32_t m_depthFormat;
647     uint32_t m_stencilFormat;
648     uint32_t m_srcBuffers;
649     IVec2 m_srcSize;
650     IVec4 m_srcRect;
651     uint32_t m_dstBuffers;
652     IVec2 m_dstSize;
653     IVec4 m_dstRect;
654     uint32_t m_copyBuffers;
655 };
656 
657 class BlitDefaultFramebufferCase : public FboTestCase
658 {
659 public:
BlitDefaultFramebufferCase(Context & context,const char * name,const char * desc,uint32_t format,uint32_t filter)660     BlitDefaultFramebufferCase(Context &context, const char *name, const char *desc, uint32_t format, uint32_t filter)
661         : FboTestCase(context, name, desc)
662         , m_format(format)
663         , m_filter(filter)
664     {
665     }
666 
667 protected:
preCheck(void)668     void preCheck(void)
669     {
670         if (m_context.getRenderTarget().getNumSamples() > 0)
671             throw tcu::NotSupportedError("Not supported in MSAA config");
672 
673         checkFormatSupport(m_format);
674     }
675 
render(tcu::Surface & dst)676     virtual void render(tcu::Surface &dst)
677     {
678         tcu::TextureFormat colorFormat  = glu::mapGLInternalFormat(m_format);
679         glu::TransferFormat transferFmt = glu::getTransferFormat(colorFormat);
680         GradientShader gradShader(glu::TYPE_FLOAT_VEC4);
681         Texture2DShader texShader(DataTypes() << glu::getSampler2DType(colorFormat), glu::TYPE_FLOAT_VEC4);
682         uint32_t gradShaderID = getCurrentContext()->createProgram(&gradShader);
683         uint32_t texShaderID  = getCurrentContext()->createProgram(&texShader);
684         uint32_t fbo          = 0;
685         uint32_t tex          = 0;
686         const int texW        = 128;
687         const int texH        = 128;
688 
689         // Setup shaders
690         gradShader.setGradient(*getCurrentContext(), gradShaderID, Vec4(0.0f), Vec4(1.0f));
691         texShader.setUniforms(*getCurrentContext(), texShaderID);
692 
693         // FBO
694         glGenFramebuffers(1, &fbo);
695         glGenTextures(1, &tex);
696 
697         glBindTexture(GL_TEXTURE_2D, tex);
698         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
699         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
700         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_filter);
701         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_filter);
702         glTexImage2D(GL_TEXTURE_2D, 0, m_format, texW, texH, 0, transferFmt.format, transferFmt.dataType, DE_NULL);
703 
704         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
705         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
706         checkError();
707         checkFramebufferStatus(GL_FRAMEBUFFER);
708 
709         // Render gradient to screen.
710         glBindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
711 
712         sglr::drawQuad(*getCurrentContext(), gradShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
713 
714         // Blit gradient from screen to fbo.
715         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
716         glBlitFramebuffer(0, 0, getWidth(), getHeight(), 0, 0, texW, texH, GL_COLOR_BUFFER_BIT, m_filter);
717 
718         // Fill left half of viewport with quad that uses texture.
719         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
720         glClearBufferfv(GL_COLOR, 0, Vec4(1.0f, 0.0f, 0.0f, 1.0f).getPtr());
721         sglr::drawQuad(*getCurrentContext(), texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(0.0f, 1.0f, 0.0f));
722 
723         // Blit fbo to right half.
724         glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
725         glBlitFramebuffer(0, 0, texW, texH, getWidth() / 2, 0, getWidth(), getHeight(), GL_COLOR_BUFFER_BIT, m_filter);
726 
727         glBindFramebuffer(GL_READ_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
728         readPixels(dst, 0, 0, getWidth(), getHeight());
729     }
730 
compare(const tcu::Surface & reference,const tcu::Surface & result)731     bool compare(const tcu::Surface &reference, const tcu::Surface &result)
732     {
733         const tcu::RGBA threshold(tcu::max(getFormatThreshold(m_format), tcu::RGBA(12, 12, 12, 12)));
734 
735         m_testCtx.getLog() << TestLog::Message << "Comparing images, threshold: " << threshold << TestLog::EndMessage;
736 
737         return tcu::bilinearCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference.getAccess(),
738                                     result.getAccess(), threshold, tcu::COMPARE_LOG_RESULT);
739     }
740 
741 protected:
742     const uint32_t m_format;
743     const uint32_t m_filter;
744 };
745 
746 class DefaultFramebufferBlitCase : public BlitDefaultFramebufferCase
747 {
748 public:
749     enum BlitDirection
750     {
751         BLIT_DEFAULT_TO_TARGET,
752         BLIT_TO_DEFAULT_FROM_TARGET,
753 
754         BLIT_LAST
755     };
756     enum BlitArea
757     {
758         AREA_SCALE,
759         AREA_OUT_OF_BOUNDS,
760 
761         AREA_LAST
762     };
763 
DefaultFramebufferBlitCase(Context & context,const char * name,const char * desc,uint32_t format,uint32_t filter,BlitDirection dir,BlitArea area)764     DefaultFramebufferBlitCase(Context &context, const char *name, const char *desc, uint32_t format, uint32_t filter,
765                                BlitDirection dir, BlitArea area)
766         : BlitDefaultFramebufferCase(context, name, desc, format, filter)
767         , m_blitDir(dir)
768         , m_blitArea(area)
769         , m_srcRect(-1, -1, -1, -1)
770         , m_dstRect(-1, -1, -1, -1)
771         , m_interestingArea(-1, -1, -1, -1)
772     {
773         DE_ASSERT(dir < BLIT_LAST);
774         DE_ASSERT(area < AREA_LAST);
775     }
776 
init(void)777     void init(void)
778     {
779         // requirements
780         const int minViewportSize = 128;
781         if (m_context.getRenderTarget().getWidth() < minViewportSize ||
782             m_context.getRenderTarget().getHeight() < minViewportSize)
783             throw tcu::NotSupportedError("Viewport size " + de::toString(minViewportSize) + "x" +
784                                          de::toString(minViewportSize) + " required");
785 
786         // prevent viewport randoming
787         m_viewportWidth  = m_context.getRenderTarget().getWidth();
788         m_viewportHeight = m_context.getRenderTarget().getHeight();
789 
790         // set proper areas
791         if (m_blitArea == AREA_SCALE)
792         {
793             m_srcRect         = IVec4(10, 20, 65, 100);
794             m_dstRect         = IVec4(25, 30, 125, 94);
795             m_interestingArea = IVec4(0, 0, 128, 128);
796         }
797         else if (m_blitArea == AREA_OUT_OF_BOUNDS)
798         {
799             const tcu::IVec2 ubound =
800                 (m_blitDir == BLIT_DEFAULT_TO_TARGET) ?
801                     (tcu::IVec2(128, 128)) :
802                     (tcu::IVec2(m_context.getRenderTarget().getWidth(), m_context.getRenderTarget().getHeight()));
803 
804             m_srcRect         = IVec4(-10, -15, 100, 63);
805             m_dstRect         = ubound.swizzle(0, 1, 0, 1) + IVec4(-75, -99, 8, 16);
806             m_interestingArea = IVec4(ubound.x() - 128, ubound.y() - 128, ubound.x(), ubound.y());
807         }
808         else
809             DE_ASSERT(false);
810     }
811 
render(tcu::Surface & dst)812     void render(tcu::Surface &dst)
813     {
814         const tcu::TextureFormat colorFormat       = glu::mapGLInternalFormat(m_format);
815         const glu::TransferFormat transferFmt      = glu::getTransferFormat(colorFormat);
816         const tcu::TextureChannelClass targetClass = (m_blitDir == BLIT_DEFAULT_TO_TARGET) ?
817                                                          (tcu::getTextureChannelClass(colorFormat.type)) :
818                                                          (tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT);
819         uint32_t fbo                               = 0;
820         uint32_t fboTex                            = 0;
821         const int fboTexW                          = 128;
822         const int fboTexH                          = 128;
823         const int sourceWidth                      = (m_blitDir == BLIT_DEFAULT_TO_TARGET) ? (getWidth()) : (fboTexW);
824         const int sourceHeight                     = (m_blitDir == BLIT_DEFAULT_TO_TARGET) ? (getHeight()) : (fboTexH);
825         const int gridRenderWidth                  = de::min(256, sourceWidth);
826         const int gridRenderHeight                 = de::min(256, sourceHeight);
827 
828         int targetFbo = -1;
829         int sourceFbo = -1;
830 
831         // FBO
832         glGenFramebuffers(1, &fbo);
833         glGenTextures(1, &fboTex);
834 
835         glBindTexture(GL_TEXTURE_2D, fboTex);
836         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
837         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
838         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_filter);
839         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_filter);
840         glTexImage2D(GL_TEXTURE_2D, 0, m_format, fboTexW, fboTexH, 0, transferFmt.format, transferFmt.dataType,
841                      DE_NULL);
842 
843         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
844         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboTex, 0);
845         checkError();
846         checkFramebufferStatus(GL_FRAMEBUFFER);
847 
848         targetFbo =
849             (m_blitDir == BLIT_DEFAULT_TO_TARGET) ? (fbo) : (m_context.getRenderContext().getDefaultFramebuffer());
850         sourceFbo =
851             (m_blitDir == BLIT_DEFAULT_TO_TARGET) ? (m_context.getRenderContext().getDefaultFramebuffer()) : (fbo);
852 
853         // Render grid to source framebuffer
854         {
855             Texture2DShader texShader(DataTypes() << glu::TYPE_SAMPLER_2D, glu::TYPE_FLOAT_VEC4);
856             const uint32_t texShaderID    = getCurrentContext()->createProgram(&texShader);
857             const uint32_t internalFormat = GL_RGBA8;
858             const uint32_t format         = GL_RGBA;
859             const uint32_t dataType       = GL_UNSIGNED_BYTE;
860             const int gridTexW            = 128;
861             const int gridTexH            = 128;
862             uint32_t gridTex              = 0;
863             tcu::TextureLevel data(glu::mapGLTransferFormat(format, dataType), gridTexW, gridTexH, 1);
864 
865             tcu::fillWithGrid(data.getAccess(), 9, tcu::Vec4(0.9f, 0.5f, 0.1f, 0.9f),
866                               tcu::Vec4(0.2f, 0.8f, 0.2f, 0.7f));
867 
868             glGenTextures(1, &gridTex);
869             glBindTexture(GL_TEXTURE_2D, gridTex);
870             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
871             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
872             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
873             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
874             glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, gridTexW, gridTexH, 0, format, dataType,
875                          data.getAccess().getDataPtr());
876 
877             glBindFramebuffer(GL_FRAMEBUFFER, sourceFbo);
878             glViewport(0, 0, gridRenderWidth, gridRenderHeight);
879             glClearBufferfv(GL_COLOR, 0, Vec4(1.0f, 0.0f, 0.0f, 1.0f).getPtr());
880 
881             texShader.setUniforms(*getCurrentContext(), texShaderID);
882             sglr::drawQuad(*getCurrentContext(), texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
883             glUseProgram(0);
884         }
885 
886         // Blit source framebuffer to destination
887 
888         glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceFbo);
889         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, targetFbo);
890         checkError();
891 
892         if (targetClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT ||
893             targetClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
894             targetClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT)
895             glClearBufferfv(GL_COLOR, 0, Vec4(1.0f, 1.0f, 0.0f, 1.0f).getPtr());
896         else if (targetClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER)
897             glClearBufferiv(GL_COLOR, 0, IVec4(0, 0, 0, 0).getPtr());
898         else if (targetClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)
899             glClearBufferuiv(GL_COLOR, 0, UVec4(0, 0, 0, 0).getPtr());
900         else
901             DE_ASSERT(false);
902 
903         glBlitFramebuffer(m_srcRect.x(), m_srcRect.y(), m_srcRect.z(), m_srcRect.w(), m_dstRect.x(), m_dstRect.y(),
904                           m_dstRect.z(), m_dstRect.w(), GL_COLOR_BUFFER_BIT, m_filter);
905         checkError();
906 
907         // Read target
908 
909         glBindFramebuffer(GL_FRAMEBUFFER, targetFbo);
910 
911         if (m_blitDir == BLIT_TO_DEFAULT_FROM_TARGET)
912             readPixels(dst, m_interestingArea.x(), m_interestingArea.y(), m_interestingArea.z() - m_interestingArea.x(),
913                        m_interestingArea.w() - m_interestingArea.y());
914         else
915             readPixels(dst, m_interestingArea.x(), m_interestingArea.y(), m_interestingArea.z() - m_interestingArea.x(),
916                        m_interestingArea.w() - m_interestingArea.y(), colorFormat, tcu::Vec4(1.0f), tcu::Vec4(0.0f));
917 
918         checkError();
919     }
920 
921 private:
922     const BlitDirection m_blitDir;
923     const BlitArea m_blitArea;
924     tcu::IVec4 m_srcRect;
925     tcu::IVec4 m_dstRect;
926     tcu::IVec4 m_interestingArea;
927 };
928 
FramebufferBlitTests(Context & context)929 FramebufferBlitTests::FramebufferBlitTests(Context &context) : TestCaseGroup(context, "blit", "Framebuffer blit tests")
930 {
931 }
932 
~FramebufferBlitTests(void)933 FramebufferBlitTests::~FramebufferBlitTests(void)
934 {
935 }
936 
init(void)937 void FramebufferBlitTests::init(void)
938 {
939     static const uint32_t colorFormats[] = {
940         // RGBA formats
941         GL_RGBA32I, GL_RGBA32UI, GL_RGBA16I, GL_RGBA16UI, GL_RGBA8, GL_RGBA8I, GL_RGBA8UI, GL_SRGB8_ALPHA8, GL_RGB10_A2,
942         GL_RGB10_A2UI, GL_RGBA4, GL_RGB5_A1,
943 
944         // RGB formats
945         GL_RGB8, GL_RGB565,
946 
947         // RG formats
948         GL_RG32I, GL_RG32UI, GL_RG16I, GL_RG16UI, GL_RG8, GL_RG8I, GL_RG8UI,
949 
950         // R formats
951         GL_R32I, GL_R32UI, GL_R16I, GL_R16UI, GL_R8, GL_R8I, GL_R8UI,
952 
953         // GL_EXT_color_buffer_float
954         GL_RGBA32F, GL_RGBA16F, GL_R11F_G11F_B10F, GL_RG32F, GL_RG16F, GL_R32F, GL_R16F};
955 
956     static const uint32_t depthStencilFormats[] = {GL_NONE,
957                                                    GL_DEPTH_COMPONENT32F,
958                                                    GL_DEPTH_COMPONENT24,
959                                                    GL_DEPTH_COMPONENT16,
960                                                    GL_DEPTH32F_STENCIL8,
961                                                    GL_DEPTH24_STENCIL8};
962 
963     static const uint32_t stencilFormats[] = {GL_NONE, GL_STENCIL_INDEX8};
964 
965     // .rect
966     {
967         static const struct
968         {
969             const char *name;
970             IVec4 srcRect;
971             IVec4 dstRect;
972         } copyRects[] = {
973             {"basic", IVec4(10, 20, 65, 100), IVec4(45, 5, 100, 85)},
974             {"scale", IVec4(10, 20, 65, 100), IVec4(25, 30, 125, 94)},
975             {"out_of_bounds", IVec4(-10, -15, 100, 63), IVec4(50, 30, 136, 144)},
976         };
977 
978         static const struct
979         {
980             const char *name;
981             IVec4 srcRect;
982             IVec4 dstRect;
983         } filterConsistencyRects[] = {
984             {"mag", IVec4(20, 10, 74, 88), IVec4(10, 10, 91, 101)},
985             {"min", IVec4(10, 20, 78, 100), IVec4(20, 20, 71, 80)},
986             {"out_of_bounds_mag", IVec4(21, 10, 73, 82), IVec4(11, 43, 141, 151)},
987             {"out_of_bounds_min", IVec4(11, 21, 77, 97), IVec4(80, 82, 135, 139)},
988         };
989 
990         static const struct
991         {
992             const char *name;
993             IVec4 srcSwizzle;
994             IVec4 dstSwizzle;
995         } swizzles[] = {{DE_NULL, IVec4(0, 1, 2, 3), IVec4(0, 1, 2, 3)},
996                         {"reverse_src_x", IVec4(2, 1, 0, 3), IVec4(0, 1, 2, 3)},
997                         {"reverse_src_y", IVec4(0, 3, 2, 1), IVec4(0, 1, 2, 3)},
998                         {"reverse_dst_x", IVec4(0, 1, 2, 3), IVec4(2, 1, 0, 3)},
999                         {"reverse_dst_y", IVec4(0, 1, 2, 3), IVec4(0, 3, 2, 1)},
1000                         {"reverse_src_dst_x", IVec4(2, 1, 0, 3), IVec4(2, 1, 0, 3)},
1001                         {"reverse_src_dst_y", IVec4(0, 3, 2, 1), IVec4(0, 3, 2, 1)}};
1002 
1003         const IVec2 srcSize(127, 119);
1004         const IVec2 dstSize(132, 128);
1005 
1006         // Blit rectangle tests.
1007         tcu::TestCaseGroup *rectGroup = new tcu::TestCaseGroup(m_testCtx, "rect", "Blit rectangle tests");
1008         addChild(rectGroup);
1009         for (int rectNdx = 0; rectNdx < DE_LENGTH_OF_ARRAY(copyRects); rectNdx++)
1010         {
1011             for (int swzNdx = 0; swzNdx < DE_LENGTH_OF_ARRAY(swizzles); swzNdx++)
1012             {
1013                 string name = string(copyRects[rectNdx].name) +
1014                               (swizzles[swzNdx].name ? (string("_") + swizzles[swzNdx].name) : string());
1015                 IVec4 srcSwz  = swizzles[swzNdx].srcSwizzle;
1016                 IVec4 dstSwz  = swizzles[swzNdx].dstSwizzle;
1017                 IVec4 srcRect = copyRects[rectNdx].srcRect.swizzle(srcSwz[0], srcSwz[1], srcSwz[2], srcSwz[3]);
1018                 IVec4 dstRect = copyRects[rectNdx].dstRect.swizzle(dstSwz[0], dstSwz[1], dstSwz[2], dstSwz[3]);
1019 
1020                 rectGroup->addChild(new BlitRectCase(m_context, (name + "_nearest").c_str(), "", GL_NEAREST, srcSize,
1021                                                      srcRect, dstSize, dstRect));
1022                 rectGroup->addChild(new BlitRectCase(m_context, (name + "_linear").c_str(), "", GL_LINEAR, srcSize,
1023                                                      srcRect, dstSize, dstRect));
1024             }
1025         }
1026 
1027         // Nearest filter tests
1028         for (int rectNdx = 0; rectNdx < DE_LENGTH_OF_ARRAY(filterConsistencyRects); rectNdx++)
1029         {
1030             for (int swzNdx = 0; swzNdx < DE_LENGTH_OF_ARRAY(swizzles); swzNdx++)
1031             {
1032                 string name = string("nearest_consistency_") + filterConsistencyRects[rectNdx].name +
1033                               (swizzles[swzNdx].name ? (string("_") + swizzles[swzNdx].name) : string());
1034                 IVec4 srcSwz = swizzles[swzNdx].srcSwizzle;
1035                 IVec4 dstSwz = swizzles[swzNdx].dstSwizzle;
1036                 IVec4 srcRect =
1037                     filterConsistencyRects[rectNdx].srcRect.swizzle(srcSwz[0], srcSwz[1], srcSwz[2], srcSwz[3]);
1038                 IVec4 dstRect =
1039                     filterConsistencyRects[rectNdx].dstRect.swizzle(dstSwz[0], dstSwz[1], dstSwz[2], dstSwz[3]);
1040 
1041                 rectGroup->addChild(new BlitNearestFilterConsistencyCase(m_context, name.c_str(),
1042                                                                          "Test consistency of the nearest filter",
1043                                                                          srcSize, srcRect, dstSize, dstRect));
1044             }
1045         }
1046     }
1047 
1048     // .conversion
1049     {
1050         tcu::TestCaseGroup *conversionGroup = new tcu::TestCaseGroup(m_testCtx, "conversion", "Color conversion tests");
1051         addChild(conversionGroup);
1052 
1053         for (int srcFmtNdx = 0; srcFmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); srcFmtNdx++)
1054         {
1055             for (int dstFmtNdx = 0; dstFmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); dstFmtNdx++)
1056             {
1057                 uint32_t srcFormat               = colorFormats[srcFmtNdx];
1058                 tcu::TextureFormat srcTexFmt     = glu::mapGLInternalFormat(srcFormat);
1059                 tcu::TextureChannelClass srcType = tcu::getTextureChannelClass(srcTexFmt.type);
1060                 uint32_t dstFormat               = colorFormats[dstFmtNdx];
1061                 tcu::TextureFormat dstTexFmt     = glu::mapGLInternalFormat(dstFormat);
1062                 tcu::TextureChannelClass dstType = tcu::getTextureChannelClass(dstTexFmt.type);
1063 
1064                 if (((srcType == tcu::TEXTURECHANNELCLASS_FLOATING_POINT ||
1065                       srcType == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT) !=
1066                      (dstType == tcu::TEXTURECHANNELCLASS_FLOATING_POINT ||
1067                       dstType == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)) ||
1068                     ((srcType == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER) !=
1069                      (dstType == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER)) ||
1070                     ((srcType == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER) !=
1071                      (dstType == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)))
1072                     continue; // Conversion not supported.
1073 
1074                 string name = string(getFormatName(srcFormat)) + "_to_" + getFormatName(dstFormat);
1075 
1076                 conversionGroup->addChild(
1077                     new BlitColorConversionCase(m_context, name.c_str(), "", srcFormat, dstFormat, IVec2(127, 113)));
1078             }
1079         }
1080     }
1081 
1082     // .depth_stencil
1083     {
1084         tcu::TestCaseGroup *depthStencilGroup =
1085             new tcu::TestCaseGroup(m_testCtx, "depth_stencil", "Depth and stencil blits");
1086         addChild(depthStencilGroup);
1087 
1088         for (int dFmtNdx = 0; dFmtNdx < DE_LENGTH_OF_ARRAY(depthStencilFormats); dFmtNdx++)
1089         {
1090             for (int sFmtNdx = 0; sFmtNdx < DE_LENGTH_OF_ARRAY(stencilFormats); sFmtNdx++)
1091             {
1092                 uint32_t depthFormat   = depthStencilFormats[dFmtNdx];
1093                 uint32_t stencilFormat = stencilFormats[sFmtNdx];
1094                 bool depth             = false;
1095                 bool stencil           = false;
1096                 string fmtName;
1097 
1098                 if (depthFormat != GL_NONE)
1099                 {
1100                     tcu::TextureFormat info = glu::mapGLInternalFormat(depthFormat);
1101 
1102                     fmtName += getFormatName(depthFormat);
1103                     if (info.order == tcu::TextureFormat::D || info.order == tcu::TextureFormat::DS)
1104                         depth = true;
1105                     if (info.order == tcu::TextureFormat::DS)
1106                         stencil = true;
1107                 }
1108 
1109                 if (stencilFormat != GL_NONE)
1110                 {
1111                     // Do not try separate stencil along with a combined depth/stencil
1112                     if (stencil)
1113                         continue;
1114 
1115                     if (depthFormat != GL_NONE)
1116                         fmtName += "_";
1117                     fmtName += getFormatName(stencilFormat);
1118                     stencil = true;
1119                 }
1120 
1121                 if (!stencil && !depth)
1122                     continue;
1123 
1124                 uint32_t buffers = (depth ? GL_DEPTH_BUFFER_BIT : 0) | (stencil ? GL_STENCIL_BUFFER_BIT : 0);
1125 
1126                 depthStencilGroup->addChild(new BlitDepthStencilCase(
1127                     m_context, (fmtName + "_basic").c_str(), "", depthFormat, stencilFormat, buffers, IVec2(128, 128),
1128                     IVec4(0, 0, 128, 128), buffers, IVec2(128, 128), IVec4(0, 0, 128, 128), buffers));
1129                 depthStencilGroup->addChild(new BlitDepthStencilCase(
1130                     m_context, (fmtName + "_scale").c_str(), "", depthFormat, stencilFormat, buffers, IVec2(127, 119),
1131                     IVec4(10, 30, 100, 70), buffers, IVec2(111, 130), IVec4(20, 5, 80, 130), buffers));
1132 
1133                 if (depth && stencil)
1134                 {
1135                     depthStencilGroup->addChild(
1136                         new BlitDepthStencilCase(m_context, (fmtName + "_depth_only").c_str(), "", depthFormat,
1137                                                  stencilFormat, buffers, IVec2(128, 128), IVec4(0, 0, 128, 128),
1138                                                  buffers, IVec2(128, 128), IVec4(0, 0, 128, 128), GL_DEPTH_BUFFER_BIT));
1139                     depthStencilGroup->addChild(new BlitDepthStencilCase(
1140                         m_context, (fmtName + "_stencil_only").c_str(), "", depthFormat, stencilFormat, buffers,
1141                         IVec2(128, 128), IVec4(0, 0, 128, 128), buffers, IVec2(128, 128), IVec4(0, 0, 128, 128),
1142                         GL_STENCIL_BUFFER_BIT));
1143                 }
1144             }
1145         }
1146     }
1147 
1148     // .default_framebuffer
1149     {
1150         static const struct
1151         {
1152             const char *name;
1153             DefaultFramebufferBlitCase::BlitArea area;
1154         } areas[] = {
1155             {"scale", DefaultFramebufferBlitCase::AREA_SCALE},
1156             {"out_of_bounds", DefaultFramebufferBlitCase::AREA_OUT_OF_BOUNDS},
1157         };
1158 
1159         tcu::TestCaseGroup *defaultFbGroup =
1160             new tcu::TestCaseGroup(m_testCtx, "default_framebuffer", "Blits with default framebuffer");
1161         addChild(defaultFbGroup);
1162 
1163         for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++)
1164         {
1165             const uint32_t format                   = colorFormats[fmtNdx];
1166             const tcu::TextureFormat texFmt         = glu::mapGLInternalFormat(format);
1167             const tcu::TextureChannelClass fmtClass = tcu::getTextureChannelClass(texFmt.type);
1168             const uint32_t filter = glu::isGLInternalColorFormatFilterable(format) ? GL_LINEAR : GL_NEAREST;
1169             const bool filterable = glu::isGLInternalColorFormatFilterable(format);
1170 
1171             if (fmtClass != tcu::TEXTURECHANNELCLASS_FLOATING_POINT &&
1172                 fmtClass != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT &&
1173                 fmtClass != tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT)
1174                 continue; // Conversion not supported.
1175 
1176             defaultFbGroup->addChild(
1177                 new BlitDefaultFramebufferCase(m_context, getFormatName(format), "", format, filter));
1178 
1179             for (int areaNdx = 0; areaNdx < DE_LENGTH_OF_ARRAY(areas); areaNdx++)
1180             {
1181                 const string name    = string(areas[areaNdx].name);
1182                 const bool addLinear = filterable;
1183                 const bool addNearest =
1184                     !addLinear || (areas[areaNdx].area !=
1185                                    DefaultFramebufferBlitCase::
1186                                        AREA_OUT_OF_BOUNDS); // No need to check out-of-bounds with different filtering
1187 
1188                 if (addNearest)
1189                 {
1190                     defaultFbGroup->addChild(new DefaultFramebufferBlitCase(
1191                         m_context,
1192                         (std::string(getFormatName(format)) + "_nearest_" + name + "_blit_from_default").c_str(), "",
1193                         format, GL_NEAREST, DefaultFramebufferBlitCase::BLIT_DEFAULT_TO_TARGET, areas[areaNdx].area));
1194                     defaultFbGroup->addChild(new DefaultFramebufferBlitCase(
1195                         m_context,
1196                         (std::string(getFormatName(format)) + "_nearest_" + name + "_blit_to_default").c_str(), "",
1197                         format, GL_NEAREST, DefaultFramebufferBlitCase::BLIT_TO_DEFAULT_FROM_TARGET,
1198                         areas[areaNdx].area));
1199                 }
1200 
1201                 if (addLinear)
1202                 {
1203                     defaultFbGroup->addChild(new DefaultFramebufferBlitCase(
1204                         m_context,
1205                         (std::string(getFormatName(format)) + "_linear_" + name + "_blit_from_default").c_str(), "",
1206                         format, GL_LINEAR, DefaultFramebufferBlitCase::BLIT_DEFAULT_TO_TARGET, areas[areaNdx].area));
1207                     defaultFbGroup->addChild(new DefaultFramebufferBlitCase(
1208                         m_context,
1209                         (std::string(getFormatName(format)) + "_linear_" + name + "_blit_to_default").c_str(), "",
1210                         format, GL_LINEAR, DefaultFramebufferBlitCase::BLIT_TO_DEFAULT_FROM_TARGET,
1211                         areas[areaNdx].area));
1212                 }
1213             }
1214         }
1215     }
1216 }
1217 
1218 } // namespace Functional
1219 } // namespace gles3
1220 } // namespace deqp
1221