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