blob: 4c92d1fb5a8a82fe8cc06cdef386617a41b2e946 [file] [log] [blame]
Brian Paulddc82ee2005-02-05 19:56:45 +00001/*
2 * Mesa 3-D graphics library
Brian Paul3dc65912008-07-03 15:40:38 -06003 * Version: 7.1
Brian Paulddc82ee2005-02-05 19:56:45 +00004 *
Brian Paul3dc65912008-07-03 15:40:38 -06005 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
Brian Paulddc82ee2005-02-05 19:56:45 +00006 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
Brian Paul463642c2005-02-08 02:06:00 +000026/*
27 * Authors:
28 * Brian Paul
29 */
30
31
Roland Scheideggera1bc0d02007-07-18 20:17:14 +020032#include "buffers.h"
Brian Paulddc82ee2005-02-05 19:56:45 +000033#include "context.h"
34#include "fbobject.h"
Brian Paule4b23562005-05-04 20:11:35 +000035#include "framebuffer.h"
Brian Paulddc82ee2005-02-05 19:56:45 +000036#include "hash.h"
Brian Paul24edd902006-09-29 01:24:26 +000037#include "mipmap.h"
Brian Paule4b23562005-05-04 20:11:35 +000038#include "renderbuffer.h"
Brian Paul99745402006-03-01 02:02:43 +000039#include "state.h"
Brian Paul463642c2005-02-08 02:06:00 +000040#include "teximage.h"
Brian Paulea4fe662006-03-26 05:22:17 +000041#include "texobj.h"
Brian Paul463642c2005-02-08 02:06:00 +000042#include "texstore.h"
Brian Paulddc82ee2005-02-05 19:56:45 +000043
44
Brian Pauld9468c92005-02-10 16:08:07 +000045/**
46 * Notes:
47 *
48 * None of the GL_EXT_framebuffer_object functions are compiled into
49 * display lists.
50 */
51
52
53
Brian Paul923b6fc2005-02-08 04:08:56 +000054/*
55 * When glGenRender/FramebuffersEXT() is called we insert pointers to
56 * these placeholder objects into the hash table.
57 * Later, when the object ID is first bound, we replace the placeholder
58 * with the real frame/renderbuffer.
59 */
Brian Paul2c6f9112005-02-24 05:47:06 +000060static struct gl_framebuffer DummyFramebuffer;
61static struct gl_renderbuffer DummyRenderbuffer;
Brian Paul1864c7d2005-02-08 03:46:37 +000062
63
Brian Paul3deaa012005-02-07 05:08:24 +000064#define IS_CUBE_FACE(TARGET) \
65 ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \
66 (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
Brian Paulddc82ee2005-02-05 19:56:45 +000067
68
Brian Paul3dc65912008-07-03 15:40:38 -060069static void
70delete_dummy_renderbuffer(struct gl_renderbuffer *rb)
71{
72 /* no op */
73}
74
75static void
76delete_dummy_framebuffer(struct gl_framebuffer *fb)
77{
78 /* no op */
79}
80
81
82void
83_mesa_init_fbobjects(GLcontext *ctx)
84{
85 DummyFramebuffer.Delete = delete_dummy_framebuffer;
86 DummyRenderbuffer.Delete = delete_dummy_renderbuffer;
87}
88
89
Brian Paulddc82ee2005-02-05 19:56:45 +000090/**
Brian Paul2c6f9112005-02-24 05:47:06 +000091 * Helper routine for getting a gl_renderbuffer.
Brian Paulddc82ee2005-02-05 19:56:45 +000092 */
Brian Paulea4fe662006-03-26 05:22:17 +000093struct gl_renderbuffer *
94_mesa_lookup_renderbuffer(GLcontext *ctx, GLuint id)
Brian Paulddc82ee2005-02-05 19:56:45 +000095{
Brian Paul2c6f9112005-02-24 05:47:06 +000096 struct gl_renderbuffer *rb;
Brian Paulddc82ee2005-02-05 19:56:45 +000097
Brian Paul1864c7d2005-02-08 03:46:37 +000098 if (id == 0)
Brian Paulddc82ee2005-02-05 19:56:45 +000099 return NULL;
100
Brian Paul2c6f9112005-02-24 05:47:06 +0000101 rb = (struct gl_renderbuffer *)
Brian Paulddc82ee2005-02-05 19:56:45 +0000102 _mesa_HashLookup(ctx->Shared->RenderBuffers, id);
103 return rb;
104}
105
106
107/**
Brian Paul2c6f9112005-02-24 05:47:06 +0000108 * Helper routine for getting a gl_framebuffer.
Brian Paulddc82ee2005-02-05 19:56:45 +0000109 */
Brian Paulea4fe662006-03-26 05:22:17 +0000110struct gl_framebuffer *
111_mesa_lookup_framebuffer(GLcontext *ctx, GLuint id)
Brian Paulddc82ee2005-02-05 19:56:45 +0000112{
Brian Paul2c6f9112005-02-24 05:47:06 +0000113 struct gl_framebuffer *fb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000114
Brian Paul1864c7d2005-02-08 03:46:37 +0000115 if (id == 0)
Brian Paulddc82ee2005-02-05 19:56:45 +0000116 return NULL;
117
Brian Paul2c6f9112005-02-24 05:47:06 +0000118 fb = (struct gl_framebuffer *)
Brian Paulddc82ee2005-02-05 19:56:45 +0000119 _mesa_HashLookup(ctx->Shared->FrameBuffers, id);
Brian Paul463642c2005-02-08 02:06:00 +0000120 return fb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000121}
122
123
124/**
Brian Pauld9468c92005-02-10 16:08:07 +0000125 * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding
Brian Paul2c6f9112005-02-24 05:47:06 +0000126 * gl_renderbuffer_attachment object.
Brian Pauld9468c92005-02-10 16:08:07 +0000127 */
Brian Paul84716042005-11-16 04:05:54 +0000128struct gl_renderbuffer_attachment *
129_mesa_get_attachment(GLcontext *ctx, struct gl_framebuffer *fb,
130 GLenum attachment)
Brian Paul3deaa012005-02-07 05:08:24 +0000131{
132 GLuint i;
133
134 switch (attachment) {
135 case GL_COLOR_ATTACHMENT0_EXT:
136 case GL_COLOR_ATTACHMENT1_EXT:
137 case GL_COLOR_ATTACHMENT2_EXT:
138 case GL_COLOR_ATTACHMENT3_EXT:
139 case GL_COLOR_ATTACHMENT4_EXT:
140 case GL_COLOR_ATTACHMENT5_EXT:
141 case GL_COLOR_ATTACHMENT6_EXT:
142 case GL_COLOR_ATTACHMENT7_EXT:
143 case GL_COLOR_ATTACHMENT8_EXT:
144 case GL_COLOR_ATTACHMENT9_EXT:
145 case GL_COLOR_ATTACHMENT10_EXT:
146 case GL_COLOR_ATTACHMENT11_EXT:
147 case GL_COLOR_ATTACHMENT12_EXT:
148 case GL_COLOR_ATTACHMENT13_EXT:
149 case GL_COLOR_ATTACHMENT14_EXT:
150 case GL_COLOR_ATTACHMENT15_EXT:
151 i = attachment - GL_COLOR_ATTACHMENT0_EXT;
152 if (i >= ctx->Const.MaxColorAttachments) {
153 return NULL;
154 }
Brian Paule4b23562005-05-04 20:11:35 +0000155 return &fb->Attachment[BUFFER_COLOR0 + i];
Brian Paul3deaa012005-02-07 05:08:24 +0000156 case GL_DEPTH_ATTACHMENT_EXT:
Brian Paule4b23562005-05-04 20:11:35 +0000157 return &fb->Attachment[BUFFER_DEPTH];
Brian Paul3deaa012005-02-07 05:08:24 +0000158 case GL_STENCIL_ATTACHMENT_EXT:
Brian Paule4b23562005-05-04 20:11:35 +0000159 return &fb->Attachment[BUFFER_STENCIL];
Brian Paul3deaa012005-02-07 05:08:24 +0000160 default:
161 return NULL;
162 }
163}
164
165
Brian Pauld9468c92005-02-10 16:08:07 +0000166/**
167 * Remove any texture or renderbuffer attached to the given attachment
168 * point. Update reference counts, etc.
169 */
Brian Paule4b23562005-05-04 20:11:35 +0000170void
171_mesa_remove_attachment(GLcontext *ctx, struct gl_renderbuffer_attachment *att)
Brian Paul3deaa012005-02-07 05:08:24 +0000172{
173 if (att->Type == GL_TEXTURE) {
174 ASSERT(att->Texture);
Brian9e01b912007-08-13 11:29:46 +0100175 if (ctx->Driver.FinishRenderTexture) {
176 /* tell driver we're done rendering to this texobj */
177 ctx->Driver.FinishRenderTexture(ctx, att);
Brian Paul3deaa012005-02-07 05:08:24 +0000178 }
Brian9e01b912007-08-13 11:29:46 +0100179 _mesa_reference_texobj(&att->Texture, NULL); /* unbind */
180 ASSERT(!att->Texture);
Brian Paul3deaa012005-02-07 05:08:24 +0000181 }
Brian Paul0e31e022005-12-01 00:25:00 +0000182 if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) {
Brian Paul3deaa012005-02-07 05:08:24 +0000183 ASSERT(!att->Texture);
Brian9e01b912007-08-13 11:29:46 +0100184 _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */
185 ASSERT(!att->Renderbuffer);
Brian Paul3deaa012005-02-07 05:08:24 +0000186 }
187 att->Type = GL_NONE;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000188 att->Complete = GL_TRUE;
Brian Paul3deaa012005-02-07 05:08:24 +0000189}
190
191
Brian Pauld9468c92005-02-10 16:08:07 +0000192/**
193 * Bind a texture object to an attachment point.
194 * The previous binding, if any, will be removed first.
195 */
Brian Paule4b23562005-05-04 20:11:35 +0000196void
197_mesa_set_texture_attachment(GLcontext *ctx,
Brian Paul519b23b2006-03-20 18:51:57 +0000198 struct gl_framebuffer *fb,
Brian Paule4b23562005-05-04 20:11:35 +0000199 struct gl_renderbuffer_attachment *att,
200 struct gl_texture_object *texObj,
201 GLenum texTarget, GLuint level, GLuint zoffset)
Brian Paul3deaa012005-02-07 05:08:24 +0000202{
Brian Paul0e31e022005-12-01 00:25:00 +0000203 if (att->Texture == texObj) {
204 /* re-attaching same texture */
205 ASSERT(att->Type == GL_TEXTURE);
206 }
207 else {
208 /* new attachment */
209 _mesa_remove_attachment(ctx, att);
210 att->Type = GL_TEXTURE;
Brian9e01b912007-08-13 11:29:46 +0100211 assert(!att->Texture);
212 _mesa_reference_texobj(&att->Texture, texObj);
Brian Paul0e31e022005-12-01 00:25:00 +0000213 }
214
215 /* always update these fields */
Brian Paul3deaa012005-02-07 05:08:24 +0000216 att->TextureLevel = level;
217 if (IS_CUBE_FACE(texTarget)) {
218 att->CubeMapFace = texTarget - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
219 }
220 else {
221 att->CubeMapFace = 0;
222 }
223 att->Zoffset = zoffset;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000224 att->Complete = GL_FALSE;
Brian Paul519b23b2006-03-20 18:51:57 +0000225
226 if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) {
Brian Paulea4fe662006-03-26 05:22:17 +0000227 ctx->Driver.RenderTexture(ctx, fb, att);
Brian Paul519b23b2006-03-20 18:51:57 +0000228 }
Brian Paul3deaa012005-02-07 05:08:24 +0000229}
230
231
Brian Pauld9468c92005-02-10 16:08:07 +0000232/**
233 * Bind a renderbuffer to an attachment point.
234 * The previous binding, if any, will be removed first.
235 */
Brian Paule4b23562005-05-04 20:11:35 +0000236void
237_mesa_set_renderbuffer_attachment(GLcontext *ctx,
238 struct gl_renderbuffer_attachment *att,
239 struct gl_renderbuffer *rb)
Brian Paul3deaa012005-02-07 05:08:24 +0000240{
Brian Paulea4fe662006-03-26 05:22:17 +0000241 /* XXX check if re-doing same attachment, exit early */
Brian Paule4b23562005-05-04 20:11:35 +0000242 _mesa_remove_attachment(ctx, att);
Brian Paul3deaa012005-02-07 05:08:24 +0000243 att->Type = GL_RENDERBUFFER_EXT;
Brian Paul2c6f9112005-02-24 05:47:06 +0000244 att->Texture = NULL; /* just to be safe */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000245 att->Complete = GL_FALSE;
Briandccd9c42007-04-02 09:56:28 -0600246 _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
Brian Paul3deaa012005-02-07 05:08:24 +0000247}
248
Brian Paulddc82ee2005-02-05 19:56:45 +0000249
Brian Paulf0bbbf62005-02-09 03:50:30 +0000250/**
Brian Paule4b23562005-05-04 20:11:35 +0000251 * Fallback for ctx->Driver.FramebufferRenderbuffer()
Brian Paul84716042005-11-16 04:05:54 +0000252 * Attach a renderbuffer object to a framebuffer object.
Brian Paule4b23562005-05-04 20:11:35 +0000253 */
254void
Brian Paul84716042005-11-16 04:05:54 +0000255_mesa_framebuffer_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb,
256 GLenum attachment, struct gl_renderbuffer *rb)
Brian Paule4b23562005-05-04 20:11:35 +0000257{
Brian Paul84716042005-11-16 04:05:54 +0000258 struct gl_renderbuffer_attachment *att;
259
Brian Paulea4fe662006-03-26 05:22:17 +0000260 _glthread_LOCK_MUTEX(fb->Mutex);
Brian Paulea4fe662006-03-26 05:22:17 +0000261
Brian Paul84716042005-11-16 04:05:54 +0000262 att = _mesa_get_attachment(ctx, fb, attachment);
263 ASSERT(att);
Brian Paule4b23562005-05-04 20:11:35 +0000264 if (rb) {
265 _mesa_set_renderbuffer_attachment(ctx, att, rb);
266 }
267 else {
268 _mesa_remove_attachment(ctx, att);
269 }
Brian Paulea4fe662006-03-26 05:22:17 +0000270
Brian Paulea4fe662006-03-26 05:22:17 +0000271 _glthread_UNLOCK_MUTEX(fb->Mutex);
Brian Paule4b23562005-05-04 20:11:35 +0000272}
273
274
275/**
Brian Paulf0bbbf62005-02-09 03:50:30 +0000276 * Test if an attachment point is complete and update its Complete field.
277 * \param format if GL_COLOR, this is a color attachment point,
278 * if GL_DEPTH, this is a depth component attachment point,
279 * if GL_STENCIL, this is a stencil component attachment point.
280 */
281static void
282test_attachment_completeness(const GLcontext *ctx, GLenum format,
Brian Paul2c6f9112005-02-24 05:47:06 +0000283 struct gl_renderbuffer_attachment *att)
Brian Paulf0bbbf62005-02-09 03:50:30 +0000284{
285 assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL);
286
287 /* assume complete */
288 att->Complete = GL_TRUE;
289
Brian Paulf0bbbf62005-02-09 03:50:30 +0000290 /* Look for reasons why the attachment might be incomplete */
291 if (att->Type == GL_TEXTURE) {
Brian Paule4b23562005-05-04 20:11:35 +0000292 const struct gl_texture_object *texObj = att->Texture;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000293 struct gl_texture_image *texImage;
294
Brian Paule4b23562005-05-04 20:11:35 +0000295 if (!texObj) {
296 att->Complete = GL_FALSE;
297 return;
298 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000299
300 texImage = texObj->Image[att->CubeMapFace][att->TextureLevel];
301 if (!texImage) {
302 att->Complete = GL_FALSE;
303 return;
304 }
305 if (texImage->Width < 1 || texImage->Height < 1) {
306 att->Complete = GL_FALSE;
307 return;
308 }
309 if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) {
310 att->Complete = GL_FALSE;
311 return;
312 }
313
314 if (format == GL_COLOR) {
Brian Paule4b23562005-05-04 20:11:35 +0000315 if (texImage->TexFormat->BaseFormat != GL_RGB &&
316 texImage->TexFormat->BaseFormat != GL_RGBA) {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000317 att->Complete = GL_FALSE;
318 return;
319 }
320 }
321 else if (format == GL_DEPTH) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000322 if (texImage->TexFormat->BaseFormat == GL_DEPTH_COMPONENT) {
323 /* OK */
324 }
325 else if (ctx->Extensions.EXT_packed_depth_stencil &&
Brian635e9642008-03-28 13:24:12 -0600326 texImage->TexFormat->BaseFormat == GL_DEPTH_STENCIL_EXT) {
Brian Paul1ad7b992005-09-28 02:29:50 +0000327 /* OK */
328 }
329 else {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000330 att->Complete = GL_FALSE;
331 return;
332 }
333 }
334 else {
335 /* no such thing as stencil textures */
336 att->Complete = GL_FALSE;
337 return;
338 }
339 }
Brian Paule4b23562005-05-04 20:11:35 +0000340 else if (att->Type == GL_RENDERBUFFER_EXT) {
Brian Paul49918882006-03-20 15:27:55 +0000341 ASSERT(att->Renderbuffer);
342 if (!att->Renderbuffer->InternalFormat ||
343 att->Renderbuffer->Width < 1 ||
344 att->Renderbuffer->Height < 1) {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000345 att->Complete = GL_FALSE;
346 return;
347 }
348 if (format == GL_COLOR) {
349 if (att->Renderbuffer->_BaseFormat != GL_RGB &&
350 att->Renderbuffer->_BaseFormat != GL_RGBA) {
Brian Paul49918882006-03-20 15:27:55 +0000351 ASSERT(att->Renderbuffer->RedBits);
352 ASSERT(att->Renderbuffer->GreenBits);
353 ASSERT(att->Renderbuffer->BlueBits);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000354 att->Complete = GL_FALSE;
355 return;
356 }
357 }
358 else if (format == GL_DEPTH) {
Brian Paul49918882006-03-20 15:27:55 +0000359 ASSERT(att->Renderbuffer->DepthBits);
Brian Paul1ad7b992005-09-28 02:29:50 +0000360 if (att->Renderbuffer->_BaseFormat == GL_DEPTH_COMPONENT) {
361 /* OK */
362 }
363 else if (ctx->Extensions.EXT_packed_depth_stencil &&
364 att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
365 /* OK */
366 }
367 else {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000368 att->Complete = GL_FALSE;
369 return;
370 }
371 }
372 else {
373 assert(format == GL_STENCIL);
Brian Paul49918882006-03-20 15:27:55 +0000374 ASSERT(att->Renderbuffer->StencilBits);
Brian Paul1ad7b992005-09-28 02:29:50 +0000375 if (att->Renderbuffer->_BaseFormat == GL_STENCIL_INDEX) {
376 /* OK */
377 }
378 else if (ctx->Extensions.EXT_packed_depth_stencil &&
379 att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
380 /* OK */
381 }
382 else {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000383 att->Complete = GL_FALSE;
384 return;
385 }
386 }
387 }
Brian Paule4b23562005-05-04 20:11:35 +0000388 else {
389 ASSERT(att->Type == GL_NONE);
390 /* complete */
391 return;
392 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000393}
394
395
396/**
Brian Paul49918882006-03-20 15:27:55 +0000397 * Helpful for debugging
398 */
399static void
400fbo_incomplete(const char *msg, int index)
401{
Brian Paul13abf912006-04-13 19:17:13 +0000402 (void) msg;
403 (void) index;
Brian Paul49918882006-03-20 15:27:55 +0000404 /*
405 _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index);
406 */
407}
408
409
410/**
Brian Paulf0bbbf62005-02-09 03:50:30 +0000411 * Test if the given framebuffer object is complete and update its
412 * Status field with the results.
Brian Paule4b23562005-05-04 20:11:35 +0000413 * Also update the framebuffer's Width and Height fields if the
414 * framebuffer is complete.
Brian Paulf0bbbf62005-02-09 03:50:30 +0000415 */
Brian Paule4b23562005-05-04 20:11:35 +0000416void
417_mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb)
Brian Paulf0bbbf62005-02-09 03:50:30 +0000418{
Brian Paul6c0c9172005-02-27 16:23:41 +0000419 GLuint numImages, width = 0, height = 0;
420 GLenum intFormat = GL_NONE;
Brian Paule4b23562005-05-04 20:11:35 +0000421 GLuint w = 0, h = 0;
422 GLint i;
Brian Paul28b014e2006-04-05 03:05:17 +0000423 GLuint j;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000424
Brian Paulc7264412005-06-01 00:50:23 +0000425 assert(fb->Name != 0);
426
Brian Paulf0bbbf62005-02-09 03:50:30 +0000427 numImages = 0;
Brian Paule4b23562005-05-04 20:11:35 +0000428 fb->Width = 0;
429 fb->Height = 0;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000430
431 /* Start at -2 to more easily loop over all attachment points */
Brian Paule4b23562005-05-04 20:11:35 +0000432 for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) {
Brian Paul2c6f9112005-02-24 05:47:06 +0000433 struct gl_renderbuffer_attachment *att;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000434 GLenum f;
435
436 if (i == -2) {
Brian Paule4b23562005-05-04 20:11:35 +0000437 att = &fb->Attachment[BUFFER_DEPTH];
Brian Paulf0bbbf62005-02-09 03:50:30 +0000438 test_attachment_completeness(ctx, GL_DEPTH, att);
439 if (!att->Complete) {
Brian Paule4b23562005-05-04 20:11:35 +0000440 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000441 fbo_incomplete("depth attachment incomplete", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000442 return;
443 }
444 }
445 else if (i == -1) {
Brian Paule4b23562005-05-04 20:11:35 +0000446 att = &fb->Attachment[BUFFER_STENCIL];
Brian Paulf0bbbf62005-02-09 03:50:30 +0000447 test_attachment_completeness(ctx, GL_STENCIL, att);
448 if (!att->Complete) {
Brian Paule4b23562005-05-04 20:11:35 +0000449 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000450 fbo_incomplete("stencil attachment incomplete", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000451 return;
452 }
453 }
454 else {
Brian Paule4b23562005-05-04 20:11:35 +0000455 att = &fb->Attachment[BUFFER_COLOR0 + i];
Brian Paulf0bbbf62005-02-09 03:50:30 +0000456 test_attachment_completeness(ctx, GL_COLOR, att);
457 if (!att->Complete) {
Brian Paule4b23562005-05-04 20:11:35 +0000458 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000459 fbo_incomplete("color attachment incomplete", i);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000460 return;
461 }
462 }
463
464 if (att->Type == GL_TEXTURE) {
Brian Paula9fc8ba2005-10-05 01:48:07 +0000465 const struct gl_texture_image *texImg
466 = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
467 w = texImg->Width;
468 h = texImg->Height;
469 f = texImg->_BaseFormat;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000470 numImages++;
Brian Paul9f6ff492006-03-28 15:24:50 +0000471 if (f != GL_RGB && f != GL_RGBA && f != GL_DEPTH_COMPONENT
472 && f != GL_DEPTH_STENCIL_EXT) {
Brian Pauled7f3ae2005-06-07 15:03:40 +0000473 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000474 fbo_incomplete("texture attachment incomplete", -1);
Brian Pauled7f3ae2005-06-07 15:03:40 +0000475 return;
476 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000477 }
478 else if (att->Type == GL_RENDERBUFFER_EXT) {
479 w = att->Renderbuffer->Width;
480 h = att->Renderbuffer->Height;
481 f = att->Renderbuffer->InternalFormat;
482 numImages++;
483 }
484 else {
485 assert(att->Type == GL_NONE);
486 continue;
487 }
488
489 if (numImages == 1) {
490 /* set required width, height and format */
491 width = w;
492 height = h;
493 if (i >= 0)
494 intFormat = f;
495 }
496 else {
497 /* check that width, height, format are same */
498 if (w != width || h != height) {
Brian Paule4b23562005-05-04 20:11:35 +0000499 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000500 fbo_incomplete("width or height mismatch", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000501 return;
502 }
Brian Paule4b23562005-05-04 20:11:35 +0000503 if (intFormat != GL_NONE && f != intFormat) {
504 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000505 fbo_incomplete("format mismatch", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000506 return;
507 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000508 }
509 }
510
Brian Paul868c09a2008-08-08 13:06:54 -0600511#ifndef FEATURE_OES_framebuffer_object
Brian Paulf0bbbf62005-02-09 03:50:30 +0000512 /* Check that all DrawBuffers are present */
Brian Paul28b014e2006-04-05 03:05:17 +0000513 for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) {
514 if (fb->ColorDrawBuffer[j] != GL_NONE) {
Brian Paule4b23562005-05-04 20:11:35 +0000515 const struct gl_renderbuffer_attachment *att
Brian Paul28b014e2006-04-05 03:05:17 +0000516 = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]);
Brian Paule4b23562005-05-04 20:11:35 +0000517 assert(att);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000518 if (att->Type == GL_NONE) {
Brian Paule4b23562005-05-04 20:11:35 +0000519 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT;
Brian Paul28b014e2006-04-05 03:05:17 +0000520 fbo_incomplete("missing drawbuffer", j);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000521 return;
522 }
523 }
524 }
525
526 /* Check that the ReadBuffer is present */
Brian Paule4b23562005-05-04 20:11:35 +0000527 if (fb->ColorReadBuffer != GL_NONE) {
528 const struct gl_renderbuffer_attachment *att
Brian Paul84716042005-11-16 04:05:54 +0000529 = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer);
Brian Paule4b23562005-05-04 20:11:35 +0000530 assert(att);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000531 if (att->Type == GL_NONE) {
Brian Paule4b23562005-05-04 20:11:35 +0000532 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000533 fbo_incomplete("missing readbuffer", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000534 return;
535 }
536 }
Brian Paul868c09a2008-08-08 13:06:54 -0600537#endif
Brian Paulf0bbbf62005-02-09 03:50:30 +0000538
539 if (numImages == 0) {
Brian Paule4b23562005-05-04 20:11:35 +0000540 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT;
Brian Paul49918882006-03-20 15:27:55 +0000541 fbo_incomplete("no attachments", -1);
Brian Paulf0bbbf62005-02-09 03:50:30 +0000542 return;
543 }
Brian Paulf0bbbf62005-02-09 03:50:30 +0000544
Brian Paule4b23562005-05-04 20:11:35 +0000545 /*
546 * If we get here, the framebuffer is complete!
547 */
548 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT;
549 fb->Width = w;
550 fb->Height = h;
551}
Brian Paulf0bbbf62005-02-09 03:50:30 +0000552
553
Brian Paul1864c7d2005-02-08 03:46:37 +0000554GLboolean GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000555_mesa_IsRenderbufferEXT(GLuint renderbuffer)
556{
Brian Paulddc82ee2005-02-05 19:56:45 +0000557 GET_CURRENT_CONTEXT(ctx);
Brian Paulddc82ee2005-02-05 19:56:45 +0000558 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
Brian Paulbc6cced2005-10-04 15:01:27 +0000559 if (renderbuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +0000560 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
Brian Paulbc6cced2005-10-04 15:01:27 +0000561 if (rb != NULL && rb != &DummyRenderbuffer)
562 return GL_TRUE;
563 }
564 return GL_FALSE;
Brian Paulddc82ee2005-02-05 19:56:45 +0000565}
566
567
Brian Paul1864c7d2005-02-08 03:46:37 +0000568void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000569_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
570{
Brian42aaa542007-03-25 10:39:36 -0600571 struct gl_renderbuffer *newRb;
Brian Paulddc82ee2005-02-05 19:56:45 +0000572 GET_CURRENT_CONTEXT(ctx);
573
574 ASSERT_OUTSIDE_BEGIN_END(ctx);
575
Brian Paul3deaa012005-02-07 05:08:24 +0000576 if (target != GL_RENDERBUFFER_EXT) {
577 _mesa_error(ctx, GL_INVALID_ENUM,
578 "glBindRenderbufferEXT(target)");
Brian Paulddc82ee2005-02-05 19:56:45 +0000579 return;
580 }
581
Brian Paul474f28e2005-10-08 14:41:17 +0000582 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Keith Whitwelldf058292006-09-22 11:40:35 +0000583 /* The above doesn't fully flush the drivers in the way that a
584 * glFlush does, but that is required here:
585 */
586 if (ctx->Driver.Flush)
587 ctx->Driver.Flush(ctx);
588
Brian Paul474f28e2005-10-08 14:41:17 +0000589
Brian Paul3deaa012005-02-07 05:08:24 +0000590 if (renderbuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +0000591 newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +0000592 if (newRb == &DummyRenderbuffer) {
593 /* ID was reserved, but no real renderbuffer object made yet */
594 newRb = NULL;
595 }
Brian Paul3deaa012005-02-07 05:08:24 +0000596 if (!newRb) {
597 /* create new renderbuffer object */
Brian Paul2c6f9112005-02-24 05:47:06 +0000598 newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer);
Brian Paul3deaa012005-02-07 05:08:24 +0000599 if (!newRb) {
600 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT");
601 return;
602 }
Brian Paul2c6f9112005-02-24 05:47:06 +0000603 ASSERT(newRb->AllocStorage);
Brian Paul1864c7d2005-02-08 03:46:37 +0000604 _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb);
Brian42aaa542007-03-25 10:39:36 -0600605 newRb->RefCount = 1; /* referenced by hash table */
Brian Paul3deaa012005-02-07 05:08:24 +0000606 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000607 }
Brian Paul463642c2005-02-08 02:06:00 +0000608 else {
609 newRb = NULL;
610 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000611
Brian Paul1864c7d2005-02-08 03:46:37 +0000612 ASSERT(newRb != &DummyRenderbuffer);
613
Brian42aaa542007-03-25 10:39:36 -0600614 _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb);
Brian Paulddc82ee2005-02-05 19:56:45 +0000615}
616
617
Brian Paul1864c7d2005-02-08 03:46:37 +0000618void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000619_mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers)
620{
621 GLint i;
622 GET_CURRENT_CONTEXT(ctx);
623
624 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +0000625 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paulddc82ee2005-02-05 19:56:45 +0000626
627 for (i = 0; i < n; i++) {
Brian Paul2c6f9112005-02-24 05:47:06 +0000628 if (renderbuffers[i] > 0) {
629 struct gl_renderbuffer *rb;
Brian Paulea4fe662006-03-26 05:22:17 +0000630 rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]);
Brian Paul3deaa012005-02-07 05:08:24 +0000631 if (rb) {
Brian Paul91802fd2005-10-04 16:01:02 +0000632 /* check if deleting currently bound renderbuffer object */
633 if (rb == ctx->CurrentRenderbuffer) {
634 /* bind default */
635 ASSERT(rb->RefCount >= 2);
636 _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
637 }
638
Brian42aaa542007-03-25 10:39:36 -0600639 /* Remove from hash table immediately, to free the ID.
640 * But the object will not be freed until it's no longer
641 * referenced anywhere else.
642 */
Brian Paul3deaa012005-02-07 05:08:24 +0000643 _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]);
Brian Paulddc82ee2005-02-05 19:56:45 +0000644
Brian Paul1864c7d2005-02-08 03:46:37 +0000645 if (rb != &DummyRenderbuffer) {
Brian42aaa542007-03-25 10:39:36 -0600646 /* no longer referenced by hash table */
647 _mesa_reference_renderbuffer(&rb, NULL);
Brian Paul3deaa012005-02-07 05:08:24 +0000648 }
649 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000650 }
651 }
652}
653
654
Brian Paul1864c7d2005-02-08 03:46:37 +0000655void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000656_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers)
657{
658 GET_CURRENT_CONTEXT(ctx);
659 GLuint first;
660 GLint i;
661
662 ASSERT_OUTSIDE_BEGIN_END(ctx);
663
664 if (n < 0) {
665 _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)");
666 return;
667 }
668
669 if (!renderbuffers)
670 return;
671
672 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n);
673
674 for (i = 0; i < n; i++) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000675 GLuint name = first + i;
Brian Paulf0bbbf62005-02-09 03:50:30 +0000676 renderbuffers[i] = name;
Brian Paul1864c7d2005-02-08 03:46:37 +0000677 /* insert dummy placeholder into hash table */
Brian Paulddc82ee2005-02-05 19:56:45 +0000678 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
Brian Paul1864c7d2005-02-08 03:46:37 +0000679 _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer);
Brian Paulddc82ee2005-02-05 19:56:45 +0000680 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
Brian Paulddc82ee2005-02-05 19:56:45 +0000681 }
682}
683
684
Brian Pauld9468c92005-02-10 16:08:07 +0000685/**
686 * Given an internal format token for a render buffer, return the
687 * corresponding base format.
Brian Paul59e0faa2006-03-15 17:48:00 +0000688 * This is very similar to _mesa_base_tex_format() but the set of valid
689 * internal formats is somewhat different.
690 *
Brian Pauld9468c92005-02-10 16:08:07 +0000691 * \return one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT
Brian Paul1ad7b992005-09-28 02:29:50 +0000692 * GL_DEPTH_STENCIL_EXT or zero if error.
Brian Pauld9468c92005-02-10 16:08:07 +0000693 */
Brian Paul59e0faa2006-03-15 17:48:00 +0000694GLenum
695_mesa_base_fbo_format(GLcontext *ctx, GLenum internalFormat)
Brian Paul463642c2005-02-08 02:06:00 +0000696{
697 switch (internalFormat) {
Brian Paulf0bbbf62005-02-09 03:50:30 +0000698 case GL_RGB:
699 case GL_R3_G3_B2:
700 case GL_RGB4:
701 case GL_RGB5:
702 case GL_RGB8:
703 case GL_RGB10:
704 case GL_RGB12:
705 case GL_RGB16:
706 return GL_RGB;
707 case GL_RGBA:
708 case GL_RGBA2:
709 case GL_RGBA4:
710 case GL_RGB5_A1:
711 case GL_RGBA8:
712 case GL_RGB10_A2:
713 case GL_RGBA12:
714 case GL_RGBA16:
715 return GL_RGBA;
716 case GL_STENCIL_INDEX:
717 case GL_STENCIL_INDEX1_EXT:
718 case GL_STENCIL_INDEX4_EXT:
719 case GL_STENCIL_INDEX8_EXT:
720 case GL_STENCIL_INDEX16_EXT:
721 return GL_STENCIL_INDEX;
722 case GL_DEPTH_COMPONENT:
Brian Paul2c6f9112005-02-24 05:47:06 +0000723 case GL_DEPTH_COMPONENT16:
724 case GL_DEPTH_COMPONENT24:
725 case GL_DEPTH_COMPONENT32:
Brian Paulf0bbbf62005-02-09 03:50:30 +0000726 return GL_DEPTH_COMPONENT;
Brian Paul1ad7b992005-09-28 02:29:50 +0000727 case GL_DEPTH_STENCIL_EXT:
728 case GL_DEPTH24_STENCIL8_EXT:
729 if (ctx->Extensions.EXT_packed_depth_stencil)
730 return GL_DEPTH_STENCIL_EXT;
731 else
732 return 0;
Brian Pauld9468c92005-02-10 16:08:07 +0000733 /* XXX add floating point formats eventually */
Brian Paulf0bbbf62005-02-09 03:50:30 +0000734 default:
735 return 0;
Brian Paul463642c2005-02-08 02:06:00 +0000736 }
Brian Paul463642c2005-02-08 02:06:00 +0000737}
738
739
Brian Paul1864c7d2005-02-08 03:46:37 +0000740void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000741_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat,
742 GLsizei width, GLsizei height)
743{
Brian Paul2c6f9112005-02-24 05:47:06 +0000744 struct gl_renderbuffer *rb;
Brian Paul463642c2005-02-08 02:06:00 +0000745 GLenum baseFormat;
Brian Paulddc82ee2005-02-05 19:56:45 +0000746 GET_CURRENT_CONTEXT(ctx);
747
748 ASSERT_OUTSIDE_BEGIN_END(ctx);
749
Brian Paul463642c2005-02-08 02:06:00 +0000750 if (target != GL_RENDERBUFFER_EXT) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000751 _mesa_error(ctx, GL_INVALID_ENUM, "glRenderbufferStorageEXT(target)");
752 return;
753 }
754
Brian Paul59e0faa2006-03-15 17:48:00 +0000755 baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
Brian Paul463642c2005-02-08 02:06:00 +0000756 if (baseFormat == 0) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000757 _mesa_error(ctx, GL_INVALID_ENUM,
758 "glRenderbufferStorageEXT(internalFormat)");
759 return;
760 }
761
Brian Paul13abf912006-04-13 19:17:13 +0000762 if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000763 _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(width)");
764 return;
765 }
766
Brian Paul13abf912006-04-13 19:17:13 +0000767 if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000768 _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(height)");
769 return;
770 }
771
Brian Paul2c6f9112005-02-24 05:47:06 +0000772 rb = ctx->CurrentRenderbuffer;
773
774 if (!rb) {
Brian Paul463642c2005-02-08 02:06:00 +0000775 _mesa_error(ctx, GL_INVALID_OPERATION, "glRenderbufferStorageEXT");
776 return;
777 }
778
Brian Paul474f28e2005-10-08 14:41:17 +0000779 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
780
Brian Paul311bcf52005-11-18 02:24:14 +0000781 if (rb->InternalFormat == internalFormat &&
Brian Paul13abf912006-04-13 19:17:13 +0000782 rb->Width == (GLuint) width &&
783 rb->Height == (GLuint) height) {
Brian Paul311bcf52005-11-18 02:24:14 +0000784 /* no change in allocation needed */
785 return;
786 }
787
Brian Paulea4fe662006-03-26 05:22:17 +0000788 /* These MUST get set by the AllocStorage func */
789 rb->_ActualFormat = 0;
790 rb->RedBits =
791 rb->GreenBits =
792 rb->BlueBits =
793 rb->AlphaBits =
794 rb->IndexBits =
795 rb->DepthBits =
796 rb->StencilBits = 0;
797
Brian Paul2c6f9112005-02-24 05:47:06 +0000798 /* Now allocate the storage */
799 ASSERT(rb->AllocStorage);
800 if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) {
801 /* No error - check/set fields now */
Brian Paulea4fe662006-03-26 05:22:17 +0000802 assert(rb->_ActualFormat);
Brian Paul13abf912006-04-13 19:17:13 +0000803 assert(rb->Width == (GLuint) width);
804 assert(rb->Height == (GLuint) height);
Brian Paul0e31e022005-12-01 00:25:00 +0000805 assert(rb->RedBits || rb->GreenBits || rb->BlueBits || rb->AlphaBits ||
806 rb->DepthBits || rb->StencilBits || rb->IndexBits);
Brian Paulea4fe662006-03-26 05:22:17 +0000807 rb->InternalFormat = internalFormat;
Brian Paul2c6f9112005-02-24 05:47:06 +0000808 rb->_BaseFormat = baseFormat;
809 }
810 else {
811 /* Probably ran out of memory - clear the fields */
812 rb->Width = 0;
813 rb->Height = 0;
814 rb->InternalFormat = GL_NONE;
Brian Paulea4fe662006-03-26 05:22:17 +0000815 rb->_ActualFormat = GL_NONE;
Brian Paul2c6f9112005-02-24 05:47:06 +0000816 rb->_BaseFormat = GL_NONE;
Brian Paul0e31e022005-12-01 00:25:00 +0000817 rb->RedBits =
818 rb->GreenBits =
819 rb->BlueBits =
820 rb->AlphaBits =
821 rb->IndexBits =
822 rb->DepthBits =
823 rb->StencilBits = 0;
Brian Paul463642c2005-02-08 02:06:00 +0000824 }
825
Brian Paule4b23562005-05-04 20:11:35 +0000826 /*
827 test_framebuffer_completeness(ctx, fb);
828 */
Brian Paul2c6f9112005-02-24 05:47:06 +0000829 /* XXX if this renderbuffer is attached anywhere, invalidate attachment
830 * points???
831 */
Brian Paulddc82ee2005-02-05 19:56:45 +0000832}
833
834
Brian Paul1864c7d2005-02-08 03:46:37 +0000835void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000836_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params)
837{
838 GET_CURRENT_CONTEXT(ctx);
839
840 ASSERT_OUTSIDE_BEGIN_END(ctx);
841
Brian Paul463642c2005-02-08 02:06:00 +0000842 if (target != GL_RENDERBUFFER_EXT) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000843 _mesa_error(ctx, GL_INVALID_ENUM,
844 "glGetRenderbufferParameterivEXT(target)");
845 return;
846 }
847
Brian Paul463642c2005-02-08 02:06:00 +0000848 if (!ctx->CurrentRenderbuffer) {
Brian Paulddc82ee2005-02-05 19:56:45 +0000849 _mesa_error(ctx, GL_INVALID_OPERATION,
850 "glGetRenderbufferParameterivEXT");
851 return;
852 }
853
Brian Paul474f28e2005-10-08 14:41:17 +0000854 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
855
Brian Paul463642c2005-02-08 02:06:00 +0000856 switch (pname) {
857 case GL_RENDERBUFFER_WIDTH_EXT:
858 *params = ctx->CurrentRenderbuffer->Width;
859 return;
860 case GL_RENDERBUFFER_HEIGHT_EXT:
861 *params = ctx->CurrentRenderbuffer->Height;
862 return;
863 case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT:
864 *params = ctx->CurrentRenderbuffer->InternalFormat;
865 return;
Brian Paul1b939532005-05-31 23:55:21 +0000866 case GL_RENDERBUFFER_RED_SIZE_EXT:
Brian Paul311bcf52005-11-18 02:24:14 +0000867 *params = ctx->CurrentRenderbuffer->RedBits;
Brian Paul1b939532005-05-31 23:55:21 +0000868 break;
869 case GL_RENDERBUFFER_GREEN_SIZE_EXT:
Brian Paul311bcf52005-11-18 02:24:14 +0000870 *params = ctx->CurrentRenderbuffer->GreenBits;
Brian Paul1b939532005-05-31 23:55:21 +0000871 break;
872 case GL_RENDERBUFFER_BLUE_SIZE_EXT:
Brian Paul311bcf52005-11-18 02:24:14 +0000873 *params = ctx->CurrentRenderbuffer->BlueBits;
Brian Paul1b939532005-05-31 23:55:21 +0000874 break;
875 case GL_RENDERBUFFER_ALPHA_SIZE_EXT:
Brian Paul311bcf52005-11-18 02:24:14 +0000876 *params = ctx->CurrentRenderbuffer->AlphaBits;
Brian Paul1b939532005-05-31 23:55:21 +0000877 break;
878 case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
Brian Paul311bcf52005-11-18 02:24:14 +0000879 *params = ctx->CurrentRenderbuffer->DepthBits;
Brian Paul1b939532005-05-31 23:55:21 +0000880 break;
881 case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
Brian Paul311bcf52005-11-18 02:24:14 +0000882 *params = ctx->CurrentRenderbuffer->StencilBits;
Brian Paul1b939532005-05-31 23:55:21 +0000883 break;
Brian Paul463642c2005-02-08 02:06:00 +0000884 default:
885 _mesa_error(ctx, GL_INVALID_ENUM,
886 "glGetRenderbufferParameterivEXT(target)");
887 return;
888 }
Brian Paulddc82ee2005-02-05 19:56:45 +0000889}
890
891
Brian Paul1864c7d2005-02-08 03:46:37 +0000892GLboolean GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000893_mesa_IsFramebufferEXT(GLuint framebuffer)
894{
Brian Paulddc82ee2005-02-05 19:56:45 +0000895 GET_CURRENT_CONTEXT(ctx);
Brian Paulddc82ee2005-02-05 19:56:45 +0000896 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
Brian Paulbc6cced2005-10-04 15:01:27 +0000897 if (framebuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +0000898 struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer);
Brian Paulbc6cced2005-10-04 15:01:27 +0000899 if (rb != NULL && rb != &DummyFramebuffer)
900 return GL_TRUE;
901 }
902 return GL_FALSE;
Brian Paulddc82ee2005-02-05 19:56:45 +0000903}
904
905
Brian Paulea4fe662006-03-26 05:22:17 +0000906static void
907check_begin_texture_render(GLcontext *ctx, struct gl_framebuffer *fb)
908{
909 GLuint i;
910 ASSERT(ctx->Driver.RenderTexture);
911 for (i = 0; i < BUFFER_COUNT; i++) {
912 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
913 struct gl_texture_object *texObj = att->Texture;
Brian Paul9f6ff492006-03-28 15:24:50 +0000914 if (texObj
915 && att->Texture->Image[att->CubeMapFace][att->TextureLevel]) {
Brian Paulea4fe662006-03-26 05:22:17 +0000916 ctx->Driver.RenderTexture(ctx, fb, att);
917 }
918 }
919}
920
921
Brian Paul0e31e022005-12-01 00:25:00 +0000922/**
923 * Examine all the framebuffer's attachments to see if any are textures.
924 * If so, call ctx->Driver.FinishRenderTexture() for each texture to
925 * notify the device driver that the texture image may have changed.
926 */
927static void
Brian Paulea4fe662006-03-26 05:22:17 +0000928check_end_texture_render(GLcontext *ctx, struct gl_framebuffer *fb)
Brian Paul0e31e022005-12-01 00:25:00 +0000929{
930 if (ctx->Driver.FinishRenderTexture) {
931 GLuint i;
932 for (i = 0; i < BUFFER_COUNT; i++) {
933 struct gl_renderbuffer_attachment *att = fb->Attachment + i;
Brian8b361662007-11-09 08:55:49 -0700934 if (att->Texture && att->Renderbuffer) {
Brian Paul519b23b2006-03-20 18:51:57 +0000935 ctx->Driver.FinishRenderTexture(ctx, att);
Brian Paul0e31e022005-12-01 00:25:00 +0000936 }
937 }
938 }
939}
940
941
Brian Paul1864c7d2005-02-08 03:46:37 +0000942void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +0000943_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
944{
Roland Scheideggerdbfb3752007-07-17 17:29:55 +0200945 struct gl_framebuffer *newFb, *newFbread;
Brian Paul0bffb112005-11-08 14:45:48 +0000946 GLboolean bindReadBuf, bindDrawBuf;
Brian Paulddc82ee2005-02-05 19:56:45 +0000947 GET_CURRENT_CONTEXT(ctx);
948
949 ASSERT_OUTSIDE_BEGIN_END(ctx);
950
Brian Paulea4fe662006-03-26 05:22:17 +0000951 if (!ctx->Extensions.EXT_framebuffer_object) {
952 _mesa_error(ctx, GL_INVALID_OPERATION,
953 "glBindFramebufferEXT(unsupported)");
954 return;
955 }
956
Brian Paul0bffb112005-11-08 14:45:48 +0000957 switch (target) {
958#if FEATURE_EXT_framebuffer_blit
959 case GL_DRAW_FRAMEBUFFER_EXT:
960 if (!ctx->Extensions.EXT_framebuffer_blit) {
961 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
962 return;
963 }
964 bindDrawBuf = GL_TRUE;
965 bindReadBuf = GL_FALSE;
966 break;
967 case GL_READ_FRAMEBUFFER_EXT:
968 if (!ctx->Extensions.EXT_framebuffer_blit) {
969 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
970 return;
971 }
972 bindDrawBuf = GL_FALSE;
973 bindReadBuf = GL_TRUE;
974 break;
975#endif
976 case GL_FRAMEBUFFER_EXT:
977 bindDrawBuf = GL_TRUE;
978 bindReadBuf = GL_TRUE;
979 break;
980 default:
Brian Pauleba4ff62005-09-06 21:22:16 +0000981 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)");
Brian Paulddc82ee2005-02-05 19:56:45 +0000982 return;
983 }
984
Brian Paul474f28e2005-10-08 14:41:17 +0000985 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian32d86eb2007-08-16 18:52:48 +0100986
Keith Whitwell5ac93f82006-11-01 14:21:57 +0000987 if (ctx->Driver.Flush) {
988 ctx->Driver.Flush(ctx);
989 }
Brian32d86eb2007-08-16 18:52:48 +0100990
Brian Paul3deaa012005-02-07 05:08:24 +0000991 if (framebuffer) {
Brian Paule4b23562005-05-04 20:11:35 +0000992 /* Binding a user-created framebuffer object */
Brian Paulea4fe662006-03-26 05:22:17 +0000993 newFb = _mesa_lookup_framebuffer(ctx, framebuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +0000994 if (newFb == &DummyFramebuffer) {
Brian Paul923b6fc2005-02-08 04:08:56 +0000995 /* ID was reserved, but no real framebuffer object made yet */
Brian Paul1864c7d2005-02-08 03:46:37 +0000996 newFb = NULL;
997 }
Brian Paul3deaa012005-02-07 05:08:24 +0000998 if (!newFb) {
999 /* create new framebuffer object */
Brian Paul2c6f9112005-02-24 05:47:06 +00001000 newFb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
Brian Paul3deaa012005-02-07 05:08:24 +00001001 if (!newFb) {
1002 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT");
1003 return;
1004 }
Brian Paul1864c7d2005-02-08 03:46:37 +00001005 _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newFb);
Brian Paul3deaa012005-02-07 05:08:24 +00001006 }
Roland Scheideggerdbfb3752007-07-17 17:29:55 +02001007 newFbread = newFb;
Brian Paul3deaa012005-02-07 05:08:24 +00001008 }
Brian Paul463642c2005-02-08 02:06:00 +00001009 else {
Brian Paule4b23562005-05-04 20:11:35 +00001010 /* Binding the window system framebuffer (which was originally set
1011 * with MakeCurrent).
1012 */
1013 newFb = ctx->WinSysDrawBuffer;
Roland Scheideggerdbfb3752007-07-17 17:29:55 +02001014 newFbread = ctx->WinSysReadBuffer;
Brian Paul3deaa012005-02-07 05:08:24 +00001015 }
1016
Brian Paulea4fe662006-03-26 05:22:17 +00001017 ASSERT(newFb);
Brian Paul1864c7d2005-02-08 03:46:37 +00001018 ASSERT(newFb != &DummyFramebuffer);
1019
Brian Paulea4fe662006-03-26 05:22:17 +00001020 /*
1021 * XXX check if re-binding same buffer and skip some of this code.
1022 */
1023
Brian Paul0bffb112005-11-08 14:45:48 +00001024 if (bindReadBuf) {
Roland Scheideggerdbfb3752007-07-17 17:29:55 +02001025 _mesa_reference_framebuffer(&ctx->ReadBuffer, newFbread);
Brian Paul0bffb112005-11-08 14:45:48 +00001026 }
1027
1028 if (bindDrawBuf) {
Briana510bc32007-03-06 10:07:59 -07001029 /* check if old FB had any texture attachments */
1030 check_end_texture_render(ctx, ctx->DrawBuffer);
Brian32d86eb2007-08-16 18:52:48 +01001031
Briana510bc32007-03-06 10:07:59 -07001032 /* check if time to delete this framebuffer */
Briana510bc32007-03-06 10:07:59 -07001033 _mesa_reference_framebuffer(&ctx->DrawBuffer, newFb);
Brian32d86eb2007-08-16 18:52:48 +01001034
1035 if (newFb->Name != 0) {
1036 /* check if newly bound framebuffer has any texture attachments */
1037 check_begin_texture_render(ctx, newFb);
1038 }
Brian Paul0bffb112005-11-08 14:45:48 +00001039 }
Brian Paul59e0faa2006-03-15 17:48:00 +00001040
1041 if (ctx->Driver.BindFramebuffer) {
Roland Scheideggerdbfb3752007-07-17 17:29:55 +02001042 ctx->Driver.BindFramebuffer(ctx, target, newFb, newFbread);
Brian Paul59e0faa2006-03-15 17:48:00 +00001043 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001044}
1045
1046
Brian Paul1864c7d2005-02-08 03:46:37 +00001047void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001048_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers)
1049{
1050 GLint i;
1051 GET_CURRENT_CONTEXT(ctx);
1052
1053 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +00001054 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Keith Whitwelldf058292006-09-22 11:40:35 +00001055 /* The above doesn't fully flush the drivers in the way that a
1056 * glFlush does, but that is required here:
1057 */
1058 if (ctx->Driver.Flush)
1059 ctx->Driver.Flush(ctx);
Brian Paulddc82ee2005-02-05 19:56:45 +00001060
1061 for (i = 0; i < n; i++) {
Brian Paul2c6f9112005-02-24 05:47:06 +00001062 if (framebuffers[i] > 0) {
1063 struct gl_framebuffer *fb;
Brian Paulea4fe662006-03-26 05:22:17 +00001064 fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]);
Brian Paul3deaa012005-02-07 05:08:24 +00001065 if (fb) {
Brian Paule4b23562005-05-04 20:11:35 +00001066 ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]);
Brian Paul91802fd2005-10-04 16:01:02 +00001067
1068 /* check if deleting currently bound framebuffer object */
1069 if (fb == ctx->DrawBuffer) {
1070 /* bind default */
1071 ASSERT(fb->RefCount >= 2);
1072 _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1073 }
1074
Brian Paul3deaa012005-02-07 05:08:24 +00001075 /* remove from hash table immediately, to free the ID */
1076 _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]);
Brian Paulddc82ee2005-02-05 19:56:45 +00001077
Brian Paul1864c7d2005-02-08 03:46:37 +00001078 if (fb != &DummyFramebuffer) {
1079 /* But the object will not be freed until it's no longer
1080 * bound in any context.
1081 */
Briana510bc32007-03-06 10:07:59 -07001082 _mesa_unreference_framebuffer(&fb);
Brian Paul3deaa012005-02-07 05:08:24 +00001083 }
1084 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001085 }
1086 }
1087}
1088
1089
Brian Paul1864c7d2005-02-08 03:46:37 +00001090void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001091_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers)
1092{
1093 GET_CURRENT_CONTEXT(ctx);
1094 GLuint first;
1095 GLint i;
1096
1097 ASSERT_OUTSIDE_BEGIN_END(ctx);
1098
1099 if (n < 0) {
1100 _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)");
1101 return;
1102 }
1103
1104 if (!framebuffers)
1105 return;
1106
1107 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n);
1108
1109 for (i = 0; i < n; i++) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001110 GLuint name = first + i;
Brian Paulf0bbbf62005-02-09 03:50:30 +00001111 framebuffers[i] = name;
1112 /* insert dummy placeholder into hash table */
Brian Paulddc82ee2005-02-05 19:56:45 +00001113 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
Brian Paul1864c7d2005-02-08 03:46:37 +00001114 _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer);
Brian Paulddc82ee2005-02-05 19:56:45 +00001115 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
Brian Paulddc82ee2005-02-05 19:56:45 +00001116 }
1117}
1118
1119
1120
Brian Paul1864c7d2005-02-08 03:46:37 +00001121GLenum GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001122_mesa_CheckFramebufferStatusEXT(GLenum target)
1123{
Brian Paul0bffb112005-11-08 14:45:48 +00001124 struct gl_framebuffer *buffer;
Brian Paulddc82ee2005-02-05 19:56:45 +00001125 GET_CURRENT_CONTEXT(ctx);
1126
Brian Paule4b23562005-05-04 20:11:35 +00001127 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
Brian Paulddc82ee2005-02-05 19:56:45 +00001128
Brian Paul0bffb112005-11-08 14:45:48 +00001129 switch (target) {
1130#if FEATURE_EXT_framebuffer_blit
1131 case GL_DRAW_FRAMEBUFFER_EXT:
1132 if (!ctx->Extensions.EXT_framebuffer_blit) {
1133 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1134 return 0;
1135 }
1136 buffer = ctx->DrawBuffer;
1137 break;
1138 case GL_READ_FRAMEBUFFER_EXT:
1139 if (!ctx->Extensions.EXT_framebuffer_blit) {
1140 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
1141 return 0;
1142 }
1143 buffer = ctx->ReadBuffer;
1144 break;
1145#endif
1146 case GL_FRAMEBUFFER_EXT:
1147 buffer = ctx->DrawBuffer;
1148 break;
1149 default:
Brian Paulf0bbbf62005-02-09 03:50:30 +00001150 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)");
Brian Paule4b23562005-05-04 20:11:35 +00001151 return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */
Brian Paulddc82ee2005-02-05 19:56:45 +00001152 }
1153
Brian Paul0bffb112005-11-08 14:45:48 +00001154 if (buffer->Name == 0) {
Brian Paulf0bbbf62005-02-09 03:50:30 +00001155 /* The window system / default framebuffer is always complete */
1156 return GL_FRAMEBUFFER_COMPLETE_EXT;
1157 }
1158
Brian Paul474f28e2005-10-08 14:41:17 +00001159 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1160
Brian Paul0bffb112005-11-08 14:45:48 +00001161 _mesa_test_framebuffer_completeness(ctx, buffer);
1162 return buffer->_Status;
Brian Paulddc82ee2005-02-05 19:56:45 +00001163}
1164
1165
1166
1167/**
Brian Paulea4fe662006-03-26 05:22:17 +00001168 * Common code called by glFramebufferTexture1D/2D/3DEXT().
Brian Paulddc82ee2005-02-05 19:56:45 +00001169 */
Brian Paulea4fe662006-03-26 05:22:17 +00001170static void
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001171framebuffer_texture(GLcontext *ctx, const char *caller, GLenum target,
1172 GLenum attachment, GLenum textarget, GLuint texture,
Brian Paulea4fe662006-03-26 05:22:17 +00001173 GLint level, GLint zoffset)
Brian Paulddc82ee2005-02-05 19:56:45 +00001174{
Brian Paul2c6f9112005-02-24 05:47:06 +00001175 struct gl_renderbuffer_attachment *att;
Brian Paulea4fe662006-03-26 05:22:17 +00001176 struct gl_texture_object *texObj = NULL;
1177 struct gl_framebuffer *fb;
Brian Paulddc82ee2005-02-05 19:56:45 +00001178
1179 ASSERT_OUTSIDE_BEGIN_END(ctx);
1180
Brian Paulea4fe662006-03-26 05:22:17 +00001181 if (target != GL_FRAMEBUFFER_EXT) {
1182 _mesa_error(ctx, GL_INVALID_ENUM,
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001183 "glFramebufferTexture%sEXT(target)", caller);
Brian Paulddc82ee2005-02-05 19:56:45 +00001184 return;
Brian Paulea4fe662006-03-26 05:22:17 +00001185 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001186
Brian Paulea4fe662006-03-26 05:22:17 +00001187 fb = ctx->DrawBuffer;
1188 ASSERT(fb);
Brian Paul3deaa012005-02-07 05:08:24 +00001189
Brian Paulea4fe662006-03-26 05:22:17 +00001190 /* check framebuffer binding */
1191 if (fb->Name == 0) {
1192 _mesa_error(ctx, GL_INVALID_OPERATION,
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001193 "glFramebufferTexture%sEXT", caller);
Brian Paulea4fe662006-03-26 05:22:17 +00001194 return;
1195 }
1196
Brian Paulea4fe662006-03-26 05:22:17 +00001197
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001198 /* The textarget, level, and zoffset parameters are only validated if
1199 * texture is non-zero.
1200 */
1201 if (texture) {
1202 GLboolean err = GL_TRUE;
1203
1204 texObj = _mesa_lookup_texture(ctx, texture);
1205 if (texObj != NULL) {
Ian Romanickbb372f12007-05-16 15:34:22 -07001206 if (textarget == 0) {
1207 err = (texObj->Target != GL_TEXTURE_3D) &&
1208 (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) &&
1209 (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT);
1210 }
1211 else {
1212 err = (texObj->Target == GL_TEXTURE_CUBE_MAP)
1213 ? !IS_CUBE_FACE(textarget)
1214 : (texObj->Target != textarget);
1215 }
Brian Paulea4fe662006-03-26 05:22:17 +00001216 }
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001217
1218 if (err) {
Brian Paulea4fe662006-03-26 05:22:17 +00001219 _mesa_error(ctx, GL_INVALID_OPERATION,
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001220 "glFramebufferTexture%sEXT(texture target mismatch)",
1221 caller);
Brian Paulea4fe662006-03-26 05:22:17 +00001222 return;
1223 }
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001224
1225 if (texObj->Target == GL_TEXTURE_3D) {
Brian Paulea4fe662006-03-26 05:22:17 +00001226 const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
1227 if (zoffset < 0 || zoffset >= maxSize) {
1228 _mesa_error(ctx, GL_INVALID_VALUE,
Ian Romanickbb372f12007-05-16 15:34:22 -07001229 "glFramebufferTexture%sEXT(zoffset)", caller);
Brian Paulea4fe662006-03-26 05:22:17 +00001230 return;
1231 }
1232 }
Ian Romanickbb372f12007-05-16 15:34:22 -07001233 else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) ||
1234 (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
1235 if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) {
1236 _mesa_error(ctx, GL_INVALID_VALUE,
1237 "glFramebufferTexture%sEXT(layer)", caller);
1238 return;
1239 }
1240 }
1241
Brian Paulea4fe662006-03-26 05:22:17 +00001242
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001243 if ((level < 0) ||
1244 (level >= _mesa_max_texture_levels(ctx, texObj->Target))) {
1245 _mesa_error(ctx, GL_INVALID_VALUE,
1246 "glFramebufferTexture%sEXT(level)", caller);
1247 return;
1248 }
Brian Paulea4fe662006-03-26 05:22:17 +00001249 }
1250
1251 att = _mesa_get_attachment(ctx, fb, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00001252 if (att == NULL) {
1253 _mesa_error(ctx, GL_INVALID_ENUM,
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001254 "glFramebufferTexture%sEXT(attachment)", caller);
Brian Paul3deaa012005-02-07 05:08:24 +00001255 return;
1256 }
1257
Brian Paul474f28e2005-10-08 14:41:17 +00001258 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Keith Whitwelldf058292006-09-22 11:40:35 +00001259 /* The above doesn't fully flush the drivers in the way that a
1260 * glFlush does, but that is required here:
1261 */
1262 if (ctx->Driver.Flush)
1263 ctx->Driver.Flush(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +00001264
Brian Paulea4fe662006-03-26 05:22:17 +00001265 _glthread_LOCK_MUTEX(fb->Mutex);
1266 if (texObj) {
1267 _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget,
1268 level, zoffset);
Brian Paul3deaa012005-02-07 05:08:24 +00001269 }
1270 else {
Brian Paul519b23b2006-03-20 18:51:57 +00001271 _mesa_remove_attachment(ctx, att);
Brian Paul3deaa012005-02-07 05:08:24 +00001272 }
Brian Paulea4fe662006-03-26 05:22:17 +00001273 _glthread_UNLOCK_MUTEX(fb->Mutex);
1274}
1275
1276
1277
1278void GLAPIENTRY
1279_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment,
1280 GLenum textarget, GLuint texture, GLint level)
1281{
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001282 GET_CURRENT_CONTEXT(ctx);
1283
1284 if ((texture != 0) && (textarget != GL_TEXTURE_1D)) {
1285 _mesa_error(ctx, GL_INVALID_ENUM,
1286 "glFramebufferTexture1DEXT(textarget)");
1287 return;
1288 }
1289
1290 framebuffer_texture(ctx, "1D", target, attachment, textarget, texture,
1291 level, 0);
Brian Paulddc82ee2005-02-05 19:56:45 +00001292}
1293
1294
Brian Paul1864c7d2005-02-08 03:46:37 +00001295void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001296_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
1297 GLenum textarget, GLuint texture, GLint level)
1298{
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001299 GET_CURRENT_CONTEXT(ctx);
1300
1301 if ((texture != 0) &&
1302 (textarget != GL_TEXTURE_2D) &&
1303 (textarget != GL_TEXTURE_RECTANGLE_ARB) &&
1304 (!IS_CUBE_FACE(textarget))) {
1305 _mesa_error(ctx, GL_INVALID_OPERATION,
1306 "glFramebufferTexture2DEXT(textarget)");
1307 return;
1308 }
1309
1310 framebuffer_texture(ctx, "2D", target, attachment, textarget, texture,
1311 level, 0);
Brian Paulddc82ee2005-02-05 19:56:45 +00001312}
1313
1314
Brian Paul1864c7d2005-02-08 03:46:37 +00001315void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001316_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment,
1317 GLenum textarget, GLuint texture,
1318 GLint level, GLint zoffset)
1319{
Ian Romanickb0fe0d82007-05-15 13:42:25 -07001320 GET_CURRENT_CONTEXT(ctx);
1321
1322 if ((texture != 0) && (textarget != GL_TEXTURE_3D)) {
1323 _mesa_error(ctx, GL_INVALID_ENUM,
1324 "glFramebufferTexture3DEXT(textarget)");
1325 return;
1326 }
1327
1328 framebuffer_texture(ctx, "3D", target, attachment, textarget, texture,
Brian Paulea4fe662006-03-26 05:22:17 +00001329 level, zoffset);
Brian Paulddc82ee2005-02-05 19:56:45 +00001330}
1331
1332
Brian Paul1864c7d2005-02-08 03:46:37 +00001333void GLAPIENTRY
Ian Romanickbb372f12007-05-16 15:34:22 -07001334_mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment,
1335 GLuint texture, GLint level, GLint layer)
1336{
1337 GET_CURRENT_CONTEXT(ctx);
1338
1339 framebuffer_texture(ctx, "Layer", target, attachment, 0, texture,
1340 level, layer);
1341}
1342
1343
1344void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001345_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
1346 GLenum renderbufferTarget,
1347 GLuint renderbuffer)
1348{
Brian Paul2c6f9112005-02-24 05:47:06 +00001349 struct gl_renderbuffer_attachment *att;
Brian Paul0bffb112005-11-08 14:45:48 +00001350 struct gl_framebuffer *fb;
Brian Paule4b23562005-05-04 20:11:35 +00001351 struct gl_renderbuffer *rb;
Brian Paulddc82ee2005-02-05 19:56:45 +00001352 GET_CURRENT_CONTEXT(ctx);
1353
1354 ASSERT_OUTSIDE_BEGIN_END(ctx);
1355
Brian Paul0bffb112005-11-08 14:45:48 +00001356 switch (target) {
1357#if FEATURE_EXT_framebuffer_blit
1358 case GL_DRAW_FRAMEBUFFER_EXT:
1359 if (!ctx->Extensions.EXT_framebuffer_blit) {
1360 _mesa_error(ctx, GL_INVALID_ENUM,
1361 "glFramebufferRenderbufferEXT(target)");
1362 return;
1363 }
1364 fb = ctx->DrawBuffer;
1365 break;
1366 case GL_READ_FRAMEBUFFER_EXT:
1367 if (!ctx->Extensions.EXT_framebuffer_blit) {
1368 _mesa_error(ctx, GL_INVALID_ENUM,
1369 "glFramebufferRenderbufferEXT(target)");
1370 return;
1371 }
1372 fb = ctx->ReadBuffer;
1373 break;
1374#endif
1375 case GL_FRAMEBUFFER_EXT:
1376 fb = ctx->DrawBuffer;
1377 break;
1378 default:
Brian Paulddc82ee2005-02-05 19:56:45 +00001379 _mesa_error(ctx, GL_INVALID_ENUM,
1380 "glFramebufferRenderbufferEXT(target)");
1381 return;
1382 }
1383
Brian Paul3deaa012005-02-07 05:08:24 +00001384 if (renderbufferTarget != GL_RENDERBUFFER_EXT) {
Brian Paule4b23562005-05-04 20:11:35 +00001385 _mesa_error(ctx, GL_INVALID_ENUM,
1386 "glFramebufferRenderbufferEXT(renderbufferTarget)");
Brian Paul3deaa012005-02-07 05:08:24 +00001387 return;
1388 }
1389
Brian Paul0bffb112005-11-08 14:45:48 +00001390 if (fb->Name == 0) {
Brian Paulab8ef282005-09-07 23:21:59 +00001391 /* Can't attach new renderbuffers to a window system framebuffer */
Brian Paul3deaa012005-02-07 05:08:24 +00001392 _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT");
1393 return;
1394 }
1395
Brian Paul84716042005-11-16 04:05:54 +00001396 att = _mesa_get_attachment(ctx, fb, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00001397 if (att == NULL) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001398 _mesa_error(ctx, GL_INVALID_ENUM,
1399 "glFramebufferRenderbufferEXT(attachment)");
1400 return;
1401 }
1402
Brian Paul1864c7d2005-02-08 03:46:37 +00001403 if (renderbuffer) {
Brian Paulea4fe662006-03-26 05:22:17 +00001404 rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
Brian Paul1864c7d2005-02-08 03:46:37 +00001405 if (!rb) {
Brian Paule4b23562005-05-04 20:11:35 +00001406 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Paul1864c7d2005-02-08 03:46:37 +00001407 "glFramebufferRenderbufferEXT(renderbuffer)");
1408 return;
1409 }
Brian Paul1864c7d2005-02-08 03:46:37 +00001410 }
1411 else {
Brian Paule4b23562005-05-04 20:11:35 +00001412 /* remove renderbuffer attachment */
1413 rb = NULL;
Brian Paul1864c7d2005-02-08 03:46:37 +00001414 }
Brian Paule4b23562005-05-04 20:11:35 +00001415
Brian Paul474f28e2005-10-08 14:41:17 +00001416 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Keith Whitwelldf058292006-09-22 11:40:35 +00001417 /* The above doesn't fully flush the drivers in the way that a
1418 * glFlush does, but that is required here:
1419 */
1420 if (ctx->Driver.Flush)
1421 ctx->Driver.Flush(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +00001422
Brian Paule4b23562005-05-04 20:11:35 +00001423 assert(ctx->Driver.FramebufferRenderbuffer);
Brian Paul84716042005-11-16 04:05:54 +00001424 ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
Brian Paul2e019182006-03-07 01:43:52 +00001425
1426 /* Some subsequent GL commands may depend on the framebuffer's visual
1427 * after the binding is updated. Update visual info now.
1428 */
1429 _mesa_update_framebuffer_visual(fb);
Brian Paulddc82ee2005-02-05 19:56:45 +00001430}
1431
1432
Brian Paul1864c7d2005-02-08 03:46:37 +00001433void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001434_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
1435 GLenum pname, GLint *params)
1436{
Brian Paul2c6f9112005-02-24 05:47:06 +00001437 const struct gl_renderbuffer_attachment *att;
Brian Paul0bffb112005-11-08 14:45:48 +00001438 struct gl_framebuffer *buffer;
Brian Paulddc82ee2005-02-05 19:56:45 +00001439 GET_CURRENT_CONTEXT(ctx);
1440
1441 ASSERT_OUTSIDE_BEGIN_END(ctx);
1442
Brian Paul0bffb112005-11-08 14:45:48 +00001443 switch (target) {
1444#if FEATURE_EXT_framebuffer_blit
1445 case GL_DRAW_FRAMEBUFFER_EXT:
1446 if (!ctx->Extensions.EXT_framebuffer_blit) {
1447 _mesa_error(ctx, GL_INVALID_ENUM,
1448 "glGetFramebufferAttachmentParameterivEXT(target)");
1449 return;
1450 }
1451 buffer = ctx->DrawBuffer;
1452 break;
1453 case GL_READ_FRAMEBUFFER_EXT:
1454 if (!ctx->Extensions.EXT_framebuffer_blit) {
1455 _mesa_error(ctx, GL_INVALID_ENUM,
1456 "glGetFramebufferAttachmentParameterivEXT(target)");
1457 return;
1458 }
1459 buffer = ctx->ReadBuffer;
1460 break;
1461#endif
1462 case GL_FRAMEBUFFER_EXT:
1463 buffer = ctx->DrawBuffer;
1464 break;
1465 default:
Brian Paulddc82ee2005-02-05 19:56:45 +00001466 _mesa_error(ctx, GL_INVALID_ENUM,
1467 "glGetFramebufferAttachmentParameterivEXT(target)");
1468 return;
1469 }
1470
Brian Paul0bffb112005-11-08 14:45:48 +00001471 if (buffer->Name == 0) {
Brian Paul3deaa012005-02-07 05:08:24 +00001472 _mesa_error(ctx, GL_INVALID_OPERATION,
1473 "glGetFramebufferAttachmentParameterivEXT");
1474 return;
1475 }
1476
Brian Paul84716042005-11-16 04:05:54 +00001477 att = _mesa_get_attachment(ctx, buffer, attachment);
Brian Paul3deaa012005-02-07 05:08:24 +00001478 if (att == NULL) {
Brian Paulddc82ee2005-02-05 19:56:45 +00001479 _mesa_error(ctx, GL_INVALID_ENUM,
1480 "glGetFramebufferAttachmentParameterivEXT(attachment)");
1481 return;
1482 }
1483
Brian Paul474f28e2005-10-08 14:41:17 +00001484 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Keith Whitwelldf058292006-09-22 11:40:35 +00001485 /* The above doesn't fully flush the drivers in the way that a
1486 * glFlush does, but that is required here:
1487 */
1488 if (ctx->Driver.Flush)
1489 ctx->Driver.Flush(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +00001490
Brian Paulddc82ee2005-02-05 19:56:45 +00001491 switch (pname) {
1492 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001493 *params = att->Type;
1494 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001495 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001496 if (att->Type == GL_RENDERBUFFER_EXT) {
1497 *params = att->Renderbuffer->Name;
1498 }
1499 else if (att->Type == GL_TEXTURE) {
1500 *params = att->Texture->Name;
1501 }
1502 else {
1503 _mesa_error(ctx, GL_INVALID_ENUM,
1504 "glGetFramebufferAttachmentParameterivEXT(pname)");
1505 }
1506 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001507 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001508 if (att->Type == GL_TEXTURE) {
1509 *params = att->TextureLevel;
1510 }
1511 else {
1512 _mesa_error(ctx, GL_INVALID_ENUM,
1513 "glGetFramebufferAttachmentParameterivEXT(pname)");
1514 }
1515 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001516 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001517 if (att->Type == GL_TEXTURE) {
Brian Paulf1e4ca72008-08-06 08:39:54 -06001518 if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) {
1519 *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace;
1520 }
1521 else {
1522 *params = 0;
1523 }
Brian Paul3deaa012005-02-07 05:08:24 +00001524 }
1525 else {
1526 _mesa_error(ctx, GL_INVALID_ENUM,
1527 "glGetFramebufferAttachmentParameterivEXT(pname)");
1528 }
1529 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001530 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT:
Brian Paul3deaa012005-02-07 05:08:24 +00001531 if (att->Type == GL_TEXTURE) {
Brian Paulf1e4ca72008-08-06 08:39:54 -06001532 if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) {
1533 *params = att->Zoffset;
1534 }
1535 else {
1536 *params = 0;
1537 }
Brian Paul3deaa012005-02-07 05:08:24 +00001538 }
1539 else {
1540 _mesa_error(ctx, GL_INVALID_ENUM,
1541 "glGetFramebufferAttachmentParameterivEXT(pname)");
1542 }
1543 return;
Brian Paulddc82ee2005-02-05 19:56:45 +00001544 default:
1545 _mesa_error(ctx, GL_INVALID_ENUM,
1546 "glGetFramebufferAttachmentParameterivEXT(pname)");
1547 return;
1548 }
Brian Paulddc82ee2005-02-05 19:56:45 +00001549}
1550
1551
Brian Paul1864c7d2005-02-08 03:46:37 +00001552void GLAPIENTRY
Brian Paulddc82ee2005-02-05 19:56:45 +00001553_mesa_GenerateMipmapEXT(GLenum target)
1554{
Brian Paul463642c2005-02-08 02:06:00 +00001555 struct gl_texture_unit *texUnit;
1556 struct gl_texture_object *texObj;
Brian Paulddc82ee2005-02-05 19:56:45 +00001557 GET_CURRENT_CONTEXT(ctx);
1558
1559 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul474f28e2005-10-08 14:41:17 +00001560 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
Brian Paulddc82ee2005-02-05 19:56:45 +00001561
1562 switch (target) {
1563 case GL_TEXTURE_1D:
1564 case GL_TEXTURE_2D:
Brian Paulddc82ee2005-02-05 19:56:45 +00001565 case GL_TEXTURE_3D:
Brian Paul463642c2005-02-08 02:06:00 +00001566 case GL_TEXTURE_CUBE_MAP:
Brian Paul1b939532005-05-31 23:55:21 +00001567 /* OK, legal value */
Brian Paulddc82ee2005-02-05 19:56:45 +00001568 break;
1569 default:
1570 _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)");
1571 return;
1572 }
1573
Brian Paul463642c2005-02-08 02:06:00 +00001574 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
1575 texObj = _mesa_select_tex_object(ctx, texUnit, target);
1576
1577 /* XXX this might not handle cube maps correctly */
Keith Whitwell5ac93f82006-11-01 14:21:57 +00001578 _mesa_lock_texture(ctx, texObj);
Briand4e1d852008-02-08 14:45:58 -07001579 ctx->Driver.GenerateMipmap(ctx, target, texObj);
Keith Whitwell5ac93f82006-11-01 14:21:57 +00001580 _mesa_unlock_texture(ctx, texObj);
Brian Paulddc82ee2005-02-05 19:56:45 +00001581}
Brian Paul0bffb112005-11-08 14:45:48 +00001582
1583
1584#if FEATURE_EXT_framebuffer_blit
1585void GLAPIENTRY
1586_mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
1587 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
1588 GLbitfield mask, GLenum filter)
1589{
1590 GET_CURRENT_CONTEXT(ctx);
1591
1592 ASSERT_OUTSIDE_BEGIN_END(ctx);
1593 FLUSH_VERTICES(ctx, _NEW_BUFFERS);
1594
Brian Paul99745402006-03-01 02:02:43 +00001595 if (ctx->NewState) {
1596 _mesa_update_state(ctx);
1597 }
1598
1599 if (!ctx->ReadBuffer) {
1600 /* XXX */
1601 }
1602
Brian Paul0bffb112005-11-08 14:45:48 +00001603 /* check for complete framebuffers */
1604 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
1605 ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1606 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
1607 "glBlitFramebufferEXT(incomplete draw/read buffers)");
1608 return;
1609 }
1610
Brian Paul99745402006-03-01 02:02:43 +00001611 if (filter != GL_NEAREST && filter != GL_LINEAR) {
1612 _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)");
1613 return;
1614 }
1615
1616 if (mask & ~(GL_COLOR_BUFFER_BIT |
1617 GL_DEPTH_BUFFER_BIT |
1618 GL_STENCIL_BUFFER_BIT)) {
1619 _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
1620 return;
1621 }
1622
Brian Paul0bffb112005-11-08 14:45:48 +00001623 /* depth/stencil must be blitted with nearest filtering */
1624 if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
1625 && filter != GL_NEAREST) {
1626 _mesa_error(ctx, GL_INVALID_OPERATION,
1627 "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter");
1628 return;
1629 }
1630
Brian Paul99745402006-03-01 02:02:43 +00001631 if (mask & GL_STENCIL_BUFFER_BIT) {
1632 struct gl_renderbuffer *readRb = ctx->ReadBuffer->_StencilBuffer;
1633 struct gl_renderbuffer *drawRb = ctx->DrawBuffer->_StencilBuffer;
1634 if (readRb->StencilBits != drawRb->StencilBits) {
1635 _mesa_error(ctx, GL_INVALID_OPERATION,
1636 "glBlitFramebufferEXT(stencil buffer size mismatch");
1637 return;
1638 }
1639 }
1640
1641 if (mask & GL_DEPTH_BUFFER_BIT) {
1642 struct gl_renderbuffer *readRb = ctx->ReadBuffer->_DepthBuffer;
1643 struct gl_renderbuffer *drawRb = ctx->DrawBuffer->_DepthBuffer;
1644 if (readRb->DepthBits != drawRb->DepthBits) {
1645 _mesa_error(ctx, GL_INVALID_OPERATION,
1646 "glBlitFramebufferEXT(depth buffer size mismatch");
1647 return;
1648 }
Brian Paul0bffb112005-11-08 14:45:48 +00001649 }
1650
1651 if (!ctx->Extensions.EXT_framebuffer_blit) {
1652 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT");
1653 return;
1654 }
1655
1656 ASSERT(ctx->Driver.BlitFramebuffer);
1657 ctx->Driver.BlitFramebuffer(ctx,
1658 srcX0, srcY0, srcX1, srcY1,
1659 dstX0, dstY0, dstX1, dstY1,
1660 mask, filter);
1661}
1662#endif /* FEATURE_EXT_framebuffer_blit */