es31cShaderImageSizeTests.cpp revision 84322c9402f810da3cd80b52e9f9ef72150a9004
1/*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2014-2016 The Khronos Group Inc.
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
22 */ /*-------------------------------------------------------------------*/
23
24#include "es31cShaderImageSizeTests.hpp"
25#include "gluContextInfo.hpp"
26#include "glwEnums.hpp"
27#include "tcuMatrix.hpp"
28#include "tcuRenderTarget.hpp"
29#include "tcuVectorUtil.hpp"
30#include <assert.h>
31#include <cstdarg>
32
33namespace glcts
34{
35using namespace glw;
36
37namespace
38{
39typedef tcu::Vec2  vec2;
40typedef tcu::Vec3  vec3;
41typedef tcu::Vec4  vec4;
42typedef tcu::IVec4 ivec4;
43typedef tcu::UVec4 uvec4;
44
45static tcu::TestLog* currentLog;
46void setOutput(tcu::TestLog& log)
47{
48	currentLog = &log;
49}
50
51void Output(const char* format, ...)
52{
53	va_list args;
54	va_start(args, format);
55
56	const int   MAX_OUTPUT_STRING_SIZE = 40000;
57	static char temp[MAX_OUTPUT_STRING_SIZE];
58
59	vsnprintf(temp, MAX_OUTPUT_STRING_SIZE - 1, format, args);
60	temp[MAX_OUTPUT_STRING_SIZE - 1] = '\0';
61
62	char* logLine = strtok(temp, "\n");
63	while (logLine != NULL)
64	{
65		currentLog->writeMessage(logLine);
66		logLine = strtok(NULL, "\n");
67	}
68	va_end(args);
69}
70
71const char* const kGLSLVer =
72	"#version 310 es\n" NL "precision highp float;" NL "precision highp int;" NL "precision highp image2D;" NL
73	"precision highp image3D;" NL "precision highp imageCube;" NL "precision highp image2DArray;" NL
74	"precision highp iimage2D;" NL "precision highp iimage3D;" NL "precision highp iimageCube;" NL
75	"precision highp iimage2DArray;" NL "precision highp uimage2D;" NL "precision highp uimage3D;" NL
76	"precision highp uimageCube;" NL "precision highp uimage2DArray;";
77
78class ShaderImageSizeBase : public glcts::SubcaseBase
79{
80public:
81	virtual std::string Title()
82	{
83		return NL "";
84	}
85	virtual std::string Purpose()
86	{
87		return NL "";
88	}
89	virtual std::string Method()
90	{
91		return NL "";
92	}
93	virtual std::string PassCriteria()
94	{
95		return NL "";
96	}
97	bool IsVSFSAvailable(int requiredVS, int requiredFS)
98	{
99		GLint imagesVS, imagesFS;
100		glGetIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &imagesVS);
101		glGetIntegerv(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, &imagesFS);
102		if (imagesVS >= requiredVS && imagesFS >= requiredFS)
103			return true;
104		else
105		{
106			std::ostringstream reason;
107			reason << "Required " << requiredVS << " VS storage blocks but only " << imagesVS << " available."
108				   << std::endl
109				   << "Required " << requiredFS << " FS storage blocks but only " << imagesFS << " available."
110				   << std::endl;
111			OutputNotSupported(reason.str());
112			return false;
113		}
114	}
115};
116
117template <typename T>
118std::string ImageTypePrefix();
119
120template <>
121std::string ImageTypePrefix<vec4>()
122{
123	return "";
124}
125
126template <>
127std::string ImageTypePrefix<ivec4>()
128{
129	return "i";
130}
131
132template <>
133std::string ImageTypePrefix<uvec4>()
134{
135	return "u";
136}
137
138template <typename T>
139std::string ImageFormatPostfix();
140
141template <>
142std::string ImageFormatPostfix<vec4>()
143{
144	return "f";
145}
146
147template <>
148std::string ImageFormatPostfix<ivec4>()
149{
150	return "i";
151}
152
153template <>
154std::string ImageFormatPostfix<uvec4>()
155{
156	return "ui";
157}
158
159template <typename T>
160GLenum TexInternalFormat();
161
162template <>
163GLenum TexInternalFormat<vec4>()
164{
165	return GL_RGBA32F;
166}
167
168template <>
169GLenum TexInternalFormat<ivec4>()
170{
171	return GL_RGBA32I;
172}
173
174template <>
175GLenum TexInternalFormat<uvec4>()
176{
177	return GL_RGBA32UI;
178}
179
180template <typename T>
181GLenum TexType();
182
183template <typename T>
184GLenum TexFormat();
185
186//=============================================================================
187// ImageSizeMachine
188//-----------------------------------------------------------------------------
189class ImageSizeMachine : public glcts::GLWrapper
190{
191	GLuint m_pipeline;
192	GLuint m_program[3];
193	GLuint m_vertex_array;
194	GLuint m_buffer;
195	bool   pipeline;
196	GLuint m_xfb_id;
197
198	bool CheckProgram(GLuint program)
199	{
200		if (program == 0)
201			return true;
202		GLint status;
203		glGetProgramiv(program, GL_LINK_STATUS, &status);
204
205		if (status == GL_FALSE)
206		{
207			GLint attached_shaders;
208			glGetProgramiv(program, GL_ATTACHED_SHADERS, &attached_shaders);
209
210			if (attached_shaders > 0)
211			{
212				std::vector<GLuint> shaders(attached_shaders);
213				glGetAttachedShaders(program, attached_shaders, NULL, &shaders[0]);
214
215				for (GLint i = 0; i < attached_shaders; ++i)
216				{
217					GLenum type;
218					glGetShaderiv(shaders[i], GL_SHADER_TYPE, reinterpret_cast<GLint*>(&type));
219					switch (type)
220					{
221					case GL_VERTEX_SHADER:
222						Output("*** Vertex Shader ***\n");
223						break;
224					case GL_FRAGMENT_SHADER:
225						Output("*** Fragment Shader ***\n");
226						break;
227					case GL_COMPUTE_SHADER:
228						Output("*** Compute Shader ***\n");
229						break;
230					default:
231						Output("*** Unknown Shader ***\n");
232						break;
233					}
234					GLint length;
235					glGetShaderiv(shaders[i], GL_SHADER_SOURCE_LENGTH, &length);
236					if (length > 0)
237					{
238						std::vector<GLchar> source(length);
239						glGetShaderSource(shaders[i], length, NULL, &source[0]);
240						Output("%s\n", &source[0]);
241					}
242					glGetShaderiv(shaders[i], GL_INFO_LOG_LENGTH, &length);
243					if (length > 0)
244					{
245						std::vector<GLchar> log(length);
246						glGetShaderInfoLog(shaders[i], length, NULL, &log[0]);
247						Output("%s\n", &log[0]);
248					}
249				}
250			}
251			GLint length;
252			glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
253			if (length > 0)
254			{
255				std::vector<GLchar> log(length);
256				glGetProgramInfoLog(program, length, NULL, &log[0]);
257				Output("%s\n", &log[0]);
258			}
259		}
260		return status == GL_TRUE ? true : false;
261	}
262
263	bool CompileShader(GLuint shader)
264	{
265		glCompileShader(shader);
266
267		GLint status;
268		glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
269		if (status == GL_FALSE)
270		{
271			GLsizei length;
272			GLchar  log[1024];
273			glGetShaderInfoLog(shader, sizeof(log), &length, log);
274			if (length > 1)
275			{
276				Output("Shader Info Log:\n%s\n", log);
277			}
278			return false;
279		}
280		return true;
281	}
282
283	bool LinkProgram(GLuint program)
284	{
285		glLinkProgram(program);
286
287		GLint status;
288		glGetProgramiv(program, GL_LINK_STATUS, &status);
289		if (status == GL_FALSE)
290		{
291			GLsizei length;
292			GLchar  log[1024];
293			glGetProgramInfoLog(program, sizeof(log), &length, log);
294			if (length > 1)
295			{
296				Output("Program Info Log:\n%s\n", log);
297			}
298			return false;
299		}
300		return true;
301	}
302
303	GLuint CreateComputeProgram(const std::string& cs)
304	{
305		const GLuint p = glCreateProgram();
306
307		if (!cs.empty())
308		{
309			const GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
310			glAttachShader(p, sh);
311			glDeleteShader(sh);
312			const char* const src[2] = { kGLSLVer, cs.c_str() };
313			glShaderSource(sh, 2, src, NULL);
314			if (!CompileShader(sh))
315			{
316				Output("%s%s\n", src[0], src[1]);
317				return p;
318			}
319		}
320		if (!LinkProgram(p))
321		{
322			if (!cs.empty())
323				Output("%s%s\n", kGLSLVer, cs.c_str());
324			return p;
325		}
326
327		return p;
328	}
329
330	GLuint BuildProgram(const char* src_vs, const char* src_fs, bool use_xfb, bool* result = NULL)
331	{
332		const GLuint p = glCreateProgram();
333
334		if (src_vs)
335		{
336			GLuint sh = glCreateShader(GL_VERTEX_SHADER);
337			glAttachShader(p, sh);
338			glDeleteShader(sh);
339			const char* const src[2] = { kGLSLVer, src_vs };
340			glShaderSource(sh, 2, src, NULL);
341			if (!CompileShader(sh))
342			{
343				Output("%s%s\n", src[0], src[1]);
344				if (result)
345					*result = false;
346				return p;
347			}
348		}
349		if (src_fs)
350		{
351			GLuint sh = glCreateShader(GL_FRAGMENT_SHADER);
352			glAttachShader(p, sh);
353			glDeleteShader(sh);
354			const char* const src[2] = { kGLSLVer, src_fs };
355			glShaderSource(sh, 2, src, NULL);
356			if (!CompileShader(sh))
357			{
358				Output("%s%s\n", src[0], src[1]);
359				if (result)
360					*result = false;
361				return p;
362			}
363		}
364		if (use_xfb)
365			SetupTransformFeedback(p);
366		if (!LinkProgram(p))
367		{
368			if (src_vs)
369				Output("%s%s\n", kGLSLVer, src_vs);
370			if (src_fs)
371				Output("%s%s\n", kGLSLVer, src_fs);
372			if (result)
373				*result = false;
374			return p;
375		}
376
377		return p;
378	}
379
380	void SetupTransformFeedback(GLuint program)
381	{
382		const char* const varying_name[] = { "count[0]", "count[1]", "count[2]", "count[3]" };
383		glTransformFeedbackVaryings(program, 4, varying_name, GL_INTERLEAVED_ATTRIBS);
384	}
385
386	inline bool Equal(const ivec4& result, const ivec4& expected)
387	{
388		if (expected[0] != result[0])
389			return false;
390		if (expected[1] != result[1])
391			return false;
392		if (expected[2] != result[2])
393			return false;
394		if (expected[3] != result[3])
395			return false;
396		return true;
397	}
398
399	template <typename T>
400	std::string GenShader(int stage)
401	{
402		std::ostringstream os;
403		os << NL "#define KSIZE 4";
404		if (stage == 0)
405		{ // VS uses transform feedback
406			os << NL "flat out ivec4 count[KSIZE];";
407		}
408		else
409		{ // CS + FS use SSBO
410			os << NL "layout(std430) buffer OutputBuffer {" NL "  ivec4 count[KSIZE];" NL "};";
411		}
412		os << NL "layout(binding = 0, rgba32" << ImageFormatPostfix<T>() << ") readonly writeonly uniform highp "
413		   << ImageTypePrefix<T>() << "image2D g_image_2d;" NL "layout(binding = 1, rgba32" << ImageFormatPostfix<T>()
414		   << ") readonly writeonly uniform highp " << ImageTypePrefix<T>()
415		   << "image3D g_image_3d;" NL "layout(binding = 2, rgba32" << ImageFormatPostfix<T>()
416		   << ") readonly writeonly uniform highp " << ImageTypePrefix<T>()
417		   << "imageCube g_image_cube;" NL "layout(binding = 3, rgba32" << ImageFormatPostfix<T>()
418		   << ") readonly writeonly uniform highp " << ImageTypePrefix<T>() << "image2DArray g_image_2d_array;";
419		if (stage == 0)
420		{ // VS
421			os << NL "void main() {" NL "  int coord = gl_VertexID;" NL "#ifdef GL_ES" NL "  gl_PointSize = 1.0;" NL
422					 "#endif";
423		}
424		else if (stage == 4)
425		{ // CS
426			os << NL "layout(local_size_x = 1) in;" NL "void main() {" NL "  int coord = int(gl_GlobalInvocationID.x);";
427		}
428		else if (stage == 5)
429		{ // FS
430			os << NL "uniform int fakePrimitiveID;" NL "void main() {" NL "  int coord = fakePrimitiveID;";
431		}
432		os << NL "  count[coord + 0] = ivec4(imageSize(g_image_2d), 0, 0);" NL
433				 "  count[coord + 1] = ivec4(imageSize(g_image_3d), 0);" NL
434				 "  count[coord + 2] = ivec4(imageSize(g_image_cube), 0, 0);" NL
435				 "  count[coord + 3] = ivec4(imageSize(g_image_2d_array), 0);" NL "}";
436		return os.str();
437	}
438
439public:
440	ImageSizeMachine() : pipeline(false)
441	{
442		if (pipeline)
443			glGenProgramPipelines(1, &m_pipeline);
444		memset(m_program, 0, sizeof(m_program));
445		glGenVertexArrays(1, &m_vertex_array);
446		glGenBuffers(1, &m_buffer);
447		glGenTransformFeedbacks(1, &m_xfb_id);
448	}
449
450	~ImageSizeMachine()
451	{
452		if (pipeline)
453		{
454			glDeleteProgramPipelines(1, &m_pipeline);
455			for (int i = 0; i < 3; ++i)
456				glDeleteProgram(m_program[i]);
457		}
458		else
459		{
460			glDeleteProgram(m_program[0]);
461		}
462		glDeleteVertexArrays(1, &m_vertex_array);
463		glDeleteBuffers(1, &m_buffer);
464		glDeleteTransformFeedbacks(1, &m_xfb_id);
465	}
466
467	template <typename T>
468	long Run(int stage, ivec4 expected_result[4])
469	{
470		const int kSize = 4;
471		if (stage == 0)
472		{ // VS
473			glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_xfb_id);
474			const char* const glsl_fs = NL "void main() {" NL "  discard;" NL "}";
475			std::string		  vs	  = GenShader<T>(stage);
476			const char* const glsl_vs = vs.c_str();
477			if (pipeline)
478			{
479				m_program[0] = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &glsl_vs);
480				m_program[1] = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &glsl_fs);
481				glUseProgramStages(m_pipeline, GL_VERTEX_SHADER_BIT, m_program[0]);
482				glUseProgramStages(m_pipeline, GL_FRAGMENT_SHADER_BIT, m_program[1]);
483			}
484			else
485			{
486				m_program[0] = BuildProgram(glsl_vs, glsl_fs, true);
487			}
488		}
489		else if (stage == 4)
490		{ // CS
491			std::string		  cs	  = GenShader<T>(stage);
492			const char* const glsl_cs = cs.c_str();
493			if (pipeline)
494			{
495				m_program[0] = glCreateShaderProgramv(GL_COMPUTE_SHADER, 1, &glsl_cs);
496				glUseProgramStages(m_pipeline, GL_COMPUTE_SHADER_BIT, m_program[0]);
497			}
498			else
499			{
500				m_program[0] = CreateComputeProgram(glsl_cs);
501			}
502		}
503		else if (stage == 5)
504		{ // FS
505			const char* const glsl_vs =
506				NL "layout(location = 0) in vec4 i_position;" NL "void main() {" NL "  gl_Position = i_position;" NL
507				   "#ifdef GL_ES" NL "  gl_PointSize = 1.0;" NL "#endif" NL "}";
508			std::string		  fs	  = GenShader<T>(stage);
509			const char* const glsl_fs = fs.c_str();
510			if (pipeline)
511			{
512				m_program[0] = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &glsl_vs);
513				m_program[1] = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &glsl_fs);
514				glUseProgramStages(m_pipeline, GL_VERTEX_SHADER_BIT, m_program[0]);
515				glUseProgramStages(m_pipeline, GL_FRAGMENT_SHADER_BIT, m_program[1]);
516			}
517			else
518			{
519				m_program[0] = BuildProgram(glsl_vs, glsl_fs, false);
520			}
521		}
522		if (!CheckProgram(m_program[0]))
523			return ERROR;
524		if (pipeline)
525			if (!CheckProgram(m_program[1]))
526				return ERROR;
527
528		ivec4 data[kSize];
529		for (int i  = 0; i < kSize; ++i)
530			data[i] = ivec4(100000);
531
532		GLenum output_buffer_type = (stage == 0) ? GL_TRANSFORM_FEEDBACK_BUFFER : GL_SHADER_STORAGE_BUFFER;
533
534		glBindBufferBase(output_buffer_type, 0, m_buffer);
535		glBufferData(output_buffer_type, kSize * 4 * 4, &data[0], GL_STATIC_DRAW);
536
537		if (pipeline)
538			glBindProgramPipeline(m_pipeline);
539		else
540			glUseProgram(m_program[0]);
541		glBindVertexArray(m_vertex_array);
542
543		if (stage == 0)
544			glBeginTransformFeedback(GL_POINTS);
545
546		if (stage == 4)
547			glDispatchCompute(1, 1, 1);
548		else
549			glDrawArrays(GL_POINTS, 0, 1);
550
551		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
552
553		if (stage == 0)
554			glEndTransformFeedback();
555
556		ivec4* map_data = (ivec4*)glMapBufferRange(output_buffer_type, 0, kSize * 4 * 4, GL_MAP_READ_BIT);
557		for (int i = 0; i < kSize; ++i)
558		{
559			if (!Equal(map_data[i], expected_result[i]))
560			{
561				Output("Returned value is: (%d %d %d %d). Expected value is: (%d %d %d %d). Image unit is: %d.\n",
562					   map_data[i][0], map_data[i][1], map_data[i][2], map_data[i][3], expected_result[i][0],
563					   expected_result[i][1], expected_result[i][2], expected_result[i][3], i);
564				return ERROR;
565			}
566		}
567		glUnmapBuffer(output_buffer_type);
568
569		if (stage == 0)
570			glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
571
572		return NO_ERROR;
573	}
574};
575
576//=============================================================================
577// 1.1.x.y BasicNonMS
578//-----------------------------------------------------------------------------
579template <typename T, int STAGE>
580class BasicNonMS : public ShaderImageSizeBase
581{
582	GLuint m_texture[4];
583
584	virtual long Setup()
585	{
586		glGenTextures(4, m_texture);
587		return NO_ERROR;
588	}
589	virtual long Run()
590	{
591		if (STAGE == 0 && !IsVSFSAvailable(4, 0))
592			return NOT_SUPPORTED;
593		if (STAGE == 5 && !IsVSFSAvailable(0, 4))
594			return NOT_SUPPORTED;
595
596		const GLenum target[4] = { GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_2D_ARRAY };
597		for (int i = 0; i < 4; ++i)
598		{
599			glBindTexture(target[i], m_texture[i]);
600			glTexParameteri(target[i], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
601			glTexParameteri(target[i], GL_TEXTURE_MAG_FILTER, GL_NEAREST);
602
603			if (i == 0)
604			{
605				glTexStorage2D(target[i], 10, TexInternalFormat<T>(), 512, 128);
606				glBindImageTexture(0, m_texture[i], 1, GL_FALSE, 0, GL_READ_ONLY, TexInternalFormat<T>());
607			}
608			else if (i == 1)
609			{
610				glTexStorage3D(target[i], 3, TexInternalFormat<T>(), 8, 8, 4);
611				glBindImageTexture(1, m_texture[i], 0, GL_TRUE, 0, GL_READ_ONLY, TexInternalFormat<T>());
612			}
613			else if (i == 2)
614			{
615				glTexStorage2D(target[i], 4, TexInternalFormat<T>(), 16, 16);
616				glBindImageTexture(2, m_texture[i], 0, GL_TRUE, 0, GL_READ_WRITE, TexInternalFormat<T>());
617			}
618			else if (i == 3)
619			{
620				glTexStorage3D(target[i], 3, TexInternalFormat<T>(), 127, 39, 12);
621				glBindImageTexture(3, m_texture[i], 2, GL_TRUE, 0, GL_READ_ONLY, TexInternalFormat<T>());
622			}
623		}
624		ImageSizeMachine machine;
625		ivec4			 res[4] = { ivec4(256, 64, 0, 0), ivec4(8, 8, 4, 0), ivec4(16, 16, 0, 0), ivec4(31, 9, 12, 0) };
626		return machine.Run<T>(STAGE, res);
627	}
628	virtual long Cleanup()
629	{
630		glDeleteTextures(4, m_texture);
631		return NO_ERROR;
632	}
633};
634//=============================================================================
635// 2.2.x.y AdvancedNonMS
636//-----------------------------------------------------------------------------
637template <typename T, int STAGE>
638class AdvancedNonMS : public ShaderImageSizeBase
639{
640	GLuint m_texture[4];
641
642	virtual long Setup()
643	{
644		glGenTextures(4, m_texture);
645		return NO_ERROR;
646	}
647	virtual long Run()
648	{
649		if (STAGE == 0 && !IsVSFSAvailable(4, 0))
650			return NOT_SUPPORTED;
651		if (STAGE == 5 && !IsVSFSAvailable(0, 4))
652			return NOT_SUPPORTED;
653
654		const GLenum target[4] = { GL_TEXTURE_2D_ARRAY, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_2D_ARRAY };
655		for (int i = 0; i < 4; ++i)
656		{
657			glBindTexture(target[i], m_texture[i]);
658			glTexParameteri(target[i], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
659			glTexParameteri(target[i], GL_TEXTURE_MAG_FILTER, GL_NEAREST);
660
661			if (i == 0)
662			{
663				glTexStorage3D(target[i], 2, TexInternalFormat<T>(), 2, 2, 7);
664				glBindImageTexture(0, m_texture[i], 1, GL_FALSE, 3, GL_READ_ONLY, TexInternalFormat<T>());
665			}
666			else if (i == 1)
667			{
668				glTexStorage3D(target[i], 3, TexInternalFormat<T>(), 4, 4, 2);
669				glBindImageTexture(1, m_texture[i], 1, GL_TRUE, 0, GL_READ_ONLY, TexInternalFormat<T>());
670			}
671			else if (i == 2)
672			{
673				glTexStorage2D(target[i], 2, TexInternalFormat<T>(), 2, 2);
674				glBindImageTexture(2, m_texture[i], 0, GL_TRUE, 0, GL_READ_WRITE, TexInternalFormat<T>());
675			}
676			else if (i == 3)
677			{
678				glTexStorage3D(target[i], 4, TexInternalFormat<T>(), 13, 7, 4);
679				glBindImageTexture(3, m_texture[i], 1, GL_TRUE, 0, GL_READ_ONLY, TexInternalFormat<T>());
680			}
681		}
682		ImageSizeMachine machine;
683		ivec4			 res[4] = { ivec4(1, 1, 0, 0), ivec4(2, 2, 1, 0), ivec4(2, 2, 0, 0), ivec4(6, 3, 4, 0) };
684		return machine.Run<T>(STAGE, res);
685	}
686	virtual long Cleanup()
687	{
688		glDeleteTextures(4, m_texture);
689		return NO_ERROR;
690	}
691};
692//=============================================================================
693// 4.1 NegativeCompileTime
694//-----------------------------------------------------------------------------
695class NegativeCompileTime : public ShaderImageSizeBase
696{
697	virtual long Run()
698	{
699		if (!Compile( // imagesize return type check
700				"#version 310 es" NL "precision highp float;" NL "precision highp int;" NL
701				"layout(local_size_x = 1) in;" NL "layout(r32f) uniform image2D g_image;" NL
702				"layout(std430) buffer OutputBuffer { vec4 g_color; };" NL "void main() {" NL
703				"  if (imageSize(g_image) == ivec3(5)) g_color = vec4(0, 1, 0, 1);" NL
704				"  else g_color = vec4(1, 0, 0, 1);" NL "}"))
705		{
706			return ERROR;
707		}
708		if (!Compile( // imageSize(samplertype)
709				"#version 310 es" NL "precision highp float;" NL "precision highp int;" NL
710				"layout(local_size_x = 1) in;" NL "layout(r32f) uniform sampler2D g_image;" NL
711				"layout(std430) buffer OutputBuffer { vec4 g_color; };" NL "void main() {" NL
712				"  if (imageSize(g_image) == ivec2(5)) g_color = vec4(0, 1, 0, 1);" NL
713				"  else g_color = vec4(1, 0, 0, 1);" NL "}"))
714		{
715			return ERROR;
716		}
717		return NO_ERROR;
718	}
719
720	bool Compile(const std::string& source)
721	{
722		const GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
723
724		const char* const src = source.c_str();
725		glShaderSource(sh, 1, &src, NULL);
726		glCompileShader(sh);
727
728		GLchar log[1024];
729		glGetShaderInfoLog(sh, sizeof(log), NULL, log);
730		Output("Shader Info Log:\n%s\n", log);
731
732		GLint status;
733		glGetShaderiv(sh, GL_COMPILE_STATUS, &status);
734		glDeleteShader(sh);
735
736		if (status == GL_TRUE)
737		{
738			Output("Compilation should fail.\n");
739			return false;
740		}
741		return true;
742	}
743};
744
745} // anonymous namespace
746
747ShaderImageSizeTests::ShaderImageSizeTests(glcts::Context& context) : TestCaseGroup(context, "shader_image_size", "")
748{
749}
750
751ShaderImageSizeTests::~ShaderImageSizeTests(void)
752{
753}
754
755void ShaderImageSizeTests::init()
756{
757	using namespace glcts;
758	setOutput(m_context.getTestContext().getLog());
759	addChild(new TestSubcase(m_context, "basic-nonMS-vs-float", TestSubcase::Create<BasicNonMS<vec4, 0> >));
760	addChild(new TestSubcase(m_context, "basic-nonMS-vs-int", TestSubcase::Create<BasicNonMS<ivec4, 0> >));
761	addChild(new TestSubcase(m_context, "basic-nonMS-vs-uint", TestSubcase::Create<BasicNonMS<uvec4, 0> >));
762	addChild(new TestSubcase(m_context, "basic-nonMS-fs-float", TestSubcase::Create<BasicNonMS<vec4, 5> >));
763	addChild(new TestSubcase(m_context, "basic-nonMS-fs-int", TestSubcase::Create<BasicNonMS<ivec4, 5> >));
764	addChild(new TestSubcase(m_context, "basic-nonMS-fs-uint", TestSubcase::Create<BasicNonMS<uvec4, 5> >));
765	addChild(new TestSubcase(m_context, "basic-nonMS-cs-float", TestSubcase::Create<BasicNonMS<vec4, 4> >));
766	addChild(new TestSubcase(m_context, "basic-nonMS-cs-int", TestSubcase::Create<BasicNonMS<ivec4, 4> >));
767	addChild(new TestSubcase(m_context, "basic-nonMS-cs-uint", TestSubcase::Create<BasicNonMS<uvec4, 4> >));
768	addChild(new TestSubcase(m_context, "advanced-nonMS-vs-float", TestSubcase::Create<AdvancedNonMS<vec4, 0> >));
769	addChild(new TestSubcase(m_context, "advanced-nonMS-vs-int", TestSubcase::Create<AdvancedNonMS<ivec4, 0> >));
770	addChild(new TestSubcase(m_context, "advanced-nonMS-vs-uint", TestSubcase::Create<AdvancedNonMS<uvec4, 0> >));
771	addChild(new TestSubcase(m_context, "advanced-nonMS-fs-float", TestSubcase::Create<AdvancedNonMS<vec4, 5> >));
772	addChild(new TestSubcase(m_context, "advanced-nonMS-fs-int", TestSubcase::Create<AdvancedNonMS<ivec4, 5> >));
773	addChild(new TestSubcase(m_context, "advanced-nonMS-fs-uint", TestSubcase::Create<AdvancedNonMS<uvec4, 5> >));
774	addChild(new TestSubcase(m_context, "advanced-nonMS-cs-float", TestSubcase::Create<AdvancedNonMS<vec4, 4> >));
775	addChild(new TestSubcase(m_context, "advanced-nonMS-cs-int", TestSubcase::Create<AdvancedNonMS<ivec4, 4> >));
776	addChild(new TestSubcase(m_context, "advanced-nonMS-cs-uint", TestSubcase::Create<AdvancedNonMS<uvec4, 4> >));
777	addChild(new TestSubcase(m_context, "negative-compileTime", TestSubcase::Create<NegativeCompileTime>));
778}
779}
780