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