added parameter -copytest-loop
[test_compression] / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <assert.h>
6 #include <GL/glew.h>
7 #include <GL/freeglut.h>
8
9 #undef USE_SRGB
10
11 #ifdef USE_SRGB
12 #define COMP_FMT        GL_COMPRESSED_SRGB8_ETC2
13 #else
14 #define COMP_FMT        GL_COMPRESSED_RGB8_ETC2
15 #endif
16
17 int init(void);
18 int texcomp(unsigned char *compix, unsigned int tofmt, unsigned char *pixels,
19                 int xsz, int ysz, unsigned int fromfmt, unsigned int fromtype);
20 void disp(void);
21 void reshape(int x, int y);
22 void keyb(unsigned char key, int x, int y);
23 void idle();
24 void gen_image(unsigned char *pixels, int xsz, int ysz);
25 unsigned char *load_compressed_image(const char *fname, int *cszptr, int *xszptr, int *yszptr);
26 int dump_compressed_image(const char *fname, unsigned char *data, int size, int w, int h);
27 void print_compressed_formats(void);
28
29 unsigned int tex, tex2, comp_tex;
30 const char *texfile;
31 int subtest, copytest, loop;
32
33 int main(int argc, char **argv)
34 {
35         int i;
36         unsigned int glut_flags = GLUT_RGB | GLUT_DOUBLE;
37 #ifdef USE_SRGB
38         glut_flags |= GLUT_SRGB;
39 #endif
40
41         for(i=1; i<argc; i++) {
42                 if(argv[i][0] == '-') {
43                         if(strcmp(argv[i], "-subtest") == 0) {
44                                 subtest = 1;
45                         } else if(strcmp(argv[i], "-copytest") == 0) {
46                                 copytest = 1;
47                         } else if(strcmp(argv[i], "-copytest-loop") == 0) {
48                                 copytest = 1;
49                                 loop = 1;
50                         } else {
51                                 fprintf(stderr, "invalid option: %s\n", argv[i]);
52                                 return 1;
53                         }
54                 } else {
55                         if(texfile) {
56                                 fprintf(stderr, "unexpected argument: %s\n", argv[i]);
57                                 return 1;
58                         }
59                         texfile = argv[i];
60                 }
61         }
62
63         glutInit(&argc, argv);
64         glutInitWindowSize(800, 600);
65         glutInitDisplayMode(glut_flags);
66         glutCreateWindow("test");
67
68         glutDisplayFunc(disp);
69         glutReshapeFunc(reshape);
70         glutKeyboardFunc(keyb);
71
72         if (loop)
73                 glutIdleFunc(idle);
74
75         glewInit();
76
77         if(init() == -1) {
78                 return 1;
79         }
80
81         glutMainLoop();
82         return 0;
83 }
84
85 int init(void)
86 {
87         unsigned char *pixels, *buf;
88         int xsz = 512;
89         int ysz = 512;
90         int is_comp = 0;
91         int comp_size = 0;
92         int tmp;
93
94         print_compressed_formats();
95
96         if(texfile) {
97                 if(!(pixels = load_compressed_image(texfile, &comp_size, &xsz, &ysz))) {
98                         return -1;
99                 }
100                 printf("loaded compressed texture file: %s (%dx%d)\n", texfile, xsz, ysz);
101
102         } else {
103                 if(!(pixels = malloc(xsz * ysz * 3))) {
104                         abort();
105                 }
106                 gen_image(pixels, xsz, ysz);
107
108                 printf("compressing texture\n");
109                 if((comp_size = texcomp(pixels, COMP_FMT, pixels, xsz, ysz, GL_RGB, GL_UNSIGNED_BYTE)) == -1) {
110                         return -1;
111                 }
112                 printf("compressed texture is %d bytes (uncompressed was: %d)\n", comp_size, xsz * ysz * 3);
113
114                 dump_compressed_image("compressed_texture", pixels, comp_size, xsz, ysz);
115         }
116
117         glGenTextures(1, &tex);
118         glBindTexture(GL_TEXTURE_2D, tex);
119         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
120         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
121         glCompressedTexImage2D(GL_TEXTURE_2D, 0, COMP_FMT, xsz, ysz, 0, comp_size, pixels);
122         if(glGetError()) {
123                 fprintf(stderr, "failed to upload compressed texture\n");
124                 return -1;
125         }
126
127         glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED, &is_comp);
128         if(!is_comp) {
129                 fprintf(stderr, "texture is not compressed\n");
130                 return -1;
131         }
132         glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &tmp);
133         if(tmp != comp_size) {
134                 fprintf(stderr, "internal compressed size differs (expected: %d, got: %d)!\n", comp_size, tmp);
135                 return -1;
136         }
137
138         if(!(buf = malloc(comp_size))) {
139                 fprintf(stderr, "failed to allocate comparison image buffer (%d bytes)\n", comp_size);
140                 return -1;
141         }
142         glGetCompressedTexImage(GL_TEXTURE_2D, 0, buf);
143
144         if(memcmp(pixels, buf, comp_size) != 0) {
145                 fprintf(stderr, "submitted and retrieved pixel data differ!\n");
146         } else {
147                 printf("submitted and retrieved sizes match (%d bytes)\n", comp_size);
148         }
149
150         if(subtest) {
151                 printf("testing glGetCompressedTextureSubImage and glCompressedTexSubImage2D\n");
152                 memset(buf, 0, comp_size);
153                 glGetCompressedTextureSubImage(tex, 0, 192, 64, 0, 64, 64, 1, comp_size, buf);
154                 glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 32, 32, 64, 64, COMP_FMT, 2048, buf);
155         }
156
157         if(copytest) {
158                 printf("testing glCopyImageSubData\n");
159
160                 glGenTextures(1, &tex2);
161                 glBindTexture(GL_TEXTURE_2D, tex2);
162                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
163                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
164                 glCompressedTexImage2D(GL_TEXTURE_2D, 0, COMP_FMT, xsz, ysz, 0, comp_size, pixels);
165                 glBindTexture(GL_TEXTURE_2D, 0);
166
167                 glCopyImageSubData(tex2, GL_TEXTURE_2D, 0, 128, 64, 0,
168                                 tex, GL_TEXTURE_2D, 0, 32, 32, 0, 64, 64, 1);
169
170                 glBindTexture(GL_TEXTURE_2D, tex);
171         }
172
173         free(buf);
174         free(pixels);
175
176 #ifdef USE_SRGB
177         glEnable(GL_FRAMEBUFFER_SRGB);
178 #endif
179
180         glEnable(GL_TEXTURE_2D);
181         return 0;
182 }
183
184 int texcomp(unsigned char *compix, unsigned int tofmt, unsigned char *pixels,
185                 int xsz, int ysz, unsigned int fromfmt, unsigned int fromtype)
186 {
187         unsigned int tex;
188         int is_comp = 0;
189         int comp_size = 0;
190
191         glGenTextures(1, &tex);
192         glBindTexture(GL_TEXTURE_2D, tex);
193         glTexImage2D(GL_TEXTURE_2D, 0, tofmt, xsz, ysz, 0, fromfmt, fromtype, pixels);
194         if(glGetError()) {
195                 fprintf(stderr, "failed to compress texture\n");
196                 return -1;
197         }
198
199         glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED, &is_comp);
200         if(!is_comp) {
201                 fprintf(stderr, "texture is not compressed\n");
202                 return -1;
203         }
204         glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &comp_size);
205
206         glGetCompressedTexImage(GL_TEXTURE_2D, 0, compix);
207         return comp_size;
208 }
209
210 void disp(void)
211 {
212         glClear(GL_COLOR_BUFFER_BIT);
213
214         glBegin(GL_QUADS);
215         glTexCoord2f(0, 1); glVertex2f(-1, -1);
216         glTexCoord2f(1, 1); glVertex2f(1, -1);
217         glTexCoord2f(1, 0); glVertex2f(1, 1);
218         glTexCoord2f(0, 0);     glVertex2f(-1, 1);
219         glEnd();
220
221         glutSwapBuffers();
222         assert(glGetError() == GL_NO_ERROR);
223 }
224
225 void reshape(int x, int y)
226 {
227         float aspect = (float)x / (float)y;
228         glViewport(0, 0, x, y);
229
230         glMatrixMode(GL_PROJECTION);
231         glLoadIdentity();
232         glScalef(1.0 / aspect, 1, 1);
233 }
234
235 void keyb(unsigned char key, int x, int y)
236 {
237         if(key == 27) {
238                 exit(0);
239         }
240 }
241
242 void idle()
243 {
244         glutPostRedisplay();
245 }
246
247 void gen_image(unsigned char *pixels, int xsz, int ysz)
248 {
249         int i, j;
250
251         for(i=0; i<ysz; i++) {
252                 for(j=0; j<xsz; j++) {
253                         int xor = i ^ j;
254
255                         *pixels++ = xor & 0xff;
256                         *pixels++ = (xor << 1) & 0xff;
257                         *pixels++ = (xor << 2) & 0xff;
258                 }
259         }
260 }
261
262 unsigned char *load_compressed_image(const char *fname, int *cszptr, int *xszptr, int *yszptr)
263 {
264         unsigned char *pixels;
265         long start, comp_size;
266         int xsz, ysz;
267         FILE *fp;
268
269         if(!(fp = fopen(texfile, "rb"))) {
270                 fprintf(stderr, "failed to open compressed texture file: %s: %s\n", texfile, strerror(errno));
271                 return 0;
272         }
273
274         if(fread(&xsz, sizeof xsz, 1, fp) < 1 || fread(&ysz, sizeof ysz, 1, fp) < 1) {
275                 fprintf(stderr, "failed to read compressed texture file header: %s: %s\n", texfile, strerror(errno));
276                 fclose(fp);
277                 return 0;
278         }
279         start = ftell(fp);
280         fseek(fp, 0, SEEK_END);
281         comp_size = ftell(fp) - start;
282         fseek(fp, start, SEEK_SET);
283
284         if(!(pixels = malloc(comp_size))) {
285                 perror("failed to allocate pixel buffer");
286                 return 0;
287         }
288         if(fread(pixels, 1, comp_size, fp) < comp_size) {
289                 fprintf(stderr, "failed to read compressed texture file: %s: %s\n", texfile, strerror(errno));
290                 fclose(fp);
291                 free(pixels);
292                 return 0;
293         }
294         fclose(fp);
295
296         *cszptr = comp_size;
297         *xszptr = xsz;
298         *yszptr = ysz;
299         return pixels;
300 }
301
302 int dump_compressed_image(const char *fname, unsigned char *data, int size, int w, int h)
303 {
304         FILE *fp;
305
306         if(!(fp = fopen(fname, "wb"))) {
307                 fprintf(stderr, "failed to open compressed texture dump file: %s: %s\n", fname, strerror(errno));
308                 return -1;
309         }
310
311         if(fwrite(&w, sizeof w, 1, fp) < 1 ||
312                         fwrite(&h, sizeof h, 1, fp) < 1 ||
313                         fwrite(data, 1, size, fp) < size) {
314                 fprintf(stderr, "failed to dump compressed texture: %s\n", strerror(errno));
315         }
316         fclose(fp);
317         return 0;
318 }
319
320 const char *fmtstr(int fmt)
321 {
322         switch(fmt) {
323         case 0x86b0: return "GL_COMPRESSED_RGB_FXT1_3DFX";
324         case 0x86b1: return "GL_COMPRESSED_RGBA_FXT1_3DFX";
325         case 0x8dbb: return "GL_COMPRESSED_RED_RGTC1";
326         case 0x8dbc: return "GL_COMPRESSED_SIGNED_RED_RGTC1";
327         case 0x8dbd: return "GL_COMPRESSED_RG_RGTC2";
328         case 0x8dbe: return "GL_COMPRESSED_SIGNED_RG_RGTC2";
329         case 0x8e8c: return "GL_COMPRESSED_RGBA_BPTC_UNORM";
330         case 0x8e8d: return "GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM";
331         case 0x8e8e: return "GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT";
332         case 0x8e8f: return "GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT";
333         case 0x9274: return "GL_COMPRESSED_RGB8_ETC2";
334         case 0x9275: return "GL_COMPRESSED_SRGB8_ETC2";
335         case 0x9276: return "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2";
336         case 0x9277: return "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2";
337         case 0x9278: return "GL_COMPRESSED_RGBA8_ETC2_EAC";
338         case 0x9279: return "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC";
339         case 0x9270: return "GL_COMPRESSED_R11_EAC";
340         case 0x9271: return "GL_COMPRESSED_SIGNED_R11_EAC";
341         case 0x9272: return "GL_COMPRESSED_RG11_EAC";
342         case 0x9273: return "GL_COMPRESSED_SIGNED_RG11_EAC";
343         case 0x83F0: return "GL_COMPRESSED_RGB_S3TC_DXT1_EXT";
344         case 0x83F1: return "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT";
345         case 0x83F2: return "GL_COMPRESSED_RGBA_S3TC_DXT3_EXT";
346         case 0x83F3: return "GL_COMPRESSED_RGBA_S3TC_DXT5_EXT";
347         case 0x8C48: return "GL_COMPRESSED_SRGB_EXT";
348         case 0x8C49: return "GL_COMPRESSED_SRGB_ALPHA_EXT";
349         case 0x8C4A: return "GL_COMPRESSED_SLUMINANCE_EXT";
350         case 0x8C4B: return "GL_COMPRESSED_SLUMINANCE_ALPHA_EXT";
351         case 0x8C4C: return "GL_COMPRESSED_SRGB_S3TC_DXT1_EXT";
352         case 0x8C4D: return "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT";
353         case 0x8C4E: return "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT";
354         case 0x8C4F: return "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT";
355         case 0x8B90: return "GL_PALETTE4_RGB8_OES";
356         case 0x8B91: return "GL_PALETTE4_RGBA8_OES";
357         case 0x8B92: return "GL_PALETTE4_R5_G6_B5_OES";
358         case 0x8B93: return "GL_PALETTE4_RGBA4_OES";
359         case 0x8B94: return "GL_PALETTE4_RGB5_A1_OES";
360         case 0x8B95: return "GL_PALETTE8_RGB8_OES";
361         case 0x8B96: return "GL_PALETTE8_RGBA8_OES";
362         case 0x8B97: return "GL_PALETTE8_R5_G6_B5_OES";
363         case 0x8B98: return "GL_PALETTE8_RGBA4_OES";
364         case 0x8B99: return "GL_PALETTE8_RGB5_A1_OES";
365         case 0x93B0: return "GL_COMPRESSED_RGBA_ASTC_4";
366         case 0x93B1: return "GL_COMPRESSED_RGBA_ASTC_5";
367         case 0x93B2: return "GL_COMPRESSED_RGBA_ASTC_5";
368         case 0x93B3: return "GL_COMPRESSED_RGBA_ASTC_6";
369         case 0x93B4: return "GL_COMPRESSED_RGBA_ASTC_6";
370         case 0x93B5: return "GL_COMPRESSED_RGBA_ASTC_8";
371         case 0x93B6: return "GL_COMPRESSED_RGBA_ASTC_8";
372         case 0x93B7: return "GL_COMPRESSED_RGBA_ASTC_8";
373         case 0x93B8: return "GL_COMPRESSED_RGBA_ASTC_10";
374         case 0x93B9: return "GL_COMPRESSED_RGBA_ASTC_10";
375         case 0x93BA: return "GL_COMPRESSED_RGBA_ASTC_10";
376         case 0x93BB: return "GL_COMPRESSED_RGBA_ASTC_10";
377         case 0x93BC: return "GL_COMPRESSED_RGBA_ASTC_12";
378         case 0x93BD: return "GL_COMPRESSED_RGBA_ASTC_12";
379         case 0x93D0: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4";
380         case 0x93D1: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5";
381         case 0x93D2: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5";
382         case 0x93D3: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6";
383         case 0x93D4: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6";
384         case 0x93D5: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8";
385         case 0x93D6: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8";
386         case 0x93D7: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8";
387         case 0x93D8: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10";
388         case 0x93D9: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10";
389         case 0x93DA: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10";
390         case 0x93DB: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10";
391         case 0x93DC: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12";
392         case 0x93DD: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12";
393         default:
394                 break;
395         }
396         return "unknown";
397 }
398
399 void print_compressed_formats(void)
400 {
401         int i, num_fmt;
402         int *fmtlist;
403
404         glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_fmt);
405         printf("%d generic compressed texture formats available:\n", num_fmt);
406
407         if(!(fmtlist = malloc(num_fmt * sizeof *fmtlist))) {
408                 fprintf(stderr, "failed to allocate texture formats enumeration buffer\n");
409                 return;
410         }
411         glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, fmtlist);
412
413         for(i=0; i<num_fmt; i++) {
414                 printf(" %05x: %s ", fmtlist[i], fmtstr(fmtlist[i]));
415                 GLint params;
416                 glGetInternalformativ(GL_TEXTURE_2D, fmtlist[i], GL_TEXTURE_COMPRESSED, 1, &params);
417                 printf("(%s format)\n", params == GL_TRUE ? "compressed" : "not compressed");
418         }
419         free(fmtlist);
420 }