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