Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1901 serge 1
/*
2
 * Mesa 3-D graphics library
3
 * Version:  7.1
4
 *
5
 * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
6
 * Copyright (C) 1999-2009  VMware, Inc.  All Rights Reserved.
7
 *
8
 * Permission is hereby granted, free of charge, to any person obtaining a
9
 * copy of this software and associated documentation files (the "Software"),
10
 * to deal in the Software without restriction, including without limitation
11
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12
 * and/or sell copies of the Software, and to permit persons to whom the
13
 * Software is furnished to do so, subject to the following conditions:
14
 *
15
 * The above copyright notice and this permission notice shall be included
16
 * in all copies or substantial portions of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21
 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
 */
25
 
26
 
27
/*
28
 * GL_EXT/ARB_framebuffer_object extensions
29
 *
30
 * Authors:
31
 *   Brian Paul
32
 */
33
 
34
 
35
#include "buffers.h"
36
#include "context.h"
37
#include "enums.h"
38
#include "fbobject.h"
39
#include "formats.h"
40
#include "framebuffer.h"
41
#include "hash.h"
42
#include "macros.h"
43
#include "renderbuffer.h"
44
#include "state.h"
45
#include "teximage.h"
46
#include "texobj.h"
47
 
48
 
49
/** Set this to 1 to help debug FBO incompleteness problems */
50
#define DEBUG_FBO 0
51
 
52
/** Set this to 1 to debug/log glBlitFramebuffer() calls */
53
#define DEBUG_BLIT 0
54
 
55
 
56
/**
57
 * Notes:
58
 *
59
 * None of the GL_EXT_framebuffer_object functions are compiled into
60
 * display lists.
61
 */
62
 
63
 
64
 
65
/*
66
 * When glGenRender/FramebuffersEXT() is called we insert pointers to
67
 * these placeholder objects into the hash table.
68
 * Later, when the object ID is first bound, we replace the placeholder
69
 * with the real frame/renderbuffer.
70
 */
71
static struct gl_framebuffer DummyFramebuffer;
72
static struct gl_renderbuffer DummyRenderbuffer;
73
 
74
/* We bind this framebuffer when applications pass a NULL
75
 * drawable/surface in make current. */
76
static struct gl_framebuffer IncompleteFramebuffer;
77
 
78
 
79
#define IS_CUBE_FACE(TARGET) \
80
   ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \
81
    (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
82
 
83
 
84
static void
85
delete_dummy_renderbuffer(struct gl_renderbuffer *rb)
86
{
87
   /* no op */
88
}
89
 
90
static void
91
delete_dummy_framebuffer(struct gl_framebuffer *fb)
92
{
93
   /* no op */
94
}
95
 
96
 
97
void
98
_mesa_init_fbobjects(struct gl_context *ctx)
99
{
100
   _glthread_INIT_MUTEX(DummyFramebuffer.Mutex);
101
   _glthread_INIT_MUTEX(DummyRenderbuffer.Mutex);
102
   _glthread_INIT_MUTEX(IncompleteFramebuffer.Mutex);
103
   DummyFramebuffer.Delete = delete_dummy_framebuffer;
104
   DummyRenderbuffer.Delete = delete_dummy_renderbuffer;
105
   IncompleteFramebuffer.Delete = delete_dummy_framebuffer;
106
}
107
 
108
struct gl_framebuffer *
109
_mesa_get_incomplete_framebuffer(void)
110
{
111
   return &IncompleteFramebuffer;
112
}
113
 
114
/**
115
 * Helper routine for getting a gl_renderbuffer.
116
 */
117
struct gl_renderbuffer *
118
_mesa_lookup_renderbuffer(struct gl_context *ctx, GLuint id)
119
{
120
   struct gl_renderbuffer *rb;
121
 
122
   if (id == 0)
123
      return NULL;
124
 
125
   rb = (struct gl_renderbuffer *)
126
      _mesa_HashLookup(ctx->Shared->RenderBuffers, id);
127
   return rb;
128
}
129
 
130
 
131
/**
132
 * Helper routine for getting a gl_framebuffer.
133
 */
134
struct gl_framebuffer *
135
_mesa_lookup_framebuffer(struct gl_context *ctx, GLuint id)
136
{
137
   struct gl_framebuffer *fb;
138
 
139
   if (id == 0)
140
      return NULL;
141
 
142
   fb = (struct gl_framebuffer *)
143
      _mesa_HashLookup(ctx->Shared->FrameBuffers, id);
144
   return fb;
145
}
146
 
147
 
148
/**
149
 * Mark the given framebuffer as invalid.  This will force the
150
 * test for framebuffer completeness to be done before the framebuffer
151
 * is used.
152
 */
153
static void
154
invalidate_framebuffer(struct gl_framebuffer *fb)
155
{
156
   fb->_Status = 0; /* "indeterminate" */
157
}
158
 
159
 
160
/**
161
 * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding
162
 * gl_renderbuffer_attachment object.
163
 * This function is only used for user-created FB objects, not the
164
 * default / window-system FB object.
165
 * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to
166
 * the depth buffer attachment point.
167
 */
168
struct gl_renderbuffer_attachment *
169
_mesa_get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
170
                     GLenum attachment)
171
{
172
   GLuint i;
173
 
174
   assert(fb->Name > 0);
175
 
176
   switch (attachment) {
177
   case GL_COLOR_ATTACHMENT0_EXT:
178
   case GL_COLOR_ATTACHMENT1_EXT:
179
   case GL_COLOR_ATTACHMENT2_EXT:
180
   case GL_COLOR_ATTACHMENT3_EXT:
181
   case GL_COLOR_ATTACHMENT4_EXT:
182
   case GL_COLOR_ATTACHMENT5_EXT:
183
   case GL_COLOR_ATTACHMENT6_EXT:
184
   case GL_COLOR_ATTACHMENT7_EXT:
185
   case GL_COLOR_ATTACHMENT8_EXT:
186
   case GL_COLOR_ATTACHMENT9_EXT:
187
   case GL_COLOR_ATTACHMENT10_EXT:
188
   case GL_COLOR_ATTACHMENT11_EXT:
189
   case GL_COLOR_ATTACHMENT12_EXT:
190
   case GL_COLOR_ATTACHMENT13_EXT:
191
   case GL_COLOR_ATTACHMENT14_EXT:
192
   case GL_COLOR_ATTACHMENT15_EXT:
193
      i = attachment - GL_COLOR_ATTACHMENT0_EXT;
194
      if (i >= ctx->Const.MaxColorAttachments) {
195
	 return NULL;
196
      }
197
      return &fb->Attachment[BUFFER_COLOR0 + i];
198
   case GL_DEPTH_STENCIL_ATTACHMENT:
199
      /* fall-through */
200
   case GL_DEPTH_BUFFER:
201
      /* fall-through / new in GL 3.0 */
202
   case GL_DEPTH_ATTACHMENT_EXT:
203
      return &fb->Attachment[BUFFER_DEPTH];
204
   case GL_STENCIL_BUFFER:
205
      /* fall-through / new in GL 3.0 */
206
   case GL_STENCIL_ATTACHMENT_EXT:
207
      return &fb->Attachment[BUFFER_STENCIL];
208
   default:
209
      return NULL;
210
   }
211
}
212
 
213
 
214
/**
215
 * As above, but only used for getting attachments of the default /
216
 * window-system framebuffer (not user-created framebuffer objects).
217
 */
218
static struct gl_renderbuffer_attachment *
219
_mesa_get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
220
                         GLenum attachment)
221
{
222
   assert(fb->Name == 0);
223
 
224
   switch (attachment) {
225
   case GL_FRONT_LEFT:
226
      return &fb->Attachment[BUFFER_FRONT_LEFT];
227
   case GL_FRONT_RIGHT:
228
      return &fb->Attachment[BUFFER_FRONT_RIGHT];
229
   case GL_BACK_LEFT:
230
      return &fb->Attachment[BUFFER_BACK_LEFT];
231
   case GL_BACK_RIGHT:
232
      return &fb->Attachment[BUFFER_BACK_RIGHT];
233
   case GL_AUX0:
234
      if (fb->Visual.numAuxBuffers == 1) {
235
         return &fb->Attachment[BUFFER_AUX0];
236
      }
237
      return NULL;
238
   case GL_DEPTH_BUFFER:
239
      /* fall-through / new in GL 3.0 */
240
   case GL_DEPTH_ATTACHMENT_EXT:
241
      return &fb->Attachment[BUFFER_DEPTH];
242
   case GL_STENCIL_BUFFER:
243
      /* fall-through / new in GL 3.0 */
244
   case GL_STENCIL_ATTACHMENT_EXT:
245
      return &fb->Attachment[BUFFER_STENCIL];
246
   default:
247
      return NULL;
248
   }
249
}
250
 
251
 
252
 
253
/**
254
 * Remove any texture or renderbuffer attached to the given attachment
255
 * point.  Update reference counts, etc.
256
 */
257
void
258
_mesa_remove_attachment(struct gl_context *ctx,
259
                        struct gl_renderbuffer_attachment *att)
260
{
261
   if (att->Type == GL_TEXTURE) {
262
      ASSERT(att->Texture);
263
      if (ctx->Driver.FinishRenderTexture) {
264
         /* tell driver that we're done rendering to this texture. */
265
         ctx->Driver.FinishRenderTexture(ctx, att);
266
      }
267
      _mesa_reference_texobj(&att->Texture, NULL); /* unbind */
268
      ASSERT(!att->Texture);
269
   }
270
   if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) {
271
      ASSERT(!att->Texture);
272
      _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */
273
      ASSERT(!att->Renderbuffer);
274
   }
275
   att->Type = GL_NONE;
276
   att->Complete = GL_TRUE;
277
}
278
 
279
 
280
/**
281
 * Bind a texture object to an attachment point.
282
 * The previous binding, if any, will be removed first.
283
 */
284
void
285
_mesa_set_texture_attachment(struct gl_context *ctx,
286
                             struct gl_framebuffer *fb,
287
                             struct gl_renderbuffer_attachment *att,
288
                             struct gl_texture_object *texObj,
289
                             GLenum texTarget, GLuint level, GLuint zoffset)
290
{
291
   if (att->Texture == texObj) {
292
      /* re-attaching same texture */
293
      ASSERT(att->Type == GL_TEXTURE);
294
      if (ctx->Driver.FinishRenderTexture)
295
	 ctx->Driver.FinishRenderTexture(ctx, att);
296
   }
297
   else {
298
      /* new attachment */
299
      if (ctx->Driver.FinishRenderTexture && att->Texture)
300
	 ctx->Driver.FinishRenderTexture(ctx, att);
301
      _mesa_remove_attachment(ctx, att);
302
      att->Type = GL_TEXTURE;
303
      assert(!att->Texture);
304
      _mesa_reference_texobj(&att->Texture, texObj);
305
   }
306
 
307
   /* always update these fields */
308
   att->TextureLevel = level;
309
   att->CubeMapFace = _mesa_tex_target_to_face(texTarget);
310
   att->Zoffset = zoffset;
311
   att->Complete = GL_FALSE;
312
 
313
   if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) {
314
      ctx->Driver.RenderTexture(ctx, fb, att);
315
   }
