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