1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 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 Memory object stress test
22  *//*--------------------------------------------------------------------*/
23 
24 #include "glsMemoryStressCase.hpp"
25 #include "gluShaderProgram.hpp"
26 #include "tcuTestLog.hpp"
27 #include "tcuCommandLine.hpp"
28 #include "deRandom.hpp"
29 #include "deClock.h"
30 #include "deString.h"
31 
32 #include "glw.h"
33 
34 #include <vector>
35 #include <iostream>
36 
37 using std::vector;
38 using tcu::TestLog;
39 
40 namespace deqp
41 {
42 namespace gls
43 {
44 
glErrorToString(deUint32 error)45 static const char* glErrorToString (deUint32 error)
46 {
47 	switch (error)
48 	{
49 		case GL_OUT_OF_MEMORY:
50 			return "GL_OUT_OF_MEMORY";
51 			break;
52 
53 		case GL_INVALID_ENUM:
54 			return "GL_INVALID_ENUM";
55 			break;
56 
57 		case GL_INVALID_FRAMEBUFFER_OPERATION:
58 			return "GL_INVALID_FRAMEBUFFER_OPERATION";
59 			break;
60 
61 		case GL_INVALID_OPERATION:
62 			return "GL_INVALID_OPERATION";
63 			break;
64 
65 		case GL_INVALID_VALUE:
66 			return "GL_INVALID_VALUE";
67 			break;
68 
69 		case 0:
70 			return "<none>";
71 			break;
72 
73 		default:
74 			// \todo [mika] Handle uknown errors?
75 			DE_ASSERT(false);
76 			return NULL;
77 			break;
78 	}
79 }
80 
81 static const float s_quadCoords[] =
82 {
83 	-1.0f, -1.0f,
84 	 1.0f, -1.0f,
85 	 1.0f,  1.0f,
86 	-1.0f,  1.0f
87 };
88 
89 static const GLubyte s_quadIndices[] =
90 {
91 	0, 1, 2,
92 	2, 3, 0
93 };
94 
95 class TextureRenderer
96 {
97 public:
98 			TextureRenderer		(tcu::TestLog& log, glu::RenderContext& renderContext);
99 			~TextureRenderer	(void);
100 	void	render				(deUint32 texture);
101 
102 private:
103 	glu::ShaderProgram*	m_program;
104 	glu::RenderContext&	m_renderCtx;
105 
106 	deUint32			m_coordBuffer;
107 	deUint32			m_indexBuffer;
108 	deUint32			m_vao;
109 
110 	static const char*	s_vertexShaderGLES2;
111 	static const char*	s_fragmentShaderGLES2;
112 
113 	static const char*	s_vertexShaderGLES3;
114 	static const char*	s_fragmentShaderGLES3;
115 
116 	static const char*	s_vertexShaderGL3;
117 	static const char*	s_fragmentShaderGL3;
118 };
119 
120 const char* TextureRenderer::s_vertexShaderGLES2 =
121 "attribute mediump vec2 a_coord;\n"
122 "varying mediump vec2 v_texCoord;\n"
123 "void main (void)\n"
124 "{\n"
125 "\tv_texCoord = 0.5 * (a_coord + vec2(1.0));\n"
126 "\tgl_Position = vec4(a_coord, 0.0, 1.0);\n"
127 "}\n";
128 
129 const char* TextureRenderer::s_fragmentShaderGLES2 =
130 "varying mediump vec2 v_texCoord;\n"
131 "uniform sampler2D u_texture;\n"
132 "void main (void)\n"
133 "{\n"
134 "\tgl_FragColor = texture2D(u_texture, v_texCoord);\n"
135 "}\n";
136 
137 const char* TextureRenderer::s_vertexShaderGLES3 =
138 "#version 300 es\n"
139 "in mediump vec2 a_coord;\n"
140 "out mediump vec2 v_texCoord;\n"
141 "void main (void)\n"
142 "{\n"
143 "\tv_texCoord = 0.5 * (a_coord + vec2(1.0));\n"
144 "\tgl_Position = vec4(a_coord, 0.0, 1.0);\n"
145 "}\n";
146 
147 const char* TextureRenderer::s_fragmentShaderGLES3 =
148 "#version 300 es\n"
149 "in mediump vec2 v_texCoord;\n"
150 "uniform sampler2D u_texture;\n"
151 "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
152 "void main (void)\n"
153 "{\n"
154 "\tdEQP_FragColor = texture(u_texture, v_texCoord);\n"
155 "}\n";
156 
157 const char* TextureRenderer::s_vertexShaderGL3 =
158 "#version 330\n"
159 "in mediump vec2 a_coord;\n"
160 "out mediump vec2 v_texCoord;\n"
161 "void main (void)\n"
162 "{\n"
163 "\tv_texCoord = 0.5 * (a_coord + vec2(1.0));\n"
164 "\tgl_Position = vec4(a_coord, 0.0, 1.0);\n"
165 "}\n";
166 
167 const char* TextureRenderer::s_fragmentShaderGL3 =
168 "#version 330\n"
169 "in mediump vec2 v_texCoord;\n"
170 "uniform sampler2D u_texture;\n"
171 "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
172 "void main (void)\n"
173 "{\n"
174 "\tdEQP_FragColor = texture(u_texture, v_texCoord);\n"
175 "}\n";
176 
TextureRenderer(tcu::TestLog & log,glu::RenderContext & renderContext)177 TextureRenderer::TextureRenderer (tcu::TestLog& log, glu::RenderContext& renderContext)
178 	: m_program		(NULL)
179 	, m_renderCtx	(renderContext)
180 	, m_coordBuffer	(0)
181 	, m_indexBuffer	(0)
182 	, m_vao			(0)
183 {
184 	const glu::ContextType ctxType = renderContext.getType();
185 
186 	if (glu::isGLSLVersionSupported(ctxType, glu::GLSL_VERSION_300_ES))
187 		m_program = new glu::ShaderProgram(m_renderCtx, glu::makeVtxFragSources(s_vertexShaderGLES3, s_fragmentShaderGLES3));
188 	else if (glu::isGLSLVersionSupported(ctxType, glu::GLSL_VERSION_100_ES))
189 		m_program = new glu::ShaderProgram(m_renderCtx, glu::makeVtxFragSources(s_vertexShaderGLES2, s_fragmentShaderGLES2));
190 	else if (glu::isGLSLVersionSupported(ctxType, glu::GLSL_VERSION_330))
191 		m_program = new glu::ShaderProgram(m_renderCtx, glu::makeVtxFragSources(s_vertexShaderGL3, s_fragmentShaderGL3));
192 	else
193 		DE_ASSERT(false);
194 
195 	if (ctxType.getProfile() == glu::PROFILE_CORE)
196 		GLU_CHECK_CALL(glGenVertexArrays(1, &m_vao));
197 
198 	GLU_CHECK_CALL(glGenBuffers(1, &m_coordBuffer));
199 	GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, m_coordBuffer));
200 	GLU_CHECK_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(s_quadCoords), s_quadCoords, GL_STATIC_DRAW));
201 
202 	GLU_CHECK_CALL(glGenBuffers(1, &m_indexBuffer));
203 	GLU_CHECK_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer));
204 	GLU_CHECK_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(s_quadIndices), s_quadIndices, GL_STATIC_DRAW));
205 
206 	if (!m_program->isOk())
207 	{
208 		log << *m_program;
209 		TCU_CHECK_MSG(m_program->isOk(), "Shader compilation failed");
210 	}
211 }
212 
~TextureRenderer(void)213 TextureRenderer::~TextureRenderer (void)
214 {
215 	delete m_program;
216 	glDeleteBuffers(1, &m_coordBuffer);
217 	glDeleteBuffers(1, &m_indexBuffer);
218 }
219 
render(deUint32 texture)220 void TextureRenderer::render (deUint32 texture)
221 {
222 	deUint32 coordLoc = -1;
223 	deUint32 texLoc	= -1;
224 
225 	GLU_CHECK_CALL(glUseProgram(m_program->getProgram()));
226 
227 	coordLoc = glGetAttribLocation(m_program->getProgram(), "a_coord");
228 	GLU_CHECK();
229 	TCU_CHECK(coordLoc != (deUint32)-1);
230 
231 	if (m_vao != 0)
232 		GLU_CHECK_CALL(glBindVertexArray(m_vao));
233 
234 	GLU_CHECK_CALL(glEnableVertexAttribArray(coordLoc));
235 
236 	GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, m_coordBuffer));
237 	GLU_CHECK_CALL(glVertexAttribPointer(coordLoc, 2, GL_FLOAT, GL_FALSE, 0, NULL));
238 
239 	GLU_CHECK_CALL(glActiveTexture(GL_TEXTURE0));
240 	GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_2D, texture));
241 
242 	texLoc = glGetUniformLocation(m_program->getProgram(), "u_texture");
243 	GLU_CHECK();
244 	TCU_CHECK(texLoc != (deUint32)-1);
245 
246 	GLU_CHECK_CALL(glUniform1i(texLoc, 0));
247 
248 	GLU_CHECK_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer));
249 	GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, NULL));
250 
251 	GLU_CHECK_CALL(glDisableVertexAttribArray(coordLoc));
252 
253 	if (m_vao != 0)
254 		GLU_CHECK_CALL(glBindVertexArray(0));
255 }
256 
257 class BufferRenderer
258 {
259 public:
260 			BufferRenderer	(tcu::TestLog& log, glu::RenderContext& renderContext);
261 			~BufferRenderer	(void);
262 	void	render			(deUint32 buffer, int size);
263 
264 private:
265 	glu::ShaderProgram*	m_program;
266 	glu::RenderContext&	m_renderCtx;
267 
268 	deUint32			m_coordBuffer;
269 	deUint32			m_indexBuffer;
270 	deUint32			m_vao;
271 
272 	static const char*	s_vertexShaderGLES2;
273 	static const char*	s_fragmentShaderGLES2;
274 
275 	static const char*	s_vertexShaderGLES3;
276 	static const char*	s_fragmentShaderGLES3;
277 
278 	static const char*	s_vertexShaderGL3;
279 	static const char*	s_fragmentShaderGL3;
280 };
281 
282 const char* BufferRenderer::s_vertexShaderGLES2 =
283 "attribute mediump vec2 a_coord;\n"
284 "attribute mediump vec4 a_buffer;\n"
285 "varying mediump vec4 v_buffer;\n"
286 "void main (void)\n"
287 "{\n"
288 "\tv_buffer = a_buffer;\n"
289 "\tgl_Position = vec4(a_coord, 0.0, 1.0);\n"
290 "}\n";
291 
292 const char* BufferRenderer::s_fragmentShaderGLES2 =
293 "varying mediump vec4 v_buffer;\n"
294 "void main (void)\n"
295 "{\n"
296 "\tgl_FragColor = v_buffer;\n"
297 "}\n";
298 
299 const char* BufferRenderer::s_vertexShaderGLES3 =
300 "#version 300 es\n"
301 "in mediump vec2 a_coord;\n"
302 "in mediump vec4 a_buffer;\n"
303 "out mediump vec4 v_buffer;\n"
304 "void main (void)\n"
305 "{\n"
306 "\tv_buffer = a_buffer;\n"
307 "\tgl_Position = vec4(a_coord, 0.0, 1.0);\n"
308 "}\n";
309 
310 const char* BufferRenderer::s_fragmentShaderGLES3 =
311 "#version 300 es\n"
312 "in mediump vec4 v_buffer;\n"
313 "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
314 "void main (void)\n"
315 "{\n"
316 "\tdEQP_FragColor = v_buffer;\n"
317 "}\n";
318 
319 const char* BufferRenderer::s_vertexShaderGL3 =
320 "#version 330\n"
321 "in mediump vec2 a_coord;\n"
322 "in mediump vec4 a_buffer;\n"
323 "out mediump vec4 v_buffer;\n"
324 "void main (void)\n"
325 "{\n"
326 "\tv_buffer = a_buffer;\n"
327 "\tgl_Position = vec4(a_coord, 0.0, 1.0);\n"
328 "}\n";
329 
330 const char* BufferRenderer::s_fragmentShaderGL3 =
331 "#version 330\n"
332 "in mediump vec4 v_buffer;\n"
333 "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
334 "void main (void)\n"
335 "{\n"
336 "\tdEQP_FragColor = v_buffer;\n"
337 "}\n";
338 
BufferRenderer(tcu::TestLog & log,glu::RenderContext & renderContext)339 BufferRenderer::BufferRenderer (tcu::TestLog& log, glu::RenderContext& renderContext)
340 	: m_program		(NULL)
341 	, m_renderCtx	(renderContext)
342 	, m_coordBuffer	(0)
343 	, m_indexBuffer	(0)
344 	, m_vao			(0)
345 {
346 	const glu::ContextType ctxType = renderContext.getType();
347 
348 	if (glu::isGLSLVersionSupported(ctxType, glu::GLSL_VERSION_300_ES))
349 		m_program = new glu::ShaderProgram(m_renderCtx, glu::makeVtxFragSources(s_vertexShaderGLES3, s_fragmentShaderGLES3));
350 	else if (glu::isGLSLVersionSupported(ctxType, glu::GLSL_VERSION_100_ES))
351 		m_program = new glu::ShaderProgram(m_renderCtx, glu::makeVtxFragSources(s_vertexShaderGLES2, s_fragmentShaderGLES2));
352 	else if (glu::isGLSLVersionSupported(ctxType, glu::GLSL_VERSION_330))
353 		m_program = new glu::ShaderProgram(m_renderCtx, glu::makeVtxFragSources(s_vertexShaderGL3, s_fragmentShaderGL3));
354 	else
355 		DE_ASSERT(false);
356 
357 	if (ctxType.getProfile() == glu::PROFILE_CORE)
358 		GLU_CHECK_CALL(glGenVertexArrays(1, &m_vao));
359 
360 	GLU_CHECK_CALL(glGenBuffers(1, &m_coordBuffer));
361 	GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, m_coordBuffer));
362 	GLU_CHECK_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(s_quadCoords), s_quadCoords, GL_STATIC_DRAW));
363 
364 	GLU_CHECK_CALL(glGenBuffers(1, &m_indexBuffer));
365 	GLU_CHECK_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer));
366 	GLU_CHECK_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(s_quadIndices), s_quadIndices, GL_STATIC_DRAW));
367 
368 	if (!m_program->isOk())
369 	{
370 		log << *m_program;
371 		TCU_CHECK_MSG(m_program->isOk(), "Shader compilation failed");
372 	}
373 }
374 
~BufferRenderer(void)375 BufferRenderer::~BufferRenderer (void)
376 {
377 	delete m_program;
378 	glDeleteBuffers(1, &m_coordBuffer);
379 	glDeleteBuffers(1, &m_indexBuffer);
380 }
381 
render(deUint32 buffer,int size)382 void BufferRenderer::render (deUint32 buffer, int size)
383 {
384 	DE_UNREF(size);
385 	DE_ASSERT((size_t)size >= sizeof(GLubyte) * 4 * 6);
386 	GLU_CHECK_CALL(glUseProgram(m_program->getProgram()));
387 
388 	deUint32 bufferLoc = glGetAttribLocation(m_program->getProgram(), "a_buffer");
389 	TCU_CHECK(bufferLoc != (deUint32)-1);
390 
391 	deUint32 coordLoc = glGetAttribLocation(m_program->getProgram(), "a_coord");
392 	TCU_CHECK(coordLoc != (deUint32)-1);
393 
394 	if (m_vao != 0)
395 		GLU_CHECK_CALL(glBindVertexArray(m_vao));
396 
397 	GLU_CHECK_CALL(glEnableVertexAttribArray(bufferLoc));
398 	GLU_CHECK_CALL(glEnableVertexAttribArray(coordLoc));
399 
400 	GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, m_coordBuffer));
401 	GLU_CHECK_CALL(glVertexAttribPointer(coordLoc, 2, GL_FLOAT, GL_FALSE, 0, NULL));
402 
403 	GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, buffer));
404 	GLU_CHECK_CALL(glVertexAttribPointer(bufferLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0));
405 	GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, 0));
406 
407 	GLU_CHECK_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer));
408 	GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, NULL));
409 
410 	GLU_CHECK_CALL(glDisableVertexAttribArray(bufferLoc));
411 	GLU_CHECK_CALL(glDisableVertexAttribArray(coordLoc));
412 
413 	if (m_vao != 0)
414 		GLU_CHECK_CALL(glBindVertexArray(0));
415 }
416 
417 class MemObjectAllocator
418 {
419 public:
420 	enum Result
421 	{
422 		RESULT_GOT_BAD_ALLOC = 0,
423 		RESULT_GEN_TEXTURES_FAILED,
424 		RESULT_GEN_BUFFERS_FAILED,
425 		RESULT_BUFFER_DATA_FAILED,
426 		RESULT_BUFFER_SUB_DATA_FAILED,
427 		RESULT_TEXTURE_IMAGE_FAILED,
428 		RESULT_TEXTURE_SUB_IMAGE_FAILED,
429 		RESULT_BIND_TEXTURE_FAILED,
430 		RESULT_BIND_BUFFER_FAILED,
431 		RESULT_DELETE_TEXTURES_FAILED,
432 		RESULT_DELETE_BUFFERS_FAILED,
433 		RESULT_RENDER_FAILED,
434 
435 		RESULT_LAST
436 	};
437 
438 						MemObjectAllocator	(tcu::TestLog& log, glu::RenderContext& renderContext, MemObjectType objectTypes, const MemObjectConfig& config, int seed);
439 						~MemObjectAllocator	(void);
440 	bool				allocUntilFailure	(void);
441 	void				clearObjects		(void);
getResult(void) const442 	Result				getResult			(void) const { return m_result; }
getGLError(void) const443 	deUint32			getGLError			(void) const { return m_glError; }
getObjectCount(void) const444 	int					getObjectCount		(void) const { return m_objectCount; }
getBytes(void) const445 	deUint32			getBytes			(void) const { return m_bytesRequired; }
446 
447 	static const char*	resultToString		(Result result);
448 
449 private:
450 
451 	void				allocateTexture		(de::Random& rnd);
452 	void				allocateBuffer		(de::Random& rnd);
453 
454 	vector<deUint32>	m_buffers;
455 	vector<deUint32>	m_textures;
456 	int					m_seed;
457 	int					m_objectCount;
458 	deUint32			m_bytesRequired;
459 	MemObjectType		m_objectTypes;
460 	Result				m_result;
461 	MemObjectConfig		m_config;
462 	deUint32			m_glError;
463 	vector<deUint8>		m_dummyData;
464 	BufferRenderer		m_bufferRenderer;
465 	TextureRenderer		m_textureRenderer;
466 };
467 
MemObjectAllocator(tcu::TestLog & log,glu::RenderContext & renderContext,MemObjectType objectTypes,const MemObjectConfig & config,int seed)468 MemObjectAllocator::MemObjectAllocator (tcu::TestLog& log, glu::RenderContext& renderContext, MemObjectType objectTypes, const MemObjectConfig& config, int seed)
469 	: m_seed			(seed)
470 	, m_objectCount		(0)
471 	, m_bytesRequired	(0)
472 	, m_objectTypes		(objectTypes)
473 	, m_result			(RESULT_LAST)
474 	, m_config			(config)
475 	, m_glError			(0)
476 	, m_bufferRenderer	(log, renderContext)
477 	, m_textureRenderer	(log, renderContext)
478 {
479 	DE_UNREF(renderContext);
480 
481 	if (m_config.useDummyData)
482 	{
483 		int dummySize = deMax32(m_config.maxBufferSize, m_config.maxTextureSize*m_config.maxTextureSize*4);
484 		m_dummyData = vector<deUint8>(dummySize);
485 	}
486 	else if (m_config.write)
487 		m_dummyData = vector<deUint8>(128);
488 }
489 
~MemObjectAllocator(void)490 MemObjectAllocator::~MemObjectAllocator (void)
491 {
492 }
493 
allocUntilFailure(void)494 bool MemObjectAllocator::allocUntilFailure (void)
495 {
496 	de::Random rnd(m_seed);
497 	GLU_CHECK_MSG("Error in init");
498 	try
499 	{
500 		const deUint64	timeoutUs	= 10000000; // 10s
501 		deUint64		beginTimeUs	= deGetMicroseconds();
502 		deUint64		currentTimeUs;
503 
504 		do
505 		{
506 			GLU_CHECK_MSG("Unkown Error");
507 			switch (m_objectTypes)
508 			{
509 				case MEMOBJECTTYPE_TEXTURE:
510 					allocateTexture(rnd);
511 					break;
512 
513 				case MEMOBJECTTYPE_BUFFER:
514 					allocateBuffer(rnd);
515 					break;
516 
517 				default:
518 				{
519 					if (rnd.getBool())
520 						allocateBuffer(rnd);
521 					else
522 						allocateTexture(rnd);
523 					break;
524 				}
525 			}
526 
527 			if (m_result != RESULT_LAST)
528 			{
529 				glFinish();
530 				return true;
531 			}
532 
533 			currentTimeUs = deGetMicroseconds();
534 		} while (currentTimeUs - beginTimeUs < timeoutUs);
535 
536 		// Timeout
537 		if (currentTimeUs - beginTimeUs >= timeoutUs)
538 			return false;
539 		else
540 			return true;
541 	}
542 	catch (const std::bad_alloc&)
543 	{
544 		m_result = RESULT_GOT_BAD_ALLOC;
545 		return true;
546 	}
547 }
548 
clearObjects(void)549 void MemObjectAllocator::clearObjects (void)
550 {
551 	deUint32 error = 0;
552 
553 	if (!m_textures.empty())
554 	{
555 		glDeleteTextures((GLsizei)m_textures.size(), &(m_textures[0]));
556 		error = glGetError();
557 		if (error != 0)
558 		{
559 			m_result	= RESULT_DELETE_TEXTURES_FAILED;
560 			m_glError	= error;
561 		}
562 
563 		m_textures.clear();
564 	}
565 
566 	if (!m_buffers.empty())
567 	{
568 		glDeleteBuffers((GLsizei)m_buffers.size(), &(m_buffers[0]));
569 		error = glGetError();
570 		if (error != 0)
571 		{
572 			m_result	= RESULT_DELETE_BUFFERS_FAILED;
573 			m_glError	= error;
574 		}
575 
576 		m_buffers.clear();
577 	}
578 }
579 
allocateTexture(de::Random & rnd)580 void MemObjectAllocator::allocateTexture (de::Random& rnd)
581 {
582 	const int	vectorBlockSize = 128;
583 	deUint32	tex		= 0;
584 	deUint32	error	= 0;
585 	int			width	= rnd.getInt(m_config.minTextureSize, m_config.maxTextureSize);
586 	int			height	= rnd.getInt(m_config.minTextureSize, m_config.maxTextureSize);
587 
588 	glGenTextures(1, &tex);
589 	error = glGetError();
590 	if (error != 0)
591 	{
592 		m_result	= RESULT_GEN_TEXTURES_FAILED;
593 		m_glError	= error;
594 		return;
595 	}
596 
597 	if (m_textures.size() % vectorBlockSize == 0)
598 		m_textures.reserve(m_textures.size() + vectorBlockSize);
599 
600 	m_textures.push_back(tex);
601 
602 	glBindTexture(GL_TEXTURE_2D, tex);
603 	error = glGetError();
604 	if (error != 0)
605 	{
606 		m_result	= RESULT_BIND_TEXTURE_FAILED;
607 		m_glError	= error;
608 		return;
609 	}
610 
611 	if (m_config.useDummyData)
612 	{
613 		DE_ASSERT((int)m_dummyData.size() >= width*height*4);
614 		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &(m_dummyData[0]));
615 	}
616 	else
617 		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
618 
619 	error = glGetError();
620 	if (error != 0)
621 	{
622 		m_result	= RESULT_TEXTURE_IMAGE_FAILED;
623 		m_glError	= error;
624 		return;
625 	}
626 
627 	if (m_config.write)
628 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &(m_dummyData[0]));
629 
630 	error = glGetError();
631 	if (error != 0)
632 	{
633 		m_result	= RESULT_TEXTURE_SUB_IMAGE_FAILED;
634 		m_glError	= error;
635 		return;
636 	}
637 
638 	if (m_config.use)
639 	{
640 		try
641 		{
642 			m_textureRenderer.render(tex);
643 		}
644 		catch (const glu::Error& err)
645 		{
646 			m_result	= RESULT_RENDER_FAILED;
647 			m_glError	= err.getError();
648 			return;
649 		}
650 		catch (const glu::OutOfMemoryError&)
651 		{
652 			m_result	= RESULT_RENDER_FAILED;
653 			m_glError	= GL_OUT_OF_MEMORY;
654 			return;
655 		}
656 	}
657 
658 	glBindTexture(GL_TEXTURE_2D, 0);
659 	error = glGetError();
660 	if (error != 0)
661 	{
662 		m_result	= RESULT_BIND_TEXTURE_FAILED;
663 		m_glError	= error;
664 		return;
665 	}
666 
667 	m_objectCount++;
668 	m_bytesRequired += width*height*4;
669 }
670 
allocateBuffer(de::Random & rnd)671 void MemObjectAllocator::allocateBuffer (de::Random& rnd)
672 {
673 	const int	vectorBlockSize = 128;
674 	deUint32	buffer			= 0;
675 	deUint32	error			= 0;
676 	int			size			= rnd.getInt(m_config.minBufferSize, m_config.maxBufferSize);
677 
678 	glGenBuffers(1, &buffer);
679 	error = glGetError();
680 	if (error != 0)
681 	{
682 		m_result	= RESULT_GEN_BUFFERS_FAILED;
683 		m_glError	= error;
684 		return;
685 	}
686 
687 	glBindBuffer(GL_ARRAY_BUFFER, buffer);
688 	error = glGetError();
689 	if (error != 0)
690 	{
691 		m_result	= RESULT_BIND_BUFFER_FAILED;
692 		m_glError	= error;
693 		return;
694 	}
695 
696 	if (m_buffers.size() % vectorBlockSize == 0)
697 		m_buffers.reserve(m_buffers.size() + vectorBlockSize);
698 
699 	m_buffers.push_back(buffer);
700 
701 	if (m_config.useDummyData)
702 	{
703 		DE_ASSERT((int)m_dummyData.size() >= size);
704 		glBufferData(GL_ARRAY_BUFFER, size, &(m_dummyData[0]), GL_DYNAMIC_DRAW);
705 	}
706 	else
707 		glBufferData(GL_ARRAY_BUFFER, size, NULL, GL_DYNAMIC_DRAW);
708 
709 	error = glGetError();
710 	if (error != 0)
711 	{
712 		m_result	= RESULT_BUFFER_DATA_FAILED;
713 		m_glError	= error;
714 		return;
715 	}
716 
717 	if (m_config.write)
718 		glBufferSubData(GL_ARRAY_BUFFER, 0, 1, &(m_dummyData[0]));
719 
720 	error = glGetError();
721 	if (error != 0)
722 	{
723 		m_result	= RESULT_BUFFER_SUB_DATA_FAILED;
724 		m_glError	= error;
725 		return;
726 	}
727 
728 	if (m_config.use)
729 	{
730 		try
731 		{
732 			m_bufferRenderer.render(buffer, size);
733 		}
734 		catch (const glu::Error& err)
735 		{
736 			m_result	= RESULT_RENDER_FAILED;
737 			m_glError	= err.getError();
738 			return;
739 		}
740 		catch (const glu::OutOfMemoryError&)
741 		{
742 			m_result	= RESULT_RENDER_FAILED;
743 			m_glError	= GL_OUT_OF_MEMORY;
744 			return;
745 		}
746 	}
747 
748 	glBindBuffer(GL_ARRAY_BUFFER, 0);
749 	error = glGetError();
750 	if (error != 0)
751 	{
752 		m_result	= RESULT_BIND_BUFFER_FAILED;
753 		m_glError	= error;
754 		return;
755 	}
756 
757 	m_objectCount++;
758 	m_bytesRequired += size;
759 }
760 
resultToString(Result result)761 const char* MemObjectAllocator::resultToString (Result result)
762 {
763 	switch (result)
764 	{
765 		case RESULT_GOT_BAD_ALLOC:
766 			return "Caught std::bad_alloc";
767 			break;
768 
769 		case RESULT_GEN_TEXTURES_FAILED:
770 			return "glGenTextures failed";
771 			break;
772 
773 		case RESULT_GEN_BUFFERS_FAILED:
774 			return "glGenBuffers failed";
775 			break;
776 
777 		case RESULT_BUFFER_DATA_FAILED:
778 			return "glBufferData failed";
779 			break;
780 
781 		case RESULT_BUFFER_SUB_DATA_FAILED:
782 			return "glBufferSubData failed";
783 			break;
784 
785 		case RESULT_TEXTURE_IMAGE_FAILED:
786 			return "glTexImage2D failed";
787 			break;
788 
789 		case RESULT_TEXTURE_SUB_IMAGE_FAILED:
790 			return "glTexSubImage2D failed";
791 			break;
792 
793 		case RESULT_BIND_TEXTURE_FAILED:
794 			return "glBindTexture failed";
795 			break;
796 
797 		case RESULT_BIND_BUFFER_FAILED:
798 			return "glBindBuffer failed";
799 			break;
800 
801 		case RESULT_DELETE_TEXTURES_FAILED:
802 			return "glDeleteTextures failed";
803 			break;
804 
805 		case RESULT_DELETE_BUFFERS_FAILED:
806 			return "glDeleteBuffers failed";
807 			break;
808 
809 		case RESULT_RENDER_FAILED:
810 			return "Rendering result failed";
811 			break;
812 
813 		default:
814 			DE_ASSERT(false);
815 			return NULL;
816 	}
817 }
818 
MemoryStressCase(tcu::TestContext & ctx,glu::RenderContext & renderContext,deUint32 objectTypes,int minTextureSize,int maxTextureSize,int minBufferSize,int maxBufferSize,bool write,bool use,bool useDummyData,bool clearAfterOOM,const char * name,const char * desc)819 MemoryStressCase::MemoryStressCase (tcu::TestContext& ctx, glu::RenderContext& renderContext, deUint32 objectTypes, int minTextureSize, int maxTextureSize, int minBufferSize, int maxBufferSize, bool write, bool use, bool useDummyData, bool clearAfterOOM, const char* name, const char* desc)
820 	: tcu::TestCase					(ctx, name, desc)
821 	, m_iteration					(0)
822 	, m_iterationCount				(5)
823 	, m_objectTypes					((MemObjectType)objectTypes)
824 	, m_zeroAlloc					(false)
825 	, m_clearAfterOOM				(clearAfterOOM)
826 	, m_renderCtx					(renderContext)
827 {
828 	m_allocated.reserve(m_iterationCount);
829 	m_config.maxTextureSize = maxTextureSize;
830 	m_config.minTextureSize = minTextureSize;
831 	m_config.maxBufferSize	= maxBufferSize;
832 	m_config.minBufferSize	= minBufferSize;
833 	m_config.useDummyData	= useDummyData;
834 	m_config.write			= write;
835 	m_config.use			= use;
836 }
837 
~MemoryStressCase(void)838 MemoryStressCase::~MemoryStressCase (void)
839 {
840 }
841 
init(void)842 void MemoryStressCase::init (void)
843 {
844 	if (!m_testCtx.getCommandLine().isOutOfMemoryTestEnabled())
845 	{
846 		m_testCtx.getLog() << TestLog::Message << "Tests that exhaust memory are disabled, use --deqp-test-oom=enable command line option to enable." << TestLog::EndMessage;
847 		throw tcu::NotSupportedError("OOM tests disabled");
848 	}
849 }
850 
deinit(void)851 void MemoryStressCase::deinit (void)
852 {
853 	TCU_CHECK(!m_zeroAlloc);
854 }
855 
iterate(void)856 tcu::TestCase::IterateResult MemoryStressCase::iterate (void)
857 {
858 	bool			end		= false;
859 	tcu::TestLog&	log		= m_testCtx.getLog();
860 
861 	MemObjectAllocator allocator(log, m_renderCtx, m_objectTypes, m_config, deStringHash(getName()));
862 
863 	if (!allocator.allocUntilFailure())
864 	{
865 		// Allocation timed out
866 		allocator.clearObjects();
867 
868 		log << TestLog::Message << "Timeout. Couldn't exhaust memory in timelimit. Allocated " << allocator.getObjectCount() << " objects." << TestLog::EndMessage;
869 
870 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
871 		return STOP;
872 	}
873 
874 	// Try to cancel rendering operations
875 	if (m_clearAfterOOM)
876 		GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT));
877 
878 	allocator.clearObjects();
879 
880 	m_allocated.push_back(allocator.getObjectCount());
881 
882 	if (m_iteration != 0  && allocator.getObjectCount() == 0)
883 		m_zeroAlloc = true;
884 
885 	log << TestLog::Message << "Got error when allocation object count: " << allocator.getObjectCount() << " bytes: " << allocator.getBytes() << TestLog::EndMessage;
886 
887 	if ((allocator.getGLError() == 0) && (allocator.getResult() == MemObjectAllocator::RESULT_GOT_BAD_ALLOC))
888 	{
889 		log << TestLog::Message << "std::bad_alloc" << TestLog::EndMessage;
890 		end = true;
891 		m_testCtx.setTestResult(QP_TEST_RESULT_RESOURCE_ERROR, "Memory allocation failed");
892 	}
893 	else if (allocator.getGLError() != GL_OUT_OF_MEMORY)
894 	{
895 		log << TestLog::Message << "Invalid Error " << MemObjectAllocator::resultToString(allocator.getResult())
896 			<< " GLError: " << glErrorToString(allocator.getGLError()) <<
897 		TestLog::EndMessage;
898 
899 		end = true;
900 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
901 	}
902 
903 	if ((m_iteration+1) == m_iterationCount)
904 	{
905 		int min = m_allocated[0];
906 		int max = m_allocated[0];
907 
908 		float threshold = 50.0f;
909 
910 		for (int allocNdx = 0; allocNdx < (int)m_allocated.size(); allocNdx++)
911 		{
912 			min = deMin32(m_allocated[allocNdx], min);
913 			max = deMax32(m_allocated[allocNdx], max);
914 		}
915 
916 		if (min == 0 && max != 0)
917 		{
918 			log << TestLog::Message << "Allocation count zero" << TestLog::EndMessage;
919 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
920 		}
921 		else
922 		{
923 			const float change = (float)(min - max) / (float)(max);
924 			if (change > threshold)
925 			{
926 				log << TestLog::Message << "Allocated objects max: " << max << ", min: " << min << ", difference: " << change << "% threshold: " << threshold << "%" << TestLog::EndMessage;
927 				m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Allocation count variation");
928 			}
929 			else
930 				m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
931 		}
932 		end = true;
933 	}
934 
935 	GLU_CHECK_CALL(glFinish());
936 
937 	m_iteration++;
938 	if (end)
939 		return STOP;
940 	else
941 		return CONTINUE;
942 }
943 
944 } // gls
945 } // deqp
946