316
 
317
   invalidate_framebuffer(fb);
318
}
319
 
320
 
321
/**
322
 * Bind a renderbuffer to an attachment point.
323
 * The previous binding, if any, will be removed first.
324
 */
325
void
326
_mesa_set_renderbuffer_attachment(struct gl_context *ctx,
327
                                  struct gl_renderbuffer_attachment *att,
328
                                  struct gl_renderbuffer *rb)
329
{
330
   /* XXX check if re-doing same attachment, exit early */
331
   _mesa_remove_attachment(ctx, att);
332
   att->Type = GL_RENDERBUFFER_EXT;
333
   att->Texture = NULL; /* just to be safe */
334
   att->Complete = GL_FALSE;
335
   _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
336
}
337
 
338
 
339
/**
340
 * Fallback for ctx->Driver.FramebufferRenderbuffer()
341
 * Attach a renderbuffer object to a framebuffer object.
342
 */
343
void
344
_mesa_framebuffer_renderbuffer(struct gl_context *ctx,
345
                               struct gl_framebuffer *fb,
346
                               GLenum attachment, struct gl_renderbuffer *rb)
347
{
348
   struct gl_renderbuffer_attachment *att;
349
 
350
   _glthread_LOCK_MUTEX(fb->Mutex);
351
 
352
   att = _mesa_get_attachment(ctx, fb, attachment);
353
   ASSERT(att);
354
   if (rb) {
355
      _mesa_set_renderbuffer_attachment(ctx, att, rb);
356
      if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
357
         /* do stencil attachment here (depth already done above) */
358
         att = _mesa_get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT);
359
         assert(att);
360
         _mesa_set_renderbuffer_attachment(ctx, att, rb);
361
      }
362
   }
363
   else {
364
      _mesa_remove_attachment(ctx, att);
365
   }
366
 
367
   invalidate_framebuffer(fb);
368
 
369
   _glthread_UNLOCK_MUTEX(fb->Mutex);
370
}
371
 
372
 
373
/**
374
 * For debug only.
375
 */
376
static void
377
att_incomplete(const char *msg)
378
{
379
#if DEBUG_FBO
380
   _mesa_debug(NULL, "attachment incomplete: %s\n", msg);
381
#else
382
   (void) msg;
383
#endif
384
}
385
 
386
 
387
/**
388
 * For debug only.
389
 */
390
static void
391
fbo_incomplete(const char *msg, int index)
392
{
393
#if DEBUG_FBO
394
   _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index);
395
#else
396
   (void) msg;
397
   (void) index;
398
#endif
399
}
400
 
401
 
402
/**
403
 * Is the given base format a legal format for a color renderbuffer?
404
 */
405
static GLboolean
406
is_legal_color_format(const struct gl_context *ctx, GLenum baseFormat)
407
{
408
   switch (baseFormat) {
409
   case GL_RGB:
410
   case GL_RGBA:
411
      return GL_TRUE;
412
   case GL_LUMINANCE:
413
   case GL_LUMINANCE_ALPHA:
414
   case GL_INTENSITY:
415
   case GL_ALPHA:
416
      return ctx->Extensions.ARB_framebuffer_object;
417
   case GL_RED:
418
   case GL_RG:
419
      return ctx->Extensions.ARB_texture_rg;
420
   default:
421
      return GL_FALSE;
422
   }
423
}
424
 
425
 
426
/**
427
 * Is the given base format a legal format for a depth/stencil renderbuffer?
428
 */
429
static GLboolean
430
is_legal_depth_format(const struct gl_context *ctx, GLenum baseFormat)
431
{
432
   switch (baseFormat) {
433
   case GL_DEPTH_COMPONENT:
434
   case GL_DEPTH_STENCIL_EXT:
435
      return GL_TRUE;
436
   default:
437
      return GL_FALSE;
438
   }
439
}
440
 
441
 
442
/**
443
 * Test if an attachment point is complete and update its Complete field.
444
 * \param format if GL_COLOR, this is a color attachment point,
445
 *               if GL_DEPTH, this is a depth component attachment point,
446
 *               if GL_STENCIL, this is a stencil component attachment point.
447
 */
448
static void
449
test_attachment_completeness(const struct gl_context *ctx, GLenum format,
450
                             struct gl_renderbuffer_attachment *att)
451
{
452
   assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL);
453
 
454
   /* assume complete */
455
   att->Complete = GL_TRUE;
456
 
457
   /* Look for reasons why the attachment might be incomplete */
458
   if (att->Type == GL_TEXTURE) {
459
      const struct gl_texture_object *texObj = att->Texture;
460
      struct gl_texture_image *texImage;
461
      GLenum baseFormat;
462
 
463
      if (!texObj) {
464
         att_incomplete("no texobj");
465
         att->Complete = GL_FALSE;
466
         return;
467
      }
468
 
469
      texImage = texObj->Image[att->CubeMapFace][att->TextureLevel];
470
      if (!texImage) {
471
         att_incomplete("no teximage");
472
         att->Complete = GL_FALSE;
473
         return;
474
      }
475
      if (texImage->Width < 1 || texImage->Height < 1) {
476
         att_incomplete("teximage width/height=0");
477
         printf("texobj = %u\n", texObj->Name);
478
         printf("level = %d\n", att->TextureLevel);
479
         att->Complete = GL_FALSE;
480
         return;
481
      }
482
      if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) {
483
         att_incomplete("bad z offset");
484
         att->Complete = GL_FALSE;
485
         return;
486
      }
487
 
488
      baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
489
 
490
      if (format == GL_COLOR) {
491
         if (!is_legal_color_format(ctx, baseFormat)) {
492
            att_incomplete("bad format");
493
            att->Complete = GL_FALSE;
494
            return;
495
         }
496
         if (_mesa_is_format_compressed(texImage->TexFormat)) {
497
            att_incomplete("compressed internalformat");
498
            att->Complete = GL_FALSE;
499
            return;
500
         }
501
      }
502
      else if (format == GL_DEPTH) {
503
         if (baseFormat == GL_DEPTH_COMPONENT) {
504
            /* OK */
505
         }
506
         else if (ctx->Extensions.EXT_packed_depth_stencil &&
507
                  ctx->Extensions.ARB_depth_texture &&
508
                  baseFormat == GL_DEPTH_STENCIL_EXT) {
509
            /* OK */
510
         }
511
         else {
512
            att->Complete = GL_FALSE;
513
            att_incomplete("bad depth format");
514
            return;
515
         }
516
      }
517
      else {
518
         ASSERT(format == GL_STENCIL);
519
         if (ctx->Extensions.EXT_packed_depth_stencil &&
520
             ctx->Extensions.ARB_depth_texture &&
521
             baseFormat == GL_DEPTH_STENCIL_EXT) {
522
            /* OK */
523
         }
524
         else {
525
            /* no such thing as stencil-only textures */
526
            att_incomplete("illegal stencil texture");
527
            att->Complete = GL_FALSE;
528
            return;
529
         }
530
      }
531
   }
532
   else if (att->Type == GL_RENDERBUFFER_EXT) {
533
      const GLenum baseFormat =
534
         _mesa_get_format_base_format(att->Renderbuffer->Format);
535
 
536
      ASSERT(att->Renderbuffer);
537
      if (!att->Renderbuffer->InternalFormat ||
538
          att->Renderbuffer->Width < 1 ||
539
          att->Renderbuffer->Height < 1) {
540
         att_incomplete("0x0 renderbuffer");
541
         att->Complete = GL_FALSE;
542
         return;
543
      }
544
      if (format == GL_COLOR) {
545
         if (baseFormat != GL_RGB &&
546
             baseFormat != GL_RGBA) {
547
            att_incomplete("bad renderbuffer color format");
548
            att->Complete = GL_FALSE;
549
            return;
550
         }
551
      }
552
      else if (format == GL_DEPTH) {
553
         if (baseFormat == GL_DEPTH_COMPONENT) {
554
            /* OK */
555
         }
556
         else if (ctx->Extensions.EXT_packed_depth_stencil &&
557
                  baseFormat == GL_DEPTH_STENCIL_EXT) {
558
            /* OK */
559
         }
560
         else {
561
            att_incomplete("bad renderbuffer depth format");
562
            att->Complete = GL_FALSE;
563
            return;
564
         }
565
      }
566
      else {
567
         assert(format == GL_STENCIL);
568
         if (baseFormat == GL_STENCIL_INDEX) {
569
            /* OK */
570
         }
571
         else if (ctx->Extensions.EXT_packed_depth_stencil &&
572
                  baseFormat == GL_DEPTH_STENCIL_EXT) {
573
            /* OK */
574
         }
575
         else {
576
            att->Complete = GL_FALSE;
577
            att_incomplete("bad renderbuffer stencil format");
578
            return;
579
         }
580
      }
581
   }
582
   else {
583
      ASSERT(att->Type == GL_NONE);
584
      /* complete */
585
      return;
586
   }
587
}
588
 
589
 
590
/**
591
 * Test if the given framebuffer object is complete and update its
592
 * Status field with the results.
593
 * Calls the ctx->Driver.ValidateFramebuffer() function to allow the
594
 * driver to make hardware-specific validation/completeness checks.
595
 * Also update the framebuffer's Width and Height fields if the
596
 * framebuffer is complete.
597
 */
598
void
599
_mesa_test_framebuffer_completeness(struct gl_context *ctx,
600
                                    struct gl_framebuffer *fb)
