Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4358 | Serge | 1 | /* |
2 | * Mesa 3-D graphics library |
||
3 | * |
||
4 | * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. |
||
5 | * Copyright (C) 1999-2009 VMware, Inc. All Rights Reserved. |
||
6 | * |
||
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 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR |
||
21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
||
22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
||
23 | * 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 | #include |
||
35 | |||
36 | #include "buffers.h" |
||
37 | #include "context.h" |
||
38 | #include "enums.h" |
||
39 | #include "fbobject.h" |
||
40 | #include "formats.h" |
||
41 | #include "framebuffer.h" |
||
42 | #include "glformats.h" |
||
43 | #include "hash.h" |
||
44 | #include "macros.h" |
||
45 | #include "multisample.h" |
||
46 | #include "mtypes.h" |
||
47 | #include "renderbuffer.h" |
||
48 | #include "state.h" |
||
49 | #include "teximage.h" |
||
50 | #include "texobj.h" |
||
51 | |||
52 | |||
53 | /** Set this to 1 to debug/log glBlitFramebuffer() calls */ |
||
54 | #define DEBUG_BLIT 0 |
||
55 | |||
56 | |||
57 | /** |
||
58 | * Notes: |
||
59 | * |
||
60 | * None of the GL_EXT_framebuffer_object functions are compiled into |
||
61 | * display lists. |
||
62 | */ |
||
63 | |||
64 | |||
65 | |||
66 | /* |
||
67 | * When glGenRender/FramebuffersEXT() is called we insert pointers to |
||
68 | * these placeholder objects into the hash table. |
||
69 | * Later, when the object ID is first bound, we replace the placeholder |
||
70 | * with the real frame/renderbuffer. |
||
71 | */ |
||
72 | static struct gl_framebuffer DummyFramebuffer; |
||
73 | static struct gl_renderbuffer DummyRenderbuffer; |
||
74 | |||
75 | /* We bind this framebuffer when applications pass a NULL |
||
76 | * drawable/surface in make current. */ |
||
77 | static struct gl_framebuffer IncompleteFramebuffer; |
||
78 | |||
79 | |||
80 | static void |
||
81 | delete_dummy_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb) |
||
82 | { |
||
83 | /* no op */ |
||
84 | } |
||
85 | |||
86 | static void |
||
87 | delete_dummy_framebuffer(struct gl_framebuffer *fb) |
||
88 | { |
||
89 | /* no op */ |
||
90 | } |
||
91 | |||
92 | |||
93 | void |
||
94 | _mesa_init_fbobjects(struct gl_context *ctx) |
||
95 | { |
||
96 | _glthread_INIT_MUTEX(DummyFramebuffer.Mutex); |
||
97 | _glthread_INIT_MUTEX(DummyRenderbuffer.Mutex); |
||
98 | _glthread_INIT_MUTEX(IncompleteFramebuffer.Mutex); |
||
99 | DummyFramebuffer.Delete = delete_dummy_framebuffer; |
||
100 | DummyRenderbuffer.Delete = delete_dummy_renderbuffer; |
||
101 | IncompleteFramebuffer.Delete = delete_dummy_framebuffer; |
||
102 | } |
||
103 | |||
104 | struct gl_framebuffer * |
||
105 | _mesa_get_incomplete_framebuffer(void) |
||
106 | { |
||
107 | return &IncompleteFramebuffer; |
||
108 | } |
||
109 | |||
110 | /** |
||
111 | * Helper routine for getting a gl_renderbuffer. |
||
112 | */ |
||
113 | struct gl_renderbuffer * |
||
114 | _mesa_lookup_renderbuffer(struct gl_context *ctx, GLuint id) |
||
115 | { |
||
116 | struct gl_renderbuffer *rb; |
||
117 | |||
118 | if (id == 0) |
||
119 | return NULL; |
||
120 | |||
121 | rb = (struct gl_renderbuffer *) |
||
122 | _mesa_HashLookup(ctx->Shared->RenderBuffers, id); |
||
123 | return rb; |
||
124 | } |
||
125 | |||
126 | |||
127 | /** |
||
128 | * Helper routine for getting a gl_framebuffer. |
||
129 | */ |
||
130 | struct gl_framebuffer * |
||
131 | _mesa_lookup_framebuffer(struct gl_context *ctx, GLuint id) |
||
132 | { |
||
133 | struct gl_framebuffer *fb; |
||
134 | |||
135 | if (id == 0) |
||
136 | return NULL; |
||
137 | |||
138 | fb = (struct gl_framebuffer *) |
||
139 | _mesa_HashLookup(ctx->Shared->FrameBuffers, id); |
||
140 | return fb; |
||
141 | } |
||
142 | |||
143 | |||
144 | /** |
||
145 | * Mark the given framebuffer as invalid. This will force the |
||
146 | * test for framebuffer completeness to be done before the framebuffer |
||
147 | * is used. |
||
148 | */ |
||
149 | static void |
||
150 | invalidate_framebuffer(struct gl_framebuffer *fb) |
||
151 | { |
||
152 | fb->_Status = 0; /* "indeterminate" */ |
||
153 | } |
||
154 | |||
155 | |||
156 | /** |
||
157 | * Return the gl_framebuffer object which corresponds to the given |
||
158 | * framebuffer target, such as GL_DRAW_FRAMEBUFFER. |
||
159 | * Check support for GL_EXT_framebuffer_blit to determine if certain |
||
160 | * targets are legal. |
||
161 | * \return gl_framebuffer pointer or NULL if target is illegal |
||
162 | */ |
||
163 | static struct gl_framebuffer * |
||
164 | get_framebuffer_target(struct gl_context *ctx, GLenum target) |
||
165 | { |
||
166 | bool have_fb_blit = _mesa_is_gles3(ctx) || |
||
167 | (ctx->Extensions.EXT_framebuffer_blit && _mesa_is_desktop_gl(ctx)); |
||
168 | switch (target) { |
||
169 | case GL_DRAW_FRAMEBUFFER: |
||
170 | return have_fb_blit ? ctx->DrawBuffer : NULL; |
||
171 | case GL_READ_FRAMEBUFFER: |
||
172 | return have_fb_blit ? ctx->ReadBuffer : NULL; |
||
173 | case GL_FRAMEBUFFER_EXT: |
||
174 | return ctx->DrawBuffer; |
||
175 | default: |
||
176 | return NULL; |
||
177 | } |
||
178 | } |
||
179 | |||
180 | |||
181 | /** |
||
182 | * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding |
||
183 | * gl_renderbuffer_attachment object. |
||
184 | * This function is only used for user-created FB objects, not the |
||
185 | * default / window-system FB object. |
||
186 | * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to |
||
187 | * the depth buffer attachment point. |
||
188 | */ |
||
189 | struct gl_renderbuffer_attachment * |
||
190 | _mesa_get_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, |
||
191 | GLenum attachment) |
||
192 | { |
||
193 | GLuint i; |
||
194 | |||
195 | assert(_mesa_is_user_fbo(fb)); |
||
196 | |||
197 | switch (attachment) { |
||
198 | case GL_COLOR_ATTACHMENT0_EXT: |
||
199 | case GL_COLOR_ATTACHMENT1_EXT: |
||
200 | case GL_COLOR_ATTACHMENT2_EXT: |
||
201 | case GL_COLOR_ATTACHMENT3_EXT: |
||
202 | case GL_COLOR_ATTACHMENT4_EXT: |
||
203 | case GL_COLOR_ATTACHMENT5_EXT: |
||
204 | case GL_COLOR_ATTACHMENT6_EXT: |
||
205 | case GL_COLOR_ATTACHMENT7_EXT: |
||
206 | case GL_COLOR_ATTACHMENT8_EXT: |
||
207 | case GL_COLOR_ATTACHMENT9_EXT: |
||
208 | case GL_COLOR_ATTACHMENT10_EXT: |
||
209 | case GL_COLOR_ATTACHMENT11_EXT: |
||
210 | case GL_COLOR_ATTACHMENT12_EXT: |
||
211 | case GL_COLOR_ATTACHMENT13_EXT: |
||
212 | case GL_COLOR_ATTACHMENT14_EXT: |
||
213 | case GL_COLOR_ATTACHMENT15_EXT: |
||
214 | /* Only OpenGL ES 1.x forbids color attachments other than |
||
215 | * GL_COLOR_ATTACHMENT0. For all other APIs the limit set by the |
||
216 | * hardware is used. |
||
217 | */ |
||
218 | i = attachment - GL_COLOR_ATTACHMENT0_EXT; |
||
219 | if (i >= ctx->Const.MaxColorAttachments |
||
220 | || (i > 0 && ctx->API == API_OPENGLES)) { |
||
221 | return NULL; |
||
222 | } |
||
223 | return &fb->Attachment[BUFFER_COLOR0 + i]; |
||
224 | case GL_DEPTH_STENCIL_ATTACHMENT: |
||
225 | if (!_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx)) |
||
226 | return NULL; |
||
227 | /* fall-through */ |
||
228 | case GL_DEPTH_ATTACHMENT_EXT: |
||
229 | return &fb->Attachment[BUFFER_DEPTH]; |
||
230 | case GL_STENCIL_ATTACHMENT_EXT: |
||
231 | return &fb->Attachment[BUFFER_STENCIL]; |
||
232 | default: |
||
233 | return NULL; |
||
234 | } |
||
235 | } |
||
236 | |||
237 | |||
238 | /** |
||
239 | * As above, but only used for getting attachments of the default / |
||
240 | * window-system framebuffer (not user-created framebuffer objects). |
||
241 | */ |
||
242 | static struct gl_renderbuffer_attachment * |
||
243 | _mesa_get_fb0_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, |
||
244 | GLenum attachment) |
||
245 | { |
||
246 | assert(_mesa_is_winsys_fbo(fb)); |
||
247 | |||
248 | if (_mesa_is_gles3(ctx)) { |
||
249 | assert(attachment == GL_BACK || |
||
250 | attachment == GL_DEPTH || |
||
251 | attachment == GL_STENCIL); |
||
252 | switch (attachment) { |
||
253 | case GL_BACK: |
||
254 | /* Since there is no stereo rendering in ES 3.0, only return the |
||
255 | * LEFT bits. |
||
256 | */ |
||
257 | if (ctx->DrawBuffer->Visual.doubleBufferMode) |
||
258 | return &fb->Attachment[BUFFER_BACK_LEFT]; |
||
259 | return &fb->Attachment[BUFFER_FRONT_LEFT]; |
||
260 | case GL_DEPTH: |
||
261 | return &fb->Attachment[BUFFER_DEPTH]; |
||
262 | case GL_STENCIL: |
||
263 | return &fb->Attachment[BUFFER_STENCIL]; |
||
264 | } |
||
265 | } |
||
266 | |||
267 | switch (attachment) { |
||
268 | case GL_FRONT_LEFT: |
||
269 | return &fb->Attachment[BUFFER_FRONT_LEFT]; |
||
270 | case GL_FRONT_RIGHT: |
||
271 | return &fb->Attachment[BUFFER_FRONT_RIGHT]; |
||
272 | case GL_BACK_LEFT: |
||
273 | return &fb->Attachment[BUFFER_BACK_LEFT]; |
||
274 | case GL_BACK_RIGHT: |
||
275 | return &fb->Attachment[BUFFER_BACK_RIGHT]; |
||
276 | case GL_AUX0: |
||
277 | if (fb->Visual.numAuxBuffers == 1) { |
||
278 | return &fb->Attachment[BUFFER_AUX0]; |
||
279 | } |
||
280 | return NULL; |
||
281 | |||
282 | /* Page 336 (page 352 of the PDF) of the OpenGL 3.0 spec says: |
||
283 | * |
||
284 | * "If the default framebuffer is bound to target, then attachment must |
||
285 | * be one of FRONT LEFT, FRONT RIGHT, BACK LEFT, BACK RIGHT, or AUXi, |
||
286 | * identifying a color buffer; DEPTH, identifying the depth buffer; or |
||
287 | * STENCIL, identifying the stencil buffer." |
||
288 | * |
||
289 | * Revision #34 of the ARB_framebuffer_object spec has essentially the same |
||
290 | * language. However, revision #33 of the ARB_framebuffer_object spec |
||
291 | * says: |
||
292 | * |
||
293 | * "If the default framebuffer is bound to |
||
294 | * must be one of FRONT_LEFT, FRONT_RIGHT, BACK_LEFT, BACK_RIGHT, AUXi, |
||
295 | * DEPTH_BUFFER, or STENCIL_BUFFER, identifying a color buffer, the |
||
296 | * depth buffer, or the stencil buffer, and |
||
297 | * FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE or |
||
298 | * FRAMEBUFFER_ATTACHMENT_OBJECT_NAME." |
||
299 | * |
||
300 | * The enum values for DEPTH_BUFFER and STENCIL_BUFFER have been removed |
||
301 | * from glext.h, so shipping apps should not use those values. |
||
302 | * |
||
303 | * Note that neither EXT_framebuffer_object nor OES_framebuffer_object |
||
304 | * support queries of the window system FBO. |
||
305 | */ |
||
306 | case GL_DEPTH: |
||
307 | return &fb->Attachment[BUFFER_DEPTH]; |
||
308 | case GL_STENCIL: |
||
309 | return &fb->Attachment[BUFFER_STENCIL]; |
||
310 | default: |
||
311 | return NULL; |
||
312 | } |
||
313 | } |
||
314 | |||
315 | |||
316 | |||
317 | /** |
||
318 | * Remove any texture or renderbuffer attached to the given attachment |
||
319 | * point. Update reference counts, etc. |
||
320 | */ |
||
321 | void |
||
322 | _mesa_remove_attachment(struct gl_context *ctx, |
||
323 | struct gl_renderbuffer_attachment *att) |
||
324 | { |
||
325 | struct gl_renderbuffer *rb = att->Renderbuffer; |
||
326 | |||
327 | /* tell driver that we're done rendering to this texture. */ |
||
328 | if (rb && rb->NeedsFinishRenderTexture) |
||
329 | ctx->Driver.FinishRenderTexture(ctx, rb); |
||
330 | |||
331 | if (att->Type == GL_TEXTURE) { |
||
332 | ASSERT(att->Texture); |
||
333 | _mesa_reference_texobj(&att->Texture, NULL); /* unbind */ |
||
334 | ASSERT(!att->Texture); |
||
335 | } |
||
336 | if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) { |
||
337 | ASSERT(!att->Texture); |
||
338 | _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */ |
||
339 | ASSERT(!att->Renderbuffer); |
||
340 | } |
||
341 | att->Type = GL_NONE; |
||
342 | att->Complete = GL_TRUE; |
||
343 | } |
||
344 | |||
345 | /** |
||
346 | * Verify a couple error conditions that will lead to an incomplete FBO and |
||
347 | * may cause problems for the driver's RenderTexture path. |
||
348 | */ |
||
349 | static bool |
||
350 | driver_RenderTexture_is_safe(const struct gl_renderbuffer_attachment *att) |
||
351 | { |
||
352 | const struct gl_texture_image *const texImage = |
||
353 | att->Texture->Image[att->CubeMapFace][att->TextureLevel]; |
||
354 | |||
355 | if (texImage->Width == 0 || texImage->Height == 0 || texImage->Depth == 0) |
||
356 | return false; |
||
357 | |||
358 | if ((texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY |
||
359 | && att->Zoffset >= texImage->Height) |
||
360 | || (texImage->TexObject->Target != GL_TEXTURE_1D_ARRAY |
||
361 | && att->Zoffset >= texImage->Depth)) |
||
362 | return false; |
||
363 | |||
364 | return true; |
||
365 | } |
||
366 | |||
367 | /** |
||
368 | * Create a renderbuffer which will be set up by the driver to wrap the |
||
369 | * texture image slice. |
||
370 | * |
||
371 | * By using a gl_renderbuffer (like user-allocated renderbuffers), drivers get |
||
372 | * to share most of their framebuffer rendering code between winsys, |
||
373 | * renderbuffer, and texture attachments. |
||
374 | * |
||
375 | * The allocated renderbuffer uses a non-zero Name so that drivers can check |
||
376 | * it for determining vertical orientation, but we use ~0 to make it fairly |
||
377 | * unambiguous with actual user (non-texture) renderbuffers. |
||
378 | */ |
||
379 | void |
||
380 | _mesa_update_texture_renderbuffer(struct gl_context *ctx, |
||
381 | struct gl_framebuffer *fb, |
||
382 | struct gl_renderbuffer_attachment *att) |
||
383 | { |
||
384 | struct gl_texture_image *texImage; |
||
385 | struct gl_renderbuffer *rb; |
||
386 | |||
387 | texImage = att->Texture->Image[att->CubeMapFace][att->TextureLevel]; |
||
388 | |||
389 | rb = att->Renderbuffer; |
||
390 | if (!rb) { |
||
391 | rb = ctx->Driver.NewRenderbuffer(ctx, ~0); |
||
392 | if (!rb) { |
||
393 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture()"); |
||
394 | return; |
||
395 | } |
||
396 | _mesa_reference_renderbuffer(&att->Renderbuffer, rb); |
||
397 | |||
398 | /* This can't get called on a texture renderbuffer, so set it to NULL |
||
399 | * for clarity compared to user renderbuffers. |
||
400 | */ |
||
401 | rb->AllocStorage = NULL; |
||
402 | |||
403 | rb->NeedsFinishRenderTexture = ctx->Driver.FinishRenderTexture != NULL; |
||
404 | } |
||
405 | |||
406 | if (!texImage) |
||
407 | return; |
||
408 | |||
409 | rb->_BaseFormat = texImage->_BaseFormat; |
||
410 | rb->Format = texImage->TexFormat; |
||
411 | rb->InternalFormat = texImage->InternalFormat; |
||
412 | rb->Width = texImage->Width2; |
||
413 | rb->Height = texImage->Height2; |
||
414 | rb->NumSamples = texImage->NumSamples; |
||
415 | rb->TexImage = texImage; |
||
416 | |||
417 | if (driver_RenderTexture_is_safe(att)) |
||
418 | ctx->Driver.RenderTexture(ctx, fb, att); |
||
419 | } |
||
420 | |||
421 | /** |
||
422 | * Bind a texture object to an attachment point. |
||
423 | * The previous binding, if any, will be removed first. |
||
424 | */ |
||
425 | void |
||
426 | _mesa_set_texture_attachment(struct gl_context *ctx, |
||
427 | struct gl_framebuffer *fb, |
||
428 | struct gl_renderbuffer_attachment *att, |
||
429 | struct gl_texture_object *texObj, |
||
430 | GLenum texTarget, GLuint level, GLuint zoffset, |
||
431 | GLboolean layered) |
||
432 | { |
||
433 | struct gl_renderbuffer *rb = att->Renderbuffer; |
||
434 | |||
435 | if (rb && rb->NeedsFinishRenderTexture) |
||
436 | ctx->Driver.FinishRenderTexture(ctx, rb); |
||
437 | |||
438 | if (att->Texture == texObj) { |
||
439 | /* re-attaching same texture */ |
||
440 | ASSERT(att->Type == GL_TEXTURE); |
||
441 | } |
||
442 | else { |
||
443 | /* new attachment */ |
||
444 | _mesa_remove_attachment(ctx, att); |
||
445 | att->Type = GL_TEXTURE; |
||
446 | assert(!att->Texture); |
||
447 | _mesa_reference_texobj(&att->Texture, texObj); |
||
448 | } |
||
449 | invalidate_framebuffer(fb); |
||
450 | |||
451 | /* always update these fields */ |
||
452 | att->TextureLevel = level; |
||
453 | att->CubeMapFace = _mesa_tex_target_to_face(texTarget); |
||
454 | att->Zoffset = zoffset; |
||
455 | att->Layered = layered; |
||
456 | att->Complete = GL_FALSE; |
||
457 | |||
458 | _mesa_update_texture_renderbuffer(ctx, fb, att); |
||
459 | } |
||
460 | |||
461 | |||
462 | /** |
||
463 | * Bind a renderbuffer to an attachment point. |
||
464 | * The previous binding, if any, will be removed first. |
||
465 | */ |
||
466 | void |
||
467 | _mesa_set_renderbuffer_attachment(struct gl_context *ctx, |
||
468 | struct gl_renderbuffer_attachment *att, |
||
469 | struct gl_renderbuffer *rb) |
||
470 | { |
||
471 | /* XXX check if re-doing same attachment, exit early */ |
||
472 | _mesa_remove_attachment(ctx, att); |
||
473 | att->Type = GL_RENDERBUFFER_EXT; |
||
474 | att->Texture = NULL; /* just to be safe */ |
||
475 | att->Complete = GL_FALSE; |
||
476 | _mesa_reference_renderbuffer(&att->Renderbuffer, rb); |
||
477 | } |
||
478 | |||
479 | |||
480 | /** |
||
481 | * Fallback for ctx->Driver.FramebufferRenderbuffer() |
||
482 | * Attach a renderbuffer object to a framebuffer object. |
||
483 | */ |
||
484 | void |
||
485 | _mesa_framebuffer_renderbuffer(struct gl_context *ctx, |
||
486 | struct gl_framebuffer *fb, |
||
487 | GLenum attachment, struct gl_renderbuffer *rb) |
||
488 | { |
||
489 | struct gl_renderbuffer_attachment *att; |
||
490 | |||
491 | _glthread_LOCK_MUTEX(fb->Mutex); |
||
492 | |||
493 | att = _mesa_get_attachment(ctx, fb, attachment); |
||
494 | ASSERT(att); |
||
495 | if (rb) { |
||
496 | _mesa_set_renderbuffer_attachment(ctx, att, rb); |
||
497 | if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { |
||
498 | /* do stencil attachment here (depth already done above) */ |
||
499 | att = _mesa_get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT); |
||
500 | assert(att); |
||
501 | _mesa_set_renderbuffer_attachment(ctx, att, rb); |
||
502 | } |
||
503 | rb->AttachedAnytime = GL_TRUE; |
||
504 | } |
||
505 | else { |
||
506 | _mesa_remove_attachment(ctx, att); |
||
507 | } |
||
508 | |||
509 | invalidate_framebuffer(fb); |
||
510 | |||
511 | _glthread_UNLOCK_MUTEX(fb->Mutex); |
||
512 | } |
||
513 | |||
514 | |||
515 | /** |
||
516 | * Fallback for ctx->Driver.ValidateFramebuffer() |
||
517 | * Check if the renderbuffer's formats are supported by the software |
||
518 | * renderer. |
||
519 | * Drivers should probably override this. |
||
520 | */ |
||
521 | void |
||
522 | _mesa_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) |
||
523 | { |
||
524 | gl_buffer_index buf; |
||
525 | for (buf = 0; buf < BUFFER_COUNT; buf++) { |
||
526 | const struct gl_renderbuffer *rb = fb->Attachment[buf].Renderbuffer; |
||
527 | if (rb) { |
||
528 | switch (rb->_BaseFormat) { |
||
529 | case GL_ALPHA: |
||
530 | case GL_LUMINANCE_ALPHA: |
||
531 | case GL_LUMINANCE: |
||
532 | case GL_INTENSITY: |
||
533 | case GL_RED: |
||
534 | case GL_RG: |
||
535 | fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; |
||
536 | return; |
||
537 | |||
538 | default: |
||
539 | switch (rb->Format) { |
||
540 | /* XXX This list is likely incomplete. */ |
||
541 | case MESA_FORMAT_RGB9_E5_FLOAT: |
||
542 | fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; |
||
543 | return; |
||
544 | default:; |
||
545 | /* render buffer format is supported by software rendering */ |
||
546 | } |
||
547 | } |
||
548 | } |
||
549 | } |
||
550 | } |
||
551 | |||
552 | |||
553 | /** |
||
554 | * Return true if the framebuffer has a combined depth/stencil |
||
555 | * renderbuffer attached. |
||
556 | */ |
||
557 | GLboolean |
||
558 | _mesa_has_depthstencil_combined(const struct gl_framebuffer *fb) |
||
559 | { |
||
560 | const struct gl_renderbuffer_attachment *depth = |
||
561 | &fb->Attachment[BUFFER_DEPTH]; |
||
562 | const struct gl_renderbuffer_attachment *stencil = |
||
563 | &fb->Attachment[BUFFER_STENCIL]; |
||
564 | |||
565 | if (depth->Type == stencil->Type) { |
||
566 | if (depth->Type == GL_RENDERBUFFER_EXT && |
||
567 | depth->Renderbuffer == stencil->Renderbuffer) |
||
568 | return GL_TRUE; |
||
569 | |||
570 | if (depth->Type == GL_TEXTURE && |
||
571 | depth->Texture == stencil->Texture) |
||
572 | return GL_TRUE; |
||
573 | } |
||
574 | |||
575 | return GL_FALSE; |
||
576 | } |
||
577 | |||
578 | |||
579 | /** |
||
580 | * For debug only. |
||
581 | */ |
||
582 | static void |
||
583 | att_incomplete(const char *msg) |
||
584 | { |
||
585 | if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) { |
||
586 | _mesa_debug(NULL, "attachment incomplete: %s\n", msg); |
||
587 | } |
||
588 | } |
||
589 | |||
590 | |||
591 | /** |
||
592 | * For debug only. |
||
593 | */ |
||
594 | static void |
||
595 | fbo_incomplete(struct gl_context *ctx, const char *msg, int index) |
||
596 | { |
||
597 | static GLuint msg_id; |
||
598 | |||
599 | _mesa_gl_debug(ctx, &msg_id, |
||
600 | MESA_DEBUG_TYPE_OTHER, |
||
601 | MESA_DEBUG_SEVERITY_MEDIUM, |
||
602 | "FBO incomplete: %s [%d]\n", msg, index); |
||
603 | |||
604 | if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) { |
||
605 | _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index); |
||
606 | } |
||
607 | } |
||
608 | |||
609 | |||
610 | /** |
||
611 | * Is the given base format a legal format for a color renderbuffer? |
||
612 | */ |
||
613 | GLboolean |
||
614 | _mesa_is_legal_color_format(const struct gl_context *ctx, GLenum baseFormat) |
||
615 | { |
||
616 | switch (baseFormat) { |
||
617 | case GL_RGB: |
||
618 | case GL_RGBA: |
||
619 | return GL_TRUE; |
||
620 | case GL_LUMINANCE: |
||
621 | case GL_LUMINANCE_ALPHA: |
||
622 | case GL_INTENSITY: |
||
623 | case GL_ALPHA: |
||
624 | return ctx->API == API_OPENGL_COMPAT && |
||
625 | ctx->Extensions.ARB_framebuffer_object; |
||
626 | case GL_RED: |
||
627 | case GL_RG: |
||
628 | return ctx->Extensions.ARB_texture_rg; |
||
629 | default: |
||
630 | return GL_FALSE; |
||
631 | } |
||
632 | } |
||
633 | |||
634 | |||
635 | /** |
||
636 | * Is the given base format a legal format for a color renderbuffer? |
||
637 | */ |
||
638 | static GLboolean |
||
639 | is_format_color_renderable(const struct gl_context *ctx, gl_format format, GLenum internalFormat) |
||
640 | { |
||
641 | const GLenum baseFormat = |
||
642 | _mesa_get_format_base_format(format); |
||
643 | GLboolean valid; |
||
644 | |||
645 | valid = _mesa_is_legal_color_format(ctx, baseFormat); |
||
646 | if (!valid || _mesa_is_desktop_gl(ctx)) { |
||
647 | return valid; |
||
648 | } |
||
649 | |||
650 | /* Reject additional cases for GLES */ |
||
651 | switch (internalFormat) { |
||
652 | case GL_RGBA8_SNORM: |
||
653 | case GL_RGB32F: |
||
654 | case GL_RGB32I: |
||
655 | case GL_RGB32UI: |
||
656 | case GL_RGB16F: |
||
657 | case GL_RGB16I: |
||
658 | case GL_RGB16UI: |
||
659 | case GL_RGB8_SNORM: |
||
660 | case GL_RGB8I: |
||
661 | case GL_RGB8UI: |
||
662 | case GL_SRGB8: |
||
663 | case GL_RGB9_E5: |
||
664 | case GL_RG8_SNORM: |
||
665 | case GL_R8_SNORM: |
||
666 | return GL_FALSE; |
||
667 | default: |
||
668 | break; |
||
669 | } |
||
670 | |||
671 | if (format == MESA_FORMAT_ARGB2101010 && internalFormat != GL_RGB10_A2) { |
||
672 | return GL_FALSE; |
||
673 | } |
||
674 | |||
675 | return GL_TRUE; |
||
676 | } |
||
677 | |||
678 | |||
679 | /** |
||
680 | * Is the given base format a legal format for a depth/stencil renderbuffer? |
||
681 | */ |
||
682 | static GLboolean |
||
683 | is_legal_depth_format(const struct gl_context *ctx, GLenum baseFormat) |
||
684 | { |
||
685 | switch (baseFormat) { |
||
686 | case GL_DEPTH_COMPONENT: |
||
687 | case GL_DEPTH_STENCIL_EXT: |
||
688 | return GL_TRUE; |
||
689 | default: |
||
690 | return GL_FALSE; |
||
691 | } |
||
692 | } |
||
693 | |||
694 | |||
695 | /** |
||
696 | * Test if an attachment point is complete and update its Complete field. |
||
697 | * \param format if GL_COLOR, this is a color attachment point, |
||
698 | * if GL_DEPTH, this is a depth component attachment point, |
||
699 | * if GL_STENCIL, this is a stencil component attachment point. |
||
700 | */ |
||
701 | static void |
||
702 | test_attachment_completeness(const struct gl_context *ctx, GLenum format, |
||
703 | struct gl_renderbuffer_attachment *att) |
||
704 | { |
||
705 | assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL); |
||
706 | |||
707 | /* assume complete */ |
||
708 | att->Complete = GL_TRUE; |
||
709 | |||
710 | /* Look for reasons why the attachment might be incomplete */ |
||
711 | if (att->Type == GL_TEXTURE) { |
||
712 | const struct gl_texture_object *texObj = att->Texture; |
||
713 | struct gl_texture_image *texImage; |
||
714 | GLenum baseFormat; |
||
715 | |||
716 | if (!texObj) { |
||
717 | att_incomplete("no texobj"); |
||
718 | att->Complete = GL_FALSE; |
||
719 | return; |
||
720 | } |
||
721 | |||
722 | texImage = texObj->Image[att->CubeMapFace][att->TextureLevel]; |
||
723 | if (!texImage) { |
||
724 | att_incomplete("no teximage"); |
||
725 | att->Complete = GL_FALSE; |
||
726 | return; |
||
727 | } |
||
728 | if (texImage->Width < 1 || texImage->Height < 1) { |
||
729 | att_incomplete("teximage width/height=0"); |
||
730 | att->Complete = GL_FALSE; |
||
731 | return; |
||
732 | } |
||
733 | |||
734 | switch (texObj->Target) { |
||
735 | case GL_TEXTURE_3D: |
||
736 | if (att->Zoffset >= texImage->Depth) { |
||
737 | att_incomplete("bad z offset"); |
||
738 | att->Complete = GL_FALSE; |
||
739 | return; |
||
740 | } |
||
741 | break; |
||
742 | case GL_TEXTURE_1D_ARRAY: |
||
743 | if (att->Zoffset >= texImage->Height) { |
||
744 | att_incomplete("bad 1D-array layer"); |
||
745 | att->Complete = GL_FALSE; |
||
746 | return; |
||
747 | } |
||
748 | break; |
||
749 | case GL_TEXTURE_2D_ARRAY: |
||
750 | if (att->Zoffset >= texImage->Depth) { |
||
751 | att_incomplete("bad 2D-array layer"); |
||
752 | att->Complete = GL_FALSE; |
||
753 | return; |
||
754 | } |
||
755 | break; |
||
756 | case GL_TEXTURE_CUBE_MAP_ARRAY: |
||
757 | if (att->Zoffset >= texImage->Depth) { |
||
758 | att_incomplete("bad cube-array layer"); |
||
759 | att->Complete = GL_FALSE; |
||
760 | return; |
||
761 | } |
||
762 | break; |
||
763 | } |
||
764 | |||
765 | baseFormat = _mesa_get_format_base_format(texImage->TexFormat); |
||
766 | |||
767 | if (format == GL_COLOR) { |
||
768 | if (!_mesa_is_legal_color_format(ctx, baseFormat)) { |
||
769 | att_incomplete("bad format"); |
||
770 | att->Complete = GL_FALSE; |
||
771 | return; |
||
772 | } |
||
773 | if (_mesa_is_format_compressed(texImage->TexFormat)) { |
||
774 | att_incomplete("compressed internalformat"); |
||
775 | att->Complete = GL_FALSE; |
||
776 | return; |
||
777 | } |
||
778 | } |
||
779 | else if (format == GL_DEPTH) { |
||
780 | if (baseFormat == GL_DEPTH_COMPONENT) { |
||
781 | /* OK */ |
||
782 | } |
||
783 | else if (ctx->Extensions.EXT_packed_depth_stencil && |
||
784 | ctx->Extensions.ARB_depth_texture && |
||
785 | baseFormat == GL_DEPTH_STENCIL_EXT) { |
||
786 | /* OK */ |
||
787 | } |
||
788 | else { |
||
789 | att->Complete = GL_FALSE; |
||
790 | att_incomplete("bad depth format"); |
||
791 | return; |
||
792 | } |
||
793 | } |
||
794 | else { |
||
795 | ASSERT(format == GL_STENCIL); |
||
796 | if (ctx->Extensions.EXT_packed_depth_stencil && |
||
797 | ctx->Extensions.ARB_depth_texture && |
||
798 | baseFormat == GL_DEPTH_STENCIL_EXT) { |
||
799 | /* OK */ |
||
800 | } |
||
801 | else { |
||
802 | /* no such thing as stencil-only textures */ |
||
803 | att_incomplete("illegal stencil texture"); |
||
804 | att->Complete = GL_FALSE; |
||
805 | return; |
||
806 | } |
||
807 | } |
||
808 | } |
||
809 | else if (att->Type == GL_RENDERBUFFER_EXT) { |
||
810 | const GLenum baseFormat = |
||
811 | _mesa_get_format_base_format(att->Renderbuffer->Format); |
||
812 | |||
813 | ASSERT(att->Renderbuffer); |
||
814 | if (!att->Renderbuffer->InternalFormat || |
||
815 | att->Renderbuffer->Width < 1 || |
||
816 | att->Renderbuffer->Height < 1) { |
||
817 | att_incomplete("0x0 renderbuffer"); |
||
818 | att->Complete = GL_FALSE; |
||
819 | return; |
||
820 | } |
||
821 | if (format == GL_COLOR) { |
||
822 | if (!_mesa_is_legal_color_format(ctx, baseFormat)) { |
||
823 | att_incomplete("bad renderbuffer color format"); |
||
824 | att->Complete = GL_FALSE; |
||
825 | return; |
||
826 | } |
||
827 | } |
||
828 | else if (format == GL_DEPTH) { |
||
829 | if (baseFormat == GL_DEPTH_COMPONENT) { |
||
830 | /* OK */ |
||
831 | } |
||
832 | else if (ctx->Extensions.EXT_packed_depth_stencil && |
||
833 | baseFormat == GL_DEPTH_STENCIL_EXT) { |
||
834 | /* OK */ |
||
835 | } |
||
836 | else { |
||
837 | att_incomplete("bad renderbuffer depth format"); |
||
838 | att->Complete = GL_FALSE; |
||
839 | return; |
||
840 | } |
||
841 | } |
||
842 | else { |
||
843 | assert(format == GL_STENCIL); |
||
844 | if (baseFormat == GL_STENCIL_INDEX) { |
||
845 | /* OK */ |
||
846 | } |
||
847 | else if (ctx->Extensions.EXT_packed_depth_stencil && |
||
848 | baseFormat == GL_DEPTH_STENCIL_EXT) { |
||
849 | /* OK */ |
||
850 | } |
||
851 | else { |
||
852 | att->Complete = GL_FALSE; |
||
853 | att_incomplete("bad renderbuffer stencil format"); |
||
854 | return; |
||
855 | } |
||
856 | } |
||
857 | } |
||
858 | else { |
||
859 | ASSERT(att->Type == GL_NONE); |
||
860 | /* complete */ |
||
861 | return; |
||
862 | } |
||
863 | } |
||
864 | |||
865 | |||
866 | /** |
||
867 | * Test if the given framebuffer object is complete and update its |
||
868 | * Status field with the results. |
||
869 | * Calls the ctx->Driver.ValidateFramebuffer() function to allow the |
||
870 | * driver to make hardware-specific validation/completeness checks. |
||
871 | * Also update the framebuffer's Width and Height fields if the |
||
872 | * framebuffer is complete. |
||
873 | */ |
||
874 | void |
||
875 | _mesa_test_framebuffer_completeness(struct gl_context *ctx, |
||
876 | struct gl_framebuffer *fb) |
||
877 | { |
||
878 | GLuint numImages; |
||
879 | GLenum intFormat = GL_NONE; /* color buffers' internal format */ |
||
880 | GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0; |
||
881 | GLint numSamples = -1; |
||
882 | GLint fixedSampleLocations = -1; |
||
883 | GLint i; |
||
884 | GLuint j; |
||
885 | bool layer_count_valid = false; |
||
886 | GLuint layer_count = 0, att_layer_count; |
||
887 | |||
888 | assert(_mesa_is_user_fbo(fb)); |
||
889 | |||
890 | /* we're changing framebuffer fields here */ |
||
891 | FLUSH_VERTICES(ctx, _NEW_BUFFERS); |
||
892 | |||
893 | numImages = 0; |
||
894 | fb->Width = 0; |
||
895 | fb->Height = 0; |
||
896 | fb->_AllColorBuffersFixedPoint = GL_TRUE; |
||
897 | fb->_HasSNormOrFloatColorBuffer = GL_FALSE; |
||
898 | |||
899 | /* Start at -2 to more easily loop over all attachment points. |
||
900 | * -2: depth buffer |
||
901 | * -1: stencil buffer |
||
902 | * >=0: color buffer |
||
903 | */ |
||
904 | for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) { |
||
905 | struct gl_renderbuffer_attachment *att; |
||
906 | GLenum f; |
||
907 | gl_format attFormat; |
||
908 | |||
909 | /* |
||
910 | * XXX for ARB_fbo, only check color buffers that are named by |
||
911 | * GL_READ_BUFFER and GL_DRAW_BUFFERi. |
||
912 | */ |
||
913 | |||
914 | /* check for attachment completeness |
||
915 | */ |
||
916 | if (i == -2) { |
||
917 | att = &fb->Attachment[BUFFER_DEPTH]; |
||
918 | test_attachment_completeness(ctx, GL_DEPTH, att); |
||
919 | if (!att->Complete) { |
||
920 | fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; |
||
921 | fbo_incomplete(ctx, "depth attachment incomplete", -1); |
||
922 | return; |
||
923 | } |
||
924 | } |
||
925 | else if (i == -1) { |
||
926 | att = &fb->Attachment[BUFFER_STENCIL]; |
||
927 | test_attachment_completeness(ctx, GL_STENCIL, att); |
||
928 | if (!att->Complete) { |
||
929 | fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; |
||
930 | fbo_incomplete(ctx, "stencil attachment incomplete", -1); |
||
931 | return; |
||
932 | } |
||
933 | } |
||
934 | else { |
||
935 | att = &fb->Attachment[BUFFER_COLOR0 + i]; |
||
936 | test_attachment_completeness(ctx, GL_COLOR, att); |
||
937 | if (!att->Complete) { |
||
938 | fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; |
||
939 | fbo_incomplete(ctx, "color attachment incomplete", i); |
||
940 | return; |
||
941 | } |
||
942 | } |
||
943 | |||
944 | /* get width, height, format of the renderbuffer/texture |
||
945 | */ |
||
946 | if (att->Type == GL_TEXTURE) { |
||
947 | const struct gl_texture_image *texImg = att->Renderbuffer->TexImage; |
||
948 | minWidth = MIN2(minWidth, texImg->Width); |
||
949 | maxWidth = MAX2(maxWidth, texImg->Width); |
||
950 | minHeight = MIN2(minHeight, texImg->Height); |
||
951 | maxHeight = MAX2(maxHeight, texImg->Height); |
||
952 | f = texImg->_BaseFormat; |
||
953 | attFormat = texImg->TexFormat; |
||
954 | numImages++; |
||
955 | |||
956 | if (!is_format_color_renderable(ctx, attFormat, texImg->InternalFormat) && |
||
957 | !is_legal_depth_format(ctx, f)) { |
||
958 | fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; |
||
959 | fbo_incomplete(ctx, "texture attachment incomplete", -1); |
||
960 | return; |
||
961 | } |
||
962 | |||
963 | if (numSamples < 0) |
||
964 | numSamples = texImg->NumSamples; |
||
965 | else if (numSamples != texImg->NumSamples) { |
||
966 | fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; |
||
967 | fbo_incomplete(ctx, "inconsistent sample count", -1); |
||
968 | return; |
||
969 | } |
||
970 | |||
971 | if (fixedSampleLocations < 0) |
||
972 | fixedSampleLocations = texImg->FixedSampleLocations; |
||
973 | else if (fixedSampleLocations != texImg->FixedSampleLocations) { |
||
974 | fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; |
||
975 | fbo_incomplete(ctx, "inconsistent fixed sample locations", -1); |
||
976 | return; |
||
977 | } |
||
978 | } |
||
979 | else if (att->Type == GL_RENDERBUFFER_EXT) { |
||
980 | minWidth = MIN2(minWidth, att->Renderbuffer->Width); |
||
981 | maxWidth = MAX2(minWidth, att->Renderbuffer->Width); |
||
982 | minHeight = MIN2(minHeight, att->Renderbuffer->Height); |
||
983 | maxHeight = MAX2(minHeight, att->Renderbuffer->Height); |
||
984 | f = att->Renderbuffer->InternalFormat; |
||
985 | attFormat = att->Renderbuffer->Format; |
||
986 | numImages++; |
||
987 | |||
988 | if (numSamples < 0) |
||
989 | numSamples = att->Renderbuffer->NumSamples; |
||
990 | else if (numSamples != att->Renderbuffer->NumSamples) { |
||
991 | fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; |
||
992 | fbo_incomplete(ctx, "inconsistent sample count", -1); |
||
993 | return; |
||
994 | } |
||
995 | |||
996 | /* RENDERBUFFER has fixedSampleLocations implicitly true */ |
||
997 | if (fixedSampleLocations < 0) |
||
998 | fixedSampleLocations = GL_TRUE; |
||
999 | else if (fixedSampleLocations != GL_TRUE) { |
||
1000 | fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; |
||
1001 | fbo_incomplete(ctx, "inconsistent fixed sample locations", -1); |
||
1002 | return; |
||
1003 | } |
||
1004 | } |
||
1005 | else { |
||
1006 | assert(att->Type == GL_NONE); |
||
1007 | continue; |
||
1008 | } |
||
1009 | |||
1010 | /* check if integer color */ |
||
1011 | fb->_IntegerColor = _mesa_is_format_integer_color(attFormat); |
||
1012 | |||
1013 | /* Update _AllColorBuffersFixedPoint and _HasSNormOrFloatColorBuffer. */ |
||
1014 | if (i >= 0) { |
||
1015 | GLenum type = _mesa_get_format_datatype(attFormat); |
||
1016 | |||
1017 | fb->_AllColorBuffersFixedPoint = |
||
1018 | fb->_AllColorBuffersFixedPoint && |
||
1019 | (type == GL_UNSIGNED_NORMALIZED || type == GL_SIGNED_NORMALIZED); |
||
1020 | |||
1021 | fb->_HasSNormOrFloatColorBuffer = |
||
1022 | fb->_HasSNormOrFloatColorBuffer || |
||
1023 | type == GL_SIGNED_NORMALIZED || type == GL_FLOAT; |
||
1024 | } |
||
1025 | |||
1026 | /* Error-check width, height, format */ |
||
1027 | if (numImages == 1) { |
||
1028 | /* save format */ |
||
1029 | if (i >= 0) { |
||
1030 | intFormat = f; |
||
1031 | } |
||
1032 | } |
||
1033 | else { |
||
1034 | if (!ctx->Extensions.ARB_framebuffer_object) { |
||
1035 | /* check that width, height, format are same */ |
||
1036 | if (minWidth != maxWidth || minHeight != maxHeight) { |
||
1037 | fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT; |
||
1038 | fbo_incomplete(ctx, "width or height mismatch", -1); |
||
1039 | return; |
||
1040 | } |
||
1041 | /* check that all color buffers are the same format */ |
||
1042 | if (intFormat != GL_NONE && f != intFormat) { |
||
1043 | fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; |
||
1044 | fbo_incomplete(ctx, "format mismatch", -1); |
||
1045 | return; |
||
1046 | } |
||
1047 | } |
||
1048 | } |
||
1049 | |||
1050 | /* Check that the format is valid. (MESA_FORMAT_NONE means unsupported) |
||
1051 | */ |
||
1052 | if (att->Type == GL_RENDERBUFFER && |
||
1053 | att->Renderbuffer->Format == MESA_FORMAT_NONE) { |
||
1054 | fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED; |
||
1055 | fbo_incomplete(ctx, "unsupported renderbuffer format", i); |
||
1056 | return; |
||
1057 | } |
||
1058 | |||
1059 | /* Check that layered rendering is consistent. */ |
||
1060 | att_layer_count = att->Layered ? att->Renderbuffer->Depth : 0; |
||
1061 | if (!layer_count_valid) { |
||
1062 | layer_count = att_layer_count; |
||
1063 | layer_count_valid = true; |
||
1064 | } else if (layer_count != att_layer_count) { |
||
1065 | if (layer_count == 0 || att_layer_count == 0) { |
||
1066 | fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS; |
||
1067 | fbo_incomplete(ctx, "framebuffer attachment layer mode is inconsistent", i); |
||
1068 | } else { |
||
1069 | fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB; |
||
1070 | fbo_incomplete(ctx, "framebuffer attachment layer count is inconsistent", i); |
||
1071 | } |
||
1072 | return; |
||
1073 | } |
||
1074 | } |
||
1075 | |||
1076 | fb->Layered = layer_count > 0; |
||
1077 | |||
1078 | if (_mesa_is_desktop_gl(ctx) && !ctx->Extensions.ARB_ES2_compatibility) { |
||
1079 | /* Check that all DrawBuffers are present */ |
||
1080 | for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) { |
||
1081 | if (fb->ColorDrawBuffer[j] != GL_NONE) { |
||
1082 | const struct gl_renderbuffer_attachment *att |
||
1083 | = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]); |
||
1084 | assert(att); |
||
1085 | if (att->Type == GL_NONE) { |
||
1086 | fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT; |
||
1087 | fbo_incomplete(ctx, "missing drawbuffer", j); |
||
1088 | return; |
||
1089 | } |
||
1090 | } |
||
1091 | } |
||
1092 | |||
1093 | /* Check that the ReadBuffer is present */ |
||
1094 | if (fb->ColorReadBuffer != GL_NONE) { |
||
1095 | const struct gl_renderbuffer_attachment *att |
||
1096 | = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer); |
||
1097 | assert(att); |
||
1098 | if (att->Type == GL_NONE) { |
||
1099 | fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT; |
||
1100 | fbo_incomplete(ctx, "missing readbuffer", -1); |
||
1101 | return; |
||
1102 | } |
||
1103 | } |
||
1104 | } |
||
1105 | |||
1106 | if (numImages == 0) { |
||
1107 | fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT; |
||
1108 | fbo_incomplete(ctx, "no attachments", -1); |
||
1109 | return; |
||
1110 | } |
||
1111 | |||
1112 | /* Provisionally set status = COMPLETE ... */ |
||
1113 | fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT; |
||
1114 | |||
1115 | /* ... but the driver may say the FB is incomplete. |
||
1116 | * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED |
||
1117 | * if anything. |
||
1118 | */ |
||
1119 | if (ctx->Driver.ValidateFramebuffer) { |
||
1120 | ctx->Driver.ValidateFramebuffer(ctx, fb); |
||
1121 | if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { |
||
1122 | fbo_incomplete(ctx, "driver marked FBO as incomplete", -1); |
||
1123 | } |
||
1124 | } |
||
1125 | |||
1126 | if (fb->_Status == GL_FRAMEBUFFER_COMPLETE_EXT) { |
||
1127 | /* |
||
1128 | * Note that if ARB_framebuffer_object is supported and the attached |
||
1129 | * renderbuffers/textures are different sizes, the framebuffer |
||
1130 | * width/height will be set to the smallest width/height. |
||
1131 | */ |
||
1132 | fb->Width = minWidth; |
||
1133 | fb->Height = minHeight; |
||
1134 | |||
1135 | /* finally, update the visual info for the framebuffer */ |
||
1136 | _mesa_update_framebuffer_visual(ctx, fb); |
||
1137 | } |
||
1138 | } |
||
1139 | |||
1140 | |||
1141 | GLboolean GLAPIENTRY |
||
1142 | _mesa_IsRenderbuffer(GLuint renderbuffer) |
||
1143 | { |
||
1144 | GET_CURRENT_CONTEXT(ctx); |
||
1145 | ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); |
||
1146 | if (renderbuffer) { |
||
1147 | struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); |
||
1148 | if (rb != NULL && rb != &DummyRenderbuffer) |
||
1149 | return GL_TRUE; |
||
1150 | } |
||
1151 | return GL_FALSE; |
||
1152 | } |
||
1153 | |||
1154 | |||
1155 | static void |
||
1156 | bind_renderbuffer(GLenum target, GLuint renderbuffer, bool allow_user_names) |
||
1157 | { |
||
1158 | struct gl_renderbuffer *newRb; |
||
1159 | GET_CURRENT_CONTEXT(ctx); |
||
1160 | |||
1161 | if (target != GL_RENDERBUFFER_EXT) { |
||
1162 | _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)"); |
||
1163 | return; |
||
1164 | } |
||
1165 | |||
1166 | /* No need to flush here since the render buffer binding has no |
||
1167 | * effect on rendering state. |
||
1168 | */ |
||
1169 | |||
1170 | if (renderbuffer) { |
||
1171 | newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer); |
||
1172 | if (newRb == &DummyRenderbuffer) { |
||
1173 | /* ID was reserved, but no real renderbuffer object made yet */ |
||
1174 | newRb = NULL; |
||
1175 | } |
||
1176 | else if (!newRb && !allow_user_names) { |
||
1177 | /* All RB IDs must be Gen'd */ |
||
1178 | _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)"); |
||
1179 | return; |
||
1180 | } |
||
1181 | |||
1182 | if (!newRb) { |
||
1183 | /* create new renderbuffer object */ |
||
1184 | newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer); |
||
1185 | if (!newRb) { |
||
1186 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT"); |
||
1187 | return; |
||
1188 | } |
||
1189 | ASSERT(newRb->AllocStorage); |
||
1190 | _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb); |
||
1191 | newRb->RefCount = 1; /* referenced by hash table */ |
||
1192 | } |
||
1193 | } |
||
1194 | else { |
||
1195 | newRb = NULL; |
||
1196 | } |
||
1197 | |||
1198 | ASSERT(newRb != &DummyRenderbuffer); |
||
1199 | |||
1200 | _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb); |
||
1201 | } |
||
1202 | |||
1203 | void GLAPIENTRY |
||
1204 | _mesa_BindRenderbuffer(GLenum target, GLuint renderbuffer) |
||
1205 | { |
||
1206 | GET_CURRENT_CONTEXT(ctx); |
||
1207 | |||
1208 | /* OpenGL ES glBindRenderbuffer and glBindRenderbufferOES use this same |
||
1209 | * entry point, but they allow the use of user-generated names. |
||
1210 | */ |
||
1211 | bind_renderbuffer(target, renderbuffer, _mesa_is_gles(ctx)); |
||
1212 | } |
||
1213 | |||
1214 | void GLAPIENTRY |
||
1215 | _mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer) |
||
1216 | { |
||
1217 | /* This function should not be in the dispatch table for core profile / |
||
1218 | * OpenGL 3.1, so execution should never get here in those cases -- no |
||
1219 | * need for an explicit test. |
||
1220 | */ |
||
1221 | bind_renderbuffer(target, renderbuffer, true); |
||
1222 | } |
||
1223 | |||
1224 | |||
1225 | /** |
||
1226 | * Remove the specified renderbuffer or texture from any attachment point in |
||
1227 | * the framebuffer. |
||
1228 | * |
||
1229 | * \returns |
||
1230 | * \c true if the renderbuffer was detached from an attachment point. \c |
||
1231 | * false otherwise. |
||
1232 | */ |
||
1233 | bool |
||
1234 | _mesa_detach_renderbuffer(struct gl_context *ctx, |
||
1235 | struct gl_framebuffer *fb, |
||
1236 | const void *att) |
||
1237 | { |
||
1238 | unsigned i; |
||
1239 | bool progress = false; |
||
1240 | |||
1241 | for (i = 0; i < BUFFER_COUNT; i++) { |
||
1242 | if (fb->Attachment[i].Texture == att |
||
1243 | || fb->Attachment[i].Renderbuffer == att) { |
||
1244 | _mesa_remove_attachment(ctx, &fb->Attachment[i]); |
||
1245 | progress = true; |
||
1246 | } |
||
1247 | } |
||
1248 | |||
1249 | /* Section 4.4.4 (Framebuffer Completeness), subsection "Whole Framebuffer |
||
1250 | * Completeness," of the OpenGL 3.1 spec says: |
||
1251 | * |
||
1252 | * "Performing any of the following actions may change whether the |
||
1253 | * framebuffer is considered complete or incomplete: |
||
1254 | * |
||
1255 | * ... |
||
1256 | * |
||
1257 | * - Deleting, with DeleteTextures or DeleteRenderbuffers, an object |
||
1258 | * containing an image that is attached to a framebuffer object |
||
1259 | * that is bound to the framebuffer." |
||
1260 | */ |
||
1261 | if (progress) |
||
1262 | invalidate_framebuffer(fb); |
||
1263 | |||
1264 | return progress; |
||
1265 | } |
||
1266 | |||
1267 | |||
1268 | void GLAPIENTRY |
||
1269 | _mesa_DeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) |
||
1270 | { |
||
1271 | GLint i; |
||
1272 | GET_CURRENT_CONTEXT(ctx); |
||
1273 | |||
1274 | FLUSH_VERTICES(ctx, _NEW_BUFFERS); |
||
1275 | |||
1276 | for (i = 0; i < n; i++) { |
||
1277 | if (renderbuffers[i] > 0) { |
||
1278 | struct gl_renderbuffer *rb; |
||
1279 | rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]); |
||
1280 | if (rb) { |
||
1281 | /* check if deleting currently bound renderbuffer object */ |
||
1282 | if (rb == ctx->CurrentRenderbuffer) { |
||
1283 | /* bind default */ |
||
1284 | ASSERT(rb->RefCount >= 2); |
||
1285 | _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, 0); |
||
1286 | } |
||
1287 | |||
1288 | /* Section 4.4.2 (Attaching Images to Framebuffer Objects), |
||
1289 | * subsection "Attaching Renderbuffer Images to a Framebuffer," of |
||
1290 | * the OpenGL 3.1 spec says: |
||
1291 | * |
||
1292 | * "If a renderbuffer object is deleted while its image is |
||
1293 | * attached to one or more attachment points in the currently |
||
1294 | * bound framebuffer, then it is as if FramebufferRenderbuffer |
||
1295 | * had been called, with a renderbuffer of 0, for each |
||
1296 | * attachment point to which this image was attached in the |
||
1297 | * currently bound framebuffer. In other words, this |
||
1298 | * renderbuffer image is first detached from all attachment |
||
1299 | * points in the currently bound framebuffer. Note that the |
||
1300 | * renderbuffer image is specifically not detached from any |
||
1301 | * non-bound framebuffers. Detaching the image from any |
||
1302 | * non-bound framebuffers is the responsibility of the |
||
1303 | * application. |
||
1304 | */ |
||
1305 | if (_mesa_is_user_fbo(ctx->DrawBuffer)) { |
||
1306 | _mesa_detach_renderbuffer(ctx, ctx->DrawBuffer, rb); |
||
1307 | } |
||
1308 | if (_mesa_is_user_fbo(ctx->ReadBuffer) |
||
1309 | && ctx->ReadBuffer != ctx->DrawBuffer) { |
||
1310 | _mesa_detach_renderbuffer(ctx, ctx->ReadBuffer, rb); |
||
1311 | } |
||
1312 | |||
1313 | /* Remove from hash table immediately, to free the ID. |
||
1314 | * But the object will not be freed until it's no longer |
||
1315 | * referenced anywhere else. |
||
1316 | */ |
||
1317 | _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]); |
||
1318 | |||
1319 | if (rb != &DummyRenderbuffer) { |
||
1320 | /* no longer referenced by hash table */ |
||
1321 | _mesa_reference_renderbuffer(&rb, NULL); |
||
1322 | } |
||
1323 | } |
||
1324 | } |
||
1325 | } |
||
1326 | } |
||
1327 | |||
1328 | |||
1329 | void GLAPIENTRY |
||
1330 | _mesa_GenRenderbuffers(GLsizei n, GLuint *renderbuffers) |
||
1331 | { |
||
1332 | GET_CURRENT_CONTEXT(ctx); |
||
1333 | GLuint first; |
||
1334 | GLint i; |
||
1335 | |||
1336 | if (n < 0) { |
||
1337 | _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)"); |
||
1338 | return; |
||
1339 | } |
||
1340 | |||
1341 | if (!renderbuffers) |
||
1342 | return; |
||
1343 | |||
1344 | first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n); |
||
1345 | |||
1346 | for (i = 0; i < n; i++) { |
||
1347 | GLuint name = first + i; |
||
1348 | renderbuffers[i] = name; |
||
1349 | /* insert dummy placeholder into hash table */ |
||
1350 | _glthread_LOCK_MUTEX(ctx->Shared->Mutex); |
||
1351 | _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer); |
||
1352 | _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); |
||
1353 | } |
||
1354 | } |
||
1355 | |||
1356 | |||
1357 | /** |
||
1358 | * Given an internal format token for a render buffer, return the |
||
1359 | * corresponding base format (one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, |
||
1360 | * GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL_EXT, GL_ALPHA, GL_LUMINANCE, |
||
1361 | * GL_LUMINANCE_ALPHA, GL_INTENSITY, etc). |
||
1362 | * |
||
1363 | * This is similar to _mesa_base_tex_format() but the set of valid |
||
1364 | * internal formats is different. |
||
1365 | * |
||
1366 | * Note that even if a format is determined to be legal here, validation |
||
1367 | * of the FBO may fail if the format is not supported by the driver/GPU. |
||
1368 | * |
||
1369 | * \param internalFormat as passed to glRenderbufferStorage() |
||
1370 | * \return the base internal format, or 0 if internalFormat is illegal |
||
1371 | */ |
||
1372 | GLenum |
||
1373 | _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat) |
||
1374 | { |
||
1375 | /* |
||
1376 | * Notes: some formats such as alpha, luminance, etc. were added |
||
1377 | * with GL_ARB_framebuffer_object. |
||
1378 | */ |
||
1379 | switch (internalFormat) { |
||
1380 | case GL_ALPHA: |
||
1381 | case GL_ALPHA4: |
||
1382 | case GL_ALPHA8: |
||
1383 | case GL_ALPHA12: |
||
1384 | case GL_ALPHA16: |
||
1385 | return ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_framebuffer_object |
||
1386 | ? GL_ALPHA : 0; |
||
1387 | case GL_LUMINANCE: |
||
1388 | case GL_LUMINANCE4: |
||
1389 | case GL_LUMINANCE8: |
||
1390 | case GL_LUMINANCE12: |
||
1391 | case GL_LUMINANCE16: |
||
1392 | return ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_framebuffer_object |
||
1393 | ? GL_LUMINANCE : 0; |
||
1394 | case GL_LUMINANCE_ALPHA: |
||
1395 | case GL_LUMINANCE4_ALPHA4: |
||
1396 | case GL_LUMINANCE6_ALPHA2: |
||
1397 | case GL_LUMINANCE8_ALPHA8: |
||
1398 | case GL_LUMINANCE12_ALPHA4: |
||
1399 | case GL_LUMINANCE12_ALPHA12: |
||
1400 | case GL_LUMINANCE16_ALPHA16: |
||
1401 | return ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_framebuffer_object |
||
1402 | ? GL_LUMINANCE_ALPHA : 0; |
||
1403 | case GL_INTENSITY: |
||
1404 | case GL_INTENSITY4: |
||
1405 | case GL_INTENSITY8: |
||
1406 | case GL_INTENSITY12: |
||
1407 | case GL_INTENSITY16: |
||
1408 | return ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_framebuffer_object |
||
1409 | ? GL_INTENSITY : 0; |
||
1410 | case GL_RGB8: |
||
1411 | return GL_RGB; |
||
1412 | case GL_RGB: |
||
1413 | case GL_R3_G3_B2: |
||
1414 | case GL_RGB4: |
||
1415 | case GL_RGB5: |
||
1416 | case GL_RGB10: |
||
1417 | case GL_RGB12: |
||
1418 | case GL_RGB16: |
||
1419 | return _mesa_is_desktop_gl(ctx) ? GL_RGB : 0; |
||
1420 | case GL_SRGB8_EXT: |
||
1421 | return _mesa_is_desktop_gl(ctx) ? GL_RGB : 0; |
||
1422 | case GL_RGBA4: |
||
1423 | case GL_RGB5_A1: |
||
1424 | case GL_RGBA8: |
||
1425 | return GL_RGBA; |
||
1426 | case GL_RGBA: |
||
1427 | case GL_RGBA2: |
||
1428 | case GL_RGBA12: |
||
1429 | case GL_RGBA16: |
||
1430 | return _mesa_is_desktop_gl(ctx) ? GL_RGBA : 0; |
||
1431 | case GL_RGB10_A2: |
||
1432 | case GL_SRGB8_ALPHA8_EXT: |
||
1433 | return _mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx) ? GL_RGBA : 0; |
||
1434 | case GL_STENCIL_INDEX: |
||
1435 | case GL_STENCIL_INDEX1_EXT: |
||
1436 | case GL_STENCIL_INDEX4_EXT: |
||
1437 | case GL_STENCIL_INDEX16_EXT: |
||
1438 | /* There are extensions for GL_STENCIL_INDEX1 and GL_STENCIL_INDEX4 in |
||
1439 | * OpenGL ES, but Mesa does not currently support them. |
||
1440 | */ |
||
1441 | return _mesa_is_desktop_gl(ctx) ? GL_STENCIL_INDEX : 0; |
||
1442 | case GL_STENCIL_INDEX8_EXT: |
||
1443 | return GL_STENCIL_INDEX; |
||
1444 | case GL_DEPTH_COMPONENT: |
||
1445 | case GL_DEPTH_COMPONENT32: |
||
1446 | return _mesa_is_desktop_gl(ctx) ? GL_DEPTH_COMPONENT : 0; |
||
1447 | case GL_DEPTH_COMPONENT16: |
||
1448 | case GL_DEPTH_COMPONENT24: |
||
1449 | return GL_DEPTH_COMPONENT; |
||
1450 | case GL_DEPTH_STENCIL_EXT: |
||
1451 | return _mesa_is_desktop_gl(ctx) |
||
1452 | && ctx->Extensions.EXT_packed_depth_stencil |
||
1453 | ? GL_DEPTH_STENCIL_EXT : 0; |
||
1454 | case GL_DEPTH24_STENCIL8_EXT: |
||
1455 | return ctx->Extensions.EXT_packed_depth_stencil |
||
1456 | ? GL_DEPTH_STENCIL_EXT : 0; |
||
1457 | case GL_DEPTH_COMPONENT32F: |
||
1458 | return ctx->Version >= 30 |
||
1459 | || (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_depth_buffer_float) |
||
1460 | ? GL_DEPTH_COMPONENT : 0; |
||
1461 | case GL_DEPTH32F_STENCIL8: |
||
1462 | return ctx->Version >= 30 |
||
1463 | || (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_depth_buffer_float) |
||
1464 | ? GL_DEPTH_STENCIL : 0; |
||
1465 | case GL_RED: |
||
1466 | case GL_R16: |
||
1467 | return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_rg |
||
1468 | ? GL_RED : 0; |
||
1469 | case GL_R8: |
||
1470 | return ctx->API != API_OPENGLES && ctx->Extensions.ARB_texture_rg |
||
1471 | ? GL_RED : 0; |
||
1472 | case GL_RG: |
||
1473 | case GL_RG16: |
||
1474 | return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_rg |
||
1475 | ? GL_RG : 0; |
||
1476 | case GL_RG8: |
||
1477 | return ctx->API != API_OPENGLES && ctx->Extensions.ARB_texture_rg |
||
1478 | ? GL_RG : 0; |
||
1479 | /* signed normalized texture formats */ |
||
1480 | case GL_RED_SNORM: |
||
1481 | case GL_R8_SNORM: |
||
1482 | case GL_R16_SNORM: |
||
1483 | return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm |
||
1484 | ? GL_RED : 0; |
||
1485 | case GL_RG_SNORM: |
||
1486 | case GL_RG8_SNORM: |
||
1487 | case GL_RG16_SNORM: |
||
1488 | return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm |
||
1489 | ? GL_RG : 0; |
||
1490 | case GL_RGB_SNORM: |
||
1491 | case GL_RGB8_SNORM: |
||
1492 | case GL_RGB16_SNORM: |
||
1493 | return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm |
||
1494 | ? GL_RGB : 0; |
||
1495 | case GL_RGBA_SNORM: |
||
1496 | case GL_RGBA8_SNORM: |
||
1497 | case GL_RGBA16_SNORM: |
||
1498 | return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm |
||
1499 | ? GL_RGBA : 0; |
||
1500 | case GL_ALPHA_SNORM: |
||
1501 | case GL_ALPHA8_SNORM: |
||
1502 | case GL_ALPHA16_SNORM: |
||
1503 | return ctx->API == API_OPENGL_COMPAT && |
||
1504 | ctx->Extensions.EXT_texture_snorm && |
||
1505 | ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0; |
||
1506 | case GL_R16F: |
||
1507 | case GL_R32F: |
||
1508 | return ((_mesa_is_desktop_gl(ctx) && |
||
1509 | ctx->Extensions.ARB_texture_rg && |
||
1510 | ctx->Extensions.ARB_texture_float) || |
||
1511 | _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ ) |
||
1512 | ? GL_RED : 0; |
||
1513 | case GL_RG16F: |
||
1514 | case GL_RG32F: |
||
1515 | return ((_mesa_is_desktop_gl(ctx) && |
||
1516 | ctx->Extensions.ARB_texture_rg && |
||
1517 | ctx->Extensions.ARB_texture_float) || |
||
1518 | _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ ) |
||
1519 | ? GL_RG : 0; |
||
1520 | case GL_RGB16F: |
||
1521 | case GL_RGB32F: |
||
1522 | return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_float) |
||
1523 | ? GL_RGB : 0; |
||
1524 | case GL_RGBA16F: |
||
1525 | case GL_RGBA32F: |
||
1526 | return ((_mesa_is_desktop_gl(ctx) && |
||
1527 | ctx->Extensions.ARB_texture_float) || |
||
1528 | _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ ) |
||
1529 | ? GL_RGBA : 0; |
||
1530 | case GL_ALPHA16F_ARB: |
||
1531 | case GL_ALPHA32F_ARB: |
||
1532 | return ctx->API == API_OPENGL_COMPAT && |
||
1533 | ctx->Extensions.ARB_texture_float && |
||
1534 | ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0; |
||
1535 | case GL_LUMINANCE16F_ARB: |
||
1536 | case GL_LUMINANCE32F_ARB: |
||
1537 | return ctx->API == API_OPENGL_COMPAT && |
||
1538 | ctx->Extensions.ARB_texture_float && |
||
1539 | ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0; |
||
1540 | case GL_LUMINANCE_ALPHA16F_ARB: |
||
1541 | case GL_LUMINANCE_ALPHA32F_ARB: |
||
1542 | return ctx->API == API_OPENGL_COMPAT && |
||
1543 | ctx->Extensions.ARB_texture_float && |
||
1544 | ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0; |
||
1545 | case GL_INTENSITY16F_ARB: |
||
1546 | case GL_INTENSITY32F_ARB: |
||
1547 | return ctx->API == API_OPENGL_COMPAT && |
||
1548 | ctx->Extensions.ARB_texture_float && |
||
1549 | ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0; |
||
1550 | case GL_RGB9_E5: |
||
1551 | return (_mesa_is_desktop_gl(ctx) |
||
1552 | && ctx->Extensions.EXT_texture_shared_exponent) |
||
1553 | ? GL_RGB : 0; |
||
1554 | case GL_R11F_G11F_B10F: |
||
1555 | return ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_packed_float) || |
||
1556 | _mesa_is_gles3(ctx) /* EXT_color_buffer_float */ ) |
||
1557 | ? GL_RGB : 0; |
||
1558 | |||
1559 | case GL_RGBA8UI_EXT: |
||
1560 | case GL_RGBA16UI_EXT: |
||
1561 | case GL_RGBA32UI_EXT: |
||
1562 | case GL_RGBA8I_EXT: |
||
1563 | case GL_RGBA16I_EXT: |
||
1564 | case GL_RGBA32I_EXT: |
||
1565 | return ctx->Version >= 30 |
||
1566 | || (_mesa_is_desktop_gl(ctx) && |
||
1567 | ctx->Extensions.EXT_texture_integer) ? GL_RGBA : 0; |
||
1568 | |||
1569 | case GL_RGB8UI_EXT: |
||
1570 | case GL_RGB16UI_EXT: |
||
1571 | case GL_RGB32UI_EXT: |
||
1572 | case GL_RGB8I_EXT: |
||
1573 | case GL_RGB16I_EXT: |
||
1574 | case GL_RGB32I_EXT: |
||
1575 | return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_integer |
||
1576 | ? GL_RGB : 0; |
||
1577 | case GL_R8UI: |
||
1578 | case GL_R8I: |
||
1579 | case GL_R16UI: |
||
1580 | case GL_R16I: |
||
1581 | case GL_R32UI: |
||
1582 | case GL_R32I: |
||
1583 | return ctx->Version >= 30 |
||
1584 | || (_mesa_is_desktop_gl(ctx) && |
||
1585 | ctx->Extensions.ARB_texture_rg && |
||
1586 | ctx->Extensions.EXT_texture_integer) ? GL_RED : 0; |
||
1587 | |||
1588 | case GL_RG8UI: |
||
1589 | case GL_RG8I: |
||
1590 | case GL_RG16UI: |
||
1591 | case GL_RG16I: |
||
1592 | case GL_RG32UI: |
||
1593 | case GL_RG32I: |
||
1594 | return ctx->Version >= 30 |
||
1595 | || (_mesa_is_desktop_gl(ctx) && |
||
1596 | ctx->Extensions.ARB_texture_rg && |
||
1597 | ctx->Extensions.EXT_texture_integer) ? GL_RG : 0; |
||
1598 | |||
1599 | case GL_INTENSITY8I_EXT: |
||
1600 | case GL_INTENSITY8UI_EXT: |
||
1601 | case GL_INTENSITY16I_EXT: |
||
1602 | case GL_INTENSITY16UI_EXT: |
||
1603 | case GL_INTENSITY32I_EXT: |
||
1604 | case GL_INTENSITY32UI_EXT: |
||
1605 | return ctx->API == API_OPENGL_COMPAT && |
||
1606 | ctx->Extensions.EXT_texture_integer && |
||
1607 | ctx->Extensions.ARB_framebuffer_object ? GL_INTENSITY : 0; |
||
1608 | |||
1609 | case GL_LUMINANCE8I_EXT: |
||
1610 | case GL_LUMINANCE8UI_EXT: |
||
1611 | case GL_LUMINANCE16I_EXT: |
||
1612 | case GL_LUMINANCE16UI_EXT: |
||
1613 | case GL_LUMINANCE32I_EXT: |
||
1614 | case GL_LUMINANCE32UI_EXT: |
||
1615 | return ctx->API == API_OPENGL_COMPAT && |
||
1616 | ctx->Extensions.EXT_texture_integer && |
||
1617 | ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE : 0; |
||
1618 | |||
1619 | case GL_LUMINANCE_ALPHA8I_EXT: |
||
1620 | case GL_LUMINANCE_ALPHA8UI_EXT: |
||
1621 | case GL_LUMINANCE_ALPHA16I_EXT: |
||
1622 | case GL_LUMINANCE_ALPHA16UI_EXT: |
||
1623 | case GL_LUMINANCE_ALPHA32I_EXT: |
||
1624 | case GL_LUMINANCE_ALPHA32UI_EXT: |
||
1625 | return ctx->API == API_OPENGL_COMPAT && |
||
1626 | ctx->Extensions.EXT_texture_integer && |
||
1627 | ctx->Extensions.ARB_framebuffer_object ? GL_LUMINANCE_ALPHA : 0; |
||
1628 | |||
1629 | case GL_ALPHA8I_EXT: |
||
1630 | case GL_ALPHA8UI_EXT: |
||
1631 | case GL_ALPHA16I_EXT: |
||
1632 | case GL_ALPHA16UI_EXT: |
||
1633 | case GL_ALPHA32I_EXT: |
||
1634 | case GL_ALPHA32UI_EXT: |
||
1635 | return ctx->API == API_OPENGL_COMPAT && |
||
1636 | ctx->Extensions.EXT_texture_integer && |
||
1637 | ctx->Extensions.ARB_framebuffer_object ? GL_ALPHA : 0; |
||
1638 | |||
1639 | case GL_RGB10_A2UI: |
||
1640 | return (_mesa_is_desktop_gl(ctx) && |
||
1641 | ctx->Extensions.ARB_texture_rgb10_a2ui) |
||
1642 | || _mesa_is_gles3(ctx) ? GL_RGBA : 0; |
||
1643 | |||
1644 | case GL_RGB565: |
||
1645 | return _mesa_is_gles(ctx) || ctx->Extensions.ARB_ES2_compatibility |
||
1646 | ? GL_RGB : 0; |
||
1647 | default: |
||
1648 | return 0; |
||
1649 | } |
||
1650 | } |
||
1651 | |||
1652 | |||
1653 | /** |
||
1654 | * Invalidate a renderbuffer attachment. Called from _mesa_HashWalk(). |
||
1655 | */ |
||
1656 | static void |
||
1657 | invalidate_rb(GLuint key, void *data, void *userData) |
||
1658 | { |
||
1659 | struct gl_framebuffer *fb = (struct gl_framebuffer *) data; |
||
1660 | struct gl_renderbuffer *rb = (struct gl_renderbuffer *) userData; |
||
1661 | |||
1662 | /* If this is a user-created FBO */ |
||
1663 | if (_mesa_is_user_fbo(fb)) { |
||
1664 | GLuint i; |
||
1665 | for (i = 0; i < BUFFER_COUNT; i++) { |
||
1666 | struct gl_renderbuffer_attachment *att = fb->Attachment + i; |
||
1667 | if (att->Type == GL_RENDERBUFFER && |
||
1668 | att->Renderbuffer == rb) { |
||
1669 | /* Mark fb status as indeterminate to force re-validation */ |
||
1670 | fb->_Status = 0; |
||
1671 | return; |
||
1672 | } |
||
1673 | } |
||
1674 | } |
||
1675 | } |
||
1676 | |||
1677 | |||
1678 | /** sentinal value, see below */ |
||
1679 | #define NO_SAMPLES 1000 |
||
1680 | |||
1681 | |||
1682 | /** |
||
1683 | * Helper function used by _mesa_RenderbufferStorage() and |
||
1684 | * _mesa_RenderbufferStorageMultisample(). |
||
1685 | * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorage(). |
||
1686 | */ |
||
1687 | static void |
||
1688 | renderbuffer_storage(GLenum target, GLenum internalFormat, |
||
1689 | GLsizei width, GLsizei height, GLsizei samples) |
||
1690 | { |
||
1691 | const char *func = samples == NO_SAMPLES ? |
||
1692 | "glRenderbufferStorage" : "glRenderbufferStorageMultisample"; |
||
1693 | struct gl_renderbuffer *rb; |
||
1694 | GLenum baseFormat; |
||
1695 | GLenum sample_count_error; |
||
1696 | GET_CURRENT_CONTEXT(ctx); |
||
1697 | |||
1698 | if (MESA_VERBOSE & VERBOSE_API) { |
||
1699 | if (samples == NO_SAMPLES) |
||
1700 | _mesa_debug(ctx, "%s(%s, %s, %d, %d)\n", |
||
1701 | func, |
||
1702 | _mesa_lookup_enum_by_nr(target), |
||
1703 | _mesa_lookup_enum_by_nr(internalFormat), |
||
1704 | width, height); |
||
1705 | else |
||
1706 | _mesa_debug(ctx, "%s(%s, %s, %d, %d, %d)\n", |
||
1707 | func, |
||
1708 | _mesa_lookup_enum_by_nr(target), |
||
1709 | _mesa_lookup_enum_by_nr(internalFormat), |
||
1710 | width, height, samples); |
||
1711 | } |
||
1712 | |||
1713 | if (target != GL_RENDERBUFFER_EXT) { |
||
1714 | _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func); |
||
1715 | return; |
||
1716 | } |
||
1717 | |||
1718 | baseFormat = _mesa_base_fbo_format(ctx, internalFormat); |
||
1719 | if (baseFormat == 0) { |
||
1720 | _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat=%s)", |
||
1721 | func, _mesa_lookup_enum_by_nr(internalFormat)); |
||
1722 | return; |
||
1723 | } |
||
1724 | |||
1725 | if (width < 0 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) { |
||
1726 | _mesa_error(ctx, GL_INVALID_VALUE, "%s(width)", func); |
||
1727 | return; |
||
1728 | } |
||
1729 | |||
1730 | if (height < 0 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) { |
||
1731 | _mesa_error(ctx, GL_INVALID_VALUE, "%s(height)", func); |
||
1732 | return; |
||
1733 | } |
||
1734 | |||
1735 | if (samples == NO_SAMPLES) { |
||
1736 | /* NumSamples == 0 indicates non-multisampling */ |
||
1737 | samples = 0; |
||
1738 | } |
||
1739 | else { |
||
1740 | /* check the sample count; |
||
1741 | * note: driver may choose to use more samples than what's requested |
||
1742 | */ |
||
1743 | sample_count_error = _mesa_check_sample_count(ctx, target, |
||
1744 | internalFormat, samples); |
||
1745 | if (sample_count_error != GL_NO_ERROR) { |
||
1746 | _mesa_error(ctx, sample_count_error, "%s(samples)", func); |
||
1747 | return; |
||
1748 | } |
||
1749 | } |
||
1750 | |||
1751 | rb = ctx->CurrentRenderbuffer; |
||
1752 | if (!rb) { |
||
1753 | _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func); |
||
1754 | return; |
||
1755 | } |
||
1756 | |||
1757 | FLUSH_VERTICES(ctx, _NEW_BUFFERS); |
||
1758 | |||
1759 | if (rb->InternalFormat == internalFormat && |
||
1760 | rb->Width == (GLuint) width && |
||
1761 | rb->Height == (GLuint) height && |
||
1762 | rb->NumSamples == samples) { |
||
1763 | /* no change in allocation needed */ |
||
1764 | return; |
||
1765 | } |
||
1766 | |||
1767 | /* These MUST get set by the AllocStorage func */ |
||
1768 | rb->Format = MESA_FORMAT_NONE; |
||
1769 | rb->NumSamples = samples; |
||
1770 | |||
1771 | /* Now allocate the storage */ |
||
1772 | ASSERT(rb->AllocStorage); |
||
1773 | if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) { |
||
1774 | /* No error - check/set fields now */ |
||
1775 | /* If rb->Format == MESA_FORMAT_NONE, the format is unsupported. */ |
||
1776 | assert(rb->Width == (GLuint) width); |
||
1777 | assert(rb->Height == (GLuint) height); |
||
1778 | rb->InternalFormat = internalFormat; |
||
1779 | rb->_BaseFormat = baseFormat; |
||
1780 | assert(rb->_BaseFormat != 0); |
||
1781 | } |
||
1782 | else { |
||
1783 | /* Probably ran out of memory - clear the fields */ |
||
1784 | rb->Width = 0; |
||
1785 | rb->Height = 0; |
||
1786 | rb->Format = MESA_FORMAT_NONE; |
||
1787 | rb->InternalFormat = GL_NONE; |
||
1788 | rb->_BaseFormat = GL_NONE; |
||
1789 | rb->NumSamples = 0; |
||
1790 | } |
||
1791 | |||
1792 | /* Invalidate the framebuffers the renderbuffer is attached in. */ |
||
1793 | if (rb->AttachedAnytime) { |
||
1794 | _mesa_HashWalk(ctx->Shared->FrameBuffers, invalidate_rb, rb); |
||
1795 | } |
||
1796 | } |
||
1797 | |||
1798 | |||
1799 | void GLAPIENTRY |
||
1800 | _mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image) |
||
1801 | { |
||
1802 | struct gl_renderbuffer *rb; |
||
1803 | GET_CURRENT_CONTEXT(ctx); |
||
1804 | |||
1805 | if (!ctx->Extensions.OES_EGL_image) { |
||
1806 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
1807 | "glEGLImageTargetRenderbufferStorageOES(unsupported)"); |
||
1808 | return; |
||
1809 | } |
||
1810 | |||
1811 | if (target != GL_RENDERBUFFER) { |
||
1812 | _mesa_error(ctx, GL_INVALID_ENUM, |
||
1813 | "EGLImageTargetRenderbufferStorageOES"); |
||
1814 | return; |
||
1815 | } |
||
1816 | |||
1817 | rb = ctx->CurrentRenderbuffer; |
||
1818 | if (!rb) { |
||
1819 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
1820 | "EGLImageTargetRenderbufferStorageOES"); |
||
1821 | return; |
||
1822 | } |
||
1823 | |||
1824 | FLUSH_VERTICES(ctx, _NEW_BUFFERS); |
||
1825 | |||
1826 | ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image); |
||
1827 | } |
||
1828 | |||
1829 | |||
1830 | /** |
||
1831 | * Helper function for _mesa_GetRenderbufferParameteriv() and |
||
1832 | * _mesa_GetFramebufferAttachmentParameteriv() |
||
1833 | * We have to be careful to respect the base format. For example, if a |
||
1834 | * renderbuffer/texture was created with internalFormat=GL_RGB but the |
||
1835 | * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE |
||
1836 | * we need to return zero. |
||
1837 | */ |
||
1838 | static GLint |
||
1839 | get_component_bits(GLenum pname, GLenum baseFormat, gl_format format) |
||
1840 | { |
||
1841 | if (_mesa_base_format_has_channel(baseFormat, pname)) |
||
1842 | return _mesa_get_format_bits(format, pname); |
||
1843 | else |
||
1844 | return 0; |
||
1845 | } |
||
1846 | |||
1847 | |||
1848 | |||
1849 | void GLAPIENTRY |
||
1850 | _mesa_RenderbufferStorage(GLenum target, GLenum internalFormat, |
||
1851 | GLsizei width, GLsizei height) |
||
1852 | { |
||
1853 | /* GL_ARB_fbo says calling this function is equivalent to calling |
||
1854 | * glRenderbufferStorageMultisample() with samples=0. We pass in |
||
1855 | * a token value here just for error reporting purposes. |
||
1856 | */ |
||
1857 | renderbuffer_storage(target, internalFormat, width, height, NO_SAMPLES); |
||
1858 | } |
||
1859 | |||
1860 | |||
1861 | void GLAPIENTRY |
||
1862 | _mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples, |
||
1863 | GLenum internalFormat, |
||
1864 | GLsizei width, GLsizei height) |
||
1865 | { |
||
1866 | renderbuffer_storage(target, internalFormat, width, height, samples); |
||
1867 | } |
||
1868 | |||
1869 | |||
1870 | /** |
||
1871 | * OpenGL ES version of glRenderBufferStorage. |
||
1872 | */ |
||
1873 | void GLAPIENTRY |
||
1874 | _es_RenderbufferStorageEXT(GLenum target, GLenum internalFormat, |
||
1875 | GLsizei width, GLsizei height) |
||
1876 | { |
||
1877 | switch (internalFormat) { |
||
1878 | case GL_RGB565: |
||
1879 | /* XXX this confuses GL_RENDERBUFFER_INTERNAL_FORMAT_OES */ |
||
1880 | /* choose a closest format */ |
||
1881 | internalFormat = GL_RGB5; |
||
1882 | break; |
||
1883 | default: |
||
1884 | break; |
||
1885 | } |
||
1886 | |||
1887 | renderbuffer_storage(target, internalFormat, width, height, 0); |
||
1888 | } |
||
1889 | |||
1890 | |||
1891 | void GLAPIENTRY |
||
1892 | _mesa_GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint *params) |
||
1893 | { |
||
1894 | struct gl_renderbuffer *rb; |
||
1895 | GET_CURRENT_CONTEXT(ctx); |
||
1896 | |||
1897 | if (target != GL_RENDERBUFFER_EXT) { |
||
1898 | _mesa_error(ctx, GL_INVALID_ENUM, |
||
1899 | "glGetRenderbufferParameterivEXT(target)"); |
||
1900 | return; |
||
1901 | } |
||
1902 | |||
1903 | rb = ctx->CurrentRenderbuffer; |
||
1904 | if (!rb) { |
||
1905 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
1906 | "glGetRenderbufferParameterivEXT"); |
||
1907 | return; |
||
1908 | } |
||
1909 | |||
1910 | /* No need to flush here since we're just quering state which is |
||
1911 | * not effected by rendering. |
||
1912 | */ |
||
1913 | |||
1914 | switch (pname) { |
||
1915 | case GL_RENDERBUFFER_WIDTH_EXT: |
||
1916 | *params = rb->Width; |
||
1917 | return; |
||
1918 | case GL_RENDERBUFFER_HEIGHT_EXT: |
||
1919 | *params = rb->Height; |
||
1920 | return; |
||
1921 | case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT: |
||
1922 | *params = rb->InternalFormat; |
||
1923 | return; |
||
1924 | case GL_RENDERBUFFER_RED_SIZE_EXT: |
||
1925 | case GL_RENDERBUFFER_GREEN_SIZE_EXT: |
||
1926 | case GL_RENDERBUFFER_BLUE_SIZE_EXT: |
||
1927 | case GL_RENDERBUFFER_ALPHA_SIZE_EXT: |
||
1928 | case GL_RENDERBUFFER_DEPTH_SIZE_EXT: |
||
1929 | case GL_RENDERBUFFER_STENCIL_SIZE_EXT: |
||
1930 | *params = get_component_bits(pname, rb->_BaseFormat, rb->Format); |
||
1931 | break; |
||
1932 | case GL_RENDERBUFFER_SAMPLES: |
||
1933 | if ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_framebuffer_object) |
||
1934 | || _mesa_is_gles3(ctx)) { |
||
1935 | *params = rb->NumSamples; |
||
1936 | break; |
||
1937 | } |
||
1938 | /* fallthrough */ |
||
1939 | default: |
||
1940 | _mesa_error(ctx, GL_INVALID_ENUM, |
||
1941 | "glGetRenderbufferParameterivEXT(target)"); |
||
1942 | return; |
||
1943 | } |
||
1944 | } |
||
1945 | |||
1946 | |||
1947 | GLboolean GLAPIENTRY |
||
1948 | _mesa_IsFramebuffer(GLuint framebuffer) |
||
1949 | { |
||
1950 | GET_CURRENT_CONTEXT(ctx); |
||
1951 | ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); |
||
1952 | if (framebuffer) { |
||
1953 | struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer); |
||
1954 | if (rb != NULL && rb != &DummyFramebuffer) |
||
1955 | return GL_TRUE; |
||
1956 | } |
||
1957 | return GL_FALSE; |
||
1958 | } |
||
1959 | |||
1960 | |||
1961 | /** |
||
1962 | * Check if any of the attachments of the given framebuffer are textures |
||
1963 | * (render to texture). Call ctx->Driver.RenderTexture() for such |
||
1964 | * attachments. |
||
1965 | */ |
||
1966 | static void |
||
1967 | check_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb) |
||
1968 | { |
||
1969 | GLuint i; |
||
1970 | ASSERT(ctx->Driver.RenderTexture); |
||
1971 | |||
1972 | if (_mesa_is_winsys_fbo(fb)) |
||
1973 | return; /* can't render to texture with winsys framebuffers */ |
||
1974 | |||
1975 | for (i = 0; i < BUFFER_COUNT; i++) { |
||
1976 | struct gl_renderbuffer_attachment *att = fb->Attachment + i; |
||
1977 | if (att->Texture && att->Renderbuffer->TexImage |
||
1978 | && driver_RenderTexture_is_safe(att)) { |
||
1979 | ctx->Driver.RenderTexture(ctx, fb, att); |
||
1980 | } |
||
1981 | } |
||
1982 | } |
||
1983 | |||
1984 | |||
1985 | /** |
||
1986 | * Examine all the framebuffer's attachments to see if any are textures. |
||
1987 | * If so, call ctx->Driver.FinishRenderTexture() for each texture to |
||
1988 | * notify the device driver that the texture image may have changed. |
||
1989 | */ |
||
1990 | static void |
||
1991 | check_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb) |
||
1992 | { |
||
1993 | if (_mesa_is_winsys_fbo(fb)) |
||
1994 | return; /* can't render to texture with winsys framebuffers */ |
||
1995 | |||
1996 | if (ctx->Driver.FinishRenderTexture) { |
||
1997 | GLuint i; |
||
1998 | for (i = 0; i < BUFFER_COUNT; i++) { |
||
1999 | struct gl_renderbuffer_attachment *att = fb->Attachment + i; |
||
2000 | struct gl_renderbuffer *rb = att->Renderbuffer; |
||
2001 | if (rb && rb->NeedsFinishRenderTexture) { |
||
2002 | ctx->Driver.FinishRenderTexture(ctx, rb); |
||
2003 | } |
||
2004 | } |
||
2005 | } |
||
2006 | } |
||
2007 | |||
2008 | |||
2009 | static void |
||
2010 | bind_framebuffer(GLenum target, GLuint framebuffer, bool allow_user_names) |
||
2011 | { |
||
2012 | struct gl_framebuffer *newDrawFb, *newReadFb; |
||
2013 | struct gl_framebuffer *oldDrawFb, *oldReadFb; |
||
2014 | GLboolean bindReadBuf, bindDrawBuf; |
||
2015 | GET_CURRENT_CONTEXT(ctx); |
||
2016 | |||
2017 | #ifdef DEBUG |
||
2018 | if (ctx->Extensions.ARB_framebuffer_object) { |
||
2019 | ASSERT(ctx->Extensions.EXT_framebuffer_blit); |
||
2020 | } |
||
2021 | #endif |
||
2022 | |||
2023 | switch (target) { |
||
2024 | case GL_DRAW_FRAMEBUFFER_EXT: |
||
2025 | if (!ctx->Extensions.EXT_framebuffer_blit) { |
||
2026 | _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); |
||
2027 | return; |
||
2028 | } |
||
2029 | bindDrawBuf = GL_TRUE; |
||
2030 | bindReadBuf = GL_FALSE; |
||
2031 | break; |
||
2032 | case GL_READ_FRAMEBUFFER_EXT: |
||
2033 | if (!ctx->Extensions.EXT_framebuffer_blit) { |
||
2034 | _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); |
||
2035 | return; |
||
2036 | } |
||
2037 | bindDrawBuf = GL_FALSE; |
||
2038 | bindReadBuf = GL_TRUE; |
||
2039 | break; |
||
2040 | case GL_FRAMEBUFFER_EXT: |
||
2041 | bindDrawBuf = GL_TRUE; |
||
2042 | bindReadBuf = GL_TRUE; |
||
2043 | break; |
||
2044 | default: |
||
2045 | _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); |
||
2046 | return; |
||
2047 | } |
||
2048 | |||
2049 | if (framebuffer) { |
||
2050 | /* Binding a user-created framebuffer object */ |
||
2051 | newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer); |
||
2052 | if (newDrawFb == &DummyFramebuffer) { |
||
2053 | /* ID was reserved, but no real framebuffer object made yet */ |
||
2054 | newDrawFb = NULL; |
||
2055 | } |
||
2056 | else if (!newDrawFb && !allow_user_names) { |
||
2057 | /* All FBO IDs must be Gen'd */ |
||
2058 | _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)"); |
||
2059 | return; |
||
2060 | } |
||
2061 | |||
2062 | if (!newDrawFb) { |
||
2063 | /* create new framebuffer object */ |
||
2064 | newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer); |
||
2065 | if (!newDrawFb) { |
||
2066 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT"); |
||
2067 | return; |
||
2068 | } |
||
2069 | _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb); |
||
2070 | } |
||
2071 | newReadFb = newDrawFb; |
||
2072 | } |
||
2073 | else { |
||
2074 | /* Binding the window system framebuffer (which was originally set |
||
2075 | * with MakeCurrent). |
||
2076 | */ |
||
2077 | newDrawFb = ctx->WinSysDrawBuffer; |
||
2078 | newReadFb = ctx->WinSysReadBuffer; |
||
2079 | } |
||
2080 | |||
2081 | ASSERT(newDrawFb); |
||
2082 | ASSERT(newDrawFb != &DummyFramebuffer); |
||
2083 | |||
2084 | /* save pointers to current/old framebuffers */ |
||
2085 | oldDrawFb = ctx->DrawBuffer; |
||
2086 | oldReadFb = ctx->ReadBuffer; |
||
2087 | |||
2088 | /* check if really changing bindings */ |
||
2089 | if (oldDrawFb == newDrawFb) |
||
2090 | bindDrawBuf = GL_FALSE; |
||
2091 | if (oldReadFb == newReadFb) |
||
2092 | bindReadBuf = GL_FALSE; |
||
2093 | |||
2094 | /* |
||
2095 | * OK, now bind the new Draw/Read framebuffers, if they're changing. |
||
2096 | * |
||
2097 | * We also check if we're beginning and/or ending render-to-texture. |
||
2098 | * When a framebuffer with texture attachments is unbound, call |
||
2099 | * ctx->Driver.FinishRenderTexture(). |
||
2100 | * When a framebuffer with texture attachments is bound, call |
||
2101 | * ctx->Driver.RenderTexture(). |
||
2102 | * |
||
2103 | * Note that if the ReadBuffer has texture attachments we don't consider |
||
2104 | * that a render-to-texture case. |
||
2105 | */ |
||
2106 | if (bindReadBuf) { |
||
2107 | FLUSH_VERTICES(ctx, _NEW_BUFFERS); |
||
2108 | |||
2109 | /* check if old readbuffer was render-to-texture */ |
||
2110 | check_end_texture_render(ctx, oldReadFb); |
||
2111 | |||
2112 | _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb); |
||
2113 | } |
||
2114 | |||
2115 | if (bindDrawBuf) { |
||
2116 | FLUSH_VERTICES(ctx, _NEW_BUFFERS); |
||
2117 | |||
2118 | /* check if old framebuffer had any texture attachments */ |
||
2119 | if (oldDrawFb) |
||
2120 | check_end_texture_render(ctx, oldDrawFb); |
||
2121 | |||
2122 | /* check if newly bound framebuffer has any texture attachments */ |
||
2123 | check_begin_texture_render(ctx, newDrawFb); |
||
2124 | |||
2125 | _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb); |
||
2126 | } |
||
2127 | |||
2128 | if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) { |
||
2129 | ctx->Driver.BindFramebuffer(ctx, target, newDrawFb, newReadFb); |
||
2130 | } |
||
2131 | } |
||
2132 | |||
2133 | void GLAPIENTRY |
||
2134 | _mesa_BindFramebuffer(GLenum target, GLuint framebuffer) |
||
2135 | { |
||
2136 | GET_CURRENT_CONTEXT(ctx); |
||
2137 | |||
2138 | /* OpenGL ES glBindFramebuffer and glBindFramebufferOES use this same entry |
||
2139 | * point, but they allow the use of user-generated names. |
||
2140 | */ |
||
2141 | bind_framebuffer(target, framebuffer, _mesa_is_gles(ctx)); |
||
2142 | } |
||
2143 | |||
2144 | void GLAPIENTRY |
||
2145 | _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer) |
||
2146 | { |
||
2147 | /* This function should not be in the dispatch table for core profile / |
||
2148 | * OpenGL 3.1, so execution should never get here in those cases -- no |
||
2149 | * need for an explicit test. |
||
2150 | */ |
||
2151 | bind_framebuffer(target, framebuffer, true); |
||
2152 | } |
||
2153 | |||
2154 | void GLAPIENTRY |
||
2155 | _mesa_DeleteFramebuffers(GLsizei n, const GLuint *framebuffers) |
||
2156 | { |
||
2157 | GLint i; |
||
2158 | GET_CURRENT_CONTEXT(ctx); |
||
2159 | |||
2160 | FLUSH_VERTICES(ctx, _NEW_BUFFERS); |
||
2161 | |||
2162 | for (i = 0; i < n; i++) { |
||
2163 | if (framebuffers[i] > 0) { |
||
2164 | struct gl_framebuffer *fb; |
||
2165 | fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]); |
||
2166 | if (fb) { |
||
2167 | ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]); |
||
2168 | |||
2169 | /* check if deleting currently bound framebuffer object */ |
||
2170 | if (ctx->Extensions.EXT_framebuffer_blit) { |
||
2171 | /* separate draw/read binding points */ |
||
2172 | if (fb == ctx->DrawBuffer) { |
||
2173 | /* bind default */ |
||
2174 | ASSERT(fb->RefCount >= 2); |
||
2175 | _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0); |
||
2176 | } |
||
2177 | if (fb == ctx->ReadBuffer) { |
||
2178 | /* bind default */ |
||
2179 | ASSERT(fb->RefCount >= 2); |
||
2180 | _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0); |
||
2181 | } |
||
2182 | } |
||
2183 | else { |
||
2184 | /* only one binding point for read/draw buffers */ |
||
2185 | if (fb == ctx->DrawBuffer || fb == ctx->ReadBuffer) { |
||
2186 | /* bind default */ |
||
2187 | ASSERT(fb->RefCount >= 2); |
||
2188 | _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, 0); |
||
2189 | } |
||
2190 | } |
||
2191 | |||
2192 | /* remove from hash table immediately, to free the ID */ |
||
2193 | _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]); |
||
2194 | |||
2195 | if (fb != &DummyFramebuffer) { |
||
2196 | /* But the object will not be freed until it's no longer |
||
2197 | * bound in any context. |
||
2198 | */ |
||
2199 | _mesa_reference_framebuffer(&fb, NULL); |
||
2200 | } |
||
2201 | } |
||
2202 | } |
||
2203 | } |
||
2204 | } |
||
2205 | |||
2206 | |||
2207 | void GLAPIENTRY |
||
2208 | _mesa_GenFramebuffers(GLsizei n, GLuint *framebuffers) |
||
2209 | { |
||
2210 | GET_CURRENT_CONTEXT(ctx); |
||
2211 | GLuint first; |
||
2212 | GLint i; |
||
2213 | |||
2214 | if (n < 0) { |
||
2215 | _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)"); |
||
2216 | return; |
||
2217 | } |
||
2218 | |||
2219 | if (!framebuffers) |
||
2220 | return; |
||
2221 | |||
2222 | first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n); |
||
2223 | |||
2224 | for (i = 0; i < n; i++) { |
||
2225 | GLuint name = first + i; |
||
2226 | framebuffers[i] = name; |
||
2227 | /* insert dummy placeholder into hash table */ |
||
2228 | _glthread_LOCK_MUTEX(ctx->Shared->Mutex); |
||
2229 | _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer); |
||
2230 | _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); |
||
2231 | } |
||
2232 | } |
||
2233 | |||
2234 | |||
2235 | |||
2236 | GLenum GLAPIENTRY |
||
2237 | _mesa_CheckFramebufferStatus(GLenum target) |
||
2238 | { |
||
2239 | struct gl_framebuffer *buffer; |
||
2240 | GET_CURRENT_CONTEXT(ctx); |
||
2241 | |||
2242 | ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); |
||
2243 | |||
2244 | if (MESA_VERBOSE & VERBOSE_API) |
||
2245 | _mesa_debug(ctx, "glCheckFramebufferStatus(%s)\n", |
||
2246 | _mesa_lookup_enum_by_nr(target)); |
||
2247 | |||
2248 | buffer = get_framebuffer_target(ctx, target); |
||
2249 | if (!buffer) { |
||
2250 | _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); |
||
2251 | return 0; |
||
2252 | } |
||
2253 | |||
2254 | if (_mesa_is_winsys_fbo(buffer)) { |
||
2255 | /* The window system / default framebuffer is always complete */ |
||
2256 | return GL_FRAMEBUFFER_COMPLETE_EXT; |
||
2257 | } |
||
2258 | |||
2259 | /* No need to flush here */ |
||
2260 | |||
2261 | if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) { |
||
2262 | _mesa_test_framebuffer_completeness(ctx, buffer); |
||
2263 | } |
||
2264 | |||
2265 | return buffer->_Status; |
||
2266 | } |
||
2267 | |||
2268 | |||
2269 | /** |
||
2270 | * Replicate the src attachment point. Used by framebuffer_texture() when |
||
2271 | * the same texture is attached at GL_DEPTH_ATTACHMENT and |
||
2272 | * GL_STENCIL_ATTACHMENT. |
||
2273 | */ |
||
2274 | static void |
||
2275 | reuse_framebuffer_texture_attachment(struct gl_framebuffer *fb, |
||
2276 | gl_buffer_index dst, |
||
2277 | gl_buffer_index src) |
||
2278 | { |
||
2279 | struct gl_renderbuffer_attachment *dst_att = &fb->Attachment[dst]; |
||
2280 | struct gl_renderbuffer_attachment *src_att = &fb->Attachment[src]; |
||
2281 | |||
2282 | assert(src_att->Texture != NULL); |
||
2283 | assert(src_att->Renderbuffer != NULL); |
||
2284 | |||
2285 | _mesa_reference_texobj(&dst_att->Texture, src_att->Texture); |
||
2286 | _mesa_reference_renderbuffer(&dst_att->Renderbuffer, src_att->Renderbuffer); |
||
2287 | dst_att->Type = src_att->Type; |
||
2288 | dst_att->Complete = src_att->Complete; |
||
2289 | dst_att->TextureLevel = src_att->TextureLevel; |
||
2290 | dst_att->Zoffset = src_att->Zoffset; |
||
2291 | } |
||
2292 | |||
2293 | |||
2294 | /** |
||
2295 | * Common code called by glFramebufferTexture1D/2D/3DEXT() and |
||
2296 | * glFramebufferTextureLayerEXT(). |
||
2297 | * Note: glFramebufferTextureLayerEXT() has no textarget parameter so we'll |
||
2298 | * get textarget=0 in that case. |
||
2299 | */ |
||
2300 | static void |
||
2301 | framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target, |
||
2302 | GLenum attachment, GLenum textarget, GLuint texture, |
||
2303 | GLint level, GLint zoffset, GLboolean layered) |
||
2304 | { |
||
2305 | struct gl_renderbuffer_attachment *att; |
||
2306 | struct gl_texture_object *texObj = NULL; |
||
2307 | struct gl_framebuffer *fb; |
||
2308 | GLenum maxLevelsTarget; |
||
2309 | |||
2310 | fb = get_framebuffer_target(ctx, target); |
||
2311 | if (!fb) { |
||
2312 | _mesa_error(ctx, GL_INVALID_ENUM, |
||
2313 | "glFramebufferTexture%sEXT(target=0x%x)", caller, target); |
||
2314 | return; |
||
2315 | } |
||
2316 | |||
2317 | /* check framebuffer binding */ |
||
2318 | if (_mesa_is_winsys_fbo(fb)) { |
||
2319 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
2320 | "glFramebufferTexture%sEXT", caller); |
||
2321 | return; |
||
2322 | } |
||
2323 | |||
2324 | /* The textarget, level, and zoffset parameters are only validated if |
||
2325 | * texture is non-zero. |
||
2326 | */ |
||
2327 | if (texture) { |
||
2328 | GLboolean err = GL_TRUE; |
||
2329 | |||
2330 | texObj = _mesa_lookup_texture(ctx, texture); |
||
2331 | if (texObj != NULL) { |
||
2332 | if (textarget == 0) { |
||
2333 | /* If textarget == 0 it means we're being called by |
||
2334 | * glFramebufferTextureLayer() and textarget is not used. |
||
2335 | * The only legal texture types for that function are 3D and |
||
2336 | * 1D/2D arrays textures. |
||
2337 | */ |
||
2338 | err = (texObj->Target != GL_TEXTURE_3D) && |
||
2339 | (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) && |
||
2340 | (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT) && |
||
2341 | (texObj->Target != GL_TEXTURE_CUBE_MAP_ARRAY) && |
||
2342 | (texObj->Target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY); |
||
2343 | } |
||
2344 | else { |
||
2345 | /* Make sure textarget is consistent with the texture's type */ |
||
2346 | err = (texObj->Target == GL_TEXTURE_CUBE_MAP) |
||
2347 | ? !_mesa_is_cube_face(textarget) |
||
2348 | : (texObj->Target != textarget); |
||
2349 | } |
||
2350 | } |
||
2351 | else { |
||
2352 | /* can't render to a non-existant texture */ |
||
2353 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
2354 | "glFramebufferTexture%sEXT(non existant texture)", |
||
2355 | caller); |
||
2356 | return; |
||
2357 | } |
||
2358 | |||
2359 | if (err) { |
||
2360 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
2361 | "glFramebufferTexture%sEXT(texture target mismatch)", |
||
2362 | caller); |
||
2363 | return; |
||
2364 | } |
||
2365 | |||
2366 | if (texObj->Target == GL_TEXTURE_3D) { |
||
2367 | const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); |
||
2368 | if (zoffset < 0 || zoffset >= maxSize) { |
||
2369 | _mesa_error(ctx, GL_INVALID_VALUE, |
||
2370 | "glFramebufferTexture%sEXT(zoffset)", caller); |
||
2371 | return; |
||
2372 | } |
||
2373 | } |
||
2374 | else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) || |
||
2375 | (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT) || |
||
2376 | (texObj->Target == GL_TEXTURE_CUBE_MAP_ARRAY) || |
||
2377 | (texObj->Target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)) { |
||
2378 | if (zoffset < 0 || |
||
2379 | zoffset >= (GLint) ctx->Const.MaxArrayTextureLayers) { |
||
2380 | _mesa_error(ctx, GL_INVALID_VALUE, |
||
2381 | "glFramebufferTexture%sEXT(layer)", caller); |
||
2382 | return; |
||
2383 | } |
||
2384 | } |
||
2385 | |||
2386 | maxLevelsTarget = textarget ? textarget : texObj->Target; |
||
2387 | if ((level < 0) || |
||
2388 | (level >= _mesa_max_texture_levels(ctx, maxLevelsTarget))) { |
||
2389 | _mesa_error(ctx, GL_INVALID_VALUE, |
||
2390 | "glFramebufferTexture%sEXT(level)", caller); |
||
2391 | return; |
||
2392 | } |
||
2393 | } |
||
2394 | |||
2395 | att = _mesa_get_attachment(ctx, fb, attachment); |
||
2396 | if (att == NULL) { |
||
2397 | _mesa_error(ctx, GL_INVALID_ENUM, |
||
2398 | "glFramebufferTexture%sEXT(attachment)", caller); |
||
2399 | return; |
||
2400 | } |
||
2401 | |||
2402 | FLUSH_VERTICES(ctx, _NEW_BUFFERS); |
||
2403 | |||
2404 | _glthread_LOCK_MUTEX(fb->Mutex); |
||
2405 | if (texObj) { |
||
2406 | if (attachment == GL_DEPTH_ATTACHMENT && |
||
2407 | texObj == fb->Attachment[BUFFER_STENCIL].Texture && |
||
2408 | level == fb->Attachment[BUFFER_STENCIL].TextureLevel && |
||
2409 | _mesa_tex_target_to_face(textarget) == |
||
2410 | fb->Attachment[BUFFER_STENCIL].CubeMapFace && |
||
2411 | zoffset == fb->Attachment[BUFFER_STENCIL].Zoffset) { |
||
2412 | /* The texture object is already attached to the stencil attachment |
||
2413 | * point. Don't create a new renderbuffer; just reuse the stencil |
||
2414 | * attachment's. This is required to prevent a GL error in |
||
2415 | * glGetFramebufferAttachmentParameteriv(GL_DEPTH_STENCIL). |
||
2416 | */ |
||
2417 | reuse_framebuffer_texture_attachment(fb, BUFFER_DEPTH, |
||
2418 | BUFFER_STENCIL); |
||
2419 | } else if (attachment == GL_STENCIL_ATTACHMENT && |
||
2420 | texObj == fb->Attachment[BUFFER_DEPTH].Texture && |
||
2421 | level == fb->Attachment[BUFFER_DEPTH].TextureLevel && |
||
2422 | _mesa_tex_target_to_face(textarget) == |
||
2423 | fb->Attachment[BUFFER_DEPTH].CubeMapFace && |
||
2424 | zoffset == fb->Attachment[BUFFER_DEPTH].Zoffset) { |
||
2425 | /* As above, but with depth and stencil transposed. */ |
||
2426 | reuse_framebuffer_texture_attachment(fb, BUFFER_STENCIL, |
||
2427 | BUFFER_DEPTH); |
||
2428 | } else { |
||
2429 | _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget, |
||
2430 | level, zoffset, layered); |
||
2431 | if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { |
||
2432 | /* Above we created a new renderbuffer and attached it to the |
||
2433 | * depth attachment point. Now attach it to the stencil attachment |
||
2434 | * point too. |
||
2435 | */ |
||
2436 | assert(att == &fb->Attachment[BUFFER_DEPTH]); |
||
2437 | reuse_framebuffer_texture_attachment(fb,BUFFER_STENCIL, |
||
2438 | BUFFER_DEPTH); |
||
2439 | } |
||
2440 | } |
||
2441 | |||
2442 | /* Set the render-to-texture flag. We'll check this flag in |
||
2443 | * glTexImage() and friends to determine if we need to revalidate |
||
2444 | * any FBOs that might be rendering into this texture. |
||
2445 | * This flag never gets cleared since it's non-trivial to determine |
||
2446 | * when all FBOs might be done rendering to this texture. That's OK |
||
2447 | * though since it's uncommon to render to a texture then repeatedly |
||
2448 | * call glTexImage() to change images in the texture. |
||
2449 | */ |
||
2450 | texObj->_RenderToTexture = GL_TRUE; |
||
2451 | } |
||
2452 | else { |
||
2453 | _mesa_remove_attachment(ctx, att); |
||
2454 | if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { |
||
2455 | assert(att == &fb->Attachment[BUFFER_DEPTH]); |
||
2456 | _mesa_remove_attachment(ctx, &fb->Attachment[BUFFER_STENCIL]); |
||
2457 | } |
||
2458 | } |
||
2459 | |||
2460 | invalidate_framebuffer(fb); |
||
2461 | |||
2462 | _glthread_UNLOCK_MUTEX(fb->Mutex); |
||
2463 | } |
||
2464 | |||
2465 | |||
2466 | |||
2467 | void GLAPIENTRY |
||
2468 | _mesa_FramebufferTexture1D(GLenum target, GLenum attachment, |
||
2469 | GLenum textarget, GLuint texture, GLint level) |
||
2470 | { |
||
2471 | GET_CURRENT_CONTEXT(ctx); |
||
2472 | |||
2473 | if (texture != 0) { |
||
2474 | GLboolean error; |
||
2475 | |||
2476 | switch (textarget) { |
||
2477 | case GL_TEXTURE_1D: |
||
2478 | error = GL_FALSE; |
||
2479 | break; |
||
2480 | case GL_TEXTURE_1D_ARRAY: |
||
2481 | error = !ctx->Extensions.EXT_texture_array; |
||
2482 | break; |
||
2483 | default: |
||
2484 | error = GL_TRUE; |
||
2485 | } |
||
2486 | |||
2487 | if (error) { |
||
2488 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
2489 | "glFramebufferTexture1DEXT(textarget=%s)", |
||
2490 | _mesa_lookup_enum_by_nr(textarget)); |
||
2491 | return; |
||
2492 | } |
||
2493 | } |
||
2494 | |||
2495 | framebuffer_texture(ctx, "1D", target, attachment, textarget, texture, |
||
2496 | level, 0, GL_FALSE); |
||
2497 | } |
||
2498 | |||
2499 | |||
2500 | void GLAPIENTRY |
||
2501 | _mesa_FramebufferTexture2D(GLenum target, GLenum attachment, |
||
2502 | GLenum textarget, GLuint texture, GLint level) |
||
2503 | { |
||
2504 | GET_CURRENT_CONTEXT(ctx); |
||
2505 | |||
2506 | if (texture != 0) { |
||
2507 | GLboolean error; |
||
2508 | |||
2509 | switch (textarget) { |
||
2510 | case GL_TEXTURE_2D: |
||
2511 | error = GL_FALSE; |
||
2512 | break; |
||
2513 | case GL_TEXTURE_RECTANGLE: |
||
2514 | error = _mesa_is_gles(ctx) |
||
2515 | || !ctx->Extensions.NV_texture_rectangle; |
||
2516 | break; |
||
2517 | case GL_TEXTURE_CUBE_MAP_POSITIVE_X: |
||
2518 | case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: |
||
2519 | case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: |
||
2520 | case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: |
||
2521 | case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: |
||
2522 | case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: |
||
2523 | error = !ctx->Extensions.ARB_texture_cube_map; |
||
2524 | break; |
||
2525 | case GL_TEXTURE_2D_ARRAY: |
||
2526 | error = (_mesa_is_gles(ctx) && ctx->Version < 30) |
||
2527 | || !ctx->Extensions.EXT_texture_array; |
||
2528 | break; |
||
2529 | case GL_TEXTURE_2D_MULTISAMPLE: |
||
2530 | case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: |
||
2531 | error = _mesa_is_gles(ctx) |
||
2532 | || !ctx->Extensions.ARB_texture_multisample; |
||
2533 | break; |
||
2534 | default: |
||
2535 | error = GL_TRUE; |
||
2536 | } |
||
2537 | |||
2538 | if (error) { |
||
2539 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
2540 | "glFramebufferTexture2DEXT(textarget=%s)", |
||
2541 | _mesa_lookup_enum_by_nr(textarget)); |
||
2542 | return; |
||
2543 | } |
||
2544 | } |
||
2545 | |||
2546 | framebuffer_texture(ctx, "2D", target, attachment, textarget, texture, |
||
2547 | level, 0, GL_FALSE); |
||
2548 | } |
||
2549 | |||
2550 | |||
2551 | void GLAPIENTRY |
||
2552 | _mesa_FramebufferTexture3D(GLenum target, GLenum attachment, |
||
2553 | GLenum textarget, GLuint texture, |
||
2554 | GLint level, GLint zoffset) |
||
2555 | { |
||
2556 | GET_CURRENT_CONTEXT(ctx); |
||
2557 | |||
2558 | if ((texture != 0) && (textarget != GL_TEXTURE_3D)) { |
||
2559 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
2560 | "glFramebufferTexture3DEXT(textarget)"); |
||
2561 | return; |
||
2562 | } |
||
2563 | |||
2564 | framebuffer_texture(ctx, "3D", target, attachment, textarget, texture, |
||
2565 | level, zoffset, GL_FALSE); |
||
2566 | } |
||
2567 | |||
2568 | |||
2569 | void GLAPIENTRY |
||
2570 | _mesa_FramebufferTextureLayer(GLenum target, GLenum attachment, |
||
2571 | GLuint texture, GLint level, GLint layer) |
||
2572 | { |
||
2573 | GET_CURRENT_CONTEXT(ctx); |
||
2574 | |||
2575 | framebuffer_texture(ctx, "Layer", target, attachment, 0, texture, |
||
2576 | level, layer, GL_FALSE); |
||
2577 | } |
||
2578 | |||
2579 | |||
2580 | void GLAPIENTRY |
||
2581 | _mesa_FramebufferTexture(GLenum target, GLenum attachment, |
||
2582 | GLuint texture, GLint level) |
||
2583 | { |
||
2584 | GET_CURRENT_CONTEXT(ctx); |
||
2585 | |||
2586 | if (ctx->Version >= 32 || ctx->Extensions.ARB_geometry_shader4) { |
||
2587 | framebuffer_texture(ctx, "Layer", target, attachment, 0, texture, |
||
2588 | level, 0, GL_TRUE); |
||
2589 | } else { |
||
2590 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
2591 | "unsupported function (glFramebufferTexture) called"); |
||
2592 | } |
||
2593 | } |
||
2594 | |||
2595 | |||
2596 | void GLAPIENTRY |
||
2597 | _mesa_FramebufferRenderbuffer(GLenum target, GLenum attachment, |
||
2598 | GLenum renderbufferTarget, |
||
2599 | GLuint renderbuffer) |
||
2600 | { |
||
2601 | struct gl_renderbuffer_attachment *att; |
||
2602 | struct gl_framebuffer *fb; |
||
2603 | struct gl_renderbuffer *rb; |
||
2604 | GET_CURRENT_CONTEXT(ctx); |
||
2605 | |||
2606 | fb = get_framebuffer_target(ctx, target); |
||
2607 | if (!fb) { |
||
2608 | _mesa_error(ctx, GL_INVALID_ENUM, "glFramebufferRenderbufferEXT(target)"); |
||
2609 | return; |
||
2610 | } |
||
2611 | |||
2612 | if (renderbufferTarget != GL_RENDERBUFFER_EXT) { |
||
2613 | _mesa_error(ctx, GL_INVALID_ENUM, |
||
2614 | "glFramebufferRenderbufferEXT(renderbufferTarget)"); |
||
2615 | return; |
||
2616 | } |
||
2617 | |||
2618 | if (_mesa_is_winsys_fbo(fb)) { |
||
2619 | /* Can't attach new renderbuffers to a window system framebuffer */ |
||
2620 | _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT"); |
||
2621 | return; |
||
2622 | } |
||
2623 | |||
2624 | att = _mesa_get_attachment(ctx, fb, attachment); |
||
2625 | if (att == NULL) { |
||
2626 | _mesa_error(ctx, GL_INVALID_ENUM, |
||
2627 | "glFramebufferRenderbufferEXT(invalid attachment %s)", |
||
2628 | _mesa_lookup_enum_by_nr(attachment)); |
||
2629 | return; |
||
2630 | } |
||
2631 | |||
2632 | if (renderbuffer) { |
||
2633 | rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); |
||
2634 | if (!rb) { |
||
2635 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
2636 | "glFramebufferRenderbufferEXT(non-existant" |
||
2637 | " renderbuffer %u)", renderbuffer); |
||
2638 | return; |
||
2639 | } |
||
2640 | else if (rb == &DummyRenderbuffer) { |
||
2641 | /* This is what NVIDIA does */ |
||
2642 | _mesa_error(ctx, GL_INVALID_VALUE, |
||
2643 | "glFramebufferRenderbufferEXT(renderbuffer %u)", |
||
2644 | renderbuffer); |
||
2645 | return; |
||
2646 | } |
||
2647 | } |
||
2648 | else { |
||
2649 | /* remove renderbuffer attachment */ |
||
2650 | rb = NULL; |
||
2651 | } |
||
2652 | |||
2653 | if (attachment == GL_DEPTH_STENCIL_ATTACHMENT && |
||
2654 | rb && rb->Format != MESA_FORMAT_NONE) { |
||
2655 | /* make sure the renderbuffer is a depth/stencil format */ |
||
2656 | const GLenum baseFormat = _mesa_get_format_base_format(rb->Format); |
||
2657 | if (baseFormat != GL_DEPTH_STENCIL) { |
||
2658 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
2659 | "glFramebufferRenderbufferEXT(renderbuffer" |
||
2660 | " is not DEPTH_STENCIL format)"); |
||
2661 | return; |
||
2662 | } |
||
2663 | } |
||
2664 | |||
2665 | |||
2666 | FLUSH_VERTICES(ctx, _NEW_BUFFERS); |
||
2667 | |||
2668 | assert(ctx->Driver.FramebufferRenderbuffer); |
||
2669 | ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb); |
||
2670 | |||
2671 | /* Some subsequent GL commands may depend on the framebuffer's visual |
||
2672 | * after the binding is updated. Update visual info now. |
||
2673 | */ |
||
2674 | _mesa_update_framebuffer_visual(ctx, fb); |
||
2675 | } |
||
2676 | |||
2677 | |||
2678 | void GLAPIENTRY |
||
2679 | _mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, |
||
2680 | GLenum pname, GLint *params) |
||
2681 | { |
||
2682 | const struct gl_renderbuffer_attachment *att; |
||
2683 | struct gl_framebuffer *buffer; |
||
2684 | GLenum err; |
||
2685 | GET_CURRENT_CONTEXT(ctx); |
||
2686 | |||
2687 | /* The error differs in GL and GLES. */ |
||
2688 | err = _mesa_is_desktop_gl(ctx) ? GL_INVALID_OPERATION : GL_INVALID_ENUM; |
||
2689 | |||
2690 | buffer = get_framebuffer_target(ctx, target); |
||
2691 | if (!buffer) { |
||
2692 | _mesa_error(ctx, GL_INVALID_ENUM, |
||
2693 | "glGetFramebufferAttachmentParameterivEXT(target)"); |
||
2694 | return; |
||
2695 | } |
||
2696 | |||
2697 | if (_mesa_is_winsys_fbo(buffer)) { |
||
2698 | /* Page 126 (page 136 of the PDF) of the OpenGL ES 2.0.25 spec |
||
2699 | * says: |
||
2700 | * |
||
2701 | * "If the framebuffer currently bound to target is zero, then |
||
2702 | * INVALID_OPERATION is generated." |
||
2703 | * |
||
2704 | * The EXT_framebuffer_object spec has the same wording, and the |
||
2705 | * OES_framebuffer_object spec refers to the EXT_framebuffer_object |
||
2706 | * spec. |
||
2707 | */ |
||
2708 | if ((!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_framebuffer_object) |
||
2709 | && !_mesa_is_gles3(ctx)) { |
||
2710 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
2711 | "glGetFramebufferAttachmentParameteriv(bound FBO = 0)"); |
||
2712 | return; |
||
2713 | } |
||
2714 | |||
2715 | if (_mesa_is_gles3(ctx) && attachment != GL_BACK && |
||
2716 | attachment != GL_DEPTH && attachment != GL_STENCIL) { |
||
2717 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
2718 | "glGetFramebufferAttachmentParameteriv(attachment)"); |
||
2719 | return; |
||
2720 | } |
||
2721 | /* the default / window-system FBO */ |
||
2722 | att = _mesa_get_fb0_attachment(ctx, buffer, attachment); |
||
2723 | } |
||
2724 | else { |
||
2725 | /* user-created framebuffer FBO */ |
||
2726 | att = _mesa_get_attachment(ctx, buffer, attachment); |
||
2727 | } |
||
2728 | |||
2729 | if (att == NULL) { |
||
2730 | _mesa_error(ctx, GL_INVALID_ENUM, |
||
2731 | "glGetFramebufferAttachmentParameterivEXT(attachment)"); |
||
2732 | return; |
||
2733 | } |
||
2734 | |||
2735 | if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { |
||
2736 | /* the depth and stencil attachments must point to the same buffer */ |
||
2737 | const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt; |
||
2738 | depthAtt = _mesa_get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT); |
||
2739 | stencilAtt = _mesa_get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT); |
||
2740 | if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) { |
||
2741 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
2742 | "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL" |
||
2743 | " attachments differ)"); |
||
2744 | return; |
||
2745 | } |
||
2746 | } |
||
2747 | |||
2748 | /* No need to flush here */ |
||
2749 | |||
2750 | switch (pname) { |
||
2751 | case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: |
||
2752 | *params = _mesa_is_winsys_fbo(buffer) |
||
2753 | ? GL_FRAMEBUFFER_DEFAULT : att->Type; |
||
2754 | return; |
||
2755 | case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: |
||
2756 | if (att->Type == GL_RENDERBUFFER_EXT) { |
||
2757 | *params = att->Renderbuffer->Name; |
||
2758 | } |
||
2759 | else if (att->Type == GL_TEXTURE) { |
||
2760 | *params = att->Texture->Name; |
||
2761 | } |
||
2762 | else { |
||
2763 | assert(att->Type == GL_NONE); |
||
2764 | if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx)) { |
||
2765 | *params = 0; |
||
2766 | } else { |
||
2767 | goto invalid_pname_enum; |
||
2768 | } |
||
2769 | } |
||
2770 | return; |
||
2771 | case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: |
||
2772 | if (att->Type == GL_TEXTURE) { |
||
2773 | *params = att->TextureLevel; |
||
2774 | } |
||
2775 | else if (att->Type == GL_NONE) { |
||
2776 | _mesa_error(ctx, err, |
||
2777 | "glGetFramebufferAttachmentParameterivEXT(pname)"); |
||
2778 | } |
||
2779 | else { |
||
2780 | goto invalid_pname_enum; |
||
2781 | } |
||
2782 | return; |
||
2783 | case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: |
||
2784 | if (att->Type == GL_TEXTURE) { |
||
2785 | if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) { |
||
2786 | *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace; |
||
2787 | } |
||
2788 | else { |
||
2789 | *params = 0; |
||
2790 | } |
||
2791 | } |
||
2792 | else if (att->Type == GL_NONE) { |
||
2793 | _mesa_error(ctx, err, |
||
2794 | "glGetFramebufferAttachmentParameterivEXT(pname)"); |
||
2795 | } |
||
2796 | else { |
||
2797 | goto invalid_pname_enum; |
||
2798 | } |
||
2799 | return; |
||
2800 | case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: |
||
2801 | if (ctx->API == API_OPENGLES) { |
||
2802 | goto invalid_pname_enum; |
||
2803 | } else if (att->Type == GL_NONE) { |
||
2804 | _mesa_error(ctx, err, |
||
2805 | "glGetFramebufferAttachmentParameterivEXT(pname)"); |
||
2806 | } else if (att->Type == GL_TEXTURE) { |
||
2807 | if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) { |
||
2808 | *params = att->Zoffset; |
||
2809 | } |
||
2810 | else { |
||
2811 | *params = 0; |
||
2812 | } |
||
2813 | } |
||
2814 | else { |
||
2815 | goto invalid_pname_enum; |
||
2816 | } |
||
2817 | return; |
||
2818 | case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: |
||
2819 | if ((!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_framebuffer_object) |
||
2820 | && !_mesa_is_gles3(ctx)) { |
||
2821 | goto invalid_pname_enum; |
||
2822 | } |
||
2823 | else if (att->Type == GL_NONE) { |
||
2824 | _mesa_error(ctx, err, |
||
2825 | "glGetFramebufferAttachmentParameterivEXT(pname)"); |
||
2826 | } |
||
2827 | else { |
||
2828 | if (ctx->Extensions.EXT_framebuffer_sRGB) { |
||
2829 | *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format); |
||
2830 | } |
||
2831 | else { |
||
2832 | /* According to ARB_framebuffer_sRGB, we should return LINEAR |
||
2833 | * if the sRGB conversion is unsupported. */ |
||
2834 | *params = GL_LINEAR; |
||
2835 | } |
||
2836 | } |
||
2837 | return; |
||
2838 | case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: |
||
2839 | if ((ctx->API != API_OPENGL_COMPAT || !ctx->Extensions.ARB_framebuffer_object) |
||
2840 | && ctx->API != API_OPENGL_CORE |
||
2841 | && !_mesa_is_gles3(ctx)) { |
||
2842 | goto invalid_pname_enum; |
||
2843 | } |
||
2844 | else if (att->Type == GL_NONE) { |
||
2845 | _mesa_error(ctx, err, |
||
2846 | "glGetFramebufferAttachmentParameterivEXT(pname)"); |
||
2847 | } |
||
2848 | else { |
||
2849 | gl_format format = att->Renderbuffer->Format; |
||
2850 | |||
2851 | /* Page 235 (page 247 of the PDF) in section 6.1.13 of the OpenGL ES |
||
2852 | * 3.0.1 spec says: |
||
2853 | * |
||
2854 | * "If pname is FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE.... If |
||
2855 | * attachment is DEPTH_STENCIL_ATTACHMENT the query will fail and |
||
2856 | * generate an INVALID_OPERATION error. |
||
2857 | */ |
||
2858 | if (_mesa_is_gles3(ctx) && attachment == GL_DEPTH_STENCIL_ATTACHMENT) { |
||
2859 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
2860 | "glGetFramebufferAttachmentParameteriv(cannot query " |
||
2861 | "GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE of " |
||
2862 | "GL_DEPTH_STENCIL_ATTACHMENT"); |
||
2863 | return; |
||
2864 | } |
||
2865 | |||
2866 | if (format == MESA_FORMAT_S8) { |
||
2867 | /* special cases */ |
||
2868 | *params = GL_INDEX; |
||
2869 | } |
||
2870 | else if (format == MESA_FORMAT_Z32_FLOAT_X24S8) { |
||
2871 | /* depends on the attachment parameter */ |
||
2872 | if (attachment == GL_STENCIL_ATTACHMENT) { |
||
2873 | *params = GL_INDEX; |
||
2874 | } |
||
2875 | else { |
||
2876 | *params = GL_FLOAT; |
||
2877 | } |
||
2878 | } |
||
2879 | else { |
||
2880 | *params = _mesa_get_format_datatype(format); |
||
2881 | } |
||
2882 | } |
||
2883 | return; |
||
2884 | case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: |
||
2885 | case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: |
||
2886 | case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: |
||
2887 | case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: |
||
2888 | case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: |
||
2889 | case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: |
||
2890 | if ((!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_framebuffer_object) |
||
2891 | && !_mesa_is_gles3(ctx)) { |
||
2892 | goto invalid_pname_enum; |
||
2893 | } |
||
2894 | else if (att->Type == GL_NONE) { |
||
2895 | _mesa_error(ctx, err, |
||
2896 | "glGetFramebufferAttachmentParameterivEXT(pname)"); |
||
2897 | } |
||
2898 | else if (att->Texture) { |
||
2899 | const struct gl_texture_image *texImage = |
||
2900 | _mesa_select_tex_image(ctx, att->Texture, att->Texture->Target, |
||
2901 | att->TextureLevel); |
||
2902 | if (texImage) { |
||
2903 | *params = get_component_bits(pname, texImage->_BaseFormat, |
||
2904 | texImage->TexFormat); |
||
2905 | } |
||
2906 | else { |
||
2907 | *params = 0; |
||
2908 | } |
||
2909 | } |
||
2910 | else if (att->Renderbuffer) { |
||
2911 | *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat, |
||
2912 | att->Renderbuffer->Format); |
||
2913 | } |
||
2914 | else { |
||
2915 | _mesa_problem(ctx, "glGetFramebufferAttachmentParameterivEXT:" |
||
2916 | " invalid FBO attachment structure"); |
||
2917 | } |
||
2918 | return; |
||
2919 | default: |
||
2920 | goto invalid_pname_enum; |
||
2921 | } |
||
2922 | |||
2923 | return; |
||
2924 | |||
2925 | invalid_pname_enum: |
||
2926 | _mesa_error(ctx, GL_INVALID_ENUM, |
||
2927 | "glGetFramebufferAttachmentParameteriv(pname)"); |
||
2928 | return; |
||
2929 | } |
||
2930 | |||
2931 | |||
2932 | void GLAPIENTRY |
||
2933 | _mesa_GenerateMipmap(GLenum target) |
||
2934 | { |
||
2935 | struct gl_texture_image *srcImage; |
||
2936 | struct gl_texture_object *texObj; |
||
2937 | GLboolean error; |
||
2938 | |||
2939 | GET_CURRENT_CONTEXT(ctx); |
||
2940 | |||
2941 | FLUSH_VERTICES(ctx, 0); |
||
2942 | |||
2943 | switch (target) { |
||
2944 | case GL_TEXTURE_1D: |
||
2945 | error = _mesa_is_gles(ctx); |
||
2946 | break; |
||
2947 | case GL_TEXTURE_2D: |
||
2948 | error = GL_FALSE; |
||
2949 | break; |
||
2950 | case GL_TEXTURE_3D: |
||
2951 | error = ctx->API == API_OPENGLES; |
||
2952 | break; |
||
2953 | case GL_TEXTURE_CUBE_MAP: |
||
2954 | error = !ctx->Extensions.ARB_texture_cube_map; |
||
2955 | break; |
||
2956 | case GL_TEXTURE_1D_ARRAY: |
||
2957 | error = _mesa_is_gles(ctx) || !ctx->Extensions.EXT_texture_array; |
||
2958 | break; |
||
2959 | case GL_TEXTURE_2D_ARRAY: |
||
2960 | error = (_mesa_is_gles(ctx) && ctx->Version < 30) |
||
2961 | || !ctx->Extensions.EXT_texture_array; |
||
2962 | break; |
||
2963 | default: |
||
2964 | error = GL_TRUE; |
||
2965 | } |
||
2966 | |||
2967 | if (error) { |
||
2968 | _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target=%s)", |
||
2969 | _mesa_lookup_enum_by_nr(target)); |
||
2970 | return; |
||
2971 | } |
||
2972 | |||
2973 | texObj = _mesa_get_current_tex_object(ctx, target); |
||
2974 | |||
2975 | if (texObj->BaseLevel >= texObj->MaxLevel) { |
||
2976 | /* nothing to do */ |
||
2977 | return; |
||
2978 | } |
||
2979 | |||
2980 | if (texObj->Target == GL_TEXTURE_CUBE_MAP && |
||
2981 | !_mesa_cube_complete(texObj)) { |
||
2982 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
2983 | "glGenerateMipmap(incomplete cube map)"); |
||
2984 | return; |
||
2985 | } |
||
2986 | |||
2987 | _mesa_lock_texture(ctx, texObj); |
||
2988 | |||
2989 | srcImage = _mesa_select_tex_image(ctx, texObj, target, texObj->BaseLevel); |
||
2990 | if (!srcImage) { |
||
2991 | _mesa_unlock_texture(ctx, texObj); |
||
2992 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
2993 | "glGenerateMipmap(zero size base image)"); |
||
2994 | return; |
||
2995 | } |
||
2996 | |||
2997 | if (_mesa_is_enum_format_integer(srcImage->InternalFormat) || |
||
2998 | _mesa_is_depthstencil_format(srcImage->InternalFormat) || |
||
2999 | _mesa_is_stencil_format(srcImage->InternalFormat)) { |
||
3000 | _mesa_unlock_texture(ctx, texObj); |
||
3001 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
3002 | "glGenerateMipmap(invalid internal format)"); |
||
3003 | return; |
||
3004 | } |
||
3005 | |||
3006 | if (target == GL_TEXTURE_CUBE_MAP) { |
||
3007 | GLuint face; |
||
3008 | for (face = 0; face < 6; face++) |
||
3009 | ctx->Driver.GenerateMipmap(ctx, |
||
3010 | GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face, |
||
3011 | texObj); |
||
3012 | } |
||
3013 | else { |
||
3014 | ctx->Driver.GenerateMipmap(ctx, target, texObj); |
||
3015 | } |
||
3016 | _mesa_unlock_texture(ctx, texObj); |
||
3017 | } |
||
3018 | |||
3019 | |||
3020 | static const struct gl_renderbuffer_attachment * |
||
3021 | find_attachment(const struct gl_framebuffer *fb, |
||
3022 | const struct gl_renderbuffer *rb) |
||
3023 | { |
||
3024 | GLuint i; |
||
3025 | for (i = 0; i < Elements(fb->Attachment); i++) { |
||
3026 | if (fb->Attachment[i].Renderbuffer == rb) |
||
3027 | return &fb->Attachment[i]; |
||
3028 | } |
||
3029 | return NULL; |
||
3030 | } |
||
3031 | |||
3032 | |||
3033 | /** |
||
3034 | * Helper function for checking if the datatypes of color buffers are |
||
3035 | * compatible for glBlitFramebuffer. From the 3.1 spec, page 198: |
||
3036 | * |
||
3037 | * "GL_INVALID_OPERATION is generated if mask contains GL_COLOR_BUFFER_BIT |
||
3038 | * and any of the following conditions hold: |
||
3039 | * - The read buffer contains fixed-point or floating-point values and any |
||
3040 | * draw buffer contains neither fixed-point nor floating-point values. |
||
3041 | * - The read buffer contains unsigned integer values and any draw buffer |
||
3042 | * does not contain unsigned integer values. |
||
3043 | * - The read buffer contains signed integer values and any draw buffer |
||
3044 | * does not contain signed integer values." |
||
3045 | */ |
||
3046 | static GLboolean |
||
3047 | compatible_color_datatypes(gl_format srcFormat, gl_format dstFormat) |
||
3048 | { |
||
3049 | GLenum srcType = _mesa_get_format_datatype(srcFormat); |
||
3050 | GLenum dstType = _mesa_get_format_datatype(dstFormat); |
||
3051 | |||
3052 | if (srcType != GL_INT && srcType != GL_UNSIGNED_INT) { |
||
3053 | assert(srcType == GL_UNSIGNED_NORMALIZED || |
||
3054 | srcType == GL_SIGNED_NORMALIZED || |
||
3055 | srcType == GL_FLOAT); |
||
3056 | /* Boil any of those types down to GL_FLOAT */ |
||
3057 | srcType = GL_FLOAT; |
||
3058 | } |
||
3059 | |||
3060 | if (dstType != GL_INT && dstType != GL_UNSIGNED_INT) { |
||
3061 | assert(dstType == GL_UNSIGNED_NORMALIZED || |
||
3062 | dstType == GL_SIGNED_NORMALIZED || |
||
3063 | dstType == GL_FLOAT); |
||
3064 | /* Boil any of those types down to GL_FLOAT */ |
||
3065 | dstType = GL_FLOAT; |
||
3066 | } |
||
3067 | |||
3068 | return srcType == dstType; |
||
3069 | } |
||
3070 | |||
3071 | |||
3072 | static GLboolean |
||
3073 | compatible_resolve_formats(const struct gl_renderbuffer *readRb, |
||
3074 | const struct gl_renderbuffer *drawRb) |
||
3075 | { |
||
3076 | GLenum readFormat, drawFormat; |
||
3077 | |||
3078 | /* The simple case where we know the backing Mesa formats are the same. |
||
3079 | */ |
||
3080 | if (_mesa_get_srgb_format_linear(readRb->Format) == |
||
3081 | _mesa_get_srgb_format_linear(drawRb->Format)) { |
||
3082 | return GL_TRUE; |
||
3083 | } |
||
3084 | |||
3085 | /* The Mesa formats are different, so we must check whether the internal |
||
3086 | * formats are compatible. |
||
3087 | * |
||
3088 | * Under some circumstances, the user may request e.g. two GL_RGBA8 |
||
3089 | * textures and get two entirely different Mesa formats like RGBA8888 and |
||
3090 | * ARGB8888. Drivers behaving like that should be able to cope with |
||
3091 | * non-matching formats by themselves, because it's not the user's fault. |
||
3092 | * |
||
3093 | * Blits between linear and sRGB formats are also allowed. |
||
3094 | */ |
||
3095 | readFormat = _mesa_get_nongeneric_internalformat(readRb->InternalFormat); |
||
3096 | drawFormat = _mesa_get_nongeneric_internalformat(drawRb->InternalFormat); |
||
3097 | readFormat = _mesa_get_linear_internalformat(readFormat); |
||
3098 | drawFormat = _mesa_get_linear_internalformat(drawFormat); |
||
3099 | |||
3100 | if (readFormat == drawFormat) { |
||
3101 | return GL_TRUE; |
||
3102 | } |
||
3103 | |||
3104 | return GL_FALSE; |
||
3105 | } |
||
3106 | |||
3107 | static GLboolean |
||
3108 | is_valid_blit_filter(const struct gl_context *ctx, GLenum filter) |
||
3109 | { |
||
3110 | switch (filter) { |
||
3111 | case GL_NEAREST: |
||
3112 | case GL_LINEAR: |
||
3113 | return true; |
||
3114 | case GL_SCALED_RESOLVE_FASTEST_EXT: |
||
3115 | case GL_SCALED_RESOLVE_NICEST_EXT: |
||
3116 | return ctx->Extensions.EXT_framebuffer_multisample_blit_scaled; |
||
3117 | default: |
||
3118 | return false; |
||
3119 | } |
||
3120 | } |
||
3121 | |||
3122 | /** |
||
3123 | * Blit rectangular region, optionally from one framebuffer to another. |
||
3124 | * |
||
3125 | * Note, if the src buffer is multisampled and the dest is not, this is |
||
3126 | * when the samples must be resolved to a single color. |
||
3127 | */ |
||
3128 | void GLAPIENTRY |
||
3129 | _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, |
||
3130 | GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, |
||
3131 | GLbitfield mask, GLenum filter) |
||
3132 | { |
||
3133 | const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT | |
||
3134 | GL_DEPTH_BUFFER_BIT | |
||
3135 | GL_STENCIL_BUFFER_BIT); |
||
3136 | const struct gl_framebuffer *readFb, *drawFb; |
||
3137 | GET_CURRENT_CONTEXT(ctx); |
||
3138 | |||
3139 | FLUSH_VERTICES(ctx, 0); |
||
3140 | |||
3141 | if (MESA_VERBOSE & VERBOSE_API) |
||
3142 | _mesa_debug(ctx, |
||
3143 | "glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d, 0x%x, %s)\n", |
||
3144 | srcX0, srcY0, srcX1, srcY1, |
||
3145 | dstX0, dstY0, dstX1, dstY1, |
||
3146 | mask, _mesa_lookup_enum_by_nr(filter)); |
||
3147 | |||
3148 | if (ctx->NewState) { |
||
3149 | _mesa_update_state(ctx); |
||
3150 | } |
||
3151 | |||
3152 | readFb = ctx->ReadBuffer; |
||
3153 | drawFb = ctx->DrawBuffer; |
||
3154 | |||
3155 | if (!readFb || !drawFb) { |
||
3156 | /* This will normally never happen but someday we may want to |
||
3157 | * support MakeCurrent() with no drawables. |
||
3158 | */ |
||
3159 | return; |
||
3160 | } |
||
3161 | |||
3162 | /* check for complete framebuffers */ |
||
3163 | if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT || |
||
3164 | readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { |
||
3165 | _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, |
||
3166 | "glBlitFramebufferEXT(incomplete draw/read buffers)"); |
||
3167 | return; |
||
3168 | } |
||
3169 | |||
3170 | if (!is_valid_blit_filter(ctx, filter)) { |
||
3171 | _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(%s)", |
||
3172 | _mesa_lookup_enum_by_nr(filter)); |
||
3173 | return; |
||
3174 | } |
||
3175 | |||
3176 | if ((filter == GL_SCALED_RESOLVE_FASTEST_EXT || |
||
3177 | filter == GL_SCALED_RESOLVE_NICEST_EXT) && |
||
3178 | (readFb->Visual.samples == 0 || drawFb->Visual.samples > 0)) { |
||
3179 | _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT(%s)", |
||
3180 | _mesa_lookup_enum_by_nr(filter)); |
||
3181 | return; |
||
3182 | } |
||
3183 | |||
3184 | if (mask & ~legalMaskBits) { |
||
3185 | _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)"); |
||
3186 | return; |
||
3187 | } |
||
3188 | |||
3189 | /* depth/stencil must be blitted with nearest filtering */ |
||
3190 | if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) |
||
3191 | && filter != GL_NEAREST) { |
||
3192 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
3193 | "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter)"); |
||
3194 | return; |
||
3195 | } |
||
3196 | |||
3197 | /* get color read/draw renderbuffers */ |
||
3198 | if (mask & GL_COLOR_BUFFER_BIT) { |
||
3199 | const GLuint numColorDrawBuffers = ctx->DrawBuffer->_NumColorDrawBuffers; |
||
3200 | const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer; |
||
3201 | const struct gl_renderbuffer *colorDrawRb = NULL; |
||
3202 | GLuint i; |
||
3203 | |||
3204 | /* From the EXT_framebuffer_object spec: |
||
3205 | * |
||
3206 | * "If a buffer is specified in |
||
3207 | * the read and draw framebuffers, the corresponding bit is silently |
||
3208 | * ignored." |
||
3209 | */ |
||
3210 | if (!colorReadRb || numColorDrawBuffers == 0) { |
||
3211 | mask &= ~GL_COLOR_BUFFER_BIT; |
||
3212 | } |
||
3213 | else { |
||
3214 | for (i = 0; i < numColorDrawBuffers; i++) { |
||
3215 | colorDrawRb = ctx->DrawBuffer->_ColorDrawBuffers[i]; |
||
3216 | if (!colorDrawRb) |
||
3217 | continue; |
||
3218 | |||
3219 | /* Page 193 (page 205 of the PDF) in section 4.3.2 of the OpenGL |
||
3220 | * ES 3.0.1 spec says: |
||
3221 | * |
||
3222 | * "If the source and destination buffers are identical, an |
||
3223 | * INVALID_OPERATION error is generated. Different mipmap |
||
3224 | * levels of a texture, different layers of a three- |
||
3225 | * dimensional texture or two-dimensional array texture, and |
||
3226 | * different faces of a cube map texture do not constitute |
||
3227 | * identical buffers." |
||
3228 | */ |
||
3229 | if (_mesa_is_gles3(ctx) && (colorDrawRb == colorReadRb)) { |
||
3230 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
3231 | "glBlitFramebuffer(source and destination color " |
||
3232 | "buffer cannot be the same)"); |
||
3233 | return; |
||
3234 | } |
||
3235 | |||
3236 | if (!compatible_color_datatypes(colorReadRb->Format, |
||
3237 | colorDrawRb->Format)) { |
||
3238 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
3239 | "glBlitFramebufferEXT(color buffer datatypes mismatch)"); |
||
3240 | return; |
||
3241 | } |
||
3242 | /* extra checks for multisample copies... */ |
||
3243 | if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) { |
||
3244 | /* color formats must match */ |
||
3245 | if (!compatible_resolve_formats(colorReadRb, colorDrawRb)) { |
||
3246 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
3247 | "glBlitFramebufferEXT(bad src/dst multisample pixel formats)"); |
||
3248 | return; |
||
3249 | } |
||
3250 | } |
||
3251 | } |
||
3252 | if (filter != GL_NEAREST) { |
||
3253 | /* From EXT_framebuffer_multisample_blit_scaled specification: |
||
3254 | * "Calling BlitFramebuffer will result in an INVALID_OPERATION error |
||
3255 | * if filter is not NEAREST and read buffer contains integer data." |
||
3256 | */ |
||
3257 | GLenum type = _mesa_get_format_datatype(colorReadRb->Format); |
||
3258 | if (type == GL_INT || type == GL_UNSIGNED_INT) { |
||
3259 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
3260 | "glBlitFramebufferEXT(integer color type)"); |
||
3261 | return; |
||
3262 | } |
||
3263 | } |
||
3264 | } |
||
3265 | } |
||
3266 | |||
3267 | if (mask & GL_STENCIL_BUFFER_BIT) { |
||
3268 | struct gl_renderbuffer *readRb = |
||
3269 | readFb->Attachment[BUFFER_STENCIL].Renderbuffer; |
||
3270 | struct gl_renderbuffer *drawRb = |
||
3271 | drawFb->Attachment[BUFFER_STENCIL].Renderbuffer; |
||
3272 | |||
3273 | /* From the EXT_framebuffer_object spec: |
||
3274 | * |
||
3275 | * "If a buffer is specified in |
||
3276 | * the read and draw framebuffers, the corresponding bit is silently |
||
3277 | * ignored." |
||
3278 | */ |
||
3279 | if ((readRb == NULL) || (drawRb == NULL)) { |
||
3280 | mask &= ~GL_STENCIL_BUFFER_BIT; |
||
3281 | } |
||
3282 | else { |
||
3283 | int read_z_bits, draw_z_bits; |
||
3284 | |||
3285 | if (_mesa_is_gles3(ctx) && (drawRb == readRb)) { |
||
3286 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
3287 | "glBlitFramebuffer(source and destination stencil " |
||
3288 | "buffer cannot be the same)"); |
||
3289 | return; |
||
3290 | } |
||
3291 | |||
3292 | if (_mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) != |
||
3293 | _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) { |
||
3294 | /* There is no need to check the stencil datatype here, because |
||
3295 | * there is only one: GL_UNSIGNED_INT. |
||
3296 | */ |
||
3297 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
3298 | "glBlitFramebuffer(stencil attachment format mismatch)"); |
||
3299 | return; |
||
3300 | } |
||
3301 | |||
3302 | read_z_bits = _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS); |
||
3303 | draw_z_bits = _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS); |
||
3304 | |||
3305 | /* If both buffers also have depth data, the depth formats must match |
||
3306 | * as well. If one doesn't have depth, it's not blitted, so we should |
||
3307 | * ignore the depth format check. |
||
3308 | */ |
||
3309 | if (read_z_bits > 0 && draw_z_bits > 0 && |
||
3310 | (read_z_bits != draw_z_bits || |
||
3311 | _mesa_get_format_datatype(readRb->Format) != |
||
3312 | _mesa_get_format_datatype(drawRb->Format))) { |
||
3313 | |||
3314 | _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebuffer" |
||
3315 | "(stencil attachment depth format mismatch)"); |
||
3316 | return; |
||
3317 | } |
||
3318 | } |
||
3319 | } |
||
3320 | |||
3321 | if (mask & GL_DEPTH_BUFFER_BIT) { |
||
3322 | struct gl_renderbuffer *readRb = |
||
3323 | readFb->Attachment[BUFFER_DEPTH].Renderbuffer; |
||
3324 | struct gl_renderbuffer *drawRb = |
||
3325 | drawFb->Attachment[BUFFER_DEPTH].Renderbuffer; |
||
3326 | |||
3327 | /* From the EXT_framebuffer_object spec: |
||
3328 | * |
||
3329 | * "If a buffer is specified in |
||
3330 | * the read and draw framebuffers, the corresponding bit is silently |
||
3331 | * ignored." |
||
3332 | */ |
||
3333 | if ((readRb == NULL) || (drawRb == NULL)) { |
||
3334 | mask &= ~GL_DEPTH_BUFFER_BIT; |
||
3335 | } |
||
3336 | else { |
||
3337 | int read_s_bit, draw_s_bit; |
||
3338 | |||
3339 | if (_mesa_is_gles3(ctx) && (drawRb == readRb)) { |
||
3340 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
3341 | "glBlitFramebuffer(source and destination depth " |
||
3342 | "buffer cannot be the same)"); |
||
3343 | return; |
||
3344 | } |
||
3345 | |||
3346 | if ((_mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) != |
||
3347 | _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) || |
||
3348 | (_mesa_get_format_datatype(readRb->Format) != |
||
3349 | _mesa_get_format_datatype(drawRb->Format))) { |
||
3350 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
3351 | "glBlitFramebuffer(depth attachment format mismatch)"); |
||
3352 | return; |
||
3353 | } |
||
3354 | |||
3355 | read_s_bit = _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS); |
||
3356 | draw_s_bit = _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS); |
||
3357 | |||
3358 | /* If both buffers also have stencil data, the stencil formats must |
||
3359 | * match as well. If one doesn't have stencil, it's not blitted, so |
||
3360 | * we should ignore the stencil format check. |
||
3361 | */ |
||
3362 | if (read_s_bit > 0 && draw_s_bit > 0 && read_s_bit != draw_s_bit) { |
||
3363 | _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebuffer" |
||
3364 | "(depth attachment stencil bits mismatch)"); |
||
3365 | return; |
||
3366 | } |
||
3367 | } |
||
3368 | } |
||
3369 | |||
3370 | |||
3371 | if (_mesa_is_gles3(ctx)) { |
||
3372 | /* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES |
||
3373 | * 3.0.1 spec says: |
||
3374 | * |
||
3375 | * "If SAMPLE_BUFFERS for the draw framebuffer is greater than zero, |
||
3376 | * an INVALID_OPERATION error is generated." |
||
3377 | */ |
||
3378 | if (drawFb->Visual.samples > 0) { |
||
3379 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
3380 | "glBlitFramebuffer(destination samples must be 0)"); |
||
3381 | return; |
||
3382 | } |
||
3383 | |||
3384 | /* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES |
||
3385 | * 3.0.1 spec says: |
||
3386 | * |
||
3387 | * "If SAMPLE_BUFFERS for the read framebuffer is greater than zero, |
||
3388 | * no copy is performed and an INVALID_OPERATION error is generated |
||
3389 | * if the formats of the read and draw framebuffers are not |
||
3390 | * identical or if the source and destination rectangles are not |
||
3391 | * defined with the same (X0, Y0) and (X1, Y1) bounds." |
||
3392 | * |
||
3393 | * The format check was made above because desktop OpenGL has the same |
||
3394 | * requirement. |
||
3395 | */ |
||
3396 | if (readFb->Visual.samples > 0 |
||
3397 | && (srcX0 != dstX0 || srcY0 != dstY0 |
||
3398 | || srcX1 != dstX1 || srcY1 != dstY1)) { |
||
3399 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
3400 | "glBlitFramebuffer(bad src/dst multisample region)"); |
||
3401 | return; |
||
3402 | } |
||
3403 | } else { |
||
3404 | if (readFb->Visual.samples > 0 && |
||
3405 | drawFb->Visual.samples > 0 && |
||
3406 | readFb->Visual.samples != drawFb->Visual.samples) { |
||
3407 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
3408 | "glBlitFramebufferEXT(mismatched samples)"); |
||
3409 | return; |
||
3410 | } |
||
3411 | |||
3412 | /* extra checks for multisample copies... */ |
||
3413 | if ((readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) && |
||
3414 | (filter == GL_NEAREST || filter == GL_LINEAR)) { |
||
3415 | /* src and dest region sizes must be the same */ |
||
3416 | if (abs(srcX1 - srcX0) != abs(dstX1 - dstX0) || |
||
3417 | abs(srcY1 - srcY0) != abs(dstY1 - dstY0)) { |
||
3418 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
3419 | "glBlitFramebufferEXT(bad src/dst multisample region sizes)"); |
||
3420 | return; |
||
3421 | } |
||
3422 | } |
||
3423 | } |
||
3424 | |||
3425 | if (!ctx->Extensions.EXT_framebuffer_blit) { |
||
3426 | _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT"); |
||
3427 | return; |
||
3428 | } |
||
3429 | |||
3430 | /* Debug code */ |
||
3431 | if (DEBUG_BLIT) { |
||
3432 | const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer; |
||
3433 | const struct gl_renderbuffer *colorDrawRb = NULL; |
||
3434 | GLuint i = 0; |
||
3435 | |||
3436 | printf("glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d," |
||
3437 | " 0x%x, 0x%x)\n", |
||
3438 | srcX0, srcY0, srcX1, srcY1, |
||
3439 | dstX0, dstY0, dstX1, dstY1, |
||
3440 | mask, filter); |
||
3441 | if (colorReadRb) { |
||
3442 | const struct gl_renderbuffer_attachment *att; |
||
3443 | |||
3444 | att = find_attachment(readFb, colorReadRb); |
||
3445 | printf(" Src FBO %u RB %u (%dx%d) ", |
||
3446 | readFb->Name, colorReadRb->Name, |
||
3447 | colorReadRb->Width, colorReadRb->Height); |
||
3448 | if (att && att->Texture) { |
||
3449 | printf("Tex %u tgt 0x%x level %u face %u", |
||
3450 | att->Texture->Name, |
||
3451 | att->Texture->Target, |
||
3452 | att->TextureLevel, |
||
3453 | att->CubeMapFace); |
||
3454 | } |
||
3455 | printf("\n"); |
||
3456 | |||
3457 | /* Print all active color render buffers */ |
||
3458 | for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) { |
||
3459 | colorDrawRb = ctx->DrawBuffer->_ColorDrawBuffers[i]; |
||
3460 | if (!colorDrawRb) |
||
3461 | continue; |
||
3462 | |||
3463 | att = find_attachment(drawFb, colorDrawRb); |
||
3464 | printf(" Dst FBO %u RB %u (%dx%d) ", |
||
3465 | drawFb->Name, colorDrawRb->Name, |
||
3466 | colorDrawRb->Width, colorDrawRb->Height); |
||
3467 | if (att && att->Texture) { |
||
3468 | printf("Tex %u tgt 0x%x level %u face %u", |
||
3469 | att->Texture->Name, |
||
3470 | att->Texture->Target, |
||
3471 | att->TextureLevel, |
||
3472 | att->CubeMapFace); |
||
3473 | } |
||
3474 | printf("\n"); |
||
3475 | } |
||
3476 | } |
||
3477 | } |
||
3478 | |||
3479 | if (!mask || |
||
3480 | (srcX1 - srcX0) == 0 || (srcY1 - srcY0) == 0 || |
||
3481 | (dstX1 - dstX0) == 0 || (dstY1 - dstY0) == 0) { |
||
3482 | return; |
||
3483 | } |
||
3484 | |||
3485 | ASSERT(ctx->Driver.BlitFramebuffer); |
||
3486 | ctx->Driver.BlitFramebuffer(ctx, |
||
3487 | srcX0, srcY0, srcX1, srcY1, |
||
3488 | dstX0, dstY0, dstX1, dstY1, |
||
3489 | mask, filter); |
||
3490 | } |
||
3491 | |||
3492 | |||
3493 | static void |
||
3494 | invalidate_framebuffer_storage(GLenum target, GLsizei numAttachments, |
||
3495 | const GLenum *attachments, GLint x, GLint y, |
||
3496 | GLsizei width, GLsizei height, const char *name) |
||
3497 | { |
||
3498 | int i; |
||
3499 | struct gl_framebuffer *fb; |
||
3500 | GET_CURRENT_CONTEXT(ctx); |
||
3501 | |||
3502 | fb = get_framebuffer_target(ctx, target); |
||
3503 | if (!fb) { |
||
3504 | _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", name); |
||
3505 | return; |
||
3506 | } |
||
3507 | |||
3508 | if (numAttachments < 0) { |
||
3509 | _mesa_error(ctx, GL_INVALID_VALUE, |
||
3510 | "%s(numAttachments < 0)", name); |
||
3511 | return; |
||
3512 | } |
||
3513 | |||
3514 | /* The GL_ARB_invalidate_subdata spec says: |
||
3515 | * |
||
3516 | * "If an attachment is specified that does not exist in the |
||
3517 | * framebuffer bound to |
||
3518 | * |
||
3519 | * It also says: |
||
3520 | * |
||
3521 | * "If |
||
3522 | * or equal to the value of MAX_COLOR_ATTACHMENTS, then the error |
||
3523 | * INVALID_OPERATION is generated." |
||
3524 | * |
||
3525 | * No mention is made of GL_AUXi being out of range. Therefore, we allow |
||
3526 | * any enum that can be allowed by the API (OpenGL ES 3.0 has a different |
||
3527 | * set of retrictions). |
||
3528 | */ |
||
3529 | for (i = 0; i < numAttachments; i++) { |
||
3530 | if (_mesa_is_winsys_fbo(fb)) { |
||
3531 | switch (attachments[i]) { |
||
3532 | case GL_ACCUM: |
||
3533 | case GL_AUX0: |
||
3534 | case GL_AUX1: |
||
3535 | case GL_AUX2: |
||
3536 | case GL_AUX3: |
||
3537 | /* Accumulation buffers and auxilary buffers were removed in |
||
3538 | * OpenGL 3.1, and they never existed in OpenGL ES. |
||
3539 | */ |
||
3540 | if (ctx->API != API_OPENGL_COMPAT) |
||
3541 | goto invalid_enum; |
||
3542 | break; |
||
3543 | case GL_COLOR: |
||
3544 | case GL_DEPTH: |
||
3545 | case GL_STENCIL: |
||
3546 | break; |
||
3547 | case GL_BACK_LEFT: |
||
3548 | case GL_BACK_RIGHT: |
||
3549 | case GL_FRONT_LEFT: |
||
3550 | case GL_FRONT_RIGHT: |
||
3551 | if (!_mesa_is_desktop_gl(ctx)) |
||
3552 | goto invalid_enum; |
||
3553 | break; |
||
3554 | default: |
||
3555 | goto invalid_enum; |
||
3556 | } |
||
3557 | } else { |
||
3558 | switch (attachments[i]) { |
||
3559 | case GL_DEPTH_ATTACHMENT: |
||
3560 | case GL_STENCIL_ATTACHMENT: |
||
3561 | break; |
||
3562 | case GL_COLOR_ATTACHMENT0: |
||
3563 | case GL_COLOR_ATTACHMENT1: |
||
3564 | case GL_COLOR_ATTACHMENT2: |
||
3565 | case GL_COLOR_ATTACHMENT3: |
||
3566 | case GL_COLOR_ATTACHMENT4: |
||
3567 | case GL_COLOR_ATTACHMENT5: |
||
3568 | case GL_COLOR_ATTACHMENT6: |
||
3569 | case GL_COLOR_ATTACHMENT7: |
||
3570 | case GL_COLOR_ATTACHMENT8: |
||
3571 | case GL_COLOR_ATTACHMENT9: |
||
3572 | case GL_COLOR_ATTACHMENT10: |
||
3573 | case GL_COLOR_ATTACHMENT11: |
||
3574 | case GL_COLOR_ATTACHMENT12: |
||
3575 | case GL_COLOR_ATTACHMENT13: |
||
3576 | case GL_COLOR_ATTACHMENT14: |
||
3577 | case GL_COLOR_ATTACHMENT15: { |
||
3578 | unsigned k = attachments[i] - GL_COLOR_ATTACHMENT0; |
||
3579 | if (k >= ctx->Const.MaxColorAttachments) { |
||
3580 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
3581 | "%s(attachment >= max. color attachments)", name); |
||
3582 | return; |
||
3583 | } |
||
3584 | break; |
||
3585 | } |
||
3586 | default: |
||
3587 | goto invalid_enum; |
||
3588 | } |
||
3589 | } |
||
3590 | } |
||
3591 | |||
3592 | /* We don't actually do anything for this yet. Just return after |
||
3593 | * validating the parameters and generating the required errors. |
||
3594 | */ |
||
3595 | return; |
||
3596 | |||
3597 | invalid_enum: |
||
3598 | _mesa_error(ctx, GL_INVALID_ENUM, "%s(attachment)", name); |
||
3599 | return; |
||
3600 | } |
||
3601 | |||
3602 | void GLAPIENTRY |
||
3603 | _mesa_InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, |
||
3604 | const GLenum *attachments, GLint x, GLint y, |
||
3605 | GLsizei width, GLsizei height) |
||
3606 | { |
||
3607 | invalidate_framebuffer_storage(target, numAttachments, attachments, |
||
3608 | x, y, width, height, |
||
3609 | "glInvalidateSubFramebuffer"); |
||
3610 | } |
||
3611 | |||
3612 | void GLAPIENTRY |
||
3613 | _mesa_InvalidateFramebuffer(GLenum target, GLsizei numAttachments, |
||
3614 | const GLenum *attachments) |
||
3615 | { |
||
3616 | /* The GL_ARB_invalidate_subdata spec says: |
||
3617 | * |
||
3618 | * "The command |
||
3619 | * |
||
3620 | * void InvalidateFramebuffer(enum target, |
||
3621 | * sizei numAttachments, |
||
3622 | * const enum *attachments); |
||
3623 | * |
||
3624 | * is equivalent to the command InvalidateSubFramebuffer with |
||
3625 | * |
||
3626 | * |
||
3627 | */ |
||
3628 | invalidate_framebuffer_storage(target, numAttachments, attachments, |
||
3629 | 0, 0, MAX_VIEWPORT_WIDTH, MAX_VIEWPORT_HEIGHT, |
||
3630 | "glInvalidateFramebuffer"); |
||
3631 | } |
||
3632 | |||
3633 | void GLAPIENTRY |
||
3634 | _mesa_DiscardFramebufferEXT(GLenum target, GLsizei numAttachments, |
||
3635 | const GLenum *attachments) |
||
3636 | { |
||
3637 | struct gl_framebuffer *fb; |
||
3638 | GLint i; |
||
3639 | |||
3640 | GET_CURRENT_CONTEXT(ctx); |
||
3641 | |||
3642 | fb = get_framebuffer_target(ctx, target); |
||
3643 | if (!fb) { |
||
3644 | _mesa_error(ctx, GL_INVALID_ENUM, |
||
3645 | "glDiscardFramebufferEXT(target %s)", |
||
3646 | _mesa_lookup_enum_by_nr(target)); |
||
3647 | return; |
||
3648 | } |
||
3649 | |||
3650 | if (numAttachments < 0) { |
||
3651 | _mesa_error(ctx, GL_INVALID_VALUE, |
||
3652 | "glDiscardFramebufferEXT(numAttachments < 0)"); |
||
3653 | return; |
||
3654 | } |
||
3655 | |||
3656 | for (i = 0; i < numAttachments; i++) { |
||
3657 | switch (attachments[i]) { |
||
3658 | case GL_COLOR: |
||
3659 | case GL_DEPTH: |
||
3660 | case GL_STENCIL: |
||
3661 | if (_mesa_is_user_fbo(fb)) |
||
3662 | goto invalid_enum; |
||
3663 | break; |
||
3664 | case GL_COLOR_ATTACHMENT0: |
||
3665 | case GL_DEPTH_ATTACHMENT: |
||
3666 | case GL_STENCIL_ATTACHMENT: |
||
3667 | if (_mesa_is_winsys_fbo(fb)) |
||
3668 | goto invalid_enum; |
||
3669 | break; |
||
3670 | default: |
||
3671 | goto invalid_enum; |
||
3672 | } |
||
3673 | } |
||
3674 | |||
3675 | if (ctx->Driver.DiscardFramebuffer) |
||
3676 | ctx->Driver.DiscardFramebuffer(ctx, target, numAttachments, attachments); |
||
3677 | |||
3678 | return; |
||
3679 | |||
3680 | invalid_enum: |
||
3681 | _mesa_error(ctx, GL_INVALID_ENUM, |
||
3682 | "glDiscardFramebufferEXT(attachment %s)", |
||
3683 | _mesa_lookup_enum_by_nr(attachments[i])); |
||
3684 | }>>>>>>>>>>>>>>>><>>>>>>>>>>>>>>>>>>>>>>>> |