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)
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
BindingRenderCase(Context & ctx,const char * name,const char * desc,bool unalignedData)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
~BindingRenderCase(void)162 BindingRenderCase::~BindingRenderCase (void)
163 {
164 deinit();
165 }
166
init(void)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
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
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
SingleBindingCase(Context & ctx,const char * name,int flags)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
~SingleBindingCase(void)275 SingleBindingCase::~SingleBindingCase (void)
276 {
277 deinit();
278 }
279
init(void)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
deinit(void)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
renderTo(tcu::Surface & dst)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
genTestSpec(int flags)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
genTestDescription(int flags)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
isDataUnaligned(int flags)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
createBuffers(void)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
createShader(void)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
genVertexSource(void)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
MultipleBindingCase(Context & ctx,const char * name,int flags)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
~MultipleBindingCase(void)569 MultipleBindingCase::~MultipleBindingCase (void)
570 {
571 deinit();
572 }
573
init(void)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
deinit(void)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
renderTo(tcu::Surface & dst)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
genTestSpec(int flags) const682 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
genTestDescription(int flags) const693 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
createBuffers(void)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
createShader(void)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
MixedBindingCase(Context & ctx,const char * name,const char * desc,CaseType caseType)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
~MixedBindingCase(void)861 MixedBindingCase::~MixedBindingCase (void)
862 {
863 deinit();
864 }
865
init(void)866 void MixedBindingCase::init (void)
867 {
868 BindingRenderCase::init();
869 }
870
deinit(void)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
renderTo(tcu::Surface & dst)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)), glu::BufferOffsetAsPointer(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)), glu::BufferOffsetAsPointer(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
createBuffers(void)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
createShader(void)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
MixedApiCase(Context & ctx,const char * name,const char * desc,CaseType caseType)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
~MixedApiCase(void)1103 MixedApiCase::~MixedApiCase (void)
1104 {
1105 deinit();
1106 }
1107
init(void)1108 void MixedApiCase::init (void)
1109 {
1110 BindingRenderCase::init();
1111 }
1112
deinit(void)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
renderTo(tcu::Surface & dst)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)), glu::BufferOffsetAsPointer(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)), glu::BufferOffsetAsPointer(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
createBuffers(void)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
createShader(void)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
DefaultVAOCase(Context & ctx,const char * name,const char * desc,CaseType caseType)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
~DefaultVAOCase(void)1310 DefaultVAOCase::~DefaultVAOCase (void)
1311 {
1312 }
1313
iterate(void)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
BindToCreateCase(Context & ctx,const char * name,const char * desc)1372 BindToCreateCase::BindToCreateCase (Context& ctx, const char* name, const char* desc)
1373 : TestCase(ctx, name, desc)
1374 {
1375 }
1376
~BindToCreateCase(void)1377 BindToCreateCase::~BindToCreateCase (void)
1378 {
1379 }
1380
iterate(void)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
NegativeApiCase(Context & ctx,const char * name,const char * desc,CaseType caseType)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
~NegativeApiCase(void)1439 NegativeApiCase::~NegativeApiCase (void)
1440 {
1441 }
1442
iterate(void)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
VertexAttributeBindingTests(Context & context)1560 VertexAttributeBindingTests::VertexAttributeBindingTests (Context& context)
1561 : TestCaseGroup(context, "vertex_attribute_binding", "Test vertex attribute binding")
1562 {
1563 }
1564
~VertexAttributeBindingTests(void)1565 VertexAttributeBindingTests::~VertexAttributeBindingTests (void)
1566 {
1567 }
1568
init(void)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
1638