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
37using std::vector;
38using tcu::TestLog;
39
40namespace deqp
41{
42namespace gls
43{
44
45static 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
74static 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
82static const GLubyte s_quadIndices[] =
83{
84	0, 1, 2,
85	2, 3, 0
86};
87
88class TextureRenderer
89{
90public:
91			TextureRenderer		(tcu::TestLog& log, glu::RenderContext& renderContext);
92			~TextureRenderer	(void);
93	void	render				(deUint32 texture);
94
95private:
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
113const 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
122const 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
130const 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
140const 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
150const 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
160const 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
170TextureRenderer::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
206TextureRenderer::~TextureRenderer (void)
207{
208	delete m_program;
209	glDeleteBuffers(1, &m_coordBuffer);
210	glDeleteBuffers(1, &m_indexBuffer);
211}
212
213void 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
250class BufferRenderer
251{
252public:
253			BufferRenderer	(tcu::TestLog& log, glu::RenderContext& renderContext);
254			~BufferRenderer	(void);
255	void	render			(deUint32 buffer, int size);
256
257private:
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
275const 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
285const 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
292const 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
303const 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
312const 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
323const 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
332BufferRenderer::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
368BufferRenderer::~BufferRenderer (void)
369{
370	delete m_program;
371	glDeleteBuffers(1, &m_coordBuffer);
372	glDeleteBuffers(1, &m_indexBuffer);
373}
374
375void 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
410class MemObjectAllocator
411{
412public:
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);
435	Result				getResult			(void) const { return m_result; }
436	deUint32			getGLError			(void) const { return m_glError; }
437	int					getObjectCount		(void) const { return m_objectCount; }
438	deUint32			getBytes			(void) const { return m_bytesRequired; }
439
440	static const char*	resultToString		(Result result);
441
442private:
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_unusedData;
457	BufferRenderer		m_bufferRenderer;
458	TextureRenderer		m_textureRenderer;
459};
460
461MemObjectAllocator::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.useUnusedData)
475	{
476		int unusedSize = deMax32(m_config.maxBufferSize, m_config.maxTextureSize*m_config.maxTextureSize*4);
477		m_unusedData = vector<deUint8>(unusedSize);
478	}
479	else if (m_config.write)
480		m_unusedData = vector<deUint8>(128);
481}
482
483MemObjectAllocator::~MemObjectAllocator (void)
484{
485}
486
487bool 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
542void 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
573void 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.useUnusedData)
605	{
606		DE_ASSERT((int)m_unusedData.size() >= width*height*4);
607		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &(m_unusedData[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_unusedData[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
664void 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.useUnusedData)
695	{
696		DE_ASSERT((int)m_unusedData.size() >= size);
697		glBufferData(GL_ARRAY_BUFFER, size, &(m_unusedData[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_unusedData[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
754const 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
800MemoryStressCase::MemoryStressCase (tcu::TestContext& ctx, glu::RenderContext& renderContext, deUint32 objectTypes, int minTextureSize, int maxTextureSize, int minBufferSize, int maxBufferSize, bool write, bool use, bool useUnusedData, 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.useUnusedData	= useUnusedData;
815	m_config.write			= write;
816	m_config.use			= use;
817}
818
819MemoryStressCase::~MemoryStressCase (void)
820{
821}
822
823void 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
832void MemoryStressCase::deinit (void)
833{
834	TCU_CHECK(!m_zeroAlloc);
835}
836
837tcu::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