1 /*
2 * Copyright (c) 2010 VMware, Inc.
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 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the 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,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NON-INFRINGEMENT. IN NO EVENT SHALL VMWARE AND/OR THEIR SUPPLIERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25 /**
26 * @file
27 * Tests FBO rendering with GL_EXT_texture_integer and GL_EXT_gpu_shader4.
28 */
29
30
31 #include "piglit-util-gl.h"
32
33 PIGLIT_GL_TEST_CONFIG_BEGIN
34
35 config.supports_gl_compat_version = 10;
36
37 config.window_visual = PIGLIT_GL_VISUAL_RGBA | PIGLIT_GL_VISUAL_DOUBLE;
38 config.khr_no_error_support = PIGLIT_NO_ERRORS;
39
40 PIGLIT_GL_TEST_CONFIG_END
41
42 static const char *TestName = "texture-integer";
43
44 static GLint TexWidth = 256, TexHeight = 256;
45
46 struct format_info
47 {
48 GLenum IntFormat, BaseFormat;
49 GLuint BitsPerChannel;
50 GLboolean Signed;
51 };
52
53
54 static const struct format_info Formats[] = {
55 /* { "GL_RGBA", GL_RGBA, GL_RGBA, 8, GL_FALSE },*/
56 { GL_RGBA8I_EXT, GL_RGBA_INTEGER_EXT, 8, GL_TRUE },
57 { GL_RGBA8UI_EXT , GL_RGBA_INTEGER_EXT, 8, GL_FALSE },
58 { GL_RGBA16I_EXT, GL_RGBA_INTEGER_EXT, 16, GL_TRUE },
59 { GL_RGBA16UI_EXT, GL_RGBA_INTEGER_EXT, 16, GL_FALSE },
60 { GL_RGBA32I_EXT, GL_RGBA_INTEGER_EXT, 32, GL_TRUE },
61 { GL_RGBA32UI_EXT, GL_RGBA_INTEGER_EXT, 32, GL_FALSE },
62
63 { GL_RGB8I_EXT, GL_RGB_INTEGER_EXT, 8, GL_TRUE },
64 { GL_RGB8UI_EXT , GL_RGB_INTEGER_EXT, 8, GL_FALSE },
65 { GL_RGB16I_EXT, GL_RGB_INTEGER_EXT, 16, GL_TRUE },
66 { GL_RGB16UI_EXT, GL_RGB_INTEGER_EXT, 16, GL_FALSE },
67 { GL_RGB32I_EXT, GL_RGB_INTEGER_EXT, 32, GL_TRUE },
68 { GL_RGB32UI_EXT, GL_RGB_INTEGER_EXT, 32, GL_FALSE },
69 };
70
71 #define NUM_FORMATS (sizeof(Formats) / sizeof(Formats[0]))
72
73 /* Need to declare an ivec4-valued output variable for rendering to
74 * an integer-valued color buffer.
75 */
76 static const char *SimpleFragShaderText =
77 "#version 130 \n"
78 "#extension GL_EXT_gpu_shader4: enable \n"
79 "uniform ivec4 value; \n"
80 "out ivec4 out_color; \n"
81 "void main() \n"
82 "{ \n"
83 " out_color = value; \n"
84 "} \n";
85
86 static GLuint SimpleFragShader, SimpleProgram;
87
88
89 /* For glDrawPixels */
90 static const char *PassthroughFragShaderText =
91 "void main() \n"
92 "{ \n"
93 " gl_FragColor = gl_Color; \n"
94 "} \n";
95
96 static GLuint PassthroughFragShader, PassthroughProgram;
97
98
99
100 static int
get_max_val(const struct format_info * info)101 get_max_val(const struct format_info *info)
102 {
103 int max;
104
105 switch (info->BitsPerChannel) {
106 case 8:
107 if (info->Signed)
108 max = 127;
109 else
110 max = 255;
111 break;
112 case 16:
113 if (info->Signed)
114 max = 32767;
115 else
116 max = 65535;
117 break;
118 case 32:
119 if (info->Signed)
120 max = 10*1000; /* don't use 0x8fffffff to avoid overflow issues */
121 else
122 max = 20*1000;
123 break;
124 default:
125 assert(0);
126 max = 0;
127 }
128
129 return max;
130 }
131
132
133 static int
num_components(GLenum format)134 num_components(GLenum format)
135 {
136 switch (format) {
137 case GL_RGBA:
138 case GL_RGBA_INTEGER_EXT:
139 return 4;
140 case GL_RGB_INTEGER_EXT:
141 return 3;
142 case GL_ALPHA_INTEGER_EXT:
143 return 1;
144 case GL_LUMINANCE_INTEGER_EXT:
145 return 1;
146 case GL_LUMINANCE_ALPHA_INTEGER_EXT:
147 return 2;
148 case GL_RED_INTEGER_EXT:
149 return 1;
150 default:
151 assert(0);
152 return 0;
153 }
154 }
155
156
157 static GLenum
get_datatype(const struct format_info * info)158 get_datatype(const struct format_info *info)
159 {
160 switch (info->BitsPerChannel) {
161 case 8:
162 return info->Signed ? GL_BYTE : GL_UNSIGNED_BYTE;
163 case 16:
164 return info->Signed ? GL_SHORT : GL_UNSIGNED_SHORT;
165 case 32:
166 return info->Signed ? GL_INT : GL_UNSIGNED_INT;
167 default:
168 assert(0);
169 return 0;
170 }
171 }
172
173
174 static GLboolean
check_error(const char * file,int line)175 check_error(const char *file, int line)
176 {
177 GLenum err = glGetError();
178 if (err) {
179 fprintf(stderr, "%s: error 0x%x at %s:%d\n", TestName, err, file, line);
180 return GL_TRUE;
181 }
182 return GL_FALSE;
183 }
184
185
186 /** \return GL_TRUE for pass, GL_FALSE for fail */
187 static GLboolean
test_fbo(const struct format_info * info)188 test_fbo(const struct format_info *info)
189 {
190 const int max = get_max_val(info);
191 const int comps = num_components(info->BaseFormat);
192 const GLenum type = get_datatype(info);
193 const char *name = piglit_get_gl_enum_name(info->IntFormat);
194 GLint f;
195 GLuint fbo, texObj;
196 GLenum status;
197 GLboolean intMode;
198 GLint buf;
199
200 if (0)
201 fprintf(stderr, "============ Testing format = %s ========\n", name);
202
203 /* Create texture */
204 glGenTextures(1, &texObj);
205 glBindTexture(GL_TEXTURE_2D, texObj);
206 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
207 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
208
209 glTexImage2D(GL_TEXTURE_2D, 0, info->IntFormat, TexWidth, TexHeight, 0,
210 info->BaseFormat, type, NULL);
211
212 if (check_error(__FILE__, __LINE__))
213 return GL_FALSE;
214
215 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &f);
216 assert(f == info->IntFormat);
217
218
219 /* Create FBO to render to texture */
220 glGenFramebuffers(1, &fbo);
221 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
222 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
223 GL_TEXTURE_2D, texObj, 0);
224
225 if (check_error(__FILE__, __LINE__))
226 return GL_FALSE;
227
228 status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
229 if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
230 fprintf(stderr, "%s: failure: framebuffer incomplete.\n", TestName);
231 return GL_FALSE;
232 }
233
234
235 glGetBooleanv(GL_RGBA_INTEGER_MODE_EXT, &intMode);
236 if (check_error(__FILE__, __LINE__))
237 return GL_FALSE;
238 if (!intMode) {
239 fprintf(stderr, "%s: GL_RGBA_INTEGER_MODE_EXT return GL_FALSE\n",
240 TestName);
241 return GL_FALSE;
242 }
243
244 glGetIntegerv(GL_READ_BUFFER, &buf);
245 assert(buf == GL_COLOR_ATTACHMENT0_EXT);
246 glGetIntegerv(GL_DRAW_BUFFER, &buf);
247 assert(buf == GL_COLOR_ATTACHMENT0_EXT);
248
249
250 /* test clearing */
251 if (1) {
252 static const GLint clr[4] = { 8, 7, 6, 5 };
253 GLint pix[4], i;
254
255 glClearColorIiEXT(clr[0], clr[1], clr[2], clr[3]);
256 glClear(GL_COLOR_BUFFER_BIT);
257
258 glReadPixels(5, 5, 1, 1, GL_RGBA_INTEGER_EXT, GL_INT, pix);
259
260 for (i = 0; i < comps; i++) {
261 if (pix[i] != clr[i]) {
262 fprintf(stderr, "%s: glClear failed\n", TestName);
263 fprintf(stderr, " Texture format = %s\n", name);
264 fprintf(stderr, " Expected %d, %d, %d, %d\n",
265 clr[0], clr[1], clr[2], clr[3]);
266 fprintf(stderr, " Found %d, %d, %d, %d\n",
267 pix[0], pix[1], pix[2], pix[3]);
268 return GL_FALSE;
269 }
270 }
271 }
272
273
274 /* Do glDraw/ReadPixels test */
275 if (1) {
276 #define W 15
277 #define H 10
278 GLint image[H * W * 4], readback[H * W * 4];
279 GLint i;
280
281 if (info->Signed) {
282 for (i = 0; i < W * H * 4; i++) {
283 image[i] = (i - 10) % max;
284 assert(image[i] < max);
285 }
286 }
287 else {
288 for (i = 0; i < W * H * 4; i++) {
289 image[i] = (i + 3) % max;
290 assert(image[i] < max);
291 }
292 }
293
294 glUseProgram(PassthroughProgram);
295 if(0)glUseProgram(SimpleProgram);
296
297 glWindowPos2i(1, 1);
298 glDrawPixels(W, H, GL_RGBA_INTEGER_EXT, GL_INT, image);
299
300 if (check_error(__FILE__, __LINE__))
301 return GL_FALSE;
302
303 glReadPixels(1, 1, W, H, GL_RGBA_INTEGER_EXT, GL_INT, readback);
304
305 if (check_error(__FILE__, __LINE__))
306 return GL_FALSE;
307
308 for (i = 0; i < W * H * 4; i++) {
309 if (readback[i] != image[i]) {
310 if (comps == 3 && i % 4 == 3 && readback[i] == 1)
311 continue; /* alpha = 1 if base format == RGB */
312
313 fprintf(stderr,
314 "%s: glDraw/ReadPixels failed at %d. Expected %d, found %d\n",
315 TestName, i, image[i], readback[i]);
316 fprintf(stderr, "Texture format = %s\n", name);
317 assert(0);
318 return GL_FALSE;
319 }
320 }
321 #undef W
322 #undef H
323 }
324
325 /* Do rendering test */
326 if (1) {
327 GLint value[4], result[4], loc, w = piglit_width, h = piglit_height;
328 GLint error = 1; /* XXX fix */
329
330 /* choose random value/color for polygon */
331 value[0] = rand() % 100;
332 value[1] = rand() % 100;
333 value[2] = rand() % 100;
334 value[3] = rand() % 100;
335
336 glUseProgram(SimpleProgram);
337 check_error(__FILE__, __LINE__);
338
339 loc = glGetUniformLocation(SimpleProgram, "value");
340 assert(loc >= 0);
341 glUniform4iv(loc, 1, value);
342 check_error(__FILE__, __LINE__);
343
344 #if 0 /* allow testing on mesa until this is implemented */
345 loc = glGetFragDataLocationEXT(SimpleProgram, "out_color");
346 assert(loc >= 0);
347 #endif
348
349 glBegin(GL_POLYGON);
350 glVertex2f(0, 0);
351 glVertex2f(w, 0);
352 glVertex2f(w, h);
353 glVertex2f(0, h);
354 glEnd();
355 check_error(__FILE__, __LINE__);
356
357 glReadPixels(w/2, h/2, 1, 1, GL_RGBA_INTEGER, GL_INT, result);
358 check_error(__FILE__, __LINE__);
359
360 if (info->BaseFormat == GL_RGB_INTEGER_EXT) {
361 value[3] = 1;
362 }
363
364 if (abs(result[0] - value[0]) > error ||
365 abs(result[1] - value[1]) > error ||
366 abs(result[2] - value[2]) > error ||
367 abs(result[3] - value[3]) > error) {
368 fprintf(stderr, "%s: failure with format %s:\n", TestName, name);
369 fprintf(stderr, " input value = %d, %d, %d, %d\n",
370 value[0], value[1], value[2], value[3]);
371 fprintf(stderr, " result color = %d, %d, %d, %d\n",
372 result[0], result[1], result[2], result[3]);
373 return GL_FALSE;
374 }
375 }
376
377 piglit_present_results();
378
379 glDeleteTextures(1, &texObj);
380 glDeleteFramebuffers(1, &fbo);
381
382 return GL_TRUE;
383 }
384
385
386 enum piglit_result
piglit_display(void)387 piglit_display(void)
388 {
389 int f;
390 for (f = 0; f < NUM_FORMATS; f++) {
391 GLboolean pass = test_fbo(&Formats[f]);
392 if (!pass)
393 return PIGLIT_FAIL;
394 }
395 return PIGLIT_PASS;
396 }
397
398
399 void
piglit_init(int argc,char ** argv)400 piglit_init(int argc, char **argv)
401 {
402 piglit_require_extension("GL_ARB_framebuffer_object");
403 piglit_require_extension("GL_EXT_texture_integer");
404 piglit_require_extension("GL_EXT_gpu_shader4");
405
406 piglit_require_GLSL_version(130);
407
408 PassthroughFragShader = piglit_compile_shader_text(GL_FRAGMENT_SHADER,
409 PassthroughFragShaderText);
410 assert(PassthroughFragShader);
411 PassthroughProgram = piglit_link_simple_program(0, PassthroughFragShader);
412
413
414 SimpleFragShader = piglit_compile_shader_text(GL_FRAGMENT_SHADER,
415 SimpleFragShaderText);
416 assert(SimpleFragShader);
417 SimpleProgram = piglit_link_simple_program(0, SimpleFragShader);
418
419
420 (void) check_error(__FILE__, __LINE__);
421
422 piglit_ortho_projection(piglit_width, piglit_height, GL_FALSE);
423 }
424