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