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