601
{
602
   GLuint numImages;
603
   GLenum intFormat = GL_NONE; /* color buffers' internal format */
604
   GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0;
605
   GLint numSamples = -1;
606
   GLint i;
607
   GLuint j;
608
 
609
   assert(fb->Name != 0);
610
 
611
   numImages = 0;
612
   fb->Width = 0;
613
   fb->Height = 0;
614
 
615
   /* Start at -2 to more easily loop over all attachment points.
616
    *  -2: depth buffer
617
    *  -1: stencil buffer
618
    * >=0: color buffer
619
    */
620
   for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) {
621
      struct gl_renderbuffer_attachment *att;
622
      GLenum f;
623
      gl_format mesaFormat;
624
 
625
      /*
626
       * XXX for ARB_fbo, only check color buffers that are named by
627
       * GL_READ_BUFFER and GL_DRAW_BUFFERi.
628
       */
629
 
630
      /* check for attachment completeness
631
       */
632
      if (i == -2) {
633
         att = &fb->Attachment[BUFFER_DEPTH];
634
         test_attachment_completeness(ctx, GL_DEPTH, att);
635
         if (!att->Complete) {
636
            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
637
            fbo_incomplete("depth attachment incomplete", -1);
638
            return;
639
         }
640
      }
641
      else if (i == -1) {
642
         att = &fb->Attachment[BUFFER_STENCIL];
643
         test_attachment_completeness(ctx, GL_STENCIL, att);
644
         if (!att->Complete) {
645
            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
646
            fbo_incomplete("stencil attachment incomplete", -1);
647
            return;
648
         }
649
      }
650
      else {
651
         att = &fb->Attachment[BUFFER_COLOR0 + i];
652
         test_attachment_completeness(ctx, GL_COLOR, att);
653
         if (!att->Complete) {
654
            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
655
            fbo_incomplete("color attachment incomplete", i);
656
            return;
657
         }
658
      }
659
 
660
      /* get width, height, format of the renderbuffer/texture
661
       */
662
      if (att->Type == GL_TEXTURE) {
663
         const struct gl_texture_image *texImg
664
            = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
665
         minWidth = MIN2(minWidth, texImg->Width);
666
         maxWidth = MAX2(maxWidth, texImg->Width);
667
         minHeight = MIN2(minHeight, texImg->Height);
668
         maxHeight = MAX2(maxHeight, texImg->Height);
669
         f = texImg->_BaseFormat;
670
         mesaFormat = texImg->TexFormat;
671
         numImages++;
672
         if (!is_legal_color_format(ctx, f) &&
673
             !is_legal_depth_format(ctx, f)) {
674
            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
675
            fbo_incomplete("texture attachment incomplete", -1);
676
            return;
677
         }
678
      }
679
      else if (att->Type == GL_RENDERBUFFER_EXT) {
680
         minWidth = MIN2(minWidth, att->Renderbuffer->Width);
681
         maxWidth = MAX2(minWidth, att->Renderbuffer->Width);
682
         minHeight = MIN2(minHeight, att->Renderbuffer->Height);
683
         maxHeight = MAX2(minHeight, att->Renderbuffer->Height);
684
         f = att->Renderbuffer->InternalFormat;
685
         mesaFormat = att->Renderbuffer->Format;
686
         numImages++;
687
      }
688
      else {
689
         assert(att->Type == GL_NONE);
690
         continue;
691
      }
692
 
693
      if (numSamples < 0) {
694
         /* first buffer */
695
         numSamples = att->Renderbuffer->NumSamples;
696
      }
697
 
698
      /* check if integer color */
699
      fb->_IntegerColor = _mesa_is_format_integer_color(mesaFormat);
700
 
701
      /* Error-check width, height, format, samples
702
       */
703
      if (numImages == 1) {
704
         /* save format, num samples */
705
         if (i >= 0) {
706
            intFormat = f;
707
         }
708
      }
709
      else {
710
         if (!ctx->Extensions.ARB_framebuffer_object) {
711
            /* check that width, height, format are same */
712
            if (minWidth != maxWidth || minHeight != maxHeight) {
713
               fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
714
               fbo_incomplete("width or height mismatch", -1);
715
               return;
716
            }
717
            /* check that all color buffer have same format */
718
            if (intFormat != GL_NONE && f != intFormat) {
719
               fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
720
               fbo_incomplete("format mismatch", -1);
721
               return;
722
            }
723
         }
724
         if (att->Renderbuffer &&
725
             att->Renderbuffer->NumSamples != numSamples) {
726
            fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
727
            fbo_incomplete("inconsistant number of samples", i);
728
            return;
729
         }
730
 
731
      }
732
   }
733
 
734
#if FEATURE_GL
735
   if (ctx->API == API_OPENGL) {
736
      /* Check that all DrawBuffers are present */
737
      for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) {
738
	 if (fb->ColorDrawBuffer[j] != GL_NONE) {
739
	    const struct gl_renderbuffer_attachment *att
740
	       = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]);
741
	    assert(att);
742
	    if (att->Type == GL_NONE) {
743
	       fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT;
744
	       fbo_incomplete("missing drawbuffer", j);
745
	       return;
746
	    }
747
	 }
748
      }
749
 
750
      /* Check that the ReadBuffer is present */
751
      if (fb->ColorReadBuffer != GL_NONE) {
752
	 const struct gl_renderbuffer_attachment *att
753
	    = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer);
754
	 assert(att);
755
	 if (att->Type == GL_NONE) {
756
	    fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT;
757
            fbo_incomplete("missing readbuffer", -1);
758
	    return;
759
	 }
760
      }
761
   }
762
#else
763
   (void) j;
764
#endif
765
 
766
   if (numImages == 0) {
767
      fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
768
      fbo_incomplete("no attachments", -1);
769
      return;
770
   }
771
 
772
   /* Provisionally set status = COMPLETE ... */
773
   fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
774
 
775
   /* ... but the driver may say the FB is incomplete.
776
    * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED
777
    * if anything.
778
    */
779
   if (ctx->Driver.ValidateFramebuffer) {
780
      ctx->Driver.ValidateFramebuffer(ctx, fb);
781
      if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
782
         fbo_incomplete("driver marked FBO as incomplete", -1);
783
      }
784
   }
785
 
786
   if (fb->_Status == GL_FRAMEBUFFER_COMPLETE_EXT) {
787
      /*
788
       * Note that if ARB_framebuffer_object is supported and the attached
789
       * renderbuffers/textures are different sizes, the framebuffer
790
       * width/height will be set to the smallest width/height.
791
       */
792
      fb->Width = minWidth;
793
      fb->Height = minHeight;
794
 
795
      /* finally, update the visual info for the framebuffer */
796
      _mesa_update_framebuffer_visual(fb);
797
   }
798
}
799
 
800
 
801
GLboolean GLAPIENTRY
802
_mesa_IsRenderbufferEXT(GLuint renderbuffer)
803
{
804
   GET_CURRENT_CONTEXT(ctx);
805
   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
806
   if (renderbuffer) {
807
      struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
808
      if (rb != NULL && rb != &DummyRenderbuffer)
809
         return GL_TRUE;
810
   }
811
   return GL_FALSE;
812
}
813
 
814
 
815
void GLAPIENTRY
816
_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
817
{
818
   struct gl_renderbuffer *newRb;
819
   GET_CURRENT_CONTEXT(ctx);
820
 
821
   ASSERT_OUTSIDE_BEGIN_END(ctx);
822
 
823
   if (target != GL_RENDERBUFFER_EXT) {
824
      _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)");
825
      return;
826
   }
827
 
828
   /* No need to flush here since the render buffer binding has no
829
    * effect on rendering state.
830
    */
831
 
832
   if (renderbuffer) {
833
      newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
834
      if (newRb == &DummyRenderbuffer) {
835
         /* ID was reserved, but no real renderbuffer object made yet */
836
         newRb = NULL;
837
      }
838
      else if (!newRb && ctx->Extensions.ARB_framebuffer_object) {
839
         /* All RB IDs must be Gen'd */
840
         _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)");
841
         return;
842
      }
843
 
844
      if (!newRb) {
845
	 /* create new renderbuffer object */
846
	 newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer);
847
	 if (!newRb) {
848
	    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT");
849
	    return;
850
	 }
851
         ASSERT(newRb->AllocStorage);
852
         _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb);
853
         newRb->RefCount = 1; /* referenced by hash table */
854
      }
855
   }
856
   else {
857
      newRb = NULL;
858
   }
859
 
860
   ASSERT(newRb != &DummyRenderbuffer);
861
 
862
   _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb);
863
}
864
 
865
 
866
/**
867
 * If the given renderbuffer is anywhere attached to the framebuffer, detach
868
 * the renderbuffer.
869
 * This is used when a renderbuffer object is deleted.
870
 * The spec calls for unbinding.
871
 */
872
static void
873
detach_renderbuffer(struct gl_context *ctx,
874
                    struct gl_framebuffer *fb,
875
                    struct gl_renderbuffer *rb)
876
{
877
   GLuint i;
878
   for (i = 0; i < BUFFER_COUNT; i++) {
879
      if (fb->Attachment[i].Renderbuffer == rb) {
880
         _mesa_remove_attachment(ctx, &fb->Attachment[i]);
881
      }
882
   }
883
   invalidate_framebuffer(fb);
884
}
885
 
886
 
887
void GLAPIENTRY
888
_mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers)
889
{
890
   GLint i;
891
   GET_CURRENT_CONTEXT(ctx);
892
 
893
   ASSERT_OUTSIDE_BEGIN_END(ctx);
894
   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
895
 
896
   for (i = 0; i < n; i++) {
897
      if (renderbuffers[i] > 0) {
898
	 struct gl_renderbuffer *rb;
899
	 rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]);
900
	 if (rb) {
901
            /* check if deleting currently bound renderbuffer object */
902
            if (rb == ctx->CurrentRenderbuffer) {
903
               /* bind default */
904
               ASSERT(rb->RefCount >= 2);
905
               _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
906
            }
907
 
908
            if (ctx->DrawBuffer->Name) {
909
               detach_renderbuffer(ctx, ctx->DrawBuffer, rb);
910
            }
911
            if (ctx->ReadBuffer->Name && ctx->ReadBuffer != ctx->DrawBuffer) {
912
               detach_renderbuffer(ctx, ctx->ReadBuffer, rb);
913
            }
914
 
915
	    /* Remove from hash table immediately, to free the ID.
916
             * But the object will not be freed until it's no longer
917
             * referenced anywhere else.
918
             */
919
	    _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]);
920
 
921
            if (rb != &DummyRenderbuffer) {
922
               /* no longer referenced by hash table */
923
               _mesa_reference_renderbuffer(&rb, NULL);
924
	    }
925
	 }
926
      }
927
   }
928
}
929
 
930
 
931
void GLAPIENTRY
932
_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers)
933
{
934
   GET_CURRENT_CONTEXT(ctx);
935
   GLuint first;
936
   GLint i;
937
 
938
   ASSERT_OUTSIDE_BEGIN_END(ctx);
939
 
940
   if (n < 0) {
941
      _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)");
942
      return;
943
   }
944
 
945
   if (!renderbuffers)
946
      return;
947
 
948
   first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n);
949
 
950
   for (i = 0; i < n; i++) {
951
      GLuint name = first + i;
952
      renderbuffers[i] = name;
953
      /* insert dummy placeholder into hash table */
954
      _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
955
      _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer);
