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