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