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			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
81static 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
89static const GLubyte s_quadIndices[] =
90{
91	0, 1, 2,
92	2, 3, 0
93};
94
95class TextureRenderer
96{
97public:
98			TextureRenderer		(tcu::TestLog& log, glu::RenderContext& renderContext);
99			~TextureRenderer	(void);
100	void	render				(deUint32 texture);
101
102private:
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
120const 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
129const 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
137const 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
147const 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
157const 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
167const 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
177TextureRenderer::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
213TextureRenderer::~TextureRenderer (void)
214{
215	delete m_program;
216	glDeleteBuffers(1, &m_coordBuffer);
217	glDeleteBuffers(1, &m_indexBuffer);
218}
219
220void 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
257class BufferRenderer
258{
259public:
260			BufferRenderer	(tcu::TestLog& log, glu::RenderContext& renderContext);
261			~BufferRenderer	(void);
262	void	render			(deUint32 buffer, int size);
263
264private:
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
282const 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
292const 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
299const 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
310const 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
319const 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
330const 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
339BufferRenderer::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
375BufferRenderer::~BufferRenderer (void)
376{
377	delete m_program;
378	glDeleteBuffers(1, &m_coordBuffer);
379	glDeleteBuffers(1, &m_indexBuffer);
380}
381
382void 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
417class MemObjectAllocator
418{
419public:
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);
442	Result				getResult			(void) const { return m_result; }
443	deUint32			getGLError			(void) const { return m_glError; }
444	int					getObjectCount		(void) const { return m_objectCount; }
445	deUint32			getBytes			(void) const { return m_bytesRequired; }
446
447	static const char*	resultToString		(Result result);
448
449private:
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
468MemObjectAllocator::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
490MemObjectAllocator::~MemObjectAllocator (void)
491{
492}
493
494bool 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
549void 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
580void 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
671void 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
761const 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
819MemoryStressCase::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
838MemoryStressCase::~MemoryStressCase (void)
839{
840}
841
842void 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
851void MemoryStressCase::deinit (void)
852{
853	TCU_CHECK(!m_zeroAlloc);
854}
855
856tcu::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 = (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