1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL (ES) 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 Framebuffer completeness tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "es3fFboCompletenessTests.hpp"
25
26 #include "glsFboCompletenessTests.hpp"
27 #include "deUniquePtr.hpp"
28 #include <sstream>
29
30 using namespace glw;
31 using deqp::gls::Range;
32 using namespace deqp::gls::FboUtil;
33 using namespace deqp::gls::FboUtil::config;
34 namespace fboc = deqp::gls::fboc;
35 typedef tcu::TestCase::IterateResult IterateResult;
36 using std::string;
37 using std::ostringstream;
38
39 namespace deqp
40 {
41 namespace gles3
42 {
43 namespace Functional
44 {
45
46 static const FormatKey s_es3ColorRenderables[] =
47 {
48 // GLES3, 4.4.4: "An internal format is color-renderable if it is one of
49 // the formats from table 3.12 noted as color-renderable..."
50 GL_R8, GL_RG8, GL_RGB8, GL_RGB565, GL_RGBA4, GL_RGB5_A1, GL_RGBA8,
51 GL_RGB10_A2, GL_RGB10_A2UI, GL_SRGB8_ALPHA8,
52 GL_R8I, GL_R8UI, GL_R16I, GL_R16UI, GL_R32I, GL_R32UI,
53 GL_RG8I, GL_RG8UI, GL_RG16I, GL_RG16UI, GL_RG32I, GL_RG32UI,
54 GL_RGBA8I, GL_RGBA8UI, GL_RGBA16I, GL_RGBA16UI, GL_RGBA32I, GL_RGBA32UI,
55 };
56
57 static const FormatKey s_es3UnsizedColorRenderables[] =
58 {
59 // "...or if it is unsized format RGBA or RGB."
60 // See Table 3.3 in GLES3.
61 GLS_UNSIZED_FORMATKEY(GL_RGBA, GL_UNSIGNED_BYTE),
62 GLS_UNSIZED_FORMATKEY(GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4),
63 GLS_UNSIZED_FORMATKEY(GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1),
64 GLS_UNSIZED_FORMATKEY(GL_RGB, GL_UNSIGNED_BYTE),
65 GLS_UNSIZED_FORMATKEY(GL_RGB, GL_UNSIGNED_SHORT_5_6_5),
66 };
67
68 static const FormatKey s_es3DepthRenderables[] =
69 {
70 // GLES3, 4.4.4: "An internal format is depth-renderable if it is one of
71 // the formats from table 3.13."
72 GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT32F,
73 GL_DEPTH24_STENCIL8, GL_DEPTH32F_STENCIL8,
74 };
75
76 static const FormatKey s_es3StencilRboRenderables[] =
77 {
78 // GLES3, 4.4.4: "An internal format is stencil-renderable if it is
79 // STENCIL_INDEX8..."
80 GL_STENCIL_INDEX8,
81 };
82
83 static const FormatKey s_es3StencilRenderables[] =
84 {
85 // "...or one of the formats from table 3.13 whose base internal format is
86 // DEPTH_STENCIL."
87 GL_DEPTH24_STENCIL8, GL_DEPTH32F_STENCIL8,
88 };
89
90 static const FormatKey s_es3TextureFloatFormats[] =
91 {
92 GL_RGBA32F, GL_RGBA16F, GL_R11F_G11F_B10F,
93 GL_RG32F, GL_RG16F, GL_R32F, GL_R16F,
94 GL_RGBA16F, GL_RGB16F, GL_RG16F, GL_R16F,
95 };
96
97 static const FormatKey s_es3NotRenderableTextureFormats[] =
98 {
99 GL_R8_SNORM, GL_RG8_SNORM, GL_RGB8_SNORM, GL_RGBA8_SNORM,
100 GL_RGB9_E5, GL_SRGB8,
101 GL_RGB8I, GL_RGB16I, GL_RGB32I,
102 GL_RGB8UI, GL_RGB16UI,GL_RGB32UI,
103 };
104
105 static const FormatEntry s_es3Formats[] =
106 {
107 // Renderbuffers don't support unsized formats
108 { REQUIRED_RENDERABLE | COLOR_RENDERABLE | TEXTURE_VALID,
109 GLS_ARRAY_RANGE(s_es3UnsizedColorRenderables) },
110 { REQUIRED_RENDERABLE | COLOR_RENDERABLE | RENDERBUFFER_VALID | TEXTURE_VALID,
111 GLS_ARRAY_RANGE(s_es3ColorRenderables) },
112 { REQUIRED_RENDERABLE | DEPTH_RENDERABLE | RENDERBUFFER_VALID | TEXTURE_VALID,
113 GLS_ARRAY_RANGE(s_es3DepthRenderables) },
114 { REQUIRED_RENDERABLE | STENCIL_RENDERABLE | RENDERBUFFER_VALID,
115 GLS_ARRAY_RANGE(s_es3StencilRboRenderables) },
116 { REQUIRED_RENDERABLE | STENCIL_RENDERABLE | RENDERBUFFER_VALID | TEXTURE_VALID,
117 GLS_ARRAY_RANGE(s_es3StencilRenderables) },
118 { TEXTURE_VALID,
119 GLS_ARRAY_RANGE(s_es3NotRenderableTextureFormats) },
120
121 // These are not color-renderable in vanilla ES3, but we need to mark them
122 // as valid for textures, since EXT_color_buffer_(half_)float brings in
123 // color-renderability and only renderbuffer-validity.
124 { TEXTURE_VALID,
125 GLS_ARRAY_RANGE(s_es3TextureFloatFormats) },
126 };
127
128 // GL_EXT_color_buffer_float
129 static const FormatKey s_extColorBufferFloatFormats[] =
130 {
131 GL_RGBA32F, GL_RGBA16F, GL_R11F_G11F_B10F, GL_RG32F, GL_RG16F, GL_R32F, GL_R16F,
132 };
133
134 // GL_QCOM_render_shared_exponent
135 static const FormatKey s_qcomRenderSharedExponent[] =
136 {
137 GL_RGB9_E5,
138 };
139 // GL_OES_texture_stencil8
140 static const FormatKey s_extOESTextureStencil8[] =
141 {
142 GL_STENCIL_INDEX8,
143 };
144
145 // GL_EXT_render_snorm
146 static const FormatKey s_extRenderSnorm[] =
147 {
148 GL_R8_SNORM, GL_RG8_SNORM, GL_RGBA8_SNORM,
149 };
150
151 static const FormatExtEntry s_es3ExtFormats[] =
152 {
153 {
154 "GL_EXT_color_buffer_float",
155 // These are already texture-valid in ES3, the extension just adds RBO
156 // support and makes them color-renderable.
157 (deUint32)(REQUIRED_RENDERABLE | COLOR_RENDERABLE | RENDERBUFFER_VALID),
158 GLS_ARRAY_RANGE(s_extColorBufferFloatFormats)
159 },
160 {
161 "GL_OES_texture_stencil8",
162 // \note: es3 RBO tests actually cover the first two requirements
163 // - kept here for completeness
164 (deUint32)(REQUIRED_RENDERABLE | STENCIL_RENDERABLE | TEXTURE_VALID),
165 GLS_ARRAY_RANGE(s_extOESTextureStencil8)
166 },
167
168 // Since GLES31 is backwards compatible to GLES3, we might actually be running on a GLES31.
169 // Add rule changes of GLES31 that have no corresponding GLES3 extension.
170 //
171 // \note Not all feature changes are listed here but only those that alter GLES3 subset of
172 // the formats
173 {
174 "DEQP_gles31_core_compatible GL_EXT_render_snorm",
175 (deUint32)(REQUIRED_RENDERABLE | COLOR_RENDERABLE | TEXTURE_VALID | RENDERBUFFER_VALID),
176 GLS_ARRAY_RANGE(s_extRenderSnorm)
177 },
178
179 {
180 "GL_QCOM_render_shared_exponent",
181 // This is already texture-valid in ES3, the extension just adds RBO
182 // support to RGB9_E5 and make it color-renderable.
183 (deUint32)(REQUIRED_RENDERABLE | COLOR_RENDERABLE | RENDERBUFFER_VALID | TEXTURE_VALID),
184 GLS_ARRAY_RANGE(s_qcomRenderSharedExponent)
185 },
186 };
187
188 class ES3Checker : public Checker
189 {
190 public:
ES3Checker(const glu::RenderContext & ctx)191 ES3Checker (const glu::RenderContext& ctx)
192 : Checker (ctx)
193 , m_ctxInfo (glu::ContextInfo::create(ctx))
194 , m_numSamples (-1)
195 , m_depthStencilImage (0)
196 , m_depthStencilType (GL_NONE) {}
197 void check (GLenum attPoint, const Attachment& att, const Image* image);
198
199 private:
200 de::UniquePtr<glu::ContextInfo> m_ctxInfo;
201
202 //! The common number of samples of images.
203 GLsizei m_numSamples;
204
205 //! The common image for depth and stencil attachments.
206 GLuint m_depthStencilImage;
207 GLenum m_depthStencilType;
208 };
209
check(GLenum attPoint,const Attachment & att,const Image * image)210 void ES3Checker::check (GLenum attPoint, const Attachment& att, const Image* image)
211 {
212 GLsizei imgSamples = imageNumSamples(*image);
213
214 if (m_numSamples == -1)
215 {
216 m_numSamples = imgSamples;
217 }
218 else
219 {
220 // GLES3: "The value of RENDERBUFFER_SAMPLES is the same for all attached
221 // renderbuffers and, if the attached images are a mix of renderbuffers
222 // and textures, the value of RENDERBUFFER_SAMPLES is zero."
223 //
224 // On creating a renderbuffer: "If _samples_ is zero, then
225 // RENDERBUFFER_SAMPLES is set to zero. Otherwise [...] the resulting
226 // value for RENDERBUFFER_SAMPLES is guaranteed to be greater than or
227 // equal to _samples_ and no more than the next larger sample count
228 // supported by the implementation."
229
230 // Either all attachments are zero-sample renderbuffers and/or
231 // textures, or none of them are.
232 if ((m_numSamples == 0) != (imgSamples == 0))
233 addFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE, "Mixed multi- and single-sampled attachments");
234
235 // If the attachments requested a different number of samples, the
236 // implementation is allowed to report this as incomplete. However, it
237 // is also possible that despite the different requests, the
238 // implementation allocated the same number of samples to both. Hence
239 // reporting the framebuffer as complete is also legal.
240 if (m_numSamples != imgSamples)
241 addPotentialFBOStatus(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE, "Number of samples differ");
242 }
243
244 // "Depth and stencil attachments, if present, are the same image."
245 if (!m_ctxInfo->isExtensionSupported("GL_EXT_separate_depth_stencil")
246 && (attPoint == GL_DEPTH_ATTACHMENT || attPoint == GL_STENCIL_ATTACHMENT))
247 {
248 if (m_depthStencilImage == 0)
249 {
250 m_depthStencilImage = att.imageName;
251 m_depthStencilType = attachmentType(att);
252 }
253 else
254 {
255 if (m_depthStencilImage != att.imageName || m_depthStencilType != attachmentType(att))
256 addFBOStatus(GL_FRAMEBUFFER_UNSUPPORTED, "Depth and stencil attachments are not the same image");
257 }
258 }
259 }
260
261 struct NumLayersParams
262 {
263 GLenum textureKind; //< GL_TEXTURE_3D or GL_TEXTURE_2D_ARRAY
264 GLsizei numLayers; //< Number of layers in texture
265 GLsizei attachmentLayer; //< Layer referenced by attachment
266
267 static string getName (const NumLayersParams& params);
268 static string getDescription (const NumLayersParams& params);
269 };
270
getName(const NumLayersParams & params)271 string NumLayersParams::getName (const NumLayersParams& params)
272 {
273 ostringstream os;
274 const string kindStr = params.textureKind == GL_TEXTURE_3D ? "3d" : "2darr";
275 os << kindStr << "_" << params.numLayers << "_" << params.attachmentLayer;
276 return os.str();
277 }
278
getDescription(const NumLayersParams & params)279 string NumLayersParams::getDescription (const NumLayersParams& params)
280 {
281 ostringstream os;
282 const string kindStr = (params.textureKind == GL_TEXTURE_3D
283 ? "3D Texture"
284 : "2D Array Texture");
285 os << kindStr + ", "
286 << params.numLayers << " layers, "
287 << "attached layer " << params.attachmentLayer << ".";
288 return os.str();
289 }
290
291 class NumLayersTest : public fboc::ParamTest<NumLayersParams>
292 {
293 public:
NumLayersTest(fboc::Context & ctx,NumLayersParams param)294 NumLayersTest (fboc::Context& ctx, NumLayersParams param)
295 : fboc::ParamTest<NumLayersParams> (ctx, param) {}
296
297 IterateResult build (FboBuilder& builder);
298 };
299
build(FboBuilder & builder)300 IterateResult NumLayersTest::build (FboBuilder& builder)
301 {
302 TextureLayered* texCfg = DE_NULL;
303 const GLenum target = GL_COLOR_ATTACHMENT0;
304
305 switch (m_params.textureKind)
306 {
307 case GL_TEXTURE_3D:
308 texCfg = &builder.makeConfig<Texture3D>();
309 break;
310 case GL_TEXTURE_2D_ARRAY:
311 texCfg = &builder.makeConfig<Texture2DArray>();
312 break;
313 default:
314 DE_FATAL("Impossible case");
315 }
316 texCfg->internalFormat = getDefaultFormat(target, GL_TEXTURE);
317 texCfg->width = 64;
318 texCfg->height = 64;
319 texCfg->numLayers = m_params.numLayers;
320 const GLuint tex = builder.glCreateTexture(*texCfg);
321
322 TextureLayerAttachment* att = &builder.makeConfig<TextureLayerAttachment>();
323 att->layer = m_params.attachmentLayer;
324 att->imageName = tex;
325
326 builder.glAttach(target, att);
327
328 return STOP;
329 }
330
331 enum
332 {
333 SAMPLES_NONE = -2,
334 SAMPLES_TEXTURE = -1
335 };
336 struct NumSamplesParams
337 {
338 // >= 0: renderbuffer with N samples, -1: texture, -2: no attachment
339 GLsizei numSamples[3];
340
341 static string getName (const NumSamplesParams& params);
342 static string getDescription (const NumSamplesParams& params);
343 };
344
getName(const NumSamplesParams & params)345 string NumSamplesParams::getName (const NumSamplesParams& params)
346 {
347 ostringstream os;
348 bool first = true;
349 for (const GLsizei* ns = DE_ARRAY_BEGIN(params.numSamples);
350 ns != DE_ARRAY_END(params.numSamples);
351 ns++)
352 {
353 if (first)
354 first = false;
355 else
356 os << "_";
357
358 if (*ns == SAMPLES_NONE)
359 os << "none";
360 else if (*ns == SAMPLES_TEXTURE)
361 os << "tex";
362 else
363 os << "rbo" << *ns;
364 }
365 return os.str();
366 }
367
getDescription(const NumSamplesParams & params)368 string NumSamplesParams::getDescription (const NumSamplesParams& params)
369 {
370 ostringstream os;
371 bool first = true;
372 static const char* const s_names[] = { "color", "depth", "stencil" };
373 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_names) == DE_LENGTH_OF_ARRAY(params.numSamples));
374
375 for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_names); i++)
376 {
377 GLsizei ns = params.numSamples[i];
378
379 if (ns == SAMPLES_NONE)
380 continue;
381
382 if (first)
383 first = false;
384 else
385 os << ", ";
386
387 if (ns == SAMPLES_TEXTURE)
388 os << "texture " << s_names[i] << " attachment";
389 else
390 os << ns << "-sample renderbuffer " << s_names[i] << " attachment";
391 }
392 return os.str();
393 }
394
395 class NumSamplesTest : public fboc::ParamTest<NumSamplesParams>
396 {
397 public:
NumSamplesTest(fboc::Context & ctx,NumSamplesParams param)398 NumSamplesTest (fboc::Context& ctx, NumSamplesParams param)
399 : fboc::ParamTest<NumSamplesParams> (ctx, param) {}
400
401 IterateResult build (FboBuilder& builder);
402 };
403
build(FboBuilder & builder)404 IterateResult NumSamplesTest::build (FboBuilder& builder)
405 {
406 static const GLenum s_targets[] =
407 {
408 GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_DEPTH_ATTACHMENT,
409 };
410 // Non-integer formats for each attachment type.
411 // \todo [2013-12-17 lauri] Add fixed/floating/integer metadata for formats so
412 // we can pick one smartly or maybe try several.
413 static const GLenum s_formats[] =
414 {
415 GL_RGBA8, GL_RGB565, GL_DEPTH_COMPONENT24,
416 };
417 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_targets) == DE_LENGTH_OF_ARRAY(m_params.numSamples));
418
419 for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_targets); i++)
420 {
421 const GLenum target = s_targets[i];
422 const ImageFormat fmt = { s_formats[i], GL_NONE };
423
424 const GLsizei ns = m_params.numSamples[i];
425 if (ns == -2)
426 continue;
427
428 if (ns == -1)
429 {
430 attachTargetToNew(target, GL_TEXTURE, fmt, 64, 64, builder);
431 }
432 else
433 {
434 Renderbuffer& rboCfg = builder.makeConfig<Renderbuffer>();
435 rboCfg.internalFormat = fmt;
436 rboCfg.width = rboCfg.height = 64;
437 rboCfg.numSamples = ns;
438
439 const GLuint rbo = builder.glCreateRbo(rboCfg);
440 // Implementations do not necessarily support sample sizes greater than 1.
441 TCU_CHECK_AND_THROW(NotSupportedError,
442 builder.getError() != GL_INVALID_OPERATION,
443 "Unsupported number of samples");
444 RenderbufferAttachment& att = builder.makeConfig<RenderbufferAttachment>();
445 att.imageName = rbo;
446 builder.glAttach(target, &att);
447 }
448 }
449
450 return STOP;
451 }
452
453 class ES3CheckerFactory : public CheckerFactory
454 {
455 public:
createChecker(const glu::RenderContext & ctx)456 Checker* createChecker (const glu::RenderContext& ctx) { return new ES3Checker(ctx); }
457 };
458
459 class TestGroup : public TestCaseGroup
460 {
461 public:
462 TestGroup (Context& context);
463 void init (void);
464 private:
465 ES3CheckerFactory m_checkerFactory;
466 fboc::Context m_fboc;
467 };
468
init(void)469 void TestGroup::init (void)
470 {
471 addChild(m_fboc.createRenderableTests());
472 addChild(m_fboc.createAttachmentTests());
473 addChild(m_fboc.createSizeTests());
474
475 TestCaseGroup* layerTests = new TestCaseGroup(
476 getContext(), "layer", "Tests for layer attachments");
477
478 static const NumLayersParams s_layersParams[] =
479 { // textureKind numLayers attachmentKind
480 { GL_TEXTURE_2D_ARRAY, 1, 0 },
481 { GL_TEXTURE_2D_ARRAY, 1, 3 },
482 { GL_TEXTURE_2D_ARRAY, 4, 3 },
483 { GL_TEXTURE_2D_ARRAY, 4, 15 },
484 { GL_TEXTURE_3D, 1, 0 },
485 { GL_TEXTURE_3D, 1, 15 },
486 { GL_TEXTURE_3D, 4, 15 },
487 { GL_TEXTURE_3D, 64, 15 },
488 };
489
490 for (const NumLayersParams* lp = DE_ARRAY_BEGIN(s_layersParams);
491 lp != DE_ARRAY_END(s_layersParams);
492 ++lp)
493 layerTests->addChild(new NumLayersTest(m_fboc, *lp));
494
495 addChild(layerTests);
496
497 TestCaseGroup* sampleTests = new TestCaseGroup(
498 getContext(), "samples", "Tests for multisample attachments");
499
500 static const NumSamplesParams s_samplesParams[] =
501 {
502 { { 0, SAMPLES_NONE, SAMPLES_NONE } },
503 { { 1, SAMPLES_NONE, SAMPLES_NONE } },
504 { { 2, SAMPLES_NONE, SAMPLES_NONE } },
505 { { 0, SAMPLES_TEXTURE, SAMPLES_NONE } },
506 { { 1, SAMPLES_TEXTURE, SAMPLES_NONE } },
507 { { 2, SAMPLES_TEXTURE, SAMPLES_NONE } },
508 { { 2, 1, SAMPLES_NONE } },
509 { { 2, 2, SAMPLES_NONE } },
510 { { 0, 0, SAMPLES_TEXTURE } },
511 { { 1, 2, 0 } },
512 { { 2, 2, 0 } },
513 { { 1, 1, 1 } },
514 { { 1, 2, 4 } },
515 };
516
517 for (const NumSamplesParams* lp = DE_ARRAY_BEGIN(s_samplesParams);
518 lp != DE_ARRAY_END(s_samplesParams);
519 ++lp)
520 sampleTests->addChild(new NumSamplesTest(m_fboc, *lp));
521
522 addChild(sampleTests);
523 }
524
TestGroup(Context & ctx)525 TestGroup::TestGroup (Context& ctx)
526 : TestCaseGroup (ctx, "completeness", "Completeness tests")
527 , m_checkerFactory ()
528 , m_fboc (ctx.getTestContext(), ctx.getRenderContext(), m_checkerFactory)
529 {
530 const FormatEntries stdRange = GLS_ARRAY_RANGE(s_es3Formats);
531 const FormatExtEntries extRange = GLS_ARRAY_RANGE(s_es3ExtFormats);
532
533 m_fboc.addFormats(stdRange);
534 m_fboc.addExtFormats(extRange);
535 m_fboc.setHaveMulticolorAtts(true); // Vanilla ES3 has multiple color attachments
536 }
537
createFboCompletenessTests(Context & context)538 tcu::TestCaseGroup* createFboCompletenessTests (Context& context)
539 {
540 return new TestGroup(context);
541 }
542
543 } // Functional
544 } // gles3
545 } // deqp
546