956
      _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
957
   }
958
}
959
 
960
 
961
/**
962
 * Given an internal format token for a render buffer, return the
963
 * corresponding base format.
964
 * This is very similar to _mesa_base_tex_format() but the set of valid
965
 * internal formats is somewhat different.
966
 *
967
 * \return one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT
968
 *  GL_DEPTH_STENCIL_EXT or zero if error.
969
 *
970
 * XXX in the future when we support red-only and red-green formats
971
 * we'll also return GL_RED and GL_RG.
972
 */
973
GLenum
974
_mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat)
975
{
976
   switch (internalFormat) {
977
   case GL_ALPHA:
978
   case GL_ALPHA4:
979
   case GL_ALPHA8:
980
   case GL_ALPHA12:
981
   case GL_ALPHA16:
982
      return GL_ALPHA;
983
   case GL_RGB:
984
   case GL_R3_G3_B2:
985
   case GL_RGB4:
986
   case GL_RGB5:
987
   case GL_RGB8:
988
   case GL_RGB10:
989
   case GL_RGB12:
990
   case GL_RGB16:
991
      return GL_RGB;
992
   case GL_RGBA:
993
   case GL_RGBA2:
994
   case GL_RGBA4:
995
   case GL_RGB5_A1:
996
   case GL_RGBA8:
997
   case GL_RGB10_A2:
998
   case GL_RGBA12:
999
   case GL_RGBA16:
1000
   case GL_RGBA16_SNORM:
1001
      return GL_RGBA;
1002
   case GL_STENCIL_INDEX:
1003
   case GL_STENCIL_INDEX1_EXT:
1004
   case GL_STENCIL_INDEX4_EXT:
1005
   case GL_STENCIL_INDEX8_EXT:
1006
   case GL_STENCIL_INDEX16_EXT:
1007
      return GL_STENCIL_INDEX;
1008
   case GL_DEPTH_COMPONENT:
1009
   case GL_DEPTH_COMPONENT16:
1010
   case GL_DEPTH_COMPONENT24:
1011
   case GL_DEPTH_COMPONENT32:
1012
      return GL_DEPTH_COMPONENT;
1013
   case GL_DEPTH_STENCIL_EXT:
1014
   case GL_DEPTH24_STENCIL8_EXT:
1015
      if (ctx->Extensions.EXT_packed_depth_stencil)
1016
         return GL_DEPTH_STENCIL_EXT;
1017
      else
1018
         return 0;
1019
   /* XXX add floating point formats eventually */
1020
   default:
1021
      return 0;
1022
   }
1023
}
1024
 
1025
 
1026
/** sentinal value, see below */
1027
#define NO_SAMPLES 1000
1028
 
1029
 
1030
/**
1031
 * Helper function used by _mesa_RenderbufferStorageEXT() and
1032
 * _mesa_RenderbufferStorageMultisample().
1033
 * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorageEXT().
1034
 */
1035
static void
1036
renderbuffer_storage(GLenum target, GLenum internalFormat,
1037
                     GLsizei width, GLsizei height, GLsizei samples)
1038
{
1039
   const char *func = samples == NO_SAMPLES ?
1040
      "glRenderbufferStorage" : "RenderbufferStorageMultisample";
1041
   struct gl_renderbuffer *rb;
1042
   GLenum baseFormat;
1043
   GET_CURRENT_CONTEXT(ctx);
1044
 
1045
   ASSERT_OUTSIDE_BEGIN_END(ctx);
1046
 
1047
   if (target != GL_RENDERBUFFER_EXT) {
1048
      _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
1049
      return;
1050
   }
1051
 
1052
   baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
1053
   if (baseFormat == 0) {
1054
      _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat)", func);
1055
      return;
1056
   }
1057
 
1058
   if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) {
1059
      _mesa_error(ctx, GL_INVALID_VALUE, "%s(width)", func);
1060
      return;
1061
   }
1062
 
1063
   if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) {
1064
      _mesa_error(ctx, GL_INVALID_VALUE, "%s(height)", func);
1065
      return;
1066
   }
1067
 
1068
   if (samples == NO_SAMPLES) {
1069
      /* NumSamples == 0 indicates non-multisampling */
1070
      samples = 0;
1071
   }
1072
   else if (samples > (GLsizei) ctx->Const.MaxSamples) {
1073
      /* note: driver may choose to use more samples than what's requested */
1074
      _mesa_error(ctx, GL_INVALID_VALUE, "%s(samples)", func);
1075
      return;
1076
   }
1077
 
1078
   rb = ctx->CurrentRenderbuffer;
1079
   if (!rb) {
1080
      _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func);
1081
      return;
1082
   }
1083
 
1084
   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1085
 
1086
   if (rb->InternalFormat == internalFormat &&
1087
       rb->Width == (GLuint) width &&
1088
       rb->Height == (GLuint) height) {
1089
      /* no change in allocation needed */
1090
      return;
1091
   }
1092
 
1093
   /* These MUST get set by the AllocStorage func */
1094
   rb->Format = MESA_FORMAT_NONE;
1095
   rb->NumSamples = samples;
1096
 
1097
   /* Now allocate the storage */
1098
   ASSERT(rb->AllocStorage);
1099
   if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
1100
      /* No error - check/set fields now */
1101
      assert(rb->Format != MESA_FORMAT_NONE);
1102
      assert(rb->Width == (GLuint) width);
1103
      assert(rb->Height == (GLuint) height);
1104
      rb->InternalFormat = internalFormat;
1105
      rb->_BaseFormat = baseFormat;
1106
      assert(rb->_BaseFormat != 0);
1107
   }
1108
   else {
1109
      /* Probably ran out of memory - clear the fields */
1110
      rb->Width = 0;
1111
      rb->Height = 0;
1112
      rb->Format = MESA_FORMAT_NONE;
1113
      rb->InternalFormat = GL_NONE;
1114
      rb->_BaseFormat = GL_NONE;
1115
      rb->NumSamples = 0;
1116
   }
1117
 
1118
   /*
1119
   test_framebuffer_completeness(ctx, fb);
1120
   */
1121
   /* XXX if this renderbuffer is attached anywhere, invalidate attachment
1122
    * points???
1123
    */
1124
}
1125
 
1126
 
1127
#if FEATURE_OES_EGL_image
1128
void GLAPIENTRY
1129
_mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
1130
{
1131
   struct gl_renderbuffer *rb;
1132
   GET_CURRENT_CONTEXT(ctx);
1133
   ASSERT_OUTSIDE_BEGIN_END(ctx);
1134
 
1135
   if (!ctx->Extensions.OES_EGL_image) {
1136
      _mesa_error(ctx, GL_INVALID_OPERATION,
1137
                  "glEGLImageTargetRenderbufferStorageOES(unsupported)");
1138
      return;
1139
   }
1140
 
1141
   if (target != GL_RENDERBUFFER) {
1142
      _mesa_error(ctx, GL_INVALID_ENUM,
1143
                  "EGLImageTargetRenderbufferStorageOES");
1144
      return;
1145
   }
1146
 
1147
   rb = ctx->CurrentRenderbuffer;
1148
   if (!rb) {
1149
      _mesa_error(ctx, GL_INVALID_OPERATION,
1150
                  "EGLImageTargetRenderbufferStorageOES");
1151
      return;
1152
   }
1153
 
1154
   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1155
 
1156
   ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image);
1157
}
1158
#endif
1159
 
1160
 
1161
/**
1162
 * Helper function for _mesa_GetRenderbufferParameterivEXT() and
1163
 * _mesa_GetFramebufferAttachmentParameterivEXT()
1164
 * We have to be careful to respect the base format.  For example, if a
1165
 * renderbuffer/texture was created with internalFormat=GL_RGB but the
1166
 * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE
1167
 * we need to return zero.
1168
 */
1169
static GLint
1170
get_component_bits(GLenum pname, GLenum baseFormat, gl_format format)
1171
{
1172
   switch (pname) {
1173
   case GL_RENDERBUFFER_RED_SIZE_EXT:
1174
   case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
1175
   case GL_RENDERBUFFER_GREEN_SIZE_EXT:
1176
   case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
1177
   case GL_RENDERBUFFER_BLUE_SIZE_EXT:
1178
   case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
1179
      if (baseFormat == GL_RGB || baseFormat == GL_RGBA)
1180
         return _mesa_get_format_bits(format, pname);
1181
      else
1182
         return 0;
1183
   case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
1184
   case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
1185
      if (baseFormat == GL_RGBA || baseFormat == GL_ALPHA)
1186
         return _mesa_get_format_bits(format, pname);
1187
      else
1188
         return 0;
1189
   case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
1190
   case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
1191
      if (baseFormat == GL_DEPTH_COMPONENT || baseFormat == GL_DEPTH_STENCIL)
1192
         return _mesa_get_format_bits(format, pname);
1193
      else
1194
         return 0;
1195
   case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
1196
   case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
1197
      if (baseFormat == GL_STENCIL_INDEX || baseFormat == GL_DEPTH_STENCIL)
1198
         return _mesa_get_format_bits(format, pname);
1199
      else
1200
         return 0;
1201
   default:
1202
      return 0;
1203
   }
1204
}
1205
 
1206
 
1207
 
1208
void GLAPIENTRY
1209
_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
1210
                             GLsizei width, GLsizei height)
1211
{
1212
   /* GL_ARB_fbo says calling this function is equivalent to calling
1213
    * glRenderbufferStorageMultisample() with samples=0.  We pass in
1214
    * a token value here just for error reporting purposes.
1215
    */
1216
   renderbuffer_storage(target, internalFormat, width, height, NO_SAMPLES);
1217
}
1218
 
1219
 
1220
void GLAPIENTRY
1221
_mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples,
1222
                                     GLenum internalFormat,
1223
                                     GLsizei width, GLsizei height)
1224
{
1225
   renderbuffer_storage(target, internalFormat, width, height, samples);
1226
}
1227
 
1228
 
1229
/**
1230
 * OpenGL ES version of glRenderBufferStorage.
1231
 */
1232
void GLAPIENTRY
1233
_es_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
1234
			   GLsizei width, GLsizei height)
1235
{
1236
   switch (internalFormat) {
1237
   case GL_RGB565:
1238
      /* XXX this confuses GL_RENDERBUFFER_INTERNAL_FORMAT_OES */
1239
      /* choose a closest format */
1240
      internalFormat = GL_RGB5;
1241
      break;
1242
   default:
1243
      break;
1244
   }
1245
 
1246
   renderbuffer_storage(target, internalFormat, width, height, 0);
1247
}
1248
 
1249
 
