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