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