xref: /aosp_15_r20/external/deqp/modules/gles31/functional/es31fVertexAttributeBindingTests.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 tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es31fVertexAttributeBindingTests.hpp"
25 #include "tcuRenderTarget.hpp"
26 #include "tcuSurface.hpp"
27 #include "gluCallLogWrapper.hpp"
28 #include "gluRenderContext.hpp"
29 #include "gluPixelTransfer.hpp"
30 #include "gluShaderProgram.hpp"
31 #include "gluObjectWrapper.hpp"
32 #include "gluStrUtil.hpp"
33 #include "glwFunctions.hpp"
34 #include "glwEnums.hpp"
35 #include "deStringUtil.hpp"
36 #include "deInt32.h"
37 
38 namespace deqp
39 {
40 namespace gles31
41 {
42 namespace Functional
43 {
44 namespace
45 {
46 
47 static const char *const s_colorFragmentShader = "#version 310 es\n"
48                                                  "in mediump vec4 v_color;\n"
49                                                  "layout(location = 0) out mediump vec4 fragColor;\n"
50                                                  "void main (void)\n"
51                                                  "{\n"
52                                                  "    fragColor = v_color;\n"
53                                                  "}\n";
54 
55 static const char *const s_positionColorShader = "#version 310 es\n"
56                                                  "in highp vec4 a_position;\n"
57                                                  "in highp vec4 a_color;\n"
58                                                  "out highp vec4 v_color;\n"
59                                                  "void main (void)\n"
60                                                  "{\n"
61                                                  "    gl_Position = a_position;\n"
62                                                  "    v_color = a_color;\n"
63                                                  "}\n";
64 
65 static const char *const s_positionColorOffsetShader = "#version 310 es\n"
66                                                        "in highp vec4 a_position;\n"
67                                                        "in highp vec4 a_offset;\n"
68                                                        "in highp vec4 a_color;\n"
69                                                        "out highp vec4 v_color;\n"
70                                                        "void main (void)\n"
71                                                        "{\n"
72                                                        "    gl_Position = a_position + a_offset;\n"
73                                                        "    v_color = a_color;\n"
74                                                        "}\n";
75 
76 // Verifies image contains only yellow or greeen, or a linear combination
77 // of these colors.
verifyImageYellowGreen(const tcu::Surface & image,tcu::TestLog & log,bool logImageOnSuccess)78 static bool verifyImageYellowGreen(const tcu::Surface &image, tcu::TestLog &log, bool logImageOnSuccess)
79 {
80     using tcu::TestLog;
81 
82     const int colorThreshold = 20;
83 
84     tcu::Surface error(image.getWidth(), image.getHeight());
85     bool isOk = true;
86 
87     log << TestLog::Message << "Verifying image contents." << TestLog::EndMessage;
88 
89     for (int y = 0; y < image.getHeight(); y++)
90         for (int x = 0; x < image.getWidth(); x++)
91         {
92             const tcu::RGBA pixel = image.getPixel(x, y);
93             bool pixelOk          = true;
94 
95             // Any pixel with !(G ~= 255) is faulty (not a linear combinations of green and yellow)
96             if (de::abs(pixel.getGreen() - 255) > colorThreshold)
97                 pixelOk = false;
98 
99             // Any pixel with !(B ~= 0) is faulty (not a linear combinations of green and yellow)
100             if (de::abs(pixel.getBlue() - 0) > colorThreshold)
101                 pixelOk = false;
102 
103             error.setPixel(x, y, (pixelOk) ? (tcu::RGBA(0, 255, 0, 255)) : (tcu::RGBA(255, 0, 0, 255)));
104             isOk = isOk && pixelOk;
105         }
106 
107     if (!isOk)
108     {
109         log << TestLog::Message << "Image verification failed." << TestLog::EndMessage;
110         log << TestLog::ImageSet("Verfication result", "Result of rendering")
111             << TestLog::Image("Result", "Result", image) << TestLog::Image("ErrorMask", "Error mask", error)
112             << TestLog::EndImageSet;
113     }
114     else
115     {
116         log << TestLog::Message << "Image verification passed." << TestLog::EndMessage;
117 
118         if (logImageOnSuccess)
119             log << TestLog::ImageSet("Verfication result", "Result of rendering")
120                 << TestLog::Image("Result", "Result", image) << TestLog::EndImageSet;
121     }
122 
123     return isOk;
124 }
125 
126 class BindingRenderCase : public TestCase
127 {
128 public:
129     enum
130     {
131         TEST_RENDER_SIZE = 64
132     };
133 
134     BindingRenderCase(Context &ctx, const char *name, const char *desc, bool unalignedData);
135     virtual ~BindingRenderCase(void);
136 
137     virtual void init(void);
138     virtual void deinit(void);
139     IterateResult iterate(void);
140 
141 private:
142     virtual void renderTo(tcu::Surface &dst) = 0;
143     virtual void createBuffers(void)         = 0;
144     virtual void createShader(void)          = 0;
145 
146 protected:
147     const bool m_unalignedData;
148     glw::GLuint m_vao;
149     glu::ShaderProgram *m_program;
150 };
151 
BindingRenderCase(Context & ctx,const char * name,const char * desc,bool unalignedData)152 BindingRenderCase::BindingRenderCase(Context &ctx, const char *name, const char *desc, bool unalignedData)
153     : TestCase(ctx, name, desc)
154     , m_unalignedData(unalignedData)
155     , m_vao(0)
156     , m_program(DE_NULL)
157 {
158 }
159 
~BindingRenderCase(void)160 BindingRenderCase::~BindingRenderCase(void)
161 {
162     deinit();
163 }
164 
init(void)165 void BindingRenderCase::init(void)
166 {
167     // check requirements
168     if (m_context.getRenderTarget().getWidth() < TEST_RENDER_SIZE ||
169         m_context.getRenderTarget().getHeight() < TEST_RENDER_SIZE)
170         throw tcu::NotSupportedError("Test requires at least " + de::toString<int>(TEST_RENDER_SIZE) + "x" +
171                                      de::toString<int>(TEST_RENDER_SIZE) + " render target");
172 
173     // resources
174     m_context.getRenderContext().getFunctions().genVertexArrays(1, &m_vao);
175     if (m_context.getRenderContext().getFunctions().getError() != GL_NO_ERROR)
176         throw tcu::TestError("could not gen vao");
177 
178     createBuffers();
179     createShader();
180 }
181 
deinit(void)182 void BindingRenderCase::deinit(void)
183 {
184     if (m_vao)
185     {
186         m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vao);
187         m_vao = 0;
188     }
189 
190     delete m_program;
191     m_program = DE_NULL;
192 }
193 
iterate(void)194 BindingRenderCase::IterateResult BindingRenderCase::iterate(void)
195 {
196     tcu::Surface surface(TEST_RENDER_SIZE, TEST_RENDER_SIZE);
197 
198     // draw pattern
199 
200     renderTo(surface);
201 
202     // verify results
203 
204     if (verifyImageYellowGreen(surface, m_testCtx.getLog(), false))
205         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
206     else if (m_unalignedData)
207         m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned data");
208     else
209         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
210 
211     return STOP;
212 }
213 
214 class SingleBindingCase : public BindingRenderCase
215 {
216 public:
217     enum CaseFlag
218     {
219         FLAG_ATTRIB_UNALIGNED = (1 << 0), // !< unalign attributes with relativeOffset
220         FLAG_ATTRIB_ALIGNED =
221             (1 << 1), // !< align attributes with relativeOffset to the buffer begin (and not buffer offset)
222         FLAG_ATTRIBS_MULTIPLE_ELEMS = (1 << 2), // !< use multiple attribute elements
223         FLAG_ATTRIBS_SHARED_ELEMS =
224             (1 << 3), // !< use multiple shared attribute elements. xyzw & rgba stored as (x, y, zr, wg, b, a)
225 
226         FLAG_BUF_ALIGNED_OFFSET   = (1 << 4), // !< use aligned offset to the buffer object
227         FLAG_BUF_UNALIGNED_OFFSET = (1 << 5), // !< use unaligned offset to the buffer object
228         FLAG_BUF_UNALIGNED_STRIDE = (1 << 6), // !< unalign buffer elements
229     };
230     SingleBindingCase(Context &ctx, const char *name, int flags);
231     ~SingleBindingCase(void);
232 
233     void init(void);
234     void deinit(void);
235 
236 private:
237     struct TestSpec
238     {
239         int bufferOffset;
240         int bufferStride;
241         int positionAttrOffset;
242         int colorAttrOffset;
243         bool hasColorAttr;
244     };
245 
246     enum
247     {
248         GRID_SIZE = 20
249     };
250 
251     void renderTo(tcu::Surface &dst);
252 
253     static TestSpec genTestSpec(int flags);
254     static std::string genTestDescription(int flags);
255     static bool isDataUnaligned(int flags);
256 
257     void createBuffers(void);
258     void createShader(void);
259     std::string genVertexSource(void);
260 
261     const TestSpec m_spec;
262     glw::GLuint m_buf;
263 };
264 
SingleBindingCase(Context & ctx,const char * name,int flags)265 SingleBindingCase::SingleBindingCase(Context &ctx, const char *name, int flags)
266     : BindingRenderCase(ctx, name, genTestDescription(flags).c_str(), isDataUnaligned(flags))
267     , m_spec(genTestSpec(flags))
268     , m_buf(0)
269 {
270     DE_ASSERT(!((flags & FLAG_ATTRIB_UNALIGNED) && (flags & FLAG_ATTRIB_ALIGNED)));
271     DE_ASSERT(!((flags & FLAG_ATTRIB_ALIGNED) && (flags & FLAG_BUF_UNALIGNED_STRIDE)));
272 
273     DE_ASSERT(!isDataUnaligned(flags));
274 }
275 
~SingleBindingCase(void)276 SingleBindingCase::~SingleBindingCase(void)
277 {
278     deinit();
279 }
280 
init(void)281 void SingleBindingCase::init(void)
282 {
283     // log what we are trying to do
284 
285     m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << (int)GRID_SIZE << "x" << (int)GRID_SIZE << " grid.\n"
286                        << "Buffer format:\n"
287                        << "    bufferOffset: " << m_spec.bufferOffset << "\n"
288                        << "    bufferStride: " << m_spec.bufferStride << "\n"
289                        << "Vertex position format:\n"
290                        << "    type: float4\n"
291                        << "    offset: " << m_spec.positionAttrOffset << "\n"
292                        << "    total offset: " << m_spec.bufferOffset + m_spec.positionAttrOffset << "\n"
293                        << tcu::TestLog::EndMessage;
294 
295     if (m_spec.hasColorAttr)
296         m_testCtx.getLog() << tcu::TestLog::Message << "Color:\n"
297                            << "    type: float4\n"
298                            << "    offset: " << m_spec.colorAttrOffset << "\n"
299                            << "    total offset: " << m_spec.bufferOffset + m_spec.colorAttrOffset << "\n"
300                            << tcu::TestLog::EndMessage;
301     // init
302 
303     BindingRenderCase::init();
304 }
305 
deinit(void)306 void SingleBindingCase::deinit(void)
307 {
308     if (m_buf)
309     {
310         m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_buf);
311         m_buf = 0;
312     }
313 
314     BindingRenderCase::deinit();
315 }
316 
renderTo(tcu::Surface & dst)317 void SingleBindingCase::renderTo(tcu::Surface &dst)
318 {
319     glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
320     const int positionLoc     = gl.glGetAttribLocation(m_program->getProgram(), "a_position");
321     const int colorLoc        = gl.glGetAttribLocation(m_program->getProgram(), "a_color");
322     const int colorUniformLoc = gl.glGetUniformLocation(m_program->getProgram(), "u_color");
323 
324     gl.enableLogging(true);
325 
326     gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
327     gl.glClear(GL_COLOR_BUFFER_BIT);
328     gl.glViewport(0, 0, dst.getWidth(), dst.getHeight());
329     gl.glBindVertexArray(m_vao);
330     GLU_EXPECT_NO_ERROR(gl.glGetError(), "set vao");
331 
332     gl.glUseProgram(m_program->getProgram());
333     GLU_EXPECT_NO_ERROR(gl.glGetError(), "use program");
334 
335     if (m_spec.hasColorAttr)
336     {
337         gl.glBindVertexBuffer(3, m_buf, m_spec.bufferOffset, m_spec.bufferStride);
338 
339         gl.glVertexAttribBinding(positionLoc, 3);
340         gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, m_spec.positionAttrOffset);
341         gl.glEnableVertexAttribArray(positionLoc);
342 
343         gl.glVertexAttribBinding(colorLoc, 3);
344         gl.glVertexAttribFormat(colorLoc, 4, GL_FLOAT, GL_FALSE, m_spec.colorAttrOffset);
345         gl.glEnableVertexAttribArray(colorLoc);
346 
347         GLU_EXPECT_NO_ERROR(gl.glGetError(), "set va");
348 
349         gl.glDrawArrays(GL_TRIANGLES, 0, GRID_SIZE * GRID_SIZE * 6);
350         GLU_EXPECT_NO_ERROR(gl.glGetError(), "draw");
351     }
352     else
353     {
354         gl.glBindVertexBuffer(3, m_buf, m_spec.bufferOffset, m_spec.bufferStride);
355         gl.glVertexAttribBinding(positionLoc, 3);
356         gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, m_spec.positionAttrOffset);
357         gl.glEnableVertexAttribArray(positionLoc);
358 
359         GLU_EXPECT_NO_ERROR(gl.glGetError(), "set va");
360         gl.glUniform4f(colorUniformLoc, 0.0f, 1.0f, 0.0f, 1.0f);
361 
362         gl.glDrawArrays(GL_TRIANGLES, 0, GRID_SIZE * GRID_SIZE * 6);
363         GLU_EXPECT_NO_ERROR(gl.glGetError(), "draw");
364     }
365 
366     gl.glFinish();
367     gl.glBindVertexArray(0);
368     gl.glUseProgram(0);
369     GLU_EXPECT_NO_ERROR(gl.glGetError(), "clean");
370 
371     glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
372 }
373 
genTestSpec(int flags)374 SingleBindingCase::TestSpec SingleBindingCase::genTestSpec(int flags)
375 {
376     const int datumSize          = 4;
377     const int bufferOffset       = (flags & FLAG_BUF_ALIGNED_OFFSET)   ? (32) :
378                                    (flags & FLAG_BUF_UNALIGNED_OFFSET) ? (19) :
379                                                                          (0);
380     const int attrBufAlignment   = ((bufferOffset % datumSize) == 0) ? (0) : (datumSize - (bufferOffset % datumSize));
381     const int positionAttrOffset = (flags & FLAG_ATTRIB_UNALIGNED) ? (3) :
382                                    (flags & FLAG_ATTRIB_ALIGNED)   ? (attrBufAlignment) :
383                                                                      (0);
384     const bool hasColorAttr      = (flags & FLAG_ATTRIBS_SHARED_ELEMS) || (flags & FLAG_ATTRIBS_MULTIPLE_ELEMS);
385     const int colorAttrOffset    = (flags & FLAG_ATTRIBS_SHARED_ELEMS)   ? (2 * datumSize) :
386                                    (flags & FLAG_ATTRIBS_MULTIPLE_ELEMS) ? (4 * datumSize) :
387                                                                            (-1);
388 
389     const int bufferStrideBase = de::max(positionAttrOffset + 4 * datumSize, colorAttrOffset + 4 * datumSize);
390     const int bufferStrideAlignment =
391         ((bufferStrideBase % datumSize) == 0) ? (0) : (datumSize - (bufferStrideBase % datumSize));
392     const int bufferStridePadding =
393         ((flags & FLAG_BUF_UNALIGNED_STRIDE) && deIsAligned32(bufferStrideBase, datumSize)) ? (13) :
394         (!(flags & FLAG_BUF_UNALIGNED_STRIDE) && !deIsAligned32(bufferStrideBase, datumSize)) ?
395                                                                                               (bufferStrideAlignment) :
396                                                                                               (0);
397 
398     TestSpec spec;
399 
400     spec.bufferOffset       = bufferOffset;
401     spec.bufferStride       = bufferStrideBase + bufferStridePadding;
402     spec.positionAttrOffset = positionAttrOffset;
403     spec.colorAttrOffset    = colorAttrOffset;
404     spec.hasColorAttr       = hasColorAttr;
405 
406     if (flags & FLAG_ATTRIB_UNALIGNED)
407         DE_ASSERT(!deIsAligned32(spec.bufferOffset + spec.positionAttrOffset, datumSize));
408     else if (flags & FLAG_ATTRIB_ALIGNED)
409         DE_ASSERT(deIsAligned32(spec.bufferOffset + spec.positionAttrOffset, datumSize));
410 
411     if (flags & FLAG_BUF_UNALIGNED_STRIDE)
412         DE_ASSERT(!deIsAligned32(spec.bufferStride, datumSize));
413     else
414         DE_ASSERT(deIsAligned32(spec.bufferStride, datumSize));
415 
416     return spec;
417 }
418 
genTestDescription(int flags)419 std::string SingleBindingCase::genTestDescription(int flags)
420 {
421     std::ostringstream buf;
422     buf << "draw test pattern";
423 
424     if (flags & FLAG_ATTRIB_UNALIGNED)
425         buf << ", attribute offset (unaligned)";
426     if (flags & FLAG_ATTRIB_ALIGNED)
427         buf << ", attribute offset (aligned)";
428 
429     if (flags & FLAG_ATTRIBS_MULTIPLE_ELEMS)
430         buf << ", 2 attributes";
431     if (flags & FLAG_ATTRIBS_SHARED_ELEMS)
432         buf << ", 2 attributes (some components shared)";
433 
434     if (flags & FLAG_BUF_ALIGNED_OFFSET)
435         buf << ", buffer offset aligned";
436     if (flags & FLAG_BUF_UNALIGNED_OFFSET)
437         buf << ", buffer offset unaligned";
438     if (flags & FLAG_BUF_UNALIGNED_STRIDE)
439         buf << ", buffer stride unaligned";
440 
441     return buf.str();
442 }
443 
isDataUnaligned(int flags)444 bool SingleBindingCase::isDataUnaligned(int flags)
445 {
446     if (flags & FLAG_ATTRIB_UNALIGNED)
447         return true;
448     if (flags & FLAG_ATTRIB_ALIGNED)
449         return false;
450 
451     return (flags & FLAG_BUF_UNALIGNED_OFFSET) || (flags & FLAG_BUF_UNALIGNED_STRIDE);
452 }
453 
createBuffers(void)454 void SingleBindingCase::createBuffers(void)
455 {
456     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
457     std::vector<uint8_t> dataBuf(m_spec.bufferOffset + m_spec.bufferStride * GRID_SIZE * GRID_SIZE * 6);
458 
459     // In interleaved mode color rg and position zw are the same. Select "good" values for r and g
460     const tcu::Vec4 colorA(0.0f, 1.0f, 0.0f, 1.0f);
461     const tcu::Vec4 colorB(0.5f, 1.0f, 0.0f, 1.0f);
462 
463     for (int y = 0; y < GRID_SIZE; ++y)
464         for (int x = 0; x < GRID_SIZE; ++x)
465         {
466             const tcu::Vec4 &color       = ((x + y) % 2 == 0) ? (colorA) : (colorB);
467             const tcu::Vec4 positions[6] = {
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 + 0) / 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 + 1) / float(GRID_SIZE) * 2.0f - 1.0f,
473                           0.0f, 1.0f),
474                 tcu::Vec4(float(x + 0) / float(GRID_SIZE) * 2.0f - 1.0f, float(y + 0) / float(GRID_SIZE) * 2.0f - 1.0f,
475                           0.0f, 1.0f),
476                 tcu::Vec4(float(x + 1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y + 1) / float(GRID_SIZE) * 2.0f - 1.0f,
477                           0.0f, 1.0f),
478                 tcu::Vec4(float(x + 1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y + 0) / float(GRID_SIZE) * 2.0f - 1.0f,
479                           0.0f, 1.0f),
480             };
481 
482             // copy cell vertices to the buffer.
483             for (int v = 0; v < 6; ++v)
484                 memcpy(&dataBuf[m_spec.bufferOffset + m_spec.positionAttrOffset +
485                                 m_spec.bufferStride * ((y * GRID_SIZE + x) * 6 + v)],
486                        positions[v].getPtr(), sizeof(positions[v]));
487 
488             // copy color to buffer
489             if (m_spec.hasColorAttr)
490                 for (int v = 0; v < 6; ++v)
491                     memcpy(&dataBuf[m_spec.bufferOffset + m_spec.colorAttrOffset +
492                                     m_spec.bufferStride * ((y * GRID_SIZE + x) * 6 + v)],
493                            color.getPtr(), sizeof(color));
494         }
495 
496     gl.genBuffers(1, &m_buf);
497     gl.bindBuffer(GL_ARRAY_BUFFER, m_buf);
498     gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)dataBuf.size(), &dataBuf[0], GL_STATIC_DRAW);
499     gl.bindBuffer(GL_ARRAY_BUFFER, 0);
500 
501     if (gl.getError() != GL_NO_ERROR)
502         throw tcu::TestError("could not init buffer");
503 }
504 
createShader(void)505 void SingleBindingCase::createShader(void)
506 {
507     m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
508                                                                          << glu::VertexSource(genVertexSource())
509                                                                          << glu::FragmentSource(s_colorFragmentShader));
510     m_testCtx.getLog() << *m_program;
511 
512     if (!m_program->isOk())
513         throw tcu::TestError("could not build shader");
514 }
515 
genVertexSource(void)516 std::string SingleBindingCase::genVertexSource(void)
517 {
518     const bool useUniformColor = !m_spec.hasColorAttr;
519     std::ostringstream buf;
520 
521     buf << "#version 310 es\n"
522            "in highp vec4 a_position;\n";
523 
524     if (!useUniformColor)
525         buf << "in highp vec4 a_color;\n";
526     else
527         buf << "uniform highp vec4 u_color;\n";
528 
529     buf << "out highp vec4 v_color;\n"
530            "void main (void)\n"
531            "{\n"
532            "    gl_Position = a_position;\n"
533            "    v_color = "
534         << ((useUniformColor) ? ("u_color") : ("a_color"))
535         << ";\n"
536            "}\n";
537 
538     return buf.str();
539 }
540 
541 class MultipleBindingCase : public BindingRenderCase
542 {
543 public:
544     enum CaseFlag
545     {
546         FLAG_ZERO_STRIDE      = (1 << 0), // !< set a buffer stride to zero
547         FLAG_INSTANCED        = (1 << 1), // !< set a buffer instance divisor to non-zero
548         FLAG_ALIASING_BUFFERS = (1 << 2), // !< bind buffer to multiple binding points
549     };
550 
551     MultipleBindingCase(Context &ctx, const char *name, int flags);
552     ~MultipleBindingCase(void);
553 
554     void init(void);
555     void deinit(void);
556 
557 private:
558     struct TestSpec
559     {
560         bool zeroStride;
561         bool instanced;
562         bool aliasingBuffers;
563     };
564 
565     enum
566     {
567         GRID_SIZE = 20
568     };
569 
570     void renderTo(tcu::Surface &dst);
571 
572     TestSpec genTestSpec(int flags) const;
573     std::string genTestDescription(int flags) const;
574     void createBuffers(void);
575     void createShader(void);
576 
577     const TestSpec m_spec;
578     glw::GLuint m_primitiveBuf;
579     glw::GLuint m_colorOffsetBuf;
580 };
581 
MultipleBindingCase(Context & ctx,const char * name,int flags)582 MultipleBindingCase::MultipleBindingCase(Context &ctx, const char *name, int flags)
583     : BindingRenderCase(ctx, name, genTestDescription(flags).c_str(), false)
584     , m_spec(genTestSpec(flags))
585     , m_primitiveBuf(0)
586     , m_colorOffsetBuf(0)
587 {
588     DE_ASSERT(!(m_spec.instanced && m_spec.zeroStride));
589 }
590 
~MultipleBindingCase(void)591 MultipleBindingCase::~MultipleBindingCase(void)
592 {
593     deinit();
594 }
595 
init(void)596 void MultipleBindingCase::init(void)
597 {
598     BindingRenderCase::init();
599 
600     // log what we are trying to do
601 
602     m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << (int)GRID_SIZE << "x" << (int)GRID_SIZE << " grid.\n"
603                        << "Vertex positions:\n"
604                        << "    binding point: 1\n"
605                        << "Vertex offsets:\n"
606                        << "    binding point: 2\n"
607                        << "Vertex colors:\n"
608                        << "    binding point: 2\n"
609                        << "Binding point 1:\n"
610                        << "    buffer object: " << m_primitiveBuf << "\n"
611                        << "Binding point 2:\n"
612                        << "    buffer object: " << ((m_spec.aliasingBuffers) ? (m_primitiveBuf) : (m_colorOffsetBuf))
613                        << "\n"
614                        << "    instance divisor: " << ((m_spec.instanced) ? (1) : (0)) << "\n"
615                        << "    stride: " << ((m_spec.zeroStride) ? (0) : (4 * 4 * 2)) << "\n"
616                        << tcu::TestLog::EndMessage;
617 }
618 
deinit(void)619 void MultipleBindingCase::deinit(void)
620 {
621     if (m_primitiveBuf)
622     {
623         m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_primitiveBuf);
624         m_primitiveBuf = DE_NULL;
625     }
626 
627     if (m_colorOffsetBuf)
628     {
629         m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_colorOffsetBuf);
630         m_colorOffsetBuf = DE_NULL;
631     }
632 
633     BindingRenderCase::deinit();
634 }
635 
renderTo(tcu::Surface & dst)636 void MultipleBindingCase::renderTo(tcu::Surface &dst)
637 {
638     glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
639     const int positionLoc = gl.glGetAttribLocation(m_program->getProgram(), "a_position");
640     const int colorLoc    = gl.glGetAttribLocation(m_program->getProgram(), "a_color");
641     const int offsetLoc   = gl.glGetAttribLocation(m_program->getProgram(), "a_offset");
642 
643     const int positionBinding    = 1;
644     const int colorOffsetBinding = 2;
645 
646     gl.enableLogging(true);
647 
648     gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
649     gl.glClear(GL_COLOR_BUFFER_BIT);
650     gl.glViewport(0, 0, dst.getWidth(), dst.getHeight());
651     gl.glBindVertexArray(m_vao);
652     GLU_EXPECT_NO_ERROR(gl.glGetError(), "set vao");
653 
654     gl.glUseProgram(m_program->getProgram());
655     GLU_EXPECT_NO_ERROR(gl.glGetError(), "use program");
656 
657     // Setup format & binding
658 
659     gl.glEnableVertexAttribArray(positionLoc);
660     gl.glEnableVertexAttribArray(colorLoc);
661     gl.glEnableVertexAttribArray(offsetLoc);
662 
663     gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, 0);
664     gl.glVertexAttribFormat(colorLoc, 4, GL_FLOAT, GL_FALSE, 0);
665     gl.glVertexAttribFormat(offsetLoc, 4, GL_FLOAT, GL_FALSE, sizeof(tcu::Vec4));
666 
667     gl.glVertexAttribBinding(positionLoc, positionBinding);
668     gl.glVertexAttribBinding(colorLoc, colorOffsetBinding);
669     gl.glVertexAttribBinding(offsetLoc, colorOffsetBinding);
670 
671     GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup attribs");
672 
673     // setup binding points
674 
675     gl.glVertexBindingDivisor(positionBinding, 0);
676     gl.glBindVertexBuffer(positionBinding, m_primitiveBuf, 0, sizeof(tcu::Vec4));
677 
678     {
679         const int stride         = (m_spec.zeroStride) ? (0) : (2 * (int)sizeof(tcu::Vec4));
680         const int offset         = (!m_spec.aliasingBuffers) ? (0) :
681                                    (m_spec.instanced)        ? (6 * (int)sizeof(tcu::Vec4)) :
682                                                                (6 * GRID_SIZE * GRID_SIZE * (int)sizeof(tcu::Vec4));
683         const glw::GLuint buffer = (m_spec.aliasingBuffers) ? (m_primitiveBuf) : (m_colorOffsetBuf);
684         const int divisor        = (m_spec.instanced) ? (1) : (0);
685 
686         gl.glVertexBindingDivisor(colorOffsetBinding, divisor);
687         gl.glBindVertexBuffer(colorOffsetBinding, buffer, offset, (glw::GLsizei)stride);
688     }
689 
690     GLU_EXPECT_NO_ERROR(gl.glGetError(), "set binding points");
691 
692     if (m_spec.instanced)
693         gl.glDrawArraysInstanced(GL_TRIANGLES, 0, 6, GRID_SIZE * GRID_SIZE);
694     else
695         gl.glDrawArrays(GL_TRIANGLES, 0, GRID_SIZE * GRID_SIZE * 6);
696     GLU_EXPECT_NO_ERROR(gl.glGetError(), "draw");
697 
698     gl.glFinish();
699     gl.glBindVertexArray(0);
700     gl.glUseProgram(0);
701     GLU_EXPECT_NO_ERROR(gl.glGetError(), "clean");
702 
703     glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
704 }
705 
genTestSpec(int flags) const706 MultipleBindingCase::TestSpec MultipleBindingCase::genTestSpec(int flags) const
707 {
708     MultipleBindingCase::TestSpec spec;
709 
710     spec.zeroStride      = !!(flags & FLAG_ZERO_STRIDE);
711     spec.instanced       = !!(flags & FLAG_INSTANCED);
712     spec.aliasingBuffers = !!(flags & FLAG_ALIASING_BUFFERS);
713 
714     return spec;
715 }
716 
genTestDescription(int flags) const717 std::string MultipleBindingCase::genTestDescription(int flags) const
718 {
719     std::ostringstream buf;
720     buf << "draw test pattern";
721 
722     if (flags & FLAG_ZERO_STRIDE)
723         buf << ", zero stride";
724     if (flags & FLAG_INSTANCED)
725         buf << ", instanced binding point";
726     if (flags & FLAG_ALIASING_BUFFERS)
727         buf << ", binding points share buffer object";
728 
729     return buf.str();
730 }
731 
createBuffers(void)732 void MultipleBindingCase::createBuffers(void)
733 {
734     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
735     const tcu::Vec4 green    = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
736     const tcu::Vec4 yellow   = tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
737 
738     const int vertexDataSize     = (m_spec.instanced) ? (6) : (6 * GRID_SIZE * GRID_SIZE);
739     const int offsetColorSize    = (m_spec.zeroStride) ? (2) :
740                                    (m_spec.instanced)  ? (2 * GRID_SIZE * GRID_SIZE) :
741                                                          (2 * 6 * GRID_SIZE * GRID_SIZE);
742     const int primitiveBufSize   = (m_spec.aliasingBuffers) ? (vertexDataSize + offsetColorSize) : (vertexDataSize);
743     const int colorOffsetBufSize = (m_spec.aliasingBuffers) ? (0) : (offsetColorSize);
744 
745     std::vector<tcu::Vec4> primitiveData(primitiveBufSize);
746     std::vector<tcu::Vec4> colorOffsetData(colorOffsetBufSize);
747     tcu::Vec4 *colorOffsetWritePtr = DE_NULL;
748 
749     if (m_spec.aliasingBuffers)
750     {
751         if (m_spec.instanced)
752             colorOffsetWritePtr = &primitiveData[6];
753         else
754             colorOffsetWritePtr = &primitiveData[GRID_SIZE * GRID_SIZE * 6];
755     }
756     else
757         colorOffsetWritePtr = &colorOffsetData[0];
758 
759     // write vertex position
760 
761     if (m_spec.instanced)
762     {
763         // store single basic primitive
764         primitiveData[0] = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
765         primitiveData[1] = tcu::Vec4(0.0f, 2.0f / float(GRID_SIZE), 0.0f, 1.0f);
766         primitiveData[2] = tcu::Vec4(2.0f / float(GRID_SIZE), 2.0f / float(GRID_SIZE), 0.0f, 1.0f);
767         primitiveData[3] = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
768         primitiveData[4] = tcu::Vec4(2.0f / float(GRID_SIZE), 2.0f / float(GRID_SIZE), 0.0f, 1.0f);
769         primitiveData[5] = tcu::Vec4(2.0f / float(GRID_SIZE), 0.0f, 0.0f, 1.0f);
770     }
771     else
772     {
773         // store whole grid
774         for (int y = 0; y < GRID_SIZE; ++y)
775             for (int x = 0; x < GRID_SIZE; ++x)
776             {
777                 primitiveData[(y * GRID_SIZE + x) * 6 + 0] =
778                     tcu::Vec4(float(x + 0) / float(GRID_SIZE) * 2.0f - 1.0f,
779                               float(y + 0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f);
780                 primitiveData[(y * GRID_SIZE + x) * 6 + 1] =
781                     tcu::Vec4(float(x + 0) / float(GRID_SIZE) * 2.0f - 1.0f,
782                               float(y + 1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f);
783                 primitiveData[(y * GRID_SIZE + x) * 6 + 2] =
784                     tcu::Vec4(float(x + 1) / float(GRID_SIZE) * 2.0f - 1.0f,
785                               float(y + 1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f);
786                 primitiveData[(y * GRID_SIZE + x) * 6 + 3] =
787                     tcu::Vec4(float(x + 0) / float(GRID_SIZE) * 2.0f - 1.0f,
788                               float(y + 0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f);
789                 primitiveData[(y * GRID_SIZE + x) * 6 + 4] =
790                     tcu::Vec4(float(x + 1) / float(GRID_SIZE) * 2.0f - 1.0f,
791                               float(y + 1) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f);
792                 primitiveData[(y * GRID_SIZE + x) * 6 + 5] =
793                     tcu::Vec4(float(x + 1) / float(GRID_SIZE) * 2.0f - 1.0f,
794                               float(y + 0) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 1.0f);
795             }
796     }
797 
798     // store color&offset
799 
800     if (m_spec.zeroStride)
801     {
802         colorOffsetWritePtr[0] = green;
803         colorOffsetWritePtr[1] = tcu::Vec4(0.0f);
804     }
805     else if (m_spec.instanced)
806     {
807         for (int y = 0; y < GRID_SIZE; ++y)
808             for (int x = 0; x < GRID_SIZE; ++x)
809             {
810                 const tcu::Vec4 &color = ((x + y) % 2 == 0) ? (green) : (yellow);
811 
812                 colorOffsetWritePtr[(y * GRID_SIZE + x) * 2 + 0] = color;
813                 colorOffsetWritePtr[(y * GRID_SIZE + x) * 2 + 1] = tcu::Vec4(
814                     float(x) / float(GRID_SIZE) * 2.0f - 1.0f, float(y) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 0.0f);
815             }
816     }
817     else
818     {
819         for (int y = 0; y < GRID_SIZE; ++y)
820             for (int x = 0; x < GRID_SIZE; ++x)
821                 for (int v = 0; v < 6; ++v)
822                 {
823                     const tcu::Vec4 &color = ((x + y) % 2 == 0) ? (green) : (yellow);
824 
825                     colorOffsetWritePtr[((y * GRID_SIZE + x) * 6 + v) * 2 + 0] = color;
826                     colorOffsetWritePtr[((y * GRID_SIZE + x) * 6 + v) * 2 + 1] = tcu::Vec4(0.0f);
827                 }
828     }
829 
830     // upload vertex data
831 
832     gl.genBuffers(1, &m_primitiveBuf);
833     gl.bindBuffer(GL_ARRAY_BUFFER, m_primitiveBuf);
834     gl.bufferData(GL_ARRAY_BUFFER, (int)(primitiveData.size() * sizeof(tcu::Vec4)), primitiveData[0].getPtr(),
835                   GL_STATIC_DRAW);
836     GLU_EXPECT_NO_ERROR(gl.getError(), "upload data");
837 
838     if (!m_spec.aliasingBuffers)
839     {
840         // upload color & offset data
841 
842         gl.genBuffers(1, &m_colorOffsetBuf);
843         gl.bindBuffer(GL_ARRAY_BUFFER, m_colorOffsetBuf);
844         gl.bufferData(GL_ARRAY_BUFFER, (int)(colorOffsetData.size() * sizeof(tcu::Vec4)), colorOffsetData[0].getPtr(),
845                       GL_STATIC_DRAW);
846         GLU_EXPECT_NO_ERROR(gl.getError(), "upload colordata");
847     }
848 }
849 
createShader(void)850 void MultipleBindingCase::createShader(void)
851 {
852     m_program = new glu::ShaderProgram(m_context.getRenderContext(),
853                                        glu::ProgramSources() << glu::VertexSource(s_positionColorOffsetShader)
854                                                              << glu::FragmentSource(s_colorFragmentShader));
855     m_testCtx.getLog() << *m_program;
856 
857     if (!m_program->isOk())
858         throw tcu::TestError("could not build shader");
859 }
860 
861 class MixedBindingCase : public BindingRenderCase
862 {
863 public:
864     enum CaseType
865     {
866         CASE_BASIC = 0,
867         CASE_INSTANCED_BINDING,
868         CASE_INSTANCED_ATTRIB,
869 
870         CASE_LAST
871     };
872 
873     MixedBindingCase(Context &ctx, const char *name, const char *desc, CaseType caseType);
874     ~MixedBindingCase(void);
875 
876     void init(void);
877     void deinit(void);
878 
879 private:
880     enum
881     {
882         GRID_SIZE = 20
883     };
884 
885     void renderTo(tcu::Surface &dst);
886     void createBuffers(void);
887     void createShader(void);
888 
889     const CaseType m_case;
890     glw::GLuint m_posBuffer;
891     glw::GLuint m_colorOffsetBuffer;
892 };
893 
MixedBindingCase(Context & ctx,const char * name,const char * desc,CaseType caseType)894 MixedBindingCase::MixedBindingCase(Context &ctx, const char *name, const char *desc, CaseType caseType)
895     : BindingRenderCase(ctx, name, desc, false)
896     , m_case(caseType)
897     , m_posBuffer(0)
898     , m_colorOffsetBuffer(0)
899 {
900     DE_ASSERT(caseType < CASE_LAST);
901 }
902 
~MixedBindingCase(void)903 MixedBindingCase::~MixedBindingCase(void)
904 {
905     deinit();
906 }
907 
init(void)908 void MixedBindingCase::init(void)
909 {
910     BindingRenderCase::init();
911 }
912 
deinit(void)913 void MixedBindingCase::deinit(void)
914 {
915     if (m_posBuffer)
916     {
917         m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_posBuffer);
918         m_posBuffer = DE_NULL;
919     }
920 
921     if (m_colorOffsetBuffer)
922     {
923         m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_colorOffsetBuffer);
924         m_colorOffsetBuffer = DE_NULL;
925     }
926 
927     BindingRenderCase::deinit();
928 }
929 
renderTo(tcu::Surface & dst)930 void MixedBindingCase::renderTo(tcu::Surface &dst)
931 {
932     glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
933     const int positionLoc = gl.glGetAttribLocation(m_program->getProgram(), "a_position");
934     const int colorLoc    = gl.glGetAttribLocation(m_program->getProgram(), "a_color");
935     const int offsetLoc   = gl.glGetAttribLocation(m_program->getProgram(), "a_offset");
936 
937     gl.enableLogging(true);
938 
939     gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
940     gl.glClear(GL_COLOR_BUFFER_BIT);
941     gl.glViewport(0, 0, dst.getWidth(), dst.getHeight());
942     gl.glBindVertexArray(m_vao);
943     GLU_EXPECT_NO_ERROR(gl.glGetError(), "set vao");
944 
945     gl.glUseProgram(m_program->getProgram());
946     GLU_EXPECT_NO_ERROR(gl.glGetError(), "use program");
947 
948     switch (m_case)
949     {
950     case CASE_BASIC:
951     {
952         // bind position using vertex_attrib_binding api
953 
954         gl.glBindVertexBuffer(positionLoc, m_posBuffer, 0, (glw::GLsizei)sizeof(tcu::Vec4));
955         gl.glVertexAttribBinding(positionLoc, positionLoc);
956         gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, 0);
957         GLU_EXPECT_NO_ERROR(gl.glGetError(), "set binding");
958 
959         // bind color using old api
960 
961         gl.glBindBuffer(GL_ARRAY_BUFFER, m_colorOffsetBuffer);
962         gl.glVertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, glw::GLsizei(2 * sizeof(tcu::Vec4)), DE_NULL);
963         gl.glVertexAttribPointer(offsetLoc, 4, GL_FLOAT, GL_FALSE, glw::GLsizei(2 * sizeof(tcu::Vec4)),
964                                  glu::BufferOffsetAsPointer(sizeof(tcu::Vec4)));
965         GLU_EXPECT_NO_ERROR(gl.glGetError(), "set va");
966 
967         // draw
968         gl.glEnableVertexAttribArray(positionLoc);
969         gl.glEnableVertexAttribArray(colorLoc);
970         gl.glEnableVertexAttribArray(offsetLoc);
971         gl.glDrawArrays(GL_TRIANGLES, 0, 6 * GRID_SIZE * GRID_SIZE);
972         break;
973     }
974 
975     case CASE_INSTANCED_BINDING:
976     {
977         // bind position using old api
978         gl.glBindBuffer(GL_ARRAY_BUFFER, m_posBuffer);
979         gl.glVertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
980         GLU_EXPECT_NO_ERROR(gl.glGetError(), "set va");
981 
982         // bind color using vertex_attrib_binding api
983         gl.glBindVertexBuffer(colorLoc, m_colorOffsetBuffer, 0, (glw::GLsizei)(2 * sizeof(tcu::Vec4)));
984         gl.glVertexBindingDivisor(colorLoc, 1);
985 
986         gl.glVertexAttribBinding(colorLoc, colorLoc);
987         gl.glVertexAttribBinding(offsetLoc, colorLoc);
988 
989         gl.glVertexAttribFormat(colorLoc, 4, GL_FLOAT, GL_FALSE, 0);
990         gl.glVertexAttribFormat(offsetLoc, 4, GL_FLOAT, GL_FALSE, sizeof(tcu::Vec4));
991 
992         GLU_EXPECT_NO_ERROR(gl.glGetError(), "set binding");
993 
994         // draw
995         gl.glEnableVertexAttribArray(positionLoc);
996         gl.glEnableVertexAttribArray(colorLoc);
997         gl.glEnableVertexAttribArray(offsetLoc);
998         gl.glDrawArraysInstanced(GL_TRIANGLES, 0, 6, GRID_SIZE * GRID_SIZE);
999         break;
1000     }
1001 
1002     case CASE_INSTANCED_ATTRIB:
1003     {
1004         // bind position using vertex_attrib_binding api
1005         gl.glBindVertexBuffer(positionLoc, m_posBuffer, 0, (glw::GLsizei)sizeof(tcu::Vec4));
1006         gl.glVertexAttribBinding(positionLoc, positionLoc);
1007         gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, 0);
1008         GLU_EXPECT_NO_ERROR(gl.glGetError(), "set binding");
1009 
1010         // bind color using old api
1011         gl.glBindBuffer(GL_ARRAY_BUFFER, m_colorOffsetBuffer);
1012         gl.glVertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, glw::GLsizei(2 * sizeof(tcu::Vec4)), DE_NULL);
1013         gl.glVertexAttribPointer(offsetLoc, 4, GL_FLOAT, GL_FALSE, glw::GLsizei(2 * sizeof(tcu::Vec4)),
1014                                  glu::BufferOffsetAsPointer(sizeof(tcu::Vec4)));
1015         gl.glVertexAttribDivisor(colorLoc, 1);
1016         gl.glVertexAttribDivisor(offsetLoc, 1);
1017         GLU_EXPECT_NO_ERROR(gl.glGetError(), "set va");
1018 
1019         // draw
1020         gl.glEnableVertexAttribArray(positionLoc);
1021         gl.glEnableVertexAttribArray(colorLoc);
1022         gl.glEnableVertexAttribArray(offsetLoc);
1023         gl.glDrawArraysInstanced(GL_TRIANGLES, 0, 6, GRID_SIZE * GRID_SIZE);
1024         break;
1025     }
1026 
1027     default:
1028         DE_ASSERT(false);
1029     }
1030 
1031     gl.glFinish();
1032     gl.glBindVertexArray(0);
1033     gl.glUseProgram(0);
1034     GLU_EXPECT_NO_ERROR(gl.glGetError(), "clean");
1035 
1036     glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
1037 }
1038 
createBuffers(void)1039 void MixedBindingCase::createBuffers(void)
1040 {
1041     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1042     const tcu::Vec4 green    = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
1043     const tcu::Vec4 yellow   = tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
1044 
1045     // draw grid. In instanced mode, each cell is an instance
1046     const bool instanced                 = (m_case == CASE_INSTANCED_BINDING) || (m_case == CASE_INSTANCED_ATTRIB);
1047     const int numCells                   = GRID_SIZE * GRID_SIZE;
1048     const int numPositionCells           = (instanced) ? (1) : (numCells);
1049     const int numPositionElements        = 6 * numPositionCells;
1050     const int numInstanceElementsPerCell = (instanced) ? (1) : (6);
1051     const int numColorOffsetElements     = numInstanceElementsPerCell * numCells;
1052 
1053     std::vector<tcu::Vec4> positionData(numPositionElements);
1054     std::vector<tcu::Vec4> colorOffsetData(2 * numColorOffsetElements);
1055 
1056     // positions
1057 
1058     for (int primNdx = 0; primNdx < numPositionCells; ++primNdx)
1059     {
1060         positionData[primNdx * 6 + 0] = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
1061         positionData[primNdx * 6 + 1] = tcu::Vec4(0.0f, 2.0f / float(GRID_SIZE), 0.0f, 1.0f);
1062         positionData[primNdx * 6 + 2] = tcu::Vec4(2.0f / float(GRID_SIZE), 2.0f / float(GRID_SIZE), 0.0f, 1.0f);
1063         positionData[primNdx * 6 + 3] = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
1064         positionData[primNdx * 6 + 4] = tcu::Vec4(2.0f / float(GRID_SIZE), 2.0f / float(GRID_SIZE), 0.0f, 1.0f);
1065         positionData[primNdx * 6 + 5] = tcu::Vec4(2.0f / float(GRID_SIZE), 0.0f, 0.0f, 1.0f);
1066     }
1067 
1068     // color & offset
1069 
1070     for (int y = 0; y < GRID_SIZE; ++y)
1071         for (int x = 0; x < GRID_SIZE; ++x)
1072         {
1073             for (int v = 0; v < numInstanceElementsPerCell; ++v)
1074             {
1075                 const tcu::Vec4 &color = ((x + y) % 2 == 0) ? (green) : (yellow);
1076 
1077                 colorOffsetData[((y * GRID_SIZE + x) * numInstanceElementsPerCell + v) * 2 + 0] = color;
1078                 colorOffsetData[((y * GRID_SIZE + x) * numInstanceElementsPerCell + v) * 2 + 1] = tcu::Vec4(
1079                     float(x) / float(GRID_SIZE) * 2.0f - 1.0f, float(y) / float(GRID_SIZE) * 2.0f - 1.0f, 0.0f, 0.0f);
1080             }
1081         }
1082 
1083     // upload vertex data
1084 
1085     gl.genBuffers(1, &m_posBuffer);
1086     gl.bindBuffer(GL_ARRAY_BUFFER, m_posBuffer);
1087     gl.bufferData(GL_ARRAY_BUFFER, (int)(positionData.size() * sizeof(tcu::Vec4)), positionData[0].getPtr(),
1088                   GL_STATIC_DRAW);
1089     GLU_EXPECT_NO_ERROR(gl.getError(), "upload position data");
1090 
1091     gl.genBuffers(1, &m_colorOffsetBuffer);
1092     gl.bindBuffer(GL_ARRAY_BUFFER, m_colorOffsetBuffer);
1093     gl.bufferData(GL_ARRAY_BUFFER, (int)(colorOffsetData.size() * sizeof(tcu::Vec4)), colorOffsetData[0].getPtr(),
1094                   GL_STATIC_DRAW);
1095     GLU_EXPECT_NO_ERROR(gl.getError(), "upload position data");
1096 }
1097 
createShader(void)1098 void MixedBindingCase::createShader(void)
1099 {
1100     m_program = new glu::ShaderProgram(m_context.getRenderContext(),
1101                                        glu::ProgramSources() << glu::VertexSource(s_positionColorOffsetShader)
1102                                                              << glu::FragmentSource(s_colorFragmentShader));
1103     m_testCtx.getLog() << *m_program;
1104 
1105     if (!m_program->isOk())
1106         throw tcu::TestError("could not build shader");
1107 }
1108 
1109 class MixedApiCase : public BindingRenderCase
1110 {
1111 public:
1112     enum CaseType
1113     {
1114         CASE_CHANGE_BUFFER = 0,
1115         CASE_CHANGE_BUFFER_OFFSET,
1116         CASE_CHANGE_BUFFER_STRIDE,
1117         CASE_CHANGE_BINDING_POINT,
1118 
1119         CASE_LAST
1120     };
1121 
1122     MixedApiCase(Context &ctx, const char *name, const char *desc, CaseType caseType);
1123     ~MixedApiCase(void);
1124 
1125     void init(void);
1126     void deinit(void);
1127 
1128 private:
1129     enum
1130     {
1131         GRID_SIZE = 20
1132     };
1133 
1134     void renderTo(tcu::Surface &dst);
1135     void createBuffers(void);
1136     void createShader(void);
1137 
1138     const CaseType m_case;
1139     glw::GLuint m_buffer;
1140 };
1141 
MixedApiCase(Context & ctx,const char * name,const char * desc,CaseType caseType)1142 MixedApiCase::MixedApiCase(Context &ctx, const char *name, const char *desc, CaseType caseType)
1143     : BindingRenderCase(ctx, name, desc, false)
1144     , m_case(caseType)
1145     , m_buffer(0)
1146 {
1147     DE_ASSERT(caseType < CASE_LAST);
1148 }
1149 
~MixedApiCase(void)1150 MixedApiCase::~MixedApiCase(void)
1151 {
1152     deinit();
1153 }
1154 
init(void)1155 void MixedApiCase::init(void)
1156 {
1157     BindingRenderCase::init();
1158 }
1159 
deinit(void)1160 void MixedApiCase::deinit(void)
1161 {
1162     if (m_buffer)
1163     {
1164         m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_buffer);
1165         m_buffer = DE_NULL;
1166     }
1167 
1168     BindingRenderCase::deinit();
1169 }
1170 
renderTo(tcu::Surface & dst)1171 void MixedApiCase::renderTo(tcu::Surface &dst)
1172 {
1173     glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
1174     const int positionLoc = gl.glGetAttribLocation(m_program->getProgram(), "a_position");
1175     const int colorLoc    = gl.glGetAttribLocation(m_program->getProgram(), "a_color");
1176     glu::Buffer unusedBuffer(m_context.getRenderContext());
1177 
1178     gl.enableLogging(true);
1179 
1180     gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1181     gl.glClear(GL_COLOR_BUFFER_BIT);
1182     gl.glViewport(0, 0, dst.getWidth(), dst.getHeight());
1183     gl.glBindVertexArray(m_vao);
1184     GLU_EXPECT_NO_ERROR(gl.glGetError(), "set vao");
1185 
1186     gl.glUseProgram(m_program->getProgram());
1187     GLU_EXPECT_NO_ERROR(gl.glGetError(), "use program");
1188 
1189     switch (m_case)
1190     {
1191     case CASE_CHANGE_BUFFER:
1192     {
1193         // bind data using old api
1194 
1195         gl.glBindBuffer(GL_ARRAY_BUFFER, *unusedBuffer);
1196         gl.glVertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(2 * sizeof(tcu::Vec4)),
1197                                  (const uint8_t *)DE_NULL);
1198         gl.glVertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(2 * sizeof(tcu::Vec4)),
1199                                  glu::BufferOffsetAsPointer(sizeof(tcu::Vec4)));
1200 
1201         // change buffer with vertex_attrib_binding
1202 
1203         gl.glBindVertexBuffer(positionLoc, m_buffer, 0, (glw::GLsizei)(2 * sizeof(tcu::Vec4)));
1204         gl.glBindVertexBuffer(colorLoc, m_buffer, sizeof(tcu::Vec4), (glw::GLsizei)(2 * sizeof(tcu::Vec4)));
1205 
1206         GLU_EXPECT_NO_ERROR(gl.glGetError(), "");
1207         break;
1208     }
1209 
1210     case CASE_CHANGE_BUFFER_OFFSET:
1211     {
1212         // bind data using old api
1213 
1214         gl.glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
1215         gl.glVertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(2 * sizeof(tcu::Vec4)),
1216                                  (const uint8_t *)DE_NULL);
1217         gl.glVertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(2 * sizeof(tcu::Vec4)),
1218                                  (const uint8_t *)DE_NULL);
1219 
1220         // change buffer offset with vertex_attrib_binding
1221 
1222         gl.glBindVertexBuffer(positionLoc, m_buffer, 0, (glw::GLsizei)(2 * sizeof(tcu::Vec4)));
1223         gl.glBindVertexBuffer(colorLoc, m_buffer, sizeof(tcu::Vec4), (glw::GLsizei)(2 * sizeof(tcu::Vec4)));
1224 
1225         GLU_EXPECT_NO_ERROR(gl.glGetError(), "");
1226         break;
1227     }
1228 
1229     case CASE_CHANGE_BUFFER_STRIDE:
1230     {
1231         // bind data using old api
1232 
1233         gl.glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
1234         gl.glVertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 8, (const uint8_t *)DE_NULL);
1235         gl.glVertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, 4, (const uint8_t *)DE_NULL);
1236 
1237         // change buffer stride with vertex_attrib_binding
1238 
1239         gl.glBindVertexBuffer(positionLoc, m_buffer, 0, (glw::GLsizei)(2 * sizeof(tcu::Vec4)));
1240         gl.glBindVertexBuffer(colorLoc, m_buffer, sizeof(tcu::Vec4), (glw::GLsizei)(2 * sizeof(tcu::Vec4)));
1241 
1242         GLU_EXPECT_NO_ERROR(gl.glGetError(), "");
1243         break;
1244     }
1245 
1246     case CASE_CHANGE_BINDING_POINT:
1247     {
1248         const int maxUsedLocation = de::max(positionLoc, colorLoc);
1249         const int bindingPoint1   = maxUsedLocation + 1;
1250         const int bindingPoint2   = maxUsedLocation + 2;
1251 
1252         // bind data using old api
1253 
1254         gl.glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
1255         gl.glVertexAttribPointer(bindingPoint1, 4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(2 * sizeof(tcu::Vec4)),
1256                                  (const uint8_t *)DE_NULL);
1257         gl.glVertexAttribPointer(bindingPoint2, 4, GL_FLOAT, GL_FALSE, (glw::GLsizei)(2 * sizeof(tcu::Vec4)),
1258                                  glu::BufferOffsetAsPointer(sizeof(tcu::Vec4)));
1259 
1260         // change buffer binding point with vertex_attrib_binding
1261 
1262         gl.glVertexAttribFormat(positionLoc, 4, GL_FLOAT, GL_FALSE, 0);
1263         gl.glVertexAttribFormat(colorLoc, 4, GL_FLOAT, GL_FALSE, 0);
1264 
1265         gl.glVertexAttribBinding(positionLoc, bindingPoint1);
1266         gl.glVertexAttribBinding(colorLoc, bindingPoint2);
1267 
1268         GLU_EXPECT_NO_ERROR(gl.glGetError(), "");
1269         break;
1270     }
1271 
1272     default:
1273         DE_ASSERT(false);
1274     }
1275 
1276     // draw
1277     gl.glEnableVertexAttribArray(positionLoc);
1278     gl.glEnableVertexAttribArray(colorLoc);
1279     gl.glDrawArrays(GL_TRIANGLES, 0, 6 * GRID_SIZE * GRID_SIZE);
1280 
1281     gl.glFinish();
1282     gl.glBindVertexArray(0);
1283     gl.glUseProgram(0);
1284     GLU_EXPECT_NO_ERROR(gl.glGetError(), "clean");
1285 
1286     glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
1287 }
1288 
createBuffers(void)1289 void MixedApiCase::createBuffers(void)
1290 {
1291     const tcu::Vec4 green  = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
1292     const tcu::Vec4 yellow = tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
1293 
1294     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1295     std::vector<tcu::Vec4> vertexData(12 * GRID_SIZE * GRID_SIZE);
1296 
1297     for (int y = 0; y < GRID_SIZE; ++y)
1298         for (int x = 0; x < GRID_SIZE; ++x)
1299         {
1300             const tcu::Vec4 &color = ((x + y) % 2 == 0) ? (green) : (yellow);
1301 
1302             vertexData[(y * GRID_SIZE + x) * 12 + 0] =
1303                 tcu::Vec4(float(x + 0) / float(GRID_SIZE) * 2.0f - 1.0f, float(y + 0) / float(GRID_SIZE) * 2.0f - 1.0f,
1304                           0.0f, 1.0f);
1305             vertexData[(y * GRID_SIZE + x) * 12 + 1] = color;
1306             vertexData[(y * GRID_SIZE + x) * 12 + 2] =
1307                 tcu::Vec4(float(x + 0) / float(GRID_SIZE) * 2.0f - 1.0f, float(y + 1) / float(GRID_SIZE) * 2.0f - 1.0f,
1308                           0.0f, 1.0f);
1309             vertexData[(y * GRID_SIZE + x) * 12 + 3] = color;
1310             vertexData[(y * GRID_SIZE + x) * 12 + 4] =
1311                 tcu::Vec4(float(x + 1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y + 1) / float(GRID_SIZE) * 2.0f - 1.0f,
1312                           0.0f, 1.0f);
1313             vertexData[(y * GRID_SIZE + x) * 12 + 5] = color;
1314             vertexData[(y * GRID_SIZE + x) * 12 + 6] =
1315                 tcu::Vec4(float(x + 0) / float(GRID_SIZE) * 2.0f - 1.0f, float(y + 0) / float(GRID_SIZE) * 2.0f - 1.0f,
1316                           0.0f, 1.0f);
1317             vertexData[(y * GRID_SIZE + x) * 12 + 7] = color;
1318             vertexData[(y * GRID_SIZE + x) * 12 + 8] =
1319                 tcu::Vec4(float(x + 1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y + 1) / float(GRID_SIZE) * 2.0f - 1.0f,
1320                           0.0f, 1.0f);
1321             vertexData[(y * GRID_SIZE + x) * 12 + 9] = color;
1322             vertexData[(y * GRID_SIZE + x) * 12 + 10] =
1323                 tcu::Vec4(float(x + 1) / float(GRID_SIZE) * 2.0f - 1.0f, float(y + 0) / float(GRID_SIZE) * 2.0f - 1.0f,
1324                           0.0f, 1.0f);
1325             vertexData[(y * GRID_SIZE + x) * 12 + 11] = color;
1326         }
1327 
1328     // upload vertex data
1329 
1330     gl.genBuffers(1, &m_buffer);
1331     gl.bindBuffer(GL_ARRAY_BUFFER, m_buffer);
1332     gl.bufferData(GL_ARRAY_BUFFER, (int)(vertexData.size() * sizeof(tcu::Vec4)), vertexData[0].getPtr(),
1333                   GL_STATIC_DRAW);
1334     GLU_EXPECT_NO_ERROR(gl.getError(), "upload data");
1335 }
1336 
createShader(void)1337 void MixedApiCase::createShader(void)
1338 {
1339     m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
1340                                                                          << glu::VertexSource(s_positionColorShader)
1341                                                                          << glu::FragmentSource(s_colorFragmentShader));
1342     m_testCtx.getLog() << *m_program;
1343 
1344     if (!m_program->isOk())
1345         throw tcu::TestError("could not build shader");
1346 }
1347 
1348 class DefaultVAOCase : public TestCase
1349 {
1350 public:
1351     enum CaseType
1352     {
1353         CASE_BIND_VERTEX_BUFFER,
1354         CASE_VERTEX_ATTRIB_FORMAT,
1355         CASE_VERTEX_ATTRIB_I_FORMAT,
1356         CASE_VERTEX_ATTRIB_BINDING,
1357         CASE_VERTEX_BINDING_DIVISOR,
1358 
1359         CASE_LAST
1360     };
1361 
1362     DefaultVAOCase(Context &ctx, const char *name, const char *desc, CaseType caseType);
1363     ~DefaultVAOCase(void);
1364 
1365     IterateResult iterate(void);
1366 
1367 private:
1368     const CaseType m_caseType;
1369 };
1370 
DefaultVAOCase(Context & ctx,const char * name,const char * desc,CaseType caseType)1371 DefaultVAOCase::DefaultVAOCase(Context &ctx, const char *name, const char *desc, CaseType caseType)
1372     : TestCase(ctx, name, desc)
1373     , m_caseType(caseType)
1374 {
1375     DE_ASSERT(caseType < CASE_LAST);
1376 }
1377 
~DefaultVAOCase(void)1378 DefaultVAOCase::~DefaultVAOCase(void)
1379 {
1380 }
1381 
iterate(void)1382 DefaultVAOCase::IterateResult DefaultVAOCase::iterate(void)
1383 {
1384     glw::GLenum error = 0;
1385     glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_context.getTestContext().getLog());
1386 
1387     gl.enableLogging(true);
1388 
1389     switch (m_caseType)
1390     {
1391     case CASE_BIND_VERTEX_BUFFER:
1392     {
1393         glu::Buffer buffer(m_context.getRenderContext());
1394         gl.glBindVertexBuffer(0, *buffer, 0, 0);
1395         break;
1396     }
1397 
1398     case CASE_VERTEX_ATTRIB_FORMAT:
1399         gl.glVertexAttribFormat(0, 4, GL_FLOAT, GL_FALSE, 0);
1400         break;
1401 
1402     case CASE_VERTEX_ATTRIB_I_FORMAT:
1403         gl.glVertexAttribIFormat(0, 4, GL_INT, 0);
1404         break;
1405 
1406     case CASE_VERTEX_ATTRIB_BINDING:
1407         gl.glVertexAttribBinding(0, 0);
1408         break;
1409 
1410     case CASE_VERTEX_BINDING_DIVISOR:
1411         gl.glVertexBindingDivisor(0, 1);
1412         break;
1413 
1414     default:
1415         DE_ASSERT(false);
1416     }
1417 
1418     error = gl.glGetError();
1419 
1420     if (error != GL_INVALID_OPERATION)
1421     {
1422         m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_INVALID_OPERATION, got "
1423                            << glu::getErrorStr(error) << tcu::TestLog::EndMessage;
1424         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid error");
1425     }
1426     else
1427         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1428 
1429     return STOP;
1430 }
1431 
1432 class BindToCreateCase : public TestCase
1433 {
1434 public:
1435     BindToCreateCase(Context &ctx, const char *name, const char *desc);
1436     ~BindToCreateCase(void);
1437 
1438     IterateResult iterate(void);
1439 };
1440 
BindToCreateCase(Context & ctx,const char * name,const char * desc)1441 BindToCreateCase::BindToCreateCase(Context &ctx, const char *name, const char *desc) : TestCase(ctx, name, desc)
1442 {
1443 }
1444 
~BindToCreateCase(void)1445 BindToCreateCase::~BindToCreateCase(void)
1446 {
1447 }
1448 
iterate(void)1449 BindToCreateCase::IterateResult BindToCreateCase::iterate(void)
1450 {
1451     glw::GLuint buffer = 0;
1452     glw::GLenum error;
1453     glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_context.getTestContext().getLog());
1454     glu::VertexArray vao(m_context.getRenderContext());
1455 
1456     gl.enableLogging(true);
1457 
1458     gl.glGenBuffers(1, &buffer);
1459     gl.glDeleteBuffers(1, &buffer);
1460     GLU_EXPECT_NO_ERROR(gl.glGetError(), "");
1461 
1462     gl.glBindVertexArray(*vao);
1463     gl.glBindVertexBuffer(0, buffer, 0, 0);
1464 
1465     error = gl.glGetError();
1466 
1467     if (error != GL_INVALID_OPERATION)
1468     {
1469         m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_INVALID_OPERATION, got "
1470                            << glu::getErrorStr(error) << tcu::TestLog::EndMessage;
1471         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid error");
1472     }
1473     else
1474         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1475 
1476     return STOP;
1477 }
1478 
1479 class NegativeApiCase : public TestCase
1480 {
1481 public:
1482     enum CaseType
1483     {
1484         CASE_LARGE_OFFSET,
1485         CASE_LARGE_STRIDE,
1486         CASE_NEGATIVE_STRIDE,
1487         CASE_NEGATIVE_OFFSET,
1488         CASE_INVALID_ATTR,
1489         CASE_INVALID_BINDING,
1490 
1491         CASE_LAST
1492     };
1493     NegativeApiCase(Context &ctx, const char *name, const char *desc, CaseType caseType);
1494     ~NegativeApiCase(void);
1495 
1496     IterateResult iterate(void);
1497 
1498 private:
1499     const CaseType m_caseType;
1500 };
1501 
NegativeApiCase(Context & ctx,const char * name,const char * desc,CaseType caseType)1502 NegativeApiCase::NegativeApiCase(Context &ctx, const char *name, const char *desc, CaseType caseType)
1503     : TestCase(ctx, name, desc)
1504     , m_caseType(caseType)
1505 {
1506 }
1507 
~NegativeApiCase(void)1508 NegativeApiCase::~NegativeApiCase(void)
1509 {
1510 }
1511 
iterate(void)1512 NegativeApiCase::IterateResult NegativeApiCase::iterate(void)
1513 {
1514     glw::GLenum error;
1515     glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_context.getTestContext().getLog());
1516     glu::VertexArray vao(m_context.getRenderContext());
1517 
1518     gl.enableLogging(true);
1519     gl.glBindVertexArray(*vao);
1520 
1521     switch (m_caseType)
1522     {
1523     case CASE_LARGE_OFFSET:
1524     {
1525         glw::GLint maxOffset = -1;
1526         glw::GLint largeOffset;
1527 
1528         gl.glGetIntegerv(GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET, &maxOffset);
1529         GLU_EXPECT_NO_ERROR(gl.glGetError(), "");
1530 
1531         largeOffset = maxOffset + 1;
1532 
1533         // skip if maximum unsigned or signed values
1534         if (maxOffset == -1 || maxOffset == 0x7FFFFFFF)
1535             throw tcu::NotSupportedError("Implementation supports all offsets");
1536 
1537         gl.glVertexAttribFormat(0, 4, GL_FLOAT, GL_FALSE, largeOffset);
1538         break;
1539     }
1540 
1541     case CASE_LARGE_STRIDE:
1542     {
1543         glu::Buffer buffer(m_context.getRenderContext());
1544         glw::GLint maxStride = -1;
1545         glw::GLint largeStride;
1546 
1547         gl.glGetIntegerv(GL_MAX_VERTEX_ATTRIB_STRIDE, &maxStride);
1548         GLU_EXPECT_NO_ERROR(gl.glGetError(), "");
1549 
1550         largeStride = maxStride + 1;
1551 
1552         // skip if maximum unsigned or signed values
1553         if (maxStride == -1 || maxStride == 0x7FFFFFFF)
1554             throw tcu::NotSupportedError("Implementation supports all strides");
1555 
1556         gl.glBindVertexBuffer(0, *buffer, 0, largeStride);
1557         break;
1558     }
1559 
1560     case CASE_NEGATIVE_STRIDE:
1561     {
1562         glu::Buffer buffer(m_context.getRenderContext());
1563         gl.glBindVertexBuffer(0, *buffer, 0, -20);
1564         break;
1565     }
1566 
1567     case CASE_NEGATIVE_OFFSET:
1568     {
1569         glu::Buffer buffer(m_context.getRenderContext());
1570         gl.glBindVertexBuffer(0, *buffer, -20, 0);
1571         break;
1572     }
1573 
1574     case CASE_INVALID_ATTR:
1575     {
1576         glw::GLint maxIndex = -1;
1577         glw::GLint largeIndex;
1578 
1579         gl.glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxIndex);
1580         GLU_EXPECT_NO_ERROR(gl.glGetError(), "");
1581 
1582         largeIndex = maxIndex + 1;
1583 
1584         // skip if maximum unsigned or signed values
1585         if (maxIndex == -1 || maxIndex == 0x7FFFFFFF)
1586             throw tcu::NotSupportedError("Implementation supports any attribute index");
1587 
1588         gl.glVertexAttribBinding(largeIndex, 0);
1589         break;
1590     }
1591 
1592     case CASE_INVALID_BINDING:
1593     {
1594         glw::GLint maxBindings = -1;
1595         glw::GLint largeBinding;
1596 
1597         gl.glGetIntegerv(GL_MAX_VERTEX_ATTRIB_BINDINGS, &maxBindings);
1598         GLU_EXPECT_NO_ERROR(gl.glGetError(), "");
1599 
1600         largeBinding = maxBindings + 1;
1601 
1602         // skip if maximum unsigned or signed values
1603         if (maxBindings == -1 || maxBindings == 0x7FFFFFFF)
1604             throw tcu::NotSupportedError("Implementation supports any binding");
1605 
1606         gl.glVertexAttribBinding(0, largeBinding);
1607         break;
1608     }
1609 
1610     default:
1611         DE_ASSERT(false);
1612     }
1613 
1614     error = gl.glGetError();
1615 
1616     if (error != GL_INVALID_VALUE)
1617     {
1618         m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_INVALID_VALUE, got "
1619                            << glu::getErrorStr(error) << tcu::TestLog::EndMessage;
1620         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid error");
1621     }
1622     else
1623         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1624 
1625     return STOP;
1626 }
1627 
1628 } // namespace
1629 
VertexAttributeBindingTests(Context & context)1630 VertexAttributeBindingTests::VertexAttributeBindingTests(Context &context)
1631     : TestCaseGroup(context, "vertex_attribute_binding", "Test vertex attribute binding")
1632 {
1633 }
1634 
~VertexAttributeBindingTests(void)1635 VertexAttributeBindingTests::~VertexAttributeBindingTests(void)
1636 {
1637 }
1638 
init(void)1639 void VertexAttributeBindingTests::init(void)
1640 {
1641     tcu::TestCaseGroup *const usageGroup    = new tcu::TestCaseGroup(m_testCtx, "usage", "Test using binding points");
1642     tcu::TestCaseGroup *const negativeGroup = new tcu::TestCaseGroup(m_testCtx, "negative", "Negative test");
1643 
1644     addChild(usageGroup);
1645     addChild(negativeGroup);
1646 
1647     // .usage
1648     {
1649         tcu::TestCaseGroup *const singleGroup =
1650             new tcu::TestCaseGroup(m_testCtx, "single_binding", "Test using single binding point");
1651         tcu::TestCaseGroup *const multipleGroup =
1652             new tcu::TestCaseGroup(m_testCtx, "multiple_bindings", "Test using multiple binding points");
1653         tcu::TestCaseGroup *const mixedGroup = new tcu::TestCaseGroup(
1654             m_testCtx, "mixed_usage", "Test using binding point and non binding point api variants");
1655 
1656         usageGroup->addChild(singleGroup);
1657         usageGroup->addChild(multipleGroup);
1658         usageGroup->addChild(mixedGroup);
1659 
1660         // single binding
1661 
1662         singleGroup->addChild(new SingleBindingCase(m_context, "elements_1", 0));
1663         singleGroup->addChild(
1664             new SingleBindingCase(m_context, "elements_2", SingleBindingCase::FLAG_ATTRIBS_MULTIPLE_ELEMS));
1665         singleGroup->addChild(new SingleBindingCase(m_context, "elements_2_share_elements",
1666                                                     SingleBindingCase::FLAG_ATTRIBS_SHARED_ELEMS));
1667         singleGroup->addChild(
1668             new SingleBindingCase(m_context, "offset_elements_1", SingleBindingCase::FLAG_BUF_ALIGNED_OFFSET | 0));
1669         singleGroup->addChild(new SingleBindingCase(m_context, "offset_elements_2",
1670                                                     SingleBindingCase::FLAG_BUF_ALIGNED_OFFSET |
1671                                                         SingleBindingCase::FLAG_ATTRIBS_MULTIPLE_ELEMS));
1672         singleGroup->addChild(new SingleBindingCase(m_context, "offset_elements_2_share_elements",
1673                                                     SingleBindingCase::FLAG_BUF_ALIGNED_OFFSET |
1674                                                         SingleBindingCase::FLAG_ATTRIBS_SHARED_ELEMS));
1675         singleGroup->addChild(
1676             new SingleBindingCase(m_context, "unaligned_offset_elements_1_aligned_elements",
1677                                   SingleBindingCase::FLAG_BUF_UNALIGNED_OFFSET |
1678                                       SingleBindingCase::FLAG_ATTRIB_ALIGNED)); // !< total offset is aligned
1679 
1680         // multiple bindings
1681 
1682         multipleGroup->addChild(new MultipleBindingCase(m_context, "basic", 0));
1683         multipleGroup->addChild(
1684             new MultipleBindingCase(m_context, "zero_stride", MultipleBindingCase::FLAG_ZERO_STRIDE));
1685         multipleGroup->addChild(new MultipleBindingCase(m_context, "instanced", MultipleBindingCase::FLAG_INSTANCED));
1686         multipleGroup->addChild(new MultipleBindingCase(m_context, "aliasing_buffer_zero_stride",
1687                                                         MultipleBindingCase::FLAG_ALIASING_BUFFERS |
1688                                                             MultipleBindingCase::FLAG_ZERO_STRIDE));
1689         multipleGroup->addChild(
1690             new MultipleBindingCase(m_context, "aliasing_buffer_instanced",
1691                                     MultipleBindingCase::FLAG_ALIASING_BUFFERS | MultipleBindingCase::FLAG_INSTANCED));
1692 
1693         // mixed cases
1694         mixedGroup->addChild(new MixedBindingCase(m_context, "mixed_attribs_basic",
1695                                                   "Use different api for different attributes",
1696                                                   MixedBindingCase::CASE_BASIC));
1697         mixedGroup->addChild(new MixedBindingCase(m_context, "mixed_attribs_instanced_binding",
1698                                                   "Use different api for different attributes",
1699                                                   MixedBindingCase::CASE_INSTANCED_BINDING));
1700         mixedGroup->addChild(new MixedBindingCase(m_context, "mixed_attribs_instanced_attrib",
1701                                                   "Use different api for different attributes",
1702                                                   MixedBindingCase::CASE_INSTANCED_ATTRIB));
1703 
1704         mixedGroup->addChild(new MixedApiCase(m_context, "mixed_api_change_buffer",
1705                                               "change buffer with vertex_attrib_binding api",
1706                                               MixedApiCase::CASE_CHANGE_BUFFER));
1707         mixedGroup->addChild(new MixedApiCase(m_context, "mixed_api_change_buffer_offset",
1708                                               "change buffer offset with vertex_attrib_binding api",
1709                                               MixedApiCase::CASE_CHANGE_BUFFER_OFFSET));
1710         mixedGroup->addChild(new MixedApiCase(m_context, "mixed_api_change_buffer_stride",
1711                                               "change buffer stride with vertex_attrib_binding api",
1712                                               MixedApiCase::CASE_CHANGE_BUFFER_STRIDE));
1713         mixedGroup->addChild(new MixedApiCase(m_context, "mixed_api_change_binding_point",
1714                                               "change binding point with vertex_attrib_binding api",
1715                                               MixedApiCase::CASE_CHANGE_BINDING_POINT));
1716     }
1717 
1718     // negative
1719     {
1720         negativeGroup->addChild(new DefaultVAOCase(m_context, "default_vao_bind_vertex_buffer", "use with default vao",
1721                                                    DefaultVAOCase::CASE_BIND_VERTEX_BUFFER));
1722         negativeGroup->addChild(new DefaultVAOCase(m_context, "default_vao_vertex_attrib_format",
1723                                                    "use with default vao", DefaultVAOCase::CASE_VERTEX_ATTRIB_FORMAT));
1724         negativeGroup->addChild(new DefaultVAOCase(m_context, "default_vao_vertex_attrib_i_format",
1725                                                    "use with default vao",
1726                                                    DefaultVAOCase::CASE_VERTEX_ATTRIB_I_FORMAT));
1727         negativeGroup->addChild(new DefaultVAOCase(m_context, "default_vao_vertex_attrib_binding",
1728                                                    "use with default vao", DefaultVAOCase::CASE_VERTEX_ATTRIB_BINDING));
1729         negativeGroup->addChild(new DefaultVAOCase(m_context, "default_vao_vertex_binding_divisor",
1730                                                    "use with default vao",
1731                                                    DefaultVAOCase::CASE_VERTEX_BINDING_DIVISOR));
1732 
1733         negativeGroup->addChild(new BindToCreateCase(m_context, "bind_create_new_buffer", "bind not existing buffer"));
1734 
1735         negativeGroup->addChild(new NegativeApiCase(m_context, "vertex_attrib_format_large_offset",
1736                                                     "large relative offset", NegativeApiCase::CASE_LARGE_OFFSET));
1737         negativeGroup->addChild(new NegativeApiCase(m_context, "bind_vertex_buffer_large_stride", "large stride",
1738                                                     NegativeApiCase::CASE_LARGE_STRIDE));
1739         negativeGroup->addChild(new NegativeApiCase(m_context, "bind_vertex_buffer_negative_stride", "negative stride",
1740                                                     NegativeApiCase::CASE_NEGATIVE_STRIDE));
1741         negativeGroup->addChild(new NegativeApiCase(m_context, "bind_vertex_buffer_negative_offset", "negative offset",
1742                                                     NegativeApiCase::CASE_NEGATIVE_OFFSET));
1743         negativeGroup->addChild(new NegativeApiCase(m_context, "vertex_attrib_binding_invalid_attr",
1744                                                     "bind invalid attr", NegativeApiCase::CASE_INVALID_ATTR));
1745         negativeGroup->addChild(new NegativeApiCase(m_context, "vertex_attrib_binding_invalid_binding",
1746                                                     "bind invalid binding", NegativeApiCase::CASE_INVALID_BINDING));
1747     }
1748 }
1749 
1750 } // namespace Functional
1751 } // namespace gles31
1752 } // namespace deqp
1753