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