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