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