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