radeon/r200/r300: cleanup some of the renderbuffer code
[mesa.git] / progs / tests / fbotexture.c
1 /*
2 * Test GL_EXT_framebuffer_object render-to-texture
3 *
4 * Draw a teapot into a texture image with stenciling.
5 * Then draw a textured quad using that texture.
6 *
7 * Brian Paul
8 * 18 Apr 2005
9 */
10
11
12 #define GL_GLEXT_PROTOTYPES
13 #include <GL/glut.h>
14 #include <assert.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <math.h>
19
20 /* For debug */
21 #define DEPTH 1
22 #define STENCIL 1
23 #define DRAW 1
24
25
26 static int Win = 0;
27 static int Width = 400, Height = 400;
28
29 static GLenum TexTarget = GL_TEXTURE_2D; /*GL_TEXTURE_RECTANGLE_ARB;*/
30 static int TexWidth = 512, TexHeight = 512;
31 /*static int TexWidth = 600, TexHeight = 600;*/
32
33 static GLuint MyFB;
34 static GLuint TexObj;
35 static GLuint DepthRB = 0, StencilRB = 0;
36 static GLboolean Anim = GL_FALSE;
37 static GLfloat Rot = 0.0;
38 static GLboolean UsePackedDepthStencil = GL_FALSE;
39 static GLboolean UsePackedDepthStencilBoth = GL_FALSE;
40 static GLboolean Use_ARB_fbo = GL_FALSE;
41 static GLuint TextureLevel = 0; /* which texture level to render to */
42 static GLenum TexIntFormat = GL_RGB; /* either GL_RGB or GL_RGBA */
43 static GLboolean Cull = GL_FALSE;
44 static GLboolean Wireframe = GL_FALSE;
45
46
47 static void
48 CheckError(int line)
49 {
50 GLenum err = glGetError();
51 if (err) {
52 printf("GL Error 0x%x at line %d\n", (int) err, line);
53 }
54 }
55
56
57 static void
58 Idle(void)
59 {
60 Rot = glutGet(GLUT_ELAPSED_TIME) * 0.1;
61 glutPostRedisplay();
62 }
63
64
65 static void
66 RenderTexture(void)
67 {
68 GLenum status;
69
70 glMatrixMode(GL_PROJECTION);
71 glLoadIdentity();
72 glOrtho(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
73 glMatrixMode(GL_MODELVIEW);
74 glLoadIdentity();
75 glTranslatef(0.0, 0.0, -15.0);
76
77 /* draw to texture image */
78 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, MyFB);
79
80 status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
81 if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
82 printf("Framebuffer incomplete!!!\n");
83 }
84
85 glViewport(0, 0, TexWidth, TexHeight);
86
87 glClearColor(0.5, 0.5, 1.0, 0.0);
88 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
89 CheckError(__LINE__);
90
91 #if DEPTH
92 glEnable(GL_DEPTH_TEST);
93 #endif
94
95 #if STENCIL
96 glEnable(GL_STENCIL_TEST);
97 glStencilFunc(GL_NEVER, 1, ~0);
98 glStencilOp(GL_REPLACE, GL_KEEP, GL_REPLACE);
99 #endif
100
101 CheckError(__LINE__);
102
103 #if DEPTH || STENCIL
104 /* draw diamond-shaped stencil pattern */
105 glColor3f(0, 1, 0);
106 glBegin(GL_POLYGON);
107 glVertex2f(-0.2, 0.0);
108 glVertex2f( 0.0, -0.2);
109 glVertex2f( 0.2, 0.0);
110 glVertex2f( 0.0, 0.2);
111 glEnd();
112 #endif
113
114 /* draw teapot where stencil != 1 */
115 #if STENCIL
116 glStencilFunc(GL_NOTEQUAL, 1, ~0);
117 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
118 #endif
119
120 CheckError(__LINE__);
121
122 if (Wireframe) {
123 glPolygonMode(GL_FRONT, GL_LINE);
124 }
125 else {
126 glPolygonMode(GL_FRONT, GL_FILL);
127 }
128
129 if (Cull) {
130 /* cull back */
131 glCullFace(GL_BACK);
132 glEnable(GL_CULL_FACE);
133 }
134 else {
135 glDisable(GL_CULL_FACE);
136 }
137
138 #if 0
139 glBegin(GL_POLYGON);
140 glColor3f(1, 0, 0);
141 glVertex2f(-1, -1);
142 glColor3f(0, 1, 0);
143 glVertex2f(1, -1);
144 glColor3f(0, 0, 1);
145 glVertex2f(0, 1);
146 glEnd();
147 #else
148 glEnable(GL_LIGHTING);
149 glEnable(GL_LIGHT0);
150 glPushMatrix();
151 glRotatef(0.5 * Rot, 1.0, 0.0, 0.0);
152 glFrontFace(GL_CW); /* Teapot patches backward */
153 glutSolidTeapot(0.5);
154 glFrontFace(GL_CCW);
155 glPopMatrix();
156 glDisable(GL_LIGHTING);
157 /*
158 PrintStencilHistogram(TexWidth, TexHeight);
159 */
160 #endif
161
162 glDisable(GL_DEPTH_TEST);
163 glDisable(GL_STENCIL_TEST);
164 glDisable(GL_CULL_FACE);
165 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
166
167 #if DRAW
168 /* Bind normal framebuffer */
169 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
170 #endif
171
172 CheckError(__LINE__);
173 }
174
175
176
177 static void
178 Display(void)
179 {
180 float ar = (float) Width / (float) Height;
181
182 RenderTexture();
183
184 /* draw textured quad in the window */
185 #if DRAW
186 glMatrixMode(GL_PROJECTION);
187 glLoadIdentity();
188 glFrustum(-ar, ar, -1.0, 1.0, 5.0, 25.0);
189 glMatrixMode(GL_MODELVIEW);
190 glLoadIdentity();
191 glTranslatef(0.0, 0.0, -7.0);
192
193 glViewport(0, 0, Width, Height);
194
195 glClearColor(0.25, 0.25, 0.25, 0);
196 glClear(GL_COLOR_BUFFER_BIT);
197
198 glPushMatrix();
199 glRotatef(Rot, 0, 1, 0);
200 glEnable(TexTarget);
201 glBindTexture(TexTarget, TexObj);
202 glBegin(GL_POLYGON);
203 glColor3f(0.25, 0.25, 0.25);
204 if (TexTarget == GL_TEXTURE_2D) {
205 glTexCoord2f(0, 0);
206 glVertex2f(-1, -1);
207 glTexCoord2f(1, 0);
208 glVertex2f(1, -1);
209 glColor3f(1.0, 1.0, 1.0);
210 glTexCoord2f(1, 1);
211 glVertex2f(1, 1);
212 glTexCoord2f(0, 1);
213 glVertex2f(-1, 1);
214 }
215 else {
216 assert(TexTarget == GL_TEXTURE_RECTANGLE_ARB);
217 glTexCoord2f(0, 0);
218 glVertex2f(-1, -1);
219 glTexCoord2f(TexWidth, 0);
220 glVertex2f(1, -1);
221 glColor3f(1.0, 1.0, 1.0);
222 glTexCoord2f(TexWidth, TexHeight);
223 glVertex2f(1, 1);
224 glTexCoord2f(0, TexHeight);
225 glVertex2f(-1, 1);
226 }
227 glEnd();
228 glPopMatrix();
229 glDisable(TexTarget);
230 #endif
231
232 glutSwapBuffers();
233 CheckError(__LINE__);
234 }
235
236
237 static void
238 Reshape(int width, int height)
239 {
240 glViewport(0, 0, width, height);
241 Width = width;
242 Height = height;
243 }
244
245
246 static void
247 CleanUp(void)
248 {
249 #if DEPTH
250 glDeleteRenderbuffersEXT(1, &DepthRB);
251 #endif
252 #if STENCIL
253 glDeleteRenderbuffersEXT(1, &StencilRB);
254 #endif
255 glDeleteFramebuffersEXT(1, &MyFB);
256
257 glDeleteTextures(1, &TexObj);
258
259 glutDestroyWindow(Win);
260
261 exit(0);
262 }
263
264
265 static void
266 Key(unsigned char key, int x, int y)
267 {
268 (void) x;
269 (void) y;
270 switch (key) {
271 case 'a':
272 Anim = !Anim;
273 if (Anim)
274 glutIdleFunc(Idle);
275 else
276 glutIdleFunc(NULL);
277 break;
278 case 'c':
279 Cull = !Cull;
280 break;
281 case 'w':
282 Wireframe = !Wireframe;
283 break;
284 case 's':
285 Rot += 2.0;
286 break;
287 case 'S':
288 Rot -= 2.0;
289 break;
290 case 27:
291 CleanUp();
292 break;
293 }
294 glutPostRedisplay();
295 }
296
297
298 /**
299 * Attach depth and stencil renderbuffer(s) to the given framebuffer object.
300 * \param tryDepthStencil if true, try to use a combined depth+stencil buffer
301 * \param bindDepthStencil if true, and tryDepthStencil is true, bind with
302 * the GL_DEPTH_STENCIL_ATTACHMENT target.
303 * \return GL_TRUE for success, GL_FALSE for failure
304 */
305 static GLboolean
306 AttachDepthAndStencilBuffers(GLuint fbo,
307 GLsizei width, GLsizei height,
308 GLboolean tryDepthStencil,
309 GLboolean bindDepthStencil,
310 GLuint *depthRbOut, GLuint *stencilRbOut)
311 {
312 GLenum status;
313
314 *depthRbOut = *stencilRbOut = 0;
315
316 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
317
318 if (tryDepthStencil) {
319 GLuint rb;
320
321 glGenRenderbuffersEXT(1, &rb);
322 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rb);
323 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,
324 GL_DEPTH24_STENCIL8_EXT,
325 width, height);
326 if (glGetError())
327 return GL_FALSE;
328
329 if (bindDepthStencil) {
330 /* attach to both depth and stencil at once */
331 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
332 GL_DEPTH_STENCIL_ATTACHMENT,
333 GL_RENDERBUFFER_EXT, rb);
334 if (glGetError())
335 return GL_FALSE;
336 }
337 else {
338 /* attach to depth attachment point */
339 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
340 GL_DEPTH_ATTACHMENT_EXT,
341 GL_RENDERBUFFER_EXT, rb);
342 if (glGetError())
343 return GL_FALSE;
344
345 /* and attach to stencil attachment point */
346 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
347 GL_STENCIL_ATTACHMENT_EXT,
348 GL_RENDERBUFFER_EXT, rb);
349 if (glGetError())
350 return GL_FALSE;
351 }
352
353 status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
354 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
355 return GL_FALSE;
356
357 *depthRbOut = *stencilRbOut = rb;
358 return GL_TRUE;
359 }
360
361 /* just depth renderbuffer */
362 {
363 GLuint rb;
364
365 glGenRenderbuffersEXT(1, &rb);
366 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rb);
367 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,
368 GL_DEPTH_COMPONENT,
369 width, height);
370 if (glGetError())
371 return GL_FALSE;
372
373 /* attach to depth attachment point */
374 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
375 GL_DEPTH_ATTACHMENT_EXT,
376 GL_RENDERBUFFER_EXT, rb);
377 if (glGetError())
378 return GL_FALSE;
379
380 status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
381 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
382 return GL_FALSE;
383
384 *depthRbOut = rb;
385 }
386
387 /* just stencil renderbuffer */
388 {
389 GLuint rb;
390
391 glGenRenderbuffersEXT(1, &rb);
392 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rb);
393 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,
394 GL_STENCIL_INDEX,
395 width, height);
396 if (glGetError())
397 return GL_FALSE;
398
399 /* attach to depth attachment point */
400 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
401 GL_STENCIL_ATTACHMENT_EXT,
402 GL_RENDERBUFFER_EXT, rb);
403 if (glGetError())
404 return GL_FALSE;
405
406 status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
407 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
408 return GL_FALSE;
409
410 *stencilRbOut = rb;
411 }
412
413 return GL_TRUE;
414 }
415
416
417 static void
418 ParseArgs(int argc, char *argv[])
419 {
420 GLint i;
421 for (i = 1; i < argc; i++) {
422 if (strcmp(argv[i], "-ds") == 0) {
423 if (!glutExtensionSupported("GL_EXT_packed_depth_stencil")) {
424 printf("GL_EXT_packed_depth_stencil not found!\n");
425 exit(0);
426 }
427 UsePackedDepthStencil = GL_TRUE;
428 printf("Using GL_EXT_packed_depth_stencil\n");
429 }
430 else if (strcmp(argv[i], "-ds2") == 0) {
431 if (!glutExtensionSupported("GL_EXT_packed_depth_stencil")) {
432 printf("GL_EXT_packed_depth_stencil not found!\n");
433 exit(0);
434 }
435 if (!glutExtensionSupported("GL_ARB_framebuffer_object")) {
436 printf("GL_ARB_framebuffer_object not found!\n");
437 exit(0);
438 }
439 UsePackedDepthStencilBoth = GL_TRUE;
440 printf("Using GL_EXT_packed_depth_stencil and GL_DEPTH_STENCIL attachment point\n");
441 }
442 else if (strcmp(argv[i], "-arb") == 0) {
443 if (!glutExtensionSupported("GL_ARB_framebuffer_object")) {
444 printf("Sorry, GL_ARB_framebuffer object not supported!\n");
445 }
446 else {
447 Use_ARB_fbo = GL_TRUE;
448 }
449 }
450 else {
451 printf("Unknown option: %s\n", argv[i]);
452 }
453 }
454 }
455
456
457 /*
458 * Make FBO to render into given texture.
459 */
460 static GLuint
461 MakeFBO_RenderTexture(GLuint TexObj)
462 {
463 GLuint fb;
464 GLint sizeFudge = 0;
465
466 glGenFramebuffersEXT(1, &fb);
467 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
468 /* Render color to texture */
469 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
470 TexTarget, TexObj, TextureLevel);
471
472 if (Use_ARB_fbo) {
473 /* use a smaller depth buffer to see what happens */
474 sizeFudge = 90;
475 }
476
477 /* Setup depth and stencil buffers */
478 {
479 GLboolean b;
480 b = AttachDepthAndStencilBuffers(fb,
481 TexWidth - sizeFudge,
482 TexHeight - sizeFudge,
483 UsePackedDepthStencil,
484 UsePackedDepthStencilBoth,
485 &DepthRB, &StencilRB);
486 if (!b) {
487 /* try !UsePackedDepthStencil */
488 b = AttachDepthAndStencilBuffers(fb,
489 TexWidth - sizeFudge,
490 TexHeight - sizeFudge,
491 !UsePackedDepthStencil,
492 UsePackedDepthStencilBoth,
493 &DepthRB, &StencilRB);
494 }
495 if (!b) {
496 printf("Unable to create/attach depth and stencil renderbuffers "
497 " to FBO!\n");
498 exit(1);
499 }
500 }
501
502 /* queries */
503 {
504 GLint bits, w, h;
505
506 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, DepthRB);
507 glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT,
508 GL_RENDERBUFFER_WIDTH_EXT, &w);
509 glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT,
510 GL_RENDERBUFFER_HEIGHT_EXT, &h);
511 printf("Color/Texture size: %d x %d\n", TexWidth, TexHeight);
512 printf("Depth buffer size: %d x %d\n", w, h);
513
514 glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT,
515 GL_RENDERBUFFER_DEPTH_SIZE_EXT, &bits);
516 printf("Depth renderbuffer size = %d bits\n", bits);
517
518 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, StencilRB);
519 glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT,
520 GL_RENDERBUFFER_STENCIL_SIZE_EXT, &bits);
521 printf("Stencil renderbuffer size = %d bits\n", bits);
522 }
523
524 /* bind the regular framebuffer */
525 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
526
527 return fb;
528 }
529
530
531 static void
532 Init(void)
533 {
534 if (!glutExtensionSupported("GL_EXT_framebuffer_object")) {
535 printf("GL_EXT_framebuffer_object not found!\n");
536 exit(0);
537 }
538
539 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
540
541 /* lighting */
542 {
543 static const GLfloat mat[4] = { 1.0, 0.5, 0.5, 1.0 };
544 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat);
545 }
546
547 /*
548 * Make texture object/image (we'll render into this texture)
549 */
550 {
551 glGenTextures(1, &TexObj);
552 glBindTexture(TexTarget, TexObj);
553
554 /* make two image levels */
555 glTexImage2D(TexTarget, 0, TexIntFormat, TexWidth, TexHeight, 0,
556 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
557 glTexImage2D(TexTarget, 1, TexIntFormat, TexWidth/2, TexHeight/2, 0,
558 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
559 TexWidth = TexWidth >> TextureLevel;
560 TexHeight = TexHeight >> TextureLevel;
561
562 glTexParameteri(TexTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
563 glTexParameteri(TexTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
564 glTexParameteri(TexTarget, GL_TEXTURE_BASE_LEVEL, TextureLevel);
565 glTexParameteri(TexTarget, GL_TEXTURE_MAX_LEVEL, TextureLevel);
566 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
567 }
568
569 MyFB = MakeFBO_RenderTexture(TexObj);
570 }
571
572
573 static void
574 Usage(void)
575 {
576 printf("Usage:\n");
577 printf(" -ds Use combined depth/stencil renderbuffer\n");
578 printf(" -arb Try GL_ARB_framebuffer_object's mismatched buffer sizes\n");
579 printf(" -ds2 Tye GL_ARB_framebuffer_object's GL_DEPTH_STENCIL_ATTACHMENT\n");
580 printf("Keys:\n");
581 printf(" a Toggle animation\n");
582 printf(" s/s Step/rotate\n");
583 printf(" c Toggle back-face culling\n");
584 printf(" w Toggle wireframe mode (front-face only)\n");
585 printf(" Esc Exit\n");
586 }
587
588
589 int
590 main(int argc, char *argv[])
591 {
592 glutInit(&argc, argv);
593 glutInitWindowPosition(0, 0);
594 glutInitWindowSize(Width, Height);
595 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
596 Win = glutCreateWindow(argv[0]);
597 glutReshapeFunc(Reshape);
598 glutKeyboardFunc(Key);
599 glutDisplayFunc(Display);
600 if (Anim)
601 glutIdleFunc(Idle);
602
603 ParseArgs(argc, argv);
604 Init();
605 Usage();
606
607 glutMainLoop();
608 return 0;
609 }