1250
void GLAPIENTRY
1251
_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params)
1252
{
1253
   struct gl_renderbuffer *rb;
1254
   GET_CURRENT_CONTEXT(ctx);
1255
 
1256
   ASSERT_OUTSIDE_BEGIN_END(ctx);
1257
 
1258
   if (target != GL_RENDERBUFFER_EXT) {
1259
      _mesa_error(ctx, GL_INVALID_ENUM,
1260
                  "glGetRenderbufferParameterivEXT(target)");
1261
      return;
1262
   }
1263
 
1264
   rb = ctx->CurrentRenderbuffer;
1265
   if (!rb) {
1266
      _mesa_error(ctx, GL_INVALID_OPERATION,
1267
                  "glGetRenderbufferParameterivEXT");
1268
      return;
1269
   }
1270
 
1271
   /* No need to flush here since we're just quering state which is
1272
    * not effected by rendering.
1273
    */
1274
 
1275
   switch (pname) {
1276
   case GL_RENDERBUFFER_WIDTH_EXT:
1277
      *params = rb->Width;
1278
      return;
1279
   case GL_RENDERBUFFER_HEIGHT_EXT:
1280
      *params = rb->Height;
1281
      return;
1282
   case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT:
1283
      *params = rb->InternalFormat;
1284
      return;
1285
   case GL_RENDERBUFFER_RED_SIZE_EXT:
1286
   case GL_RENDERBUFFER_GREEN_SIZE_EXT:
1287
   case GL_RENDERBUFFER_BLUE_SIZE_EXT:
1288
   case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
1289
   case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
1290
   case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
1291
      *params = get_component_bits(pname, rb->_BaseFormat, rb->Format);
1292
      break;
1293
   case GL_RENDERBUFFER_SAMPLES:
1294
      if (ctx->Extensions.ARB_framebuffer_object) {
1295
         *params = rb->NumSamples;
1296
         break;
1297
      }
1298
      /* fallthrough */
1299
   default:
1300
      _mesa_error(ctx, GL_INVALID_ENUM,
1301
                  "glGetRenderbufferParameterivEXT(target)");
1302
      return;
1303
   }
1304
}
1305
 
1306
 
1307
GLboolean GLAPIENTRY
1308
_mesa_IsFramebufferEXT(GLuint framebuffer)
1309
{
1310
   GET_CURRENT_CONTEXT(ctx);
1311
   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1312
   if (framebuffer) {
1313
      struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer);
1314
      if (rb != NULL && rb != &DummyFramebuffer)
1315
         return GL_TRUE;
1316
   }
1317
   return GL_FALSE;
1318
}
1319
 
1320
 
1321
/**
1322
 * Check if any of the attachments of the given framebuffer are textures
1323
 * (render to texture).  Call ctx->Driver.RenderTexture() for such
1324
 * attachments.
1325
 */
1326
static void
1327
check_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
1328
{
1329
   GLuint i;
1330
   ASSERT(ctx->Driver.RenderTexture);
1331
 
1332
   if (fb->Name == 0)
1333
      return; /* can't render to texture with winsys framebuffers */
1334
 
1335
   for (i = 0; i < BUFFER_COUNT; i++) {
1336
      struct gl_renderbuffer_attachment *att = fb->Attachment + i;
1337
      struct gl_texture_object *texObj = att->Texture;
1338
      if (texObj
1339
          && texObj->Image[att->CubeMapFace][att->TextureLevel]) {
1340
         ctx->Driver.RenderTexture(ctx, fb, att);
1341
      }
1342
   }
1343
}
1344
 
1345
 
1346
/**
1347
 * Examine all the framebuffer's attachments to see if any are textures.
1348
 * If so, call ctx->Driver.FinishRenderTexture() for each texture to
1349
 * notify the device driver that the texture image may have changed.
1350
 */
1351
static void
1352
check_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
1353
{
1354
   if (fb->Name == 0)
1355
      return; /* can't render to texture with winsys framebuffers */
1356
 
1357
   if (ctx->Driver.FinishRenderTexture) {
1358
      GLuint i;
1359
      for (i = 0; i < BUFFER_COUNT; i++) {
1360
         struct gl_renderbuffer_attachment *att = fb->Attachment + i;
1361
         if (att->Texture && att->Renderbuffer) {
1362
            ctx->Driver.FinishRenderTexture(ctx, att);
1363
         }
1364
      }
1365
   }
1366
}
1367
 
1368
 
1369
void GLAPIENTRY
1370
_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
1371
{
1372
   struct gl_framebuffer *newDrawFb, *newReadFb;
1373
   struct gl_framebuffer *oldDrawFb, *oldReadFb;
1374
   GLboolean bindReadBuf, bindDrawBuf;
1375
   GET_CURRENT_CONTEXT(ctx);
1376
 
1377
#ifdef DEBUG
1378
   if (ctx->Extensions.ARB_framebuffer_object) {
1379
      ASSERT(ctx->Extensions.EXT_framebuffer_object);
1380
      ASSERT(ctx->Extensions.EXT_framebuffer_blit);
1381
   }
1382
#endif
1383
 
1384
   ASSERT_OUTSIDE_BEGIN_END(ctx);
1385
 
1386
   if (!ctx->Extensions.EXT_framebuffer_object) {
1387
      _mesa_error(ctx, GL_INVALID_OPERATION,
1388
                  "glBindFramebufferEXT(unsupported)");
1389
      return;
1390
   }
1391
 
1392
   switch (target) {
1393
#if FEATURE_EXT_framebuffer_blit
1394
   case GL_DRAW_FRAMEBUFFER_EXT:
1395
      if (!ctx->Extensions.EXT_framebuffer_blit) {
1396
         _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
1397
         return;
1398
      }
1399
      bindDrawBuf = GL_TRUE;
1400
      bindReadBuf = GL_FALSE;
1401
      break;
1402
   case GL_READ_FRAMEBUFFER_EXT:
1403
      if (!ctx->Extensions.EXT_framebuffer_blit) {
1404
         _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
1405
         return;
1406
      }
1407
      bindDrawBuf = GL_FALSE;
1408
      bindReadBuf = GL_TRUE;
1409
      break;
1410
#endif
1411
   case GL_FRAMEBUFFER_EXT:
1412
      bindDrawBuf = GL_TRUE;
1413
      bindReadBuf = GL_TRUE;
1414
      break;
1415
   default:
1416
      _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
1417
      return;
1418
   }
1419
 
1420
   if (framebuffer) {
1421
      /* Binding a user-created framebuffer object */
1422
      newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer);
1423
      if (newDrawFb == &DummyFramebuffer) {
1424
         /* ID was reserved, but no real framebuffer object made yet */
1425
         newDrawFb = NULL;
1426
      }
1427
      else if (!newDrawFb && ctx->Extensions.ARB_framebuffer_object) {
1428
         /* All FBO IDs must be Gen'd */
1429
         _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)");
1430
         return;
1431
      }
1432
 
1433
      if (!newDrawFb) {
1434
	 /* create new framebuffer object */
1435
	 newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
1436
	 if (!newDrawFb) {
1437
	    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
1438
	    return;
1439
	 }
1440
         _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb);
1441
      }
1442
      newReadFb = newDrawFb;
1443
   }
1444
   else {
1445
      /* Binding the window system framebuffer (which was originally set
1446
       * with MakeCurrent).
1447
       */
1448
      newDrawFb = ctx->WinSysDrawBuffer;
1449
      newReadFb = ctx->WinSysReadBuffer;
1450
   }
1451
 
1452
   ASSERT(newDrawFb);
1453
   ASSERT(newDrawFb != &DummyFramebuffer);
1454
 
1455
   /* save pointers to current/old framebuffers */
1456
   oldDrawFb = ctx->DrawBuffer;
1457
   oldReadFb = ctx->ReadBuffer;
1458
 
1459
   /* check if really changing bindings */
1460
   if (oldDrawFb == newDrawFb)
1461
      bindDrawBuf = GL_FALSE;
1462
   if (oldReadFb == newReadFb)
1463
      bindReadBuf = GL_FALSE;
1464
 
1465
   /*
1466
    * OK, now bind the new Draw/Read framebuffers, if they're changing.
1467
    *
1468
    * We also check if we're beginning and/or ending render-to-texture.
1469
    * When a framebuffer with texture attachments is unbound, call
1470
    * ctx->Driver.FinishRenderTexture().
1471
    * When a framebuffer with texture attachments is bound, call
1472
    * ctx->Driver.RenderTexture().
1473
    *
1474
    * Note that if the ReadBuffer has texture attachments we don't consider
1475
    * that a render-to-texture case.
1476
    */
1477
   if (bindReadBuf) {
1478
      FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1479
 
1480
      /* check if old readbuffer was render-to-texture */
1481
      check_end_texture_render(ctx, oldReadFb);
1482
 
1483
      _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb);
1484
   }
1485
 
1486
   if (bindDrawBuf) {
1487
      FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1488
 
1489
      /* check if old read/draw buffers were render-to-texture */
1490
      if (!bindReadBuf)
1491
         check_end_texture_render(ctx, oldReadFb);
1492
 
1493
      if (oldDrawFb != oldReadFb)
1494
         check_end_texture_render(ctx, oldDrawFb);
1495
 
1496
      /* check if newly bound framebuffer has any texture attachments */
1497
      check_begin_texture_render(ctx, newDrawFb);
1498
 
1499
      _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb);
1500
   }
1501
 
1502
   if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) {
1503
      ctx->Driver.BindFramebuffer(ctx, target, newDrawFb, newReadFb);
1504
   }
1505
}
1506
 
1507
 
1508
void GLAPIENTRY
1509
_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
1510
{
1511
   GLint i;
1512
   GET_CURRENT_CONTEXT(ctx);
1513
 
1514
   ASSERT_OUTSIDE_BEGIN_END(ctx);
1515
   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1516
 
1517
   for (i = 0; i < n; i++) {
1518
      if (framebuffers[i] > 0) {
1519
	 struct gl_framebuffer *fb;
1520
	 fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]);
1521
	 if (fb) {
1522
            ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
1523
 
1524
            /* check if deleting currently bound framebuffer object */
1525
            if (ctx->Extensions.EXT_framebuffer_blit) {
1526
               /* separate draw/read binding points */
1527
               if (fb == ctx->DrawBuffer) {
1528
                  /* bind default */
1529
                  ASSERT(fb->RefCount >= 2);
1530
                  _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
1531
               }
1532
               if (fb == ctx->ReadBuffer) {
1533
                  /* bind default */
1534
                  ASSERT(fb->RefCount >= 2);
1535
                  _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
1536
               }
1537
            }
1538
            else {
1539
               /* only one binding point for read/draw buffers */
1540
               if (fb == ctx->DrawBuffer || fb == ctx->ReadBuffer) {
1541
                  /* bind default */
1542
                  ASSERT(fb->RefCount >= 2);
1543
                  _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1544
               }
1545
            }
1546
 
1547
	    /* remove from hash table immediately, to free the ID */
1548
	    _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]);
