xref: /aosp_15_r20/external/deqp/modules/gles3/functional/es3fFboCompletenessTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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 &params);
249     static string getDescription(const NumLayersParams &params);
250 };
251 
getName(const NumLayersParams & params)252 string NumLayersParams::getName(const NumLayersParams &params)
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 &params)
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 &params);
321     static string getDescription(const NumSamplesParams &params);
322 };
323 
getName(const NumSamplesParams & params)324 string NumSamplesParams::getName(const NumSamplesParams &params)
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 &params)
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