xref: /aosp_15_r20/external/deqp/modules/gles31/stress/es31sVertexAttributeBindingTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.1 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 Vertex attribute binding stress tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es31sVertexAttributeBindingTests.hpp"
25 #include "tcuVector.hpp"
26 #include "tcuTestLog.hpp"
27 #include "tcuRenderTarget.hpp"
28 #include "tcuSurface.hpp"
29 #include "gluCallLogWrapper.hpp"
30 #include "gluObjectWrapper.hpp"
31 #include "gluPixelTransfer.hpp"
32 #include "gluRenderContext.hpp"
33 #include "gluShaderProgram.hpp"
34 #include "gluStrUtil.hpp"
35 #include "glwFunctions.hpp"
36 #include "glwEnums.hpp"
37 #include "deStringUtil.hpp"
38 
39 namespace deqp
40 {
41 namespace gles31
42 {
43 namespace Stress
44 {
45 namespace
46 {
47 
48 static const char *const s_vertexSource = "#version 310 es\n"
49                                           "in highp vec4 a_position;\n"
50                                           "void main (void)\n"
51                                           "{\n"
52                                           "    gl_Position = a_position;\n"
53                                           "}\n";
54 
55 static const char *const s_fragmentSource = "#version 310 es\n"
56                                             "layout(location = 0) out mediump vec4 fragColor;\n"
57                                             "void main (void)\n"
58                                             "{\n"
59                                             "    fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
60                                             "}\n";
61 
62 static const char *const s_colorFragmentShader = "#version 310 es\n"
63                                                  "in mediump vec4 v_color;\n"
64                                                  "layout(location = 0) out mediump vec4 fragColor;\n"
65                                                  "void main (void)\n"
66                                                  "{\n"
67                                                  "    fragColor = v_color;\n"
68                                                  "}\n";
69 
70 // Verifies image contains only yellow or greeen, or a linear combination
71 // of these colors.
verifyImageYellowGreen(const tcu::Surface & image,tcu::TestLog & log,bool logImageOnSuccess)72 static bool verifyImageYellowGreen(const tcu::Surface &image, tcu::TestLog &log, bool logImageOnSuccess)
73 {
74     using tcu::TestLog;
75 
76     const int colorThreshold = 20;
77 
78     tcu::Surface error(image.getWidth(), image.getHeight());
79     bool isOk = true;
80 
81     log << TestLog::Message << "Verifying image contents." << TestLog::EndMessage;
82 
83     for (int y = 0; y < image.getHeight(); y++)
84         for (int x = 0; x < image.getWidth(); x++)
85         {
86             const tcu::RGBA pixel = image.getPixel(x, y);
87             bool pixelOk          = true;
88 
89             // Any pixel with !(G ~= 255) is faulty (not a linear combinations of green and yellow)
90             if (de::abs(pixel.getGreen() - 255) > colorThreshold)
91                 pixelOk = false;
92 
93             // Any pixel with !(B ~= 0) is faulty (not a linear combinations of green and yellow)
94             if (de::abs(pixel.getBlue() - 0) > colorThreshold)
95                 pixelOk = false;
96 
97             error.setPixel(x, y, (pixelOk) ? (tcu::RGBA(0, 255, 0, 255)) : (tcu::RGBA(255, 0, 0, 255)));
98             isOk = isOk && pixelOk;
99         }
100 
101     if (!isOk)
102     {
103         log << TestLog::Message << "Image verification failed." << TestLog::EndMessage;
104         log << TestLog::ImageSet("Verfication result", "Result of rendering")
105             << TestLog::Image("Result", "Result", image) << TestLog::Image("ErrorMask", "Error mask", error)
106             << TestLog::EndImageSet;
107     }
108     else
109     {
110         log << TestLog::Message << "Image verification passed." << TestLog::EndMessage;
111 
112         if (logImageOnSuccess)
113             log << TestLog::ImageSet("Verfication result", "Result of rendering")
114                 << TestLog::Image("Result", "Result", image) << TestLog::EndImageSet;
115     }
116 
117     return isOk;
118 }
119 
120 class BindingRenderCase : public TestCase
121 {
122 public:
123     enum
124     {
125         TEST_RENDER_SIZE = 64
126     };
127 
128     BindingRenderCase(Context &ctx, const char *name, const char *desc, bool unalignedData);
129     virtual ~BindingRenderCase(void);
130 
131     virtual void init(void);
132     virtual void deinit(void);
133     IterateResult iterate(void);
134 
135 private:
136     virtual void renderTo(tcu::Surface &dst) = 0;
137     virtual void createBuffers(void)         = 0;
138     virtual void createShader(void)          = 0;
139 
140 protected:
141     const bool m_unalignedData;
142     glw::GLuint m_vao;
143     glu::ShaderProgram *m_program;
144 };
145 
BindingRenderCase(Context & ctx,const char * name,const char * desc,bool unalignedData)146 BindingRenderCase::BindingRenderCase(Context &ctx, const char *name, const char *desc, bool unalignedData)
147     : TestCase(ctx, name, desc)
148     , m_unalignedData(unalignedData)
149     , m_vao(0)
150     , m_program(DE_NULL)
151 {
152 }
153 
~BindingRenderCase(void)154 BindingRenderCase::~BindingRenderCase(void)
155 {
156     deinit();
157 }
158 
init(void)159 void BindingRenderCase::init(void)
160 {
161     // check requirements
162     if (m_context.getRenderTarget().getWidth() < TEST_RENDER_SIZE ||
163         m_context.getRenderTarget().getHeight() < TEST_RENDER_SIZE)
164         throw tcu::NotSupportedError("Test requires at least " + de::toString<int>(TEST_RENDER_SIZE) + "x" +
165                                      de::toString<int>(TEST_RENDER_SIZE) + " render target");
166 
167     // resources
168     m_context.getRenderContext().getFunctions().genVertexArrays(1, &m_vao);
169     if (m_context.getRenderContext().getFunctions().getError() != GL_NO_ERROR)
170         throw tcu::TestError("could not gen vao");
171 
172     createBuffers();
173     createShader();
174 }
175 
deinit(void)176 void BindingRenderCase::deinit(void)
177 {
178     if (m_vao)
179     {
180         m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vao);
181         m_vao = 0;
182     }
183 
184     delete m_program;
185     m_program = DE_NULL;
186 }
187 
iterate(void)188 BindingRenderCase::IterateResult BindingRenderCase::iterate(void)
189 {
190     tcu::Surface surface(TEST_RENDER_SIZE, TEST_RENDER_SIZE);
191 
192     // draw pattern
193 
194     renderTo(surface);
195 
196     // verify results
197 
198     if (verifyImageYellowGreen(surface, m_testCtx.getLog(), false))
199         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
200     else if (m_unalignedData)
201         m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned data");
202     else
203         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
204 
205     return STOP;
206 }
207 
208 class SingleBindingCase : public BindingRenderCase
209 {
210 public:
211     enum CaseFlag
212     {
213         FLAG_ATTRIB_UNALIGNED = (1 << 0), // !< unalign attributes with relativeOffset
214         FLAG_ATTRIB_ALIGNED =
215             (1 << 1), // !< align attributes with relativeOffset to the buffer begin (and not buffer offset)
216         FLAG_ATTRIBS_MULTIPLE_ELEMS = (1 << 2), // !< use multiple attribute elements
217         FLAG_ATTRIBS_SHARED_ELEMS =
218             (1 << 3), // !< use multiple shared attribute elements. xyzw & rgba stored as (x, y, zr, wg, b, a)
219 
220         FLAG_BUF_ALIGNED_OFFSET   = (1 << 4), // !< use aligned offset to the buffer object
221         FLAG_BUF_UNALIGNED_OFFSET = (1 << 5), // !< use unaligned offset to the buffer object
222         FLAG_BUF_UNALIGNED_STRIDE = (1 << 6), // !< unalign buffer elements
223     };
224     SingleBindingCase(Context &ctx, const char *name, int flags);
225     ~SingleBindingCase(void);
226 
227     void init(void);
228     void deinit(void);
229 
230 private:
231     struct TestSpec
232     {
233         int bufferOffset;
234         int bufferStride;
235         int positionAttrOffset;
236         int colorAttrOffset;
237         bool hasColorAttr;
238     };
239 
240     enum
241     {
242         GRID_SIZE = 20
243     };
244 
245     void renderTo(tcu::Surface &dst);
246 
247     static TestSpec genTestSpec(int flags);
248     static std::string genTestDescription(int flags);
249     static bool isDataUnaligned(int flags);
250 
251     void createBuffers(void);
252     void createShader(void);
253     std::string genVertexSource(void);
254 
255     const TestSpec m_spec;
256     glw::GLuint m_buf;
257 };
258 
SingleBindingCase(Context & ctx,const char * name,int flags)259 SingleBindingCase::SingleBindingCase(Context &ctx, const char *name, int flags)
260     : BindingRenderCase(ctx, name, genTestDescription(flags).c_str(), isDataUnaligned(flags))
261     , m_spec(genTestSpec(flags))
262     , m_buf(0)
263 {
264     DE_ASSERT(!((flags & FLAG_ATTRIB_UNALIGNED) && (flags & FLAG_ATTRIB_ALIGNED)));
265     DE_ASSERT(!((flags & FLAG_ATTRIB_ALIGNED) && (flags & FLAG_BUF_UNALIGNED_STRIDE)));
266 
267     DE_ASSERT(isDataUnaligned(flags));
268 }
269 
~SingleBindingCase(void)270 SingleBindingCase::~SingleBindingCase(void)
271 {
272     deinit();
273 }
274 
init(void)275 void SingleBindingCase::init(void)
276 {
277     // log what we are trying to do
278 
279     m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << (int)GRID_SIZE << "x" << (int)GRID_SIZE << " grid.\n"
280                        << "Buffer format:\n"
281                        << "    bufferOffset: " << m_spec.bufferOffset << "\n"
282                        << "    bufferStride: " << m_spec.bufferStride << "\n"
283                        << "Vertex position format:\n"
284                        << "    type: float4\n"
285                        << "    offset: " << m_spec.positionAttrOffset << "\n"
286                        << "    total offset: " << m_spec.bufferOffset + m_spec.positionAttrOffset << "\n"
287                        << tcu::TestLog::EndMessage;
288 
289     if (m_spec.hasColorAttr)
290         m_testCtx.getLog() << tcu::TestLog::Message << "Color:\n"
291                            << "    type: float4\n"
292                            << "    offset: " << m_spec.colorAttrOffset << "\n"
293                            << "    total offset: " << m_spec.bufferOffset + m_spec.colorAttrOffset << "\n"
294                            << tcu::TestLog::EndMessage;
295     // init
296 
297     BindingRenderCase::init();
298 }
299 
deinit(void)300 void SingleBindingCase::deinit(void)
301 {
302     if (m_buf)
303     {
304         m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_buf);
305         m_buf = 0;
306     }
307 
308     BindingRenderCase::deinit();
309 }
310 
renderTo(tcu::Surface & dst)311 void SingleBindingCase::renderTo(tcu::Surface &dst)
312 {
313     glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
314     const int positionLoc     = gl.glGetAttribLocation(m_program->getProgram(), "a_position");
315     const int colorLoc        = gl.glGetAttribLocation(m_program->getProgram(), "a_color");
316     const int colorUniformLoc = gl.glGetUniformLocation(m_program->getProgram(), "u_color");
317 
318     gl.enableLogging(true);
319 
320     gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
321     gl.glClear(GL_COLOR_BUFFER_BIT);
322     gl.glViewport(0, 0, dst.getWidth(), dst.getHeight());
323     gl.glBindVertexArray(m_vao);
324     GLU_EXPECT_NO_ERROR(gl.glGetError(), "set vao");
325 
326     gl.glUseProgram(m_program->getProgram());
327     GLU_EXPECT_NO_ERROR(gl.glGetError(), "use program");
328 
329     if (m_spec.hasColorAttr)
330     {
331         gl.glBindVertexBuffer(3, m_buf, m_spec.bufferOffset, m_spec.bufferStride);
332 
333         gl.glVertexAttribBinding(positionLoc, 3);
334         gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, m_spec.positionAttrOffset);
335         gl.glEnableVertexAttribArray(positionLoc);
336 
337         gl.glVertexAttribBinding(colorLoc, 3);
338         gl.glVertexAttribFormat(colorLoc, 4, GL_FLOAT, GL_FALSE, m_spec.colorAttrOffset);
339         gl.glEnableVertexAttribArray(colorLoc);
340 
341         GLU_EXPECT_NO_ERROR(gl.glGetError(), "set va");
342 
343         gl.glDrawArrays(GL_TRIANGLES, 0, GRID_SIZE * GRID_SIZE * 6);
344         GLU_EXPECT_NO_ERROR(gl.glGetError(), "draw");
345     }
346     else
347     {
348         gl.glBindVertexBuffer(3, m_buf, m_spec.bufferOffset, m_spec.bufferStride);
349         gl.glVertexAttribBinding(positionLoc, 3);
350         gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, m_spec.positionAttrOffset);
351         gl.glEnableVertexAttribArray(positionLoc);
352 
353         GLU_EXPECT_NO_ERROR(gl.glGetError(), "set va");
354         gl.glUniform4f(colorUniformLoc, 0.0f, 1.0f, 0.0f, 1.0f);
355 
356         gl.glDrawArrays(GL_TRIANGLES, 0, GRID_SIZE * GRID_SIZE * 6);
357         GLU_EXPECT_NO_ERROR(gl.glGetError(), "draw");
358     }
359 
360     gl.glFinish();
361     gl.glBindVertexArray(0);
362     gl.glUseProgram(0);
363     GLU_EXPECT_NO_ERROR(gl.glGetError(), "clean");
364 
365     glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
366 }
367 
genTestSpec(int flags)368 SingleBindingCase::TestSpec SingleBindingCase::genTestSpec(int flags)
369 {
370     const int datumSize          = 4;
371     const int bufferOffset       = (flags & FLAG_BUF_ALIGNED_OFFSET)   ? (32) :
372                                    (flags & FLAG_BUF_UNALIGNED_OFFSET) ? (19) :
373                                                                          (0);
374     const int attrBufAlignment   = ((bufferOffset % datumSize) == 0) ? (0) : (datumSize - (bufferOffset % datumSize));
375     const int positionAttrOffset = (flags & FLAG_ATTRIB_UNALIGNED) ? (3) :
376                                    (flags & FLAG_ATTRIB_ALIGNED)   ? (attrBufAlignment) :
377                                                                      (0);
378     const bool hasColorAttr      = (flags & FLAG_ATTRIBS_SHARED_ELEMS) || (flags & FLAG_ATTRIBS_MULTIPLE_ELEMS);
379     const int colorAttrOffset    = (flags & FLAG_ATTRIBS_SHARED_ELEMS)   ? (2 * datumSize) :
380                                    (flags & FLAG_ATTRIBS_MULTIPLE_ELEMS) ? (4 * datumSize) :
381                                                                            (-1);
382 
383     const int bufferStrideBase = de::max(positionAttrOffset + 4 * datumSize, colorAttrOffset + 4 * datumSize);
384     const int bufferStrideAlignment =
385         ((bufferStrideBase % datumSize) == 0) ? (0) : (datumSize - (bufferStrideBase % datumSize));
386     const int bufferStridePadding =
387         ((flags & FLAG_BUF_UNALIGNED_STRIDE) && deIsAligned32(bufferStrideBase, datumSize)) ? (13) :
388         (!(flags & FLAG_BUF_UNALIGNED_STRIDE) && !deIsAligned32(bufferStrideBase, datumSize)) ?
389                                                                                               (bufferStrideAlignment) :
390                                                                                               (0);
391 
392     TestSpec spec;
393 
394     spec.bufferOffset       = bufferOffset;
395     spec.bufferStride       = bufferStrideBase + bufferStridePadding;
396     spec.positionAttrOffset = positionAttrOffset;
397     spec.colorAttrOffset    = colorAttrOffset;
398     spec.hasColorAttr       = hasColorAttr;
399 
400     if (flags & FLAG_ATTRIB_UNALIGNED)
401         DE_ASSERT(!deIsAligned32(spec.bufferOffset + spec.positionAttrOffset, datumSize));
402     else if (flags & FLAG_ATTRIB_ALIGNED)
403         DE_ASSERT(deIsAligned32(spec.bufferOffset + spec.positionAttrOffset, datumSize));
404 
405     if (flags & FLAG_BUF_UNALIGNED_STRIDE)
406         DE_ASSERT(!deIsAligned32(spec.bufferStride, datumSize));
407     else
408         DE_ASSERT(deIsAligned32(spec.bufferStride, datumSize));
409 
410     return spec;
411 }
412 
genTestDescription(int flags)413 std::string SingleBindingCase::genTestDescription(int flags)
414 {
415     std::ostringstream buf;
416     buf << "draw test pattern";
417 
418     if (flags & FLAG_ATTRIB_UNALIGNED)
419         buf << ", attribute offset (unaligned)";
420     if (flags & FLAG_ATTRIB_ALIGNED)
421         buf << ", attribute offset (aligned)";
422 
423     if (flags & FLAG_ATTRIBS_MULTIPLE_ELEMS)
424         buf << ", 2 attributes";
425     if (flags & FLAG_ATTRIBS_SHARED_ELEMS)
426         buf << ", 2 attributes (some components shared)";
427 
428     if (flags & FLAG_BUF_ALIGNED_OFFSET)
429         buf << ", buffer offset aligned";
430     if (flags & FLAG_BUF_UNALIGNED_OFFSET)
431         buf << ", buffer offset unaligned";
432     if (flags & FLAG_BUF_UNALIGNED_STRIDE)
433         buf << ", buffer stride unaligned";
434 
435     return buf.str();
436 }
437 
isDataUnaligned(int flags)438 bool SingleBindingCase::isDataUnaligned(int flags)
439 {
440     if (flags & FLAG_ATTRIB_UNALIGNED)
441         return true;
442     if (flags & FLAG_ATTRIB_ALIGNED)
443         return false;
444 
445     return (flags & FLAG_BUF_UNALIGNED_OFFSET) || (flags & FLAG_BUF_UNALIGNED_STRIDE);
446 }
447 
createBuffers(void)448 void SingleBindingCase::createBuffers(void)
449 {
450     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
451     std::vector<uint8_t> dataBuf(m_spec.bufferOffset + m_spec.bufferStride * GRID_SIZE * GRID_SIZE * 6);
452 
453     // In interleaved mode color rg and position zw are the same. Select "good" values for r and g
454     const tcu::Vec4 colorA(0.0f, 1.0f, 0.0f, 1.0f);
455     const tcu::Vec4 colorB(0.5f, 1.0f, 0.0f, 1.0f);
456 
457     for (int y = 0; y < GRID_SIZE; ++y)
458         for (int x = 0; x < GRID_SIZE; ++x)
459         {
460             const tcu::Vec4 &color       = ((x + y) % 2 == 0) ? (colorA) : (colorB);
461             const tcu::Vec4 positions[6] = {
462                 tcu::Vec4(float(x + 0) / float(GRID_SIZE) * 2.0f - 1.0f, float(y + 0) / float(GRID_SIZE) * 2.0f - 1.0f,
463                           0.0f, 1.0f),
464                 tcu::Vec4(float(x + 0) / float(GRID_SIZE) * 2.0f - 1.0f, float(y + 1) / float(GRID_SIZE) * 2.0f - 1.0f,
465                           0.0f, 1.0f),
466                 tcu::Vec4(float(x + 1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y + 1) / float(GRID_SIZE) * 2.0f - 1.0f,
467                           0.0f, 1.0f),
468                 tcu::Vec4(float(x + 0) / float(GRID_SIZE) * 2.0f - 1.0f, float(y + 0) / float(GRID_SIZE) * 2.0f - 1.0f,
469                           0.0f, 1.0f),
470                 tcu::Vec4(float(x + 1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y + 1) / float(GRID_SIZE) * 2.0f - 1.0f,
471                           0.0f, 1.0f),
472                 tcu::Vec4(float(x + 1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y + 0) / float(GRID_SIZE) * 2.0f - 1.0f,
473                           0.0f, 1.0f),
474             };
475 
476             // copy cell vertices to the buffer.
477             for (int v = 0; v < 6; ++v)
478                 memcpy(&dataBuf[m_spec.bufferOffset + m_spec.positionAttrOffset +
479                                 m_spec.bufferStride * ((y * GRID_SIZE + x) * 6 + v)],
480                        positions[v].getPtr(), sizeof(positions[v]));
481 
482             // copy color to buffer
483             if (m_spec.hasColorAttr)
484                 for (int v = 0; v < 6; ++v)
485                     memcpy(&dataBuf[m_spec.bufferOffset + m_spec.colorAttrOffset +
486                                     m_spec.bufferStride * ((y * GRID_SIZE + x) * 6 + v)],
487                            color.getPtr(), sizeof(color));
488         }
489 
490     gl.genBuffers(1, &m_buf);
491     gl.bindBuffer(GL_ARRAY_BUFFER, m_buf);
492     gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)dataBuf.size(), &dataBuf[0], GL_STATIC_DRAW);
493     gl.bindBuffer(GL_ARRAY_BUFFER, 0);
494 
495     if (gl.getError() != GL_NO_ERROR)
496         throw tcu::TestError("could not init buffer");
497 }
498 
createShader(void)499 void SingleBindingCase::createShader(void)
500 {
501     m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
502                                                                          << glu::VertexSource(genVertexSource())
503                                                                          << glu::FragmentSource(s_colorFragmentShader));
504     m_testCtx.getLog() << *m_program;
505 
506     if (!m_program->isOk())
507         throw tcu::TestError("could not build shader");
508 }
509 
genVertexSource(void)510 std::string SingleBindingCase::genVertexSource(void)
511 {
512     const bool useUniformColor = !m_spec.hasColorAttr;
513     std::ostringstream buf;
514 
515     buf << "#version 310 es\n"
516            "in highp vec4 a_position;\n";
517 
518     if (!useUniformColor)
519         buf << "in highp vec4 a_color;\n";
520     else
521         buf << "uniform highp vec4 u_color;\n";
522 
523     buf << "out highp vec4 v_color;\n"
524            "void main (void)\n"
525            "{\n"
526            "    gl_Position = a_position;\n"
527            "    v_color = "
528         << ((useUniformColor) ? ("u_color") : ("a_color"))
529         << ";\n"
530            "}\n";
531 
532     return buf.str();
533 }
534 
535 class BindVertexBufferCase : public TestCase
536 {
537 public:
538     BindVertexBufferCase(Context &ctx, const char *name, const char *desc, int offset, int drawCount);
539     ~BindVertexBufferCase(void);
540 
541     void init(void);
542     void deinit(void);
543     IterateResult iterate(void);
544 
545 private:
546     const int m_offset;
547     const int m_drawCount;
548     uint32_t m_buffer;
549     glu::ShaderProgram *m_program;
550 };
551 
BindVertexBufferCase(Context & ctx,const char * name,const char * desc,int offset,int drawCount)552 BindVertexBufferCase::BindVertexBufferCase(Context &ctx, const char *name, const char *desc, int offset, int drawCount)
553     : TestCase(ctx, name, desc)
554     , m_offset(offset)
555     , m_drawCount(drawCount)
556     , m_buffer(0)
557     , m_program(DE_NULL)
558 {
559 }
560 
~BindVertexBufferCase(void)561 BindVertexBufferCase::~BindVertexBufferCase(void)
562 {
563     deinit();
564 }
565 
init(void)566 void BindVertexBufferCase::init(void)
567 {
568     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
569     std::vector<tcu::Vec4> data(m_drawCount); // !< some junk data to make sure buffer is really allocated
570 
571     gl.genBuffers(1, &m_buffer);
572     gl.bindBuffer(GL_ARRAY_BUFFER, m_buffer);
573     gl.bufferData(GL_ARRAY_BUFFER, int(m_drawCount * sizeof(tcu::Vec4)), &data[0], GL_STATIC_DRAW);
574     GLU_EXPECT_NO_ERROR(gl.getError(), "buffer gen");
575 
576     m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
577                                                                          << glu::VertexSource(s_vertexSource)
578                                                                          << glu::FragmentSource(s_fragmentSource));
579     if (!m_program->isOk())
580     {
581         m_testCtx.getLog() << *m_program;
582         throw tcu::TestError("could not build program");
583     }
584 }
585 
deinit(void)586 void BindVertexBufferCase::deinit(void)
587 {
588     if (m_buffer)
589     {
590         m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_buffer);
591         m_buffer = 0;
592     }
593 
594     delete m_program;
595     m_program = DE_NULL;
596 }
597 
iterate(void)598 BindVertexBufferCase::IterateResult BindVertexBufferCase::iterate(void)
599 {
600     glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
601     const int32_t positionLoc = gl.glGetAttribLocation(m_program->getProgram(), "a_position");
602     tcu::Surface dst(m_context.getRenderTarget().getWidth(), m_context.getRenderTarget().getHeight());
603     glu::VertexArray vao(m_context.getRenderContext());
604 
605     gl.enableLogging(true);
606 
607     gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
608     gl.glClear(GL_COLOR_BUFFER_BIT);
609     GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup");
610 
611     gl.glUseProgram(m_program->getProgram());
612     GLU_EXPECT_NO_ERROR(gl.glGetError(), "use program");
613 
614     gl.glBindVertexArray(*vao);
615     gl.glEnableVertexAttribArray(positionLoc);
616     gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, 0);
617     gl.glVertexAttribBinding(positionLoc, 0);
618     gl.glBindVertexBuffer(0, m_buffer, m_offset, int(sizeof(tcu::Vec4)));
619     GLU_EXPECT_NO_ERROR(gl.glGetError(), "set buffer");
620 
621     gl.glDrawArrays(GL_POINTS, 0, m_drawCount);
622 
623     // allow errors after attempted out-of-bounds memory access
624     {
625         const uint32_t error = gl.glGetError();
626 
627         if (error != GL_NO_ERROR)
628             m_testCtx.getLog() << tcu::TestLog::Message << "Got error: " << glu::getErrorStr(error) << ", ignoring..."
629                                << tcu::TestLog::EndMessage;
630     }
631 
632     // read pixels to wait for rendering
633     gl.glFinish();
634     glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
635 
636     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
637     return STOP;
638 }
639 
640 } // namespace
641 
VertexAttributeBindingTests(Context & context)642 VertexAttributeBindingTests::VertexAttributeBindingTests(Context &context)
643     : TestCaseGroup(context, "vertex_attribute_binding", "Test vertex attribute binding stress tests")
644 {
645 }
646 
~VertexAttributeBindingTests(void)647 VertexAttributeBindingTests::~VertexAttributeBindingTests(void)
648 {
649 }
650 
init(void)651 void VertexAttributeBindingTests::init(void)
652 {
653     tcu::TestCaseGroup *const unalignedGroup = new tcu::TestCaseGroup(m_testCtx, "unaligned", "Unaligned access");
654     tcu::TestCaseGroup *const bufferRangeGroup =
655         new tcu::TestCaseGroup(m_testCtx, "buffer_bounds", "Source data over buffer bounds");
656 
657     addChild(unalignedGroup);
658     addChild(bufferRangeGroup);
659 
660     // .unaligned
661     {
662         unalignedGroup->addChild(
663             new SingleBindingCase(m_context, "elements_1_unaligned", SingleBindingCase::FLAG_ATTRIB_UNALIGNED));
664         unalignedGroup->addChild(new SingleBindingCase(m_context, "offset_elements_1_unaligned",
665                                                        SingleBindingCase::FLAG_BUF_ALIGNED_OFFSET |
666                                                            SingleBindingCase::FLAG_ATTRIB_UNALIGNED));
667 
668         unalignedGroup->addChild(new SingleBindingCase(m_context, "unaligned_offset_elements_1",
669                                                        SingleBindingCase::FLAG_BUF_UNALIGNED_OFFSET | 0));
670         unalignedGroup->addChild(new SingleBindingCase(m_context, "unaligned_offset_elements_1_unaligned",
671                                                        SingleBindingCase::FLAG_BUF_UNALIGNED_OFFSET |
672                                                            SingleBindingCase::FLAG_ATTRIB_UNALIGNED));
673         unalignedGroup->addChild(new SingleBindingCase(m_context, "unaligned_offset_elements_2",
674                                                        SingleBindingCase::FLAG_BUF_UNALIGNED_OFFSET |
675                                                            SingleBindingCase::FLAG_ATTRIBS_MULTIPLE_ELEMS));
676         unalignedGroup->addChild(new SingleBindingCase(m_context, "unaligned_offset_elements_2_share_elements",
677                                                        SingleBindingCase::FLAG_BUF_UNALIGNED_OFFSET |
678                                                            SingleBindingCase::FLAG_ATTRIBS_SHARED_ELEMS));
679 
680         unalignedGroup->addChild(new SingleBindingCase(m_context, "unaligned_stride_elements_1",
681                                                        SingleBindingCase::FLAG_BUF_UNALIGNED_STRIDE | 0));
682         unalignedGroup->addChild(new SingleBindingCase(m_context, "unaligned_stride_elements_2",
683                                                        SingleBindingCase::FLAG_BUF_UNALIGNED_STRIDE |
684                                                            SingleBindingCase::FLAG_ATTRIBS_MULTIPLE_ELEMS));
685         unalignedGroup->addChild(new SingleBindingCase(m_context, "unaligned_stride_elements_2_share_elements",
686                                                        SingleBindingCase::FLAG_BUF_UNALIGNED_STRIDE |
687                                                            SingleBindingCase::FLAG_ATTRIBS_SHARED_ELEMS));
688     }
689 
690     // .buffer_bounds
691     {
692         // bind buffer offset cases
693         bufferRangeGroup->addChild(new BindVertexBufferCase(m_context, "bind_vertex_buffer_offset_over_bounds_10",
694                                                             "Offset over buffer bounds", 0x00210000, 10));
695         bufferRangeGroup->addChild(new BindVertexBufferCase(m_context, "bind_vertex_buffer_offset_over_bounds_1000",
696                                                             "Offset over buffer bounds", 0x00210000, 1000));
697         bufferRangeGroup->addChild(new BindVertexBufferCase(m_context, "bind_vertex_buffer_offset_near_wrap_10",
698                                                             "Offset over buffer bounds, near wrapping", 0x7FFFFFF0,
699                                                             10));
700         bufferRangeGroup->addChild(new BindVertexBufferCase(m_context, "bind_vertex_buffer_offset_near_wrap_1000",
701                                                             "Offset over buffer bounds, near wrapping", 0x7FFFFFF0,
702                                                             1000));
703     }
704 }
705 
706 } // namespace Stress
707 } // namespace gles31
708 } // namespace deqp
709