1549
 
1550
            if (fb != &DummyFramebuffer) {
1551
               /* But the object will not be freed until it's no longer
1552
                * bound in any context.
1553
                */
1554
               _mesa_reference_framebuffer(&fb, NULL);
1555
	    }
1556
	 }
1557
      }
1558
   }
1559
}
1560
 
1561
 
1562
void GLAPIENTRY
1563
_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers)
1564
{
1565
   GET_CURRENT_CONTEXT(ctx);
1566
   GLuint first;
1567
   GLint i;
1568
 
1569
   ASSERT_OUTSIDE_BEGIN_END(ctx);
1570
 
1571
   if (n < 0) {
1572
      _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)");
1573
      return;
1574
   }
1575
 
1576
   if (!framebuffers)
1577
      return;
1578
 
1579
   first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n);
1580
 
1581
   for (i = 0; i < n; i++) {
1582
      GLuint name = first + i;
1583
      framebuffers[i] = name;
1584
      /* insert dummy placeholder into hash table */
1585
      _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
1586
      _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer);
1587
      _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
1588
   }
1589
}
1590
 
1591
 
1592
 
1593
GLenum GLAPIENTRY
1594
_mesa_CheckFramebufferStatusEXT(GLenum target)
1595
{
1596
   struct gl_framebuffer *buffer;
1597
   GET_CURRENT_CONTEXT(ctx);
1598
 
1599
   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
1600
 
1601
   switch (target) {
1602
#if FEATURE_EXT_framebuffer_blit
1603
   case GL_DRAW_FRAMEBUFFER_EXT:
1604
      if (!ctx->Extensions.EXT_framebuffer_blit) {
1605
         _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1606
         return 0;
1607
      }
1608
      buffer = ctx->DrawBuffer;
1609
      break;
1610
   case GL_READ_FRAMEBUFFER_EXT:
1611
      if (!ctx->Extensions.EXT_framebuffer_blit) {
1612
         _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1613
         return 0;
1614
      }
1615
      buffer = ctx->ReadBuffer;
1616
      break;
1617
#endif
1618
   case GL_FRAMEBUFFER_EXT:
1619
      buffer = ctx->DrawBuffer;
1620
      break;
1621
   default:
1622
      _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1623
      return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */
1624
   }
1625
 
1626
   if (buffer->Name == 0) {
1627
      /* The window system / default framebuffer is always complete */
1628
      return GL_FRAMEBUFFER_COMPLETE_EXT;
1629
   }
1630
 
1631
   /* No need to flush here */
1632
 
1633
   if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) {
1634
      _mesa_test_framebuffer_completeness(ctx, buffer);
1635
   }
1636
 
1637
   return buffer->_Status;
1638
}
1639
 
1640
 
1641
 
1642
/**
1643
 * Common code called by glFramebufferTexture1D/2D/3DEXT().
1644
 */
1645
static void
1646
framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target,
1647
                    GLenum attachment, GLenum textarget, GLuint texture,
1648
                    GLint level, GLint zoffset)
1649
{
1650
   struct gl_renderbuffer_attachment *att;
1651
   struct gl_texture_object *texObj = NULL;
1652
   struct gl_framebuffer *fb;
1653
   GLboolean error = GL_FALSE;
1654
 
1655
   ASSERT_OUTSIDE_BEGIN_END(ctx);
1656
 
1657
   switch (target) {
1658
   case GL_READ_FRAMEBUFFER_EXT:
1659
      error = !ctx->Extensions.EXT_framebuffer_blit;
1660
      fb = ctx->ReadBuffer;
1661
      break;
1662
   case GL_DRAW_FRAMEBUFFER_EXT:
1663
      error = !ctx->Extensions.EXT_framebuffer_blit;
1664
      /* fall-through */
1665
   case GL_FRAMEBUFFER_EXT:
1666
      fb = ctx->DrawBuffer;
1667
      break;
1668
   default:
1669
      error = GL_TRUE;
1670
   }
1671
 
1672
   if (error) {
1673
      _mesa_error(ctx, GL_INVALID_ENUM,
1674
                  "glFramebufferTexture%sEXT(target=0x%x)", caller, target);
1675
      return;
1676
   }
1677
 
1678
   ASSERT(fb);
1679
 
1680
   /* check framebuffer binding */
1681
   if (fb->Name == 0) {
1682
      _mesa_error(ctx, GL_INVALID_OPERATION,
1683
                  "glFramebufferTexture%sEXT", caller);
1684
      return;
1685
   }
1686
 
1687
 
1688
   /* The textarget, level, and zoffset parameters are only validated if
1689
    * texture is non-zero.
1690
    */
1691
   if (texture) {
1692
      GLboolean err = GL_TRUE;
1693
 
1694
      texObj = _mesa_lookup_texture(ctx, texture);
1695
      if (texObj != NULL) {
1696
         if (textarget == 0) {
1697
            /* XXX what's the purpose of this? */
1698
            err = (texObj->Target != GL_TEXTURE_3D) &&
1699
                (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) &&
1700
                (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT);
1701
         }
1702
         else {
1703
            err = (texObj->Target == GL_TEXTURE_CUBE_MAP)
1704
                ? !IS_CUBE_FACE(textarget)
1705
                : (texObj->Target != textarget);
1706
         }
1707
      }
1708
      else {
1709
         /* can't render to a non-existant texture */
1710
         _mesa_error(ctx, GL_INVALID_OPERATION,
1711
                     "glFramebufferTexture%sEXT(non existant texture)",
1712
                     caller);
1713
         return;
1714
      }
1715
 
1716
      if (err) {
1717
         _mesa_error(ctx, GL_INVALID_OPERATION,
1718
                     "glFramebufferTexture%sEXT(texture target mismatch)",
1719
                     caller);
1720
         return;
1721
      }
1722
 
1723
      if (texObj->Target == GL_TEXTURE_3D) {
1724
         const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
1725
         if (zoffset < 0 || zoffset >= maxSize) {
1726
            _mesa_error(ctx, GL_INVALID_VALUE,
1727
                        "glFramebufferTexture%sEXT(zoffset)", caller);
1728
            return;
1729
         }
1730
      }
1731
      else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) ||
1732
               (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
1733
         if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) {
1734
            _mesa_error(ctx, GL_INVALID_VALUE,
1735
                        "glFramebufferTexture%sEXT(layer)", caller);
1736
            return;
1737
         }
1738
      }
1739
 
1740
      if ((level < 0) ||
1741
          (level >= _mesa_max_texture_levels(ctx, texObj->Target))) {
1742
         _mesa_error(ctx, GL_INVALID_VALUE,
1743
                     "glFramebufferTexture%sEXT(level)", caller);
1744
         return;
1745
      }
1746
   }
1747
 
1748
   att = _mesa_get_attachment(ctx, fb, attachment);
1749
   if (att == NULL) {
1750
      _mesa_error(ctx, GL_INVALID_ENUM,
1751
                  "glFramebufferTexture%sEXT(attachment)", caller);
1752
      return;
1753
   }
1754
 
1755
   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1756
 
1757
   _glthread_LOCK_MUTEX(fb->Mutex);
1758
   if (texObj) {
1759
      _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget,
1760
                                   level, zoffset);
1761
      /* Set the render-to-texture flag.  We'll check this flag in
1762
       * glTexImage() and friends to determine if we need to revalidate
1763
       * any FBOs that might be rendering into this texture.
1764
       * This flag never gets cleared since it's non-trivial to determine
1765
       * when all FBOs might be done rendering to this texture.  That's OK
1766
       * though since it's uncommon to render to a texture then repeatedly
1767
       * call glTexImage() to change images in the texture.
1768
       */
1769
      texObj->_RenderToTexture = GL_TRUE;
1770
   }
1771
   else {
1772
      _mesa_remove_attachment(ctx, att);
1773
   }
1774
 
1775
   invalidate_framebuffer(fb);
1776
 
1777
   _glthread_UNLOCK_MUTEX(fb->Mutex);
1778
}
1779
 
1780
 
1781
 
1782
void GLAPIENTRY
1783
_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment,
1784
                              GLenum textarget, GLuint texture, GLint level)
1785
{
1786
   GET_CURRENT_CONTEXT(ctx);
1787
 
1788
   if ((texture != 0) && (textarget != GL_TEXTURE_1D)) {
1789
      _mesa_error(ctx, GL_INVALID_ENUM,
1790
                  "glFramebufferTexture1DEXT(textarget)");
1791
      return;
1792
   }
1793
 
1794
   framebuffer_texture(ctx, "1D", target, attachment, textarget, texture,
1795
                       level, 0);
1796
}
1797
 
1798
 
1799
void GLAPIENTRY
1800
_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
1801
                              GLenum textarget, GLuint texture, GLint level)
1802
{
1803
   GET_CURRENT_CONTEXT(ctx);
1804
 
1805
   if ((texture != 0) &&
1806
       (textarget != GL_TEXTURE_2D) &&
1807
       (textarget != GL_TEXTURE_RECTANGLE_ARB) &&
1808
       (!IS_CUBE_FACE(textarget))) {
1809
      _mesa_error(ctx, GL_INVALID_OPERATION,
1810
                  "glFramebufferTexture2DEXT(textarget=0x%x)", textarget);
1811
      return;
1812
   }
1813
 
1814
   framebuffer_texture(ctx, "2D", target, attachment, textarget, texture,
1815
                       level, 0);
1816
}
1817
 
1818
 
1819
void GLAPIENTRY
1820
_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment,
1821
                              GLenum textarget, GLuint texture,
1822
                              GLint level, GLint zoffset)
1823
{
1824
   GET_CURRENT_CONTEXT(ctx);
1825
 
1826
   if ((texture != 0) && (textarget != GL_TEXTURE_3D)) {
1827
      _mesa_error(ctx, GL_INVALID_ENUM,
1828
                  "glFramebufferTexture3DEXT(textarget)");
1829
      return;
1830
   }
1831
 
1832
   framebuffer_texture(ctx, "3D", target, attachment, textarget, texture,
1833
                       level, zoffset);
1834
}
1835
 
1836
 
1837
void GLAPIENTRY
1838
_mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment,
1839
                                 GLuint texture, GLint level, GLint layer)
1840
{
1841
   GET_CURRENT_CONTEXT(ctx);
1842
 
1843
   framebuffer_texture(ctx, "Layer", target, attachment, 0, texture,
1844
                       level, layer);
1845
}
1846
 
1847
 
