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