1 /*
2  * Copyright 2014 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 /** @file simple.c
25  *
26  * A simple test of glCopyImageSubData that copies a square from one
27  * 2D texture to another and back.  This test exercises texture to texture,
28  * texture to renderbuffer, renderbuffer to texture, and renderbuffer to
29  * renderbuffer copies.
30  */
31 #include "piglit-util-gl.h"
32 
33 PIGLIT_GL_TEST_CONFIG_BEGIN
34 
35 	config.supports_gl_compat_version = 13;
36 	config.khr_no_error_support = PIGLIT_HAS_ERRORS;
37 
38 PIGLIT_GL_TEST_CONFIG_END
39 
40 #define ARRAY_LENGTH(X) (sizeof(X)/sizeof(*(X)))
41 
42 void
piglit_init(int argc,char ** argv)43 piglit_init(int argc, char **argv)
44 {
45 	piglit_require_extension("GL_ARB_copy_image");
46 	piglit_require_extension("GL_EXT_framebuffer_object");
47 }
48 
49 static GLuint
image_create(GLenum target)50 image_create(GLenum target)
51 {
52 	GLuint name;
53 	if (target == GL_RENDERBUFFER_EXT)
54 		glGenRenderbuffers(1, &name);
55 	else
56 		glGenTextures(1, &name);
57 	return name;
58 }
59 
60 static void
image_delete(GLenum target,GLuint name)61 image_delete(GLenum target, GLuint name)
62 {
63 	if (target == GL_RENDERBUFFER_EXT)
64 		glDeleteRenderbuffers(1, &name);
65 	else
66 		glDeleteTextures(1, &name);
67 }
68 
69 static void
image_storage(GLenum target,GLuint name,GLenum internal_format,GLsizei width,GLsizei height)70 image_storage(GLenum target, GLuint name, GLenum internal_format,
71 	      GLsizei width, GLsizei height)
72 {
73 	if (target == GL_RENDERBUFFER_EXT) {
74 		glBindRenderbuffer(target, name);
75 		glRenderbufferStorage(target, internal_format, width, height);
76 	} else {
77 		glBindTexture(target, name);
78 		glTexStorage2D(target, 4, internal_format, width, height);
79 	}
80 }
81 
82 /* only testing legal targets below */
83 static const GLenum targets[] = {
84 	GL_TEXTURE_1D,
85 	GL_TEXTURE_1D_ARRAY,
86 	GL_TEXTURE_2D,
87 	GL_TEXTURE_RECTANGLE,
88 	GL_TEXTURE_2D_ARRAY,
89 	GL_TEXTURE_2D_MULTISAMPLE,
90 	GL_TEXTURE_2D_MULTISAMPLE_ARRAY,
91 	GL_TEXTURE_CUBE_MAP,
92 	GL_TEXTURE_CUBE_MAP_ARRAY,
93 	GL_TEXTURE_3D
94 };
95 
96 static bool
test_simple_errors(GLenum src_target,GLenum dst_target)97 test_simple_errors(GLenum src_target, GLenum dst_target)
98 {
99 	bool pass = true;
100 	GLuint i, src, src2, dst;
101 
102 	src = image_create(src_target);
103 	dst = image_create(dst_target);
104 
105 	/* Test all three combinations of incomplete src or dst  */
106 	glCopyImageSubData(src, src_target, 0, 0, 0, 0,
107 			   dst, dst_target, 0, 0, 0, 0, 0, 0, 0);
108 	pass &= piglit_check_gl_error(GL_INVALID_OPERATION);
109 
110 	image_storage(src_target, src, GL_RGBA8, 32, 32);
111 	assert(piglit_check_gl_error(GL_NO_ERROR));
112 
113 	glCopyImageSubData(src, src_target, 0, 0, 0, 0,
114 			   dst, dst_target, 0, 0, 0, 0, 0, 0, 0);
115 	pass &= piglit_check_gl_error(GL_INVALID_OPERATION);
116 
117 	image_storage(dst_target, dst, GL_RGBA8, 32, 32);
118 	assert(piglit_check_gl_error(GL_NO_ERROR));
119 
120 	/* We want to test with empty src but valid dst */
121 	src2 = image_create(src_target);
122 
123 	glCopyImageSubData(src2, src_target, 0, 0, 0, 0,
124 			   dst, dst_target, 0, 0, 0, 0, 0, 0, 0);
125 	pass &= piglit_check_gl_error(GL_INVALID_OPERATION);
126 
127 	/* This is no longer needed */
128 	image_delete(src_target, src2);
129 
130 	/* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core
131 	 * Profile spec says:
132 	 *
133 	 *     "An INVALID_ENUM error is generated if either target is
134 	 *      not RENDERBUFFER or a valid non-proxy texture target;
135 	 *      is TEXTURE_BUFFER or one of the cubemap face selectors
136 	 *      described in table 8.18; or if the target does not
137 	 *      match the type of the object."
138 	 */
139 	if (src_target != GL_RENDERBUFFER_EXT) {
140 		for (i = 0; i < ARRAY_LENGTH(targets); ++i) {
141 			if (targets[i] == src_target)
142 				continue;
143 
144 			/* here, targets[i] doesn't match src object's target */
145 			glCopyImageSubData(src, targets[i], 0, 0, 0, 0,
146 					   dst, dst_target, 0, 0, 0, 0,
147 					   0, 0, 0);
148 			pass &= piglit_check_gl_error(GL_INVALID_ENUM);
149 			if (!pass)
150 				return false;
151 		}
152 	}
153 
154 	/* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core
155 	 * Profile spec says:
156 	 *
157 	 *     "An INVALID_ENUM error is generated if either target is
158 	 *      not RENDERBUFFER or a valid non-proxy texture target;
159 	 *      is TEXTURE_BUFFER or one of the cubemap face selectors
160 	 *      described in table 8.18; or if the target does not
161 	 *      match the type of the object."
162 	 */
163 	if (dst_target != GL_RENDERBUFFER_EXT) {
164 		for (i = 0; i < ARRAY_LENGTH(targets); ++i) {
165 			if (targets[i] == dst_target)
166 				continue;
167 
168 			/* here, targets[i] doesn't match dst object's target */
169 			glCopyImageSubData(src, src_target, 0, 0, 0, 0,
170 					   dst, targets[i], 0, 0, 0, 0,
171 					   0, 0, 0);
172 			pass &= piglit_check_gl_error(GL_INVALID_ENUM);
173 			if (!pass)
174 				return false;
175 		}
176 	}
177 
178 	/* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core
179 	 * Profile spec says:
180 	 *
181 	 *     "An INVALID_VALUE error is generated if either name does not
182 	 *     correspond to a valid renderbuffer or texture object according
183 	 *     to the corresponding target parameter."
184 	 */
185 	/* 4523 should be a bogus renderbuffer/texture */
186 	glCopyImageSubData(4523, src_target, 0, 0, 0, 0,
187 			   dst, dst_target, 0, 0, 0, 0, 0, 0, 0);
188 	pass &= piglit_check_gl_error(GL_INVALID_VALUE);
189 	glCopyImageSubData(src, src_target, 0, 0, 0, 0,
190 			   4523, dst_target, 0, 0, 0, 0, 0, 0, 0);
191 	pass &= piglit_check_gl_error(GL_INVALID_VALUE);
192 
193 	/* Invalid level */
194 	glCopyImageSubData(src, src_target, 5, 0, 0, 0,
195 			   dst, dst_target, 0, 0, 0, 0, 0, 0, 0);
196 	pass &= piglit_check_gl_error(GL_INVALID_VALUE);
197 	glCopyImageSubData(src, src_target, 0, 0, 0, 0,
198 			   dst, dst_target, 5, 0, 0, 0, 0, 0, 0);
199 	pass &= piglit_check_gl_error(GL_INVALID_VALUE);
200 
201 	/* Region out of bounds */
202 	glCopyImageSubData(src, src_target, 0, 7, 5, 2,
203 			   dst, dst_target, 0, 0, 0, 0, 26, 25, 20);
204 	pass &= piglit_check_gl_error(GL_INVALID_VALUE);
205 	glCopyImageSubData(src, src_target, 0, 7, 5, 2,
206 			   dst, dst_target, 0, 0, 0, 0, 25, 30, 20);
207 	pass &= piglit_check_gl_error(GL_INVALID_VALUE);
208 	glCopyImageSubData(src, src_target, 0, 7, 5, 2,
209 			   dst, dst_target, 0, 0, 0, 0, 25, 24, 31);
210 	pass &= piglit_check_gl_error(GL_INVALID_VALUE);
211 	glCopyImageSubData(src, src_target, 0, 0, 0, 0,
212 			   dst, dst_target, 0, 7, 5, 2, 26, 25, 20);
213 	pass &= piglit_check_gl_error(GL_INVALID_VALUE);
214 	glCopyImageSubData(src, src_target, 0, 0, 0, 0,
215 			   dst, dst_target, 0, 7, 5, 2, 25, 30, 20);
216 	pass &= piglit_check_gl_error(GL_INVALID_VALUE);
217 	glCopyImageSubData(src, src_target, 0, 0, 0, 0,
218 			   dst, dst_target, 0, 7, 5, 2, 25, 24, 31);
219 	pass &= piglit_check_gl_error(GL_INVALID_VALUE);
220 
221 	image_delete(src_target, src);
222 	image_delete(dst_target, dst);
223 
224 	return pass;
225 }
226 
227 static bool
test_compressed_alignment_errors()228 test_compressed_alignment_errors()
229 {
230 	bool pass = true;
231 	GLuint tex[4];
232 
233 	glGenTextures(4, tex);
234 
235 	glBindTexture(GL_TEXTURE_2D, tex[0]);
236 	glTexStorage2D(GL_TEXTURE_2D, 1,
237 		       GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 128, 128);
238 	glBindTexture(GL_TEXTURE_2D, tex[1]);
239 	glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA16UI, 32, 32);
240 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
241 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
242 			GL_NEAREST_MIPMAP_NEAREST);
243 
244 	/* Check for alignment constaints */
245 	/* bad width = 21 */
246 	glCopyImageSubData(tex[0], GL_TEXTURE_2D, 0, 0, 0, 0,
247 			   tex[1], GL_TEXTURE_2D, 0, 0, 0, 0, 21, 24, 1);
248 	pass &= piglit_check_gl_error(GL_INVALID_VALUE);
249 	/* bad height = 22 */
250 	glCopyImageSubData(tex[0], GL_TEXTURE_2D, 0, 0, 0, 0,
251 			   tex[1], GL_TEXTURE_2D, 0, 0, 0, 0, 20, 22, 1);
252 	pass &= piglit_check_gl_error(GL_INVALID_VALUE);
253 	/* bad srcX = 2 */
254 	glCopyImageSubData(tex[0], GL_TEXTURE_2D, 0, 2, 0, 0,
255 			   tex[1], GL_TEXTURE_2D, 0, 0, 0, 0, 20, 24, 1);
256 	pass &= piglit_check_gl_error(GL_INVALID_VALUE);
257 	/* bad srcY = 1 */
258 	glCopyImageSubData(tex[0], GL_TEXTURE_2D, 0, 0, 1, 0,
259 			   tex[1], GL_TEXTURE_2D, 0, 0, 0, 0, 20, 24, 1);
260 	pass &= piglit_check_gl_error(GL_INVALID_VALUE);
261 
262 	/* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core
263 	 * Profile spec says:
264 	 *
265 	 *     "An INVALID_OPERATION error is generated if the texel size of
266 	 *     the uncompressed image is not equal to the block size of the
267 	 *     compressed image."
268 	 */
269 	glBindTexture(GL_TEXTURE_2D, tex[2]);
270 	glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGB16UI, 32, 32);
271 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
272 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
273 			GL_NEAREST_MIPMAP_NEAREST);
274 	glCopyImageSubData(tex[0], GL_TEXTURE_2D, 0, 0, 0, 0,
275 			   tex[2], GL_TEXTURE_2D, 0, 0, 0, 0, 20, 20, 1);
276 	pass &= piglit_check_gl_error(GL_INVALID_OPERATION);
277 
278 	/* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core
279 	 * Profile spec says:
280 	 *
281 	 *     "An INVALID_OPERATION error is generated if the formats are
282 	 *     not compatible."
283 	 *
284 	 * The definition of compatible refers back to table 8.22 "Compatible
285 	 * internal formats for TextureView."  This table does not contain
286 	 * S3TC formats because they are from an older extension.  Given the
287 	 * different encodings of DXT1 and DXT3 textures, it is reasonable to
288 	 * assume they would not be compatible for texture views, and this
289 	 * matches at least NVIDIA's implementation.
290 	 */
291 	glBindTexture(GL_TEXTURE_2D, tex[3]);
292 	glTexStorage2D(GL_TEXTURE_2D, 1,
293 		       GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 32, 32);
294 	glCopyImageSubData(tex[0], GL_TEXTURE_2D, 0, 0, 0, 0,
295 			   tex[3], GL_TEXTURE_2D, 0, 0, 0, 0, 20, 20, 1);
296 	pass &= piglit_check_gl_error(GL_INVALID_OPERATION);
297 
298 	glDeleteTextures(4, tex);
299 
300 	return pass;
301 }
302 
303 enum piglit_result
piglit_display(void)304 piglit_display(void)
305 {
306 	bool pass = true;
307 
308 	pass &= test_simple_errors(GL_TEXTURE_2D, GL_TEXTURE_2D);
309 	pass &= test_simple_errors(GL_RENDERBUFFER, GL_TEXTURE_2D);
310 	pass &= test_simple_errors(GL_TEXTURE_2D, GL_RENDERBUFFER);
311 	pass &= test_simple_errors(GL_RENDERBUFFER, GL_RENDERBUFFER);
312 	if (piglit_is_extension_supported("GL_EXT_texture_compression_s3tc")) {
313 		pass &= test_compressed_alignment_errors();
314 	}
315 
316 	return pass ? PIGLIT_PASS : PIGLIT_FAIL;
317 }
318