1848
void GLAPIENTRY
1849
_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
1850
                                 GLenum renderbufferTarget,
1851
                                 GLuint renderbuffer)
1852
{
1853
   struct gl_renderbuffer_attachment *att;
1854
   struct gl_framebuffer *fb;
1855
   struct gl_renderbuffer *rb;
1856
   GET_CURRENT_CONTEXT(ctx);
1857
 
1858
   ASSERT_OUTSIDE_BEGIN_END(ctx);
1859
 
1860
   switch (target) {
1861
#if FEATURE_EXT_framebuffer_blit
1862
   case GL_DRAW_FRAMEBUFFER_EXT:
1863
      if (!ctx->Extensions.EXT_framebuffer_blit) {
1864
         _mesa_error(ctx, GL_INVALID_ENUM,
1865
                     "glFramebufferRenderbufferEXT(target)");
1866
         return;
1867
      }
1868
      fb = ctx->DrawBuffer;
1869
      break;
1870
   case GL_READ_FRAMEBUFFER_EXT:
1871
      if (!ctx->Extensions.EXT_framebuffer_blit) {
1872
         _mesa_error(ctx, GL_INVALID_ENUM,
1873
                     "glFramebufferRenderbufferEXT(target)");
1874
         return;
1875
      }
1876
      fb = ctx->ReadBuffer;
1877
      break;
1878
#endif
1879
   case GL_FRAMEBUFFER_EXT:
1880
      fb = ctx->DrawBuffer;
1881
      break;
1882
   default:
1883
      _mesa_error(ctx, GL_INVALID_ENUM,
1884
                  "glFramebufferRenderbufferEXT(target)");
1885
      return;
1886
   }
1887
 
1888
   if (renderbufferTarget != GL_RENDERBUFFER_EXT) {
1889
      _mesa_error(ctx, GL_INVALID_ENUM,
1890
                  "glFramebufferRenderbufferEXT(renderbufferTarget)");
1891
      return;
1892
   }
1893
 
1894
   if (fb->Name == 0) {
1895
      /* Can't attach new renderbuffers to a window system framebuffer */
1896
      _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT");
1897
      return;
1898
   }
1899
 
1900
   att = _mesa_get_attachment(ctx, fb, attachment);
1901
   if (att == NULL) {
1902
      _mesa_error(ctx, GL_INVALID_ENUM,
1903
                  "glFramebufferRenderbufferEXT(invalid attachment %s)",
1904
                  _mesa_lookup_enum_by_nr(attachment));
1905
      return;
1906
   }
1907
 
1908
   if (renderbuffer) {
1909
      rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
1910
      if (!rb) {
1911
	 _mesa_error(ctx, GL_INVALID_OPERATION,
1912
		     "glFramebufferRenderbufferEXT(non-existant"
1913
                     " renderbuffer %u)", renderbuffer);
1914
	 return;
1915
      }
1916
      else if (rb == &DummyRenderbuffer) {
1917
         /* This is what NVIDIA does */
1918
	 _mesa_error(ctx, GL_INVALID_VALUE,
1919
		     "glFramebufferRenderbufferEXT(renderbuffer %u)",
1920
                     renderbuffer);
1921
	 return;
1922
      }
1923
   }
1924
   else {
1925
      /* remove renderbuffer attachment */
1926
      rb = NULL;
1927
   }
1928
 
1929
   if (attachment == GL_DEPTH_STENCIL_ATTACHMENT &&
1930
       rb && rb->Format != MESA_FORMAT_NONE) {
1931
      /* make sure the renderbuffer is a depth/stencil format */
1932
      const GLenum baseFormat = _mesa_get_format_base_format(rb->Format);
1933
      if (baseFormat != GL_DEPTH_STENCIL) {
1934
         _mesa_error(ctx, GL_INVALID_OPERATION,
1935
                     "glFramebufferRenderbufferEXT(renderbuffer"
1936
                     " is not DEPTH_STENCIL format)");
1937
         return;
1938
      }
1939
   }
1940
 
1941
 
1942
   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1943
 
1944
   assert(ctx->Driver.FramebufferRenderbuffer);
1945
   ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
1946
 
1947
   /* Some subsequent GL commands may depend on the framebuffer's visual
1948
    * after the binding is updated.  Update visual info now.
1949
    */
1950
   _mesa_update_framebuffer_visual(fb);
1951
}
1952
 
1953
 
1954
void GLAPIENTRY
1955
_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
1956
                                             GLenum pname, GLint *params)
1957
{
1958
   const struct gl_renderbuffer_attachment *att;
1959
   struct gl_framebuffer *buffer;
1960
   GET_CURRENT_CONTEXT(ctx);
1961
 
1962
   ASSERT_OUTSIDE_BEGIN_END(ctx);
1963
 
1964
   switch (target) {
1965
#if FEATURE_EXT_framebuffer_blit
1966
   case GL_DRAW_FRAMEBUFFER_EXT:
1967
      if (!ctx->Extensions.EXT_framebuffer_blit) {
1968
         _mesa_error(ctx, GL_INVALID_ENUM,
1969
                     "glGetFramebufferAttachmentParameterivEXT(target)");
1970
         return;
1971
      }
1972
      buffer = ctx->DrawBuffer;
1973
      break;
1974
   case GL_READ_FRAMEBUFFER_EXT:
1975
      if (!ctx->Extensions.EXT_framebuffer_blit) {
1976
         _mesa_error(ctx, GL_INVALID_ENUM,
1977
                     "glGetFramebufferAttachmentParameterivEXT(target)");
1978
         return;
1979
      }
1980
      buffer = ctx->ReadBuffer;
1981
      break;
1982
#endif
1983
   case GL_FRAMEBUFFER_EXT:
1984
      buffer = ctx->DrawBuffer;
1985
      break;
1986
   default:
1987
      _mesa_error(ctx, GL_INVALID_ENUM,
1988
                  "glGetFramebufferAttachmentParameterivEXT(target)");
1989
      return;
1990
   }
1991
 
1992
   if (buffer->Name == 0) {
1993
      /* the default / window-system FBO */
1994
      att = _mesa_get_fb0_attachment(ctx, buffer, attachment);
1995
   }
1996
   else {
1997
      /* user-created framebuffer FBO */
1998
      att = _mesa_get_attachment(ctx, buffer, attachment);
1999
   }
2000
 
2001
   if (att == NULL) {
2002
      _mesa_error(ctx, GL_INVALID_ENUM,
2003
                  "glGetFramebufferAttachmentParameterivEXT(attachment)");
2004
      return;
2005
   }
2006
 
2007
   if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
2008
      /* the depth and stencil attachments must point to the same buffer */
2009
      const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt;
2010
      depthAtt = _mesa_get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT);
2011
      stencilAtt = _mesa_get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT);
2012
      if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) {
2013
         _mesa_error(ctx, GL_INVALID_OPERATION,
2014
                     "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL"
2015
                     " attachments differ)");
2016
         return;
2017
      }
2018
   }
2019
 
2020
   /* No need to flush here */
2021
 
2022
   switch (pname) {
2023
   case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
2024
      *params = buffer->Name == 0 ? GL_FRAMEBUFFER_DEFAULT : att->Type;
2025
      return;
2026
   case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
2027
      if (att->Type == GL_RENDERBUFFER_EXT) {
2028
	 *params = att->Renderbuffer->Name;
2029
      }
2030
      else if (att->Type == GL_TEXTURE) {
2031
	 *params = att->Texture->Name;
2032
      }
2033
      else {
2034
         assert(att->Type == GL_NONE);
2035
         *params = 0;
2036
      }
2037
      return;
2038
   case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
2039
      if (att->Type == GL_TEXTURE) {
2040
	 *params = att->TextureLevel;
2041
      }
2042
      else {
2043
	 _mesa_error(ctx, GL_INVALID_ENUM,
2044
		     "glGetFramebufferAttachmentParameterivEXT(pname)");
2045
      }
2046
      return;
2047
   case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
2048
      if (att->Type == GL_TEXTURE) {
2049
         if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) {
2050
            *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
2051
         }
2052
         else {
2053
            *params = 0;
2054
         }
2055
      }
2056
      else {
2057
	 _mesa_error(ctx, GL_INVALID_ENUM,
2058
		     "glGetFramebufferAttachmentParameterivEXT(pname)");
2059
      }
2060
      return;
2061
   case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
2062
      if (att->Type == GL_TEXTURE) {
2063
         if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) {
2064
            *params = att->Zoffset;
2065
         }
2066
         else {
2067
            *params = 0;
2068
         }
2069
      }
2070
      else {
2071
	 _mesa_error(ctx, GL_INVALID_ENUM,
2072
		     "glGetFramebufferAttachmentParameterivEXT(pname)");
2073
      }
2074
      return;
2075
   case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
2076
      if (!ctx->Extensions.ARB_framebuffer_object) {
2077
         _mesa_error(ctx, GL_INVALID_ENUM,
2078
                     "glGetFramebufferAttachmentParameterivEXT(pname)");
2079
      }
2080
      else {
2081
         *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format);
2082
      }
2083
      return;
2084
   case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
2085
      if (!ctx->Extensions.ARB_framebuffer_object) {
2086
         _mesa_error(ctx, GL_INVALID_ENUM,
2087
                     "glGetFramebufferAttachmentParameterivEXT(pname)");
2088
         return;
2089
      }
2090
      else {
2091
         gl_format format = att->Renderbuffer->Format;
2092
         if (format == MESA_FORMAT_CI8 || format == MESA_FORMAT_S8) {
2093
            /* special cases */
2094
            *params = GL_INDEX;
2095
         }
2096
         else {
2097
            *params = _mesa_get_format_datatype(format);
2098
         }
2099
      }
2100
      return;
2101
   case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
2102
   case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
2103
   case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
2104
   case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
2105
   case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
2106
   case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
2107
      if (!ctx->Extensions.ARB_framebuffer_object) {
2108
         _mesa_error(ctx, GL_INVALID_ENUM,
2109
                     "glGetFramebufferAttachmentParameterivEXT(pname)");
2110
      }
2111
      else if (att->Texture) {
2112
         const struct gl_texture_image *texImage =
2113
            _mesa_select_tex_image(ctx, att->Texture, att->Texture->Target,
2114
                                   att->TextureLevel);
2115
         if (texImage) {
2116
            *params = get_component_bits(pname, texImage->_BaseFormat,
2117
                                         texImage->TexFormat);
2118
         }
2119
         else {
2120
            *params = 0;
2121
         }
2122
      }
2123
      else if (att->Renderbuffer) {
2124
         *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat,
2125
                                      att->Renderbuffer->Format);
2126
      }
2127
      else {
2128
         *params = 0;
2129
      }
2130
      return;
2131
   default:
2132
      _mesa_error(ctx, GL_INVALID_ENUM,
2133
                  "glGetFramebufferAttachmentParameterivEXT(pname)");
2134
      return;
2135
   }
2136
}
2137
 
2138
 
2139
void GLAPIENTRY
2140
_mesa_GenerateMipmapEXT(GLenum target)
2141
{
2142
   struct gl_texture_object *texObj;
2143
   GET_CURRENT_CONTEXT(ctx);
2144
 
2145
   ASSERT_OUTSIDE_BEGIN_END(ctx);
2146
   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
2147
 
2148
   switch (target) {
2149
   case GL_TEXTURE_1D:
2150
   case GL_TEXTURE_2D:
2151
   case GL_TEXTURE_3D:
2152
   case GL_TEXTURE_CUBE_MAP:
2153
      /* OK, legal value */
2154
      break;
2155
   default:
2156
      /* XXX need to implement GL_TEXTURE_1D_ARRAY and GL_TEXTURE_2D_ARRAY */
2157
      _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)");
2158
      return;
2159
   }
2160
 
2161
   texObj = _mesa_get_current_tex_object(ctx, target);
2162
 
2163
   if (texObj->BaseLevel >= texObj->MaxLevel) {
2164
      /* nothing to do */
2165
      return;
2166
   }
2167
 
2168
   if (texObj->Target == GL_TEXTURE_CUBE_MAP &&
2169
       !_mesa_cube_complete(texObj)) {
2170
      _mesa_error(ctx, GL_INVALID_OPERATION,
2171
                  "glGenerateMipmap(incomplete cube map)");
2172
      return;
2173
   }
2174
 
2175
   _mesa_lock_texture(ctx, texObj);
2176
   if (target == GL_TEXTURE_CUBE_MAP) {
2177
      GLuint face;
2178
      for (face = 0; face < 6; face++)
2179
	 ctx->Driver.GenerateMipmap(ctx,
2180
				    GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face,
2181
				    texObj);
2182
   }
2183
   else {
2184
      ctx->Driver.GenerateMipmap(ctx, target, texObj);
2185
   }
2186
   _mesa_unlock_texture(ctx, texObj);
2187
}
2188
 
2189
 
2190
#if FEATURE_EXT_framebuffer_blit
2191
 
2192
static const struct gl_renderbuffer_attachment *
2193
find_attachment(const struct gl_framebuffer *fb, const struct gl_renderbuffer *rb)
2194
{
2195
   GLuint i;
2196
   for (i = 0; i < Elements(fb->Attachment); i++) {
2197
      if (fb->Attachment[i].Renderbuffer == rb)
2198
         return &fb->Attachment[i];
2199
   }
2200
   return NULL;
2201
}
2202
 
2203
 
2204
 
2205
/**
2206
 * Blit rectangular region, optionally from one framebuffer to another.
2207
 *
2208
 * Note, if the src buffer is multisampled and the dest is not, this is
2209
 * when the samples must be resolved to a single color.
2210
 */
2211
void GLAPIENTRY
2212
_mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
2213
                         GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
2214
                         GLbitfield mask, GLenum filter)
2215
{
2216
   const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT |
2217
                                     GL_DEPTH_BUFFER_BIT |
2218
                                     GL_STENCIL_BUFFER_BIT);
2219
   const struct gl_framebuffer *readFb, *drawFb;
2220
   const struct gl_renderbuffer *colorReadRb, *colorDrawRb;
2221
   GET_CURRENT_CONTEXT(ctx);
2222
 
2223
   ASSERT_OUTSIDE_BEGIN_END(ctx);
2224
   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
2225
 
2226
   if (ctx->NewState) {
2227
      _mesa_update_state(ctx);
2228
   }
2229
 
2230
   readFb = ctx->ReadBuffer;
2231
   drawFb = ctx->DrawBuffer;
2232
 
2233
   if (!readFb || !drawFb) {
2234
      /* This will normally never happen but someday we may want to
2235
       * support MakeCurrent() with no drawables.
2236
       */
2237
      return;
2238
   }
2239
 
2240
   /* check for complete framebuffers */
2241
   if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
2242
       readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
2243
      _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
2244
                  "glBlitFramebufferEXT(incomplete draw/read buffers)");
2245
      return;
2246
   }
2247
 
2248
   if (filter != GL_NEAREST && filter != GL_LINEAR) {
2249
      _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)");
2250
      return;
2251
   }
2252
 
2253
   if (mask & ~legalMaskBits) {
2254
      _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
2255
      return;
2256
   }
2257
 
2258
   /* depth/stencil must be blitted with nearest filtering */
2259
   if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
2260
        && filter != GL_NEAREST) {
2261
      _mesa_error(ctx, GL_INVALID_OPERATION,
2262
             "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter");
2263
      return;
2264
   }
2265
 
2266
   /* get color read/draw renderbuffers */
2267
   if (mask & GL_COLOR_BUFFER_BIT) {
2268
      colorReadRb = readFb->_ColorReadBuffer;
2269
      colorDrawRb = drawFb->_ColorDrawBuffers[0];
2270
   }
2271
   else {
2272
      colorReadRb = colorDrawRb = NULL;
2273
   }
2274
 
2275
   if (mask & GL_STENCIL_BUFFER_BIT) {
2276
      struct gl_renderbuffer *readRb = readFb->_StencilBuffer;
2277
      struct gl_renderbuffer *drawRb = drawFb->_StencilBuffer;
2278
      if (!readRb ||
2279
          !drawRb ||
2280
          _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) !=
2281
          _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) {
2282
         _mesa_error(ctx, GL_INVALID_OPERATION,
2283
                     "glBlitFramebufferEXT(stencil buffer size mismatch");
2284
         return;
2285
      }
2286
   }
2287
 
2288
   if (mask & GL_DEPTH_BUFFER_BIT) {
2289
      struct gl_renderbuffer *readRb = readFb->_DepthBuffer;
2290
      struct gl_renderbuffer *drawRb = drawFb->_DepthBuffer;
2291
      if (!readRb ||
2292
          !drawRb ||
2293
          _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) !=
2294
          _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) {
2295
         _mesa_error(ctx, GL_INVALID_OPERATION,
2296
                     "glBlitFramebufferEXT(depth buffer size mismatch");
2297
         return;
2298
      }
2299
   }
2300
 
2301
   if (readFb->Visual.samples > 0 &&
2302
       drawFb->Visual.samples > 0 &&
2303
       readFb->Visual.samples != drawFb->Visual.samples) {
2304
      _mesa_error(ctx, GL_INVALID_OPERATION,
2305
                  "glBlitFramebufferEXT(mismatched samples");
2306
      return;
2307
   }
2308
 
2309
   /* extra checks for multisample copies... */
2310
   if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) {
2311
      /* src and dest region sizes must be the same */
2312
      if (srcX1 - srcX0 != dstX1 - dstX0 ||
2313
          srcY1 - srcY0 != dstY1 - dstY0) {
2314
         _mesa_error(ctx, GL_INVALID_OPERATION,
2315
                "glBlitFramebufferEXT(bad src/dst multisample region sizes");
2316
         return;
2317
      }
2318
 
2319
      /* color formats must match */
2320
      if (colorReadRb &&
2321
          colorDrawRb &&
2322
          colorReadRb->Format != colorDrawRb->Format) {
2323
         _mesa_error(ctx, GL_INVALID_OPERATION,
2324
                "glBlitFramebufferEXT(bad src/dst multisample pixel formats");
2325
         return;
2326
      }
2327
   }
2328
 
2329
   if (!ctx->Extensions.EXT_framebuffer_blit) {
2330
      _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT");
2331
      return;
2332
   }
2333
 
2334
   /* Debug code */
2335
   if (DEBUG_BLIT) {
2336
      printf("glBlitFramebuffer(%d, %d, %d, %d,  %d, %d, %d, %d,"
2337
	     " 0x%x, 0x%x)\n",
2338
	     srcX0, srcY0, srcX1, srcY1,
2339
	     dstX0, dstY0, dstX1, dstY1,
2340
	     mask, filter);
2341
      if (colorReadRb) {
2342
         const struct gl_renderbuffer_attachment *att;
2343
 
2344
         att = find_attachment(readFb, colorReadRb);
2345
         printf("  Src FBO %u  RB %u (%dx%d)  ",
2346
		readFb->Name, colorReadRb->Name,
2347
		colorReadRb->Width, colorReadRb->Height);
2348
         if (att && att->Texture) {
2349
            printf("Tex %u  tgt 0x%x  level %u  face %u",
2350
		   att->Texture->Name,
2351
		   att->Texture->Target,
2352
		   att->TextureLevel,
2353
		   att->CubeMapFace);
2354
         }
2355
         printf("\n");
2356
 
2357
         att = find_attachment(drawFb, colorDrawRb);
2358
         printf("  Dst FBO %u  RB %u (%dx%d)  ",
2359
		drawFb->Name, colorDrawRb->Name,
2360
		colorDrawRb->Width, colorDrawRb->Height);
2361
         if (att && att->Texture) {
2362
            printf("Tex %u  tgt 0x%x  level %u  face %u",
2363
		   att->Texture->Name,
2364
		   att->Texture->Target,
2365
		   att->TextureLevel,
2366
		   att->CubeMapFace);
2367
         }
2368
         printf("\n");
2369
      }
2370
   }
2371
 
2372
   ASSERT(ctx->Driver.BlitFramebuffer);
2373
   ctx->Driver.BlitFramebuffer(ctx,
2374
                               srcX0, srcY0, srcX1, srcY1,
2375
                               dstX0, dstY0, dstX1, dstY1,
2376
                               mask, filter);
2377
}
2378
#endif /* FEATURE_EXT_framebuffer_blit */
2379
 
2380
#if FEATURE_ARB_geometry_shader4
2381
void GLAPIENTRY
2382
_mesa_FramebufferTextureARB(GLenum target, GLenum attachment,
2383
                            GLuint texture, GLint level)
2384
{
2385
   GET_CURRENT_CONTEXT(ctx);
2386
   _mesa_error(ctx, GL_INVALID_OPERATION,
2387
               "glFramebufferTextureARB "
2388
               "not implemented!");
2389
}
2390
 
2391
void GLAPIENTRY
2392
_mesa_FramebufferTextureFaceARB(GLenum target, GLenum attachment,
2393
                                GLuint texture, GLint level, GLenum face)
2394
{
2395
   GET_CURRENT_CONTEXT(ctx);
2396
   _mesa_error(ctx, GL_INVALID_OPERATION,
2397
               "glFramebufferTextureFaceARB "
2398
               "not implemented!");
2399
}
2400
#endif /* FEATURE_ARB_geometry_shader4 */