intel_fbo.c revision 7c71ef3a3d0cf2620525f468960cdc76a0fb0d33
1/************************************************************************** 2 * 3 * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28 29#include "imports.h" 30#include "mtypes.h" 31#include "fbobject.h" 32#include "framebuffer.h" 33#include "renderbuffer.h" 34#include "context.h" 35#include "texformat.h" 36#include "texrender.h" 37 38#include "intel_context.h" 39#include "intel_buffers.h" 40#include "intel_depthstencil.h" 41#include "intel_fbo.h" 42#include "intel_mipmap_tree.h" 43#include "intel_regions.h" 44#include "intel_span.h" 45 46 47#define FILE_DEBUG_FLAG DEBUG_FBO 48 49#define INTEL_RB_CLASS 0x12345678 50 51 52/* XXX FBO: move this to intel_context.h (inlined) */ 53/** 54 * Return a gl_renderbuffer ptr casted to intel_renderbuffer. 55 * NULL will be returned if the rb isn't really an intel_renderbuffer. 56 * This is determiend by checking the ClassID. 57 */ 58struct intel_renderbuffer * 59intel_renderbuffer(struct gl_renderbuffer *rb) 60{ 61 struct intel_renderbuffer *irb = (struct intel_renderbuffer *) rb; 62 if (irb && irb->Base.ClassID == INTEL_RB_CLASS) { 63 /*_mesa_warning(NULL, "Returning non-intel Rb\n");*/ 64 return irb; 65 } 66 else 67 return NULL; 68} 69 70 71struct intel_renderbuffer * 72intel_get_renderbuffer(struct gl_framebuffer *fb, GLuint attIndex) 73{ 74 return intel_renderbuffer(fb->Attachment[attIndex].Renderbuffer); 75} 76 77 78void 79intel_flip_renderbuffers(struct intel_framebuffer *intel_fb) 80{ 81 int current_page = intel_fb->pf_current_page; 82 int next_page = (current_page + 1) % intel_fb->pf_num_pages; 83 struct gl_renderbuffer *tmp_rb; 84 85 /* Exchange renderbuffers if necessary but make sure their reference counts 86 * are preserved. 87 */ 88 if (intel_fb->color_rb[current_page] && 89 intel_fb->Base.Attachment[BUFFER_FRONT_LEFT].Renderbuffer != 90 &intel_fb->color_rb[current_page]->Base) { 91 tmp_rb = NULL; 92 _mesa_reference_renderbuffer(&tmp_rb, 93 intel_fb->Base.Attachment[BUFFER_FRONT_LEFT].Renderbuffer); 94 tmp_rb = &intel_fb->color_rb[current_page]->Base; 95 _mesa_reference_renderbuffer( 96 &intel_fb->Base.Attachment[BUFFER_FRONT_LEFT].Renderbuffer, tmp_rb); 97 _mesa_reference_renderbuffer(&tmp_rb, NULL); 98 } 99 100 if (intel_fb->color_rb[next_page] && 101 intel_fb->Base.Attachment[BUFFER_BACK_LEFT].Renderbuffer != 102 &intel_fb->color_rb[next_page]->Base) { 103 tmp_rb = NULL; 104 _mesa_reference_renderbuffer(&tmp_rb, 105 intel_fb->Base.Attachment[BUFFER_BACK_LEFT].Renderbuffer); 106 tmp_rb = &intel_fb->color_rb[next_page]->Base; 107 _mesa_reference_renderbuffer( 108 &intel_fb->Base.Attachment[BUFFER_BACK_LEFT].Renderbuffer, tmp_rb); 109 _mesa_reference_renderbuffer(&tmp_rb, NULL); 110 } 111} 112 113 114struct intel_region * 115intel_get_rb_region(struct gl_framebuffer *fb, GLuint attIndex) 116{ 117 struct intel_renderbuffer *irb = intel_get_renderbuffer(fb, attIndex); 118 119 if (irb) 120 return irb->region; 121 else 122 return NULL; 123} 124 125 126 127/** 128 * Create a new framebuffer object. 129 */ 130static struct gl_framebuffer * 131intel_new_framebuffer(GLcontext * ctx, GLuint name) 132{ 133 /* Only drawable state in intel_framebuffer at this time, just use Mesa's 134 * class 135 */ 136 return _mesa_new_framebuffer(ctx, name); 137} 138 139 140static void 141intel_delete_renderbuffer(struct gl_renderbuffer *rb) 142{ 143 GET_CURRENT_CONTEXT(ctx); 144 struct intel_context *intel = intel_context(ctx); 145 struct intel_renderbuffer *irb = intel_renderbuffer(rb); 146 147 ASSERT(irb); 148 149 if (irb->PairedStencil || irb->PairedDepth) { 150 intel_unpair_depth_stencil(ctx, irb); 151 } 152 153 if (intel && irb->region) { 154 intel_region_release(&irb->region); 155 } 156 157 _mesa_free(irb); 158} 159 160 161 162/** 163 * Return a pointer to a specific pixel in a renderbuffer. 164 */ 165static void * 166intel_get_pointer(GLcontext * ctx, struct gl_renderbuffer *rb, 167 GLint x, GLint y) 168{ 169 /* By returning NULL we force all software rendering to go through 170 * the span routines. 171 */ 172 return NULL; 173} 174 175 176 177/** 178 * Called via glRenderbufferStorageEXT() to set the format and allocate 179 * storage for a user-created renderbuffer. 180 */ 181static GLboolean 182intel_alloc_renderbuffer_storage(GLcontext * ctx, struct gl_renderbuffer *rb, 183 GLenum internalFormat, 184 GLuint width, GLuint height) 185{ 186 struct intel_context *intel = intel_context(ctx); 187 struct intel_renderbuffer *irb = intel_renderbuffer(rb); 188 GLboolean softwareBuffer = GL_FALSE; 189 int cpp; 190 191 ASSERT(rb->Name != 0); 192 193 switch (internalFormat) { 194 case GL_R3_G3_B2: 195 case GL_RGB4: 196 case GL_RGB5: 197 rb->_ActualFormat = GL_RGB5; 198 rb->DataType = GL_UNSIGNED_BYTE; 199 rb->RedBits = 5; 200 rb->GreenBits = 6; 201 rb->BlueBits = 5; 202 cpp = 2; 203 break; 204 case GL_RGB: 205 case GL_RGB8: 206 case GL_RGB10: 207 case GL_RGB12: 208 case GL_RGB16: 209 case GL_RGBA: 210 case GL_RGBA2: 211 case GL_RGBA4: 212 case GL_RGB5_A1: 213 case GL_RGBA8: 214 case GL_RGB10_A2: 215 case GL_RGBA12: 216 case GL_RGBA16: 217 rb->_ActualFormat = GL_RGBA8; 218 rb->DataType = GL_UNSIGNED_BYTE; 219 rb->RedBits = 8; 220 rb->GreenBits = 8; 221 rb->BlueBits = 8; 222 rb->AlphaBits = 8; 223 cpp = 4; 224 break; 225 case GL_STENCIL_INDEX: 226 case GL_STENCIL_INDEX1_EXT: 227 case GL_STENCIL_INDEX4_EXT: 228 case GL_STENCIL_INDEX8_EXT: 229 case GL_STENCIL_INDEX16_EXT: 230 /* alloc a depth+stencil buffer */ 231 rb->_ActualFormat = GL_DEPTH24_STENCIL8_EXT; 232 rb->DataType = GL_UNSIGNED_INT_24_8_EXT; 233 rb->StencilBits = 8; 234 cpp = 4; 235 break; 236 case GL_DEPTH_COMPONENT16: 237 rb->_ActualFormat = GL_DEPTH_COMPONENT16; 238 rb->DataType = GL_UNSIGNED_SHORT; 239 rb->DepthBits = 16; 240 cpp = 2; 241 break; 242 case GL_DEPTH_COMPONENT: 243 case GL_DEPTH_COMPONENT24: 244 case GL_DEPTH_COMPONENT32: 245 rb->_ActualFormat = GL_DEPTH24_STENCIL8_EXT; 246 rb->DataType = GL_UNSIGNED_INT_24_8_EXT; 247 rb->DepthBits = 24; 248 cpp = 4; 249 break; 250 case GL_DEPTH_STENCIL_EXT: 251 case GL_DEPTH24_STENCIL8_EXT: 252 rb->_ActualFormat = GL_DEPTH24_STENCIL8_EXT; 253 rb->DataType = GL_UNSIGNED_INT_24_8_EXT; 254 rb->DepthBits = 24; 255 rb->StencilBits = 8; 256 cpp = 4; 257 break; 258 default: 259 _mesa_problem(ctx, 260 "Unexpected format in intel_alloc_renderbuffer_storage"); 261 return GL_FALSE; 262 } 263 264 intelFlush(ctx); 265 266 /* free old region */ 267 if (irb->region) { 268 intel_region_release(&irb->region); 269 } 270 271 /* allocate new memory region/renderbuffer */ 272 if (softwareBuffer) { 273 return _mesa_soft_renderbuffer_storage(ctx, rb, internalFormat, 274 width, height); 275 } 276 else { 277 /* Choose a pitch to match hardware requirements: 278 */ 279 GLuint pitch = ((cpp * width + 63) & ~63) / cpp; 280 281 /* alloc hardware renderbuffer */ 282 DBG("Allocating %d x %d Intel RBO (pitch %d)\n", width, 283 height, pitch); 284 285 irb->region = intel_region_alloc(intel, cpp, pitch, height); 286 if (!irb->region) 287 return GL_FALSE; /* out of memory? */ 288 289 ASSERT(irb->region->buffer); 290 291 rb->Width = width; 292 rb->Height = height; 293 294 /* This sets the Get/PutRow/Value functions */ 295 intel_set_span_functions(&irb->Base); 296 297 return GL_TRUE; 298 } 299} 300 301 302 303/** 304 * Called for each hardware renderbuffer when a _window_ is resized. 305 * Just update fields. 306 * Not used for user-created renderbuffers! 307 */ 308static GLboolean 309intel_alloc_window_storage(GLcontext * ctx, struct gl_renderbuffer *rb, 310 GLenum internalFormat, GLuint width, GLuint height) 311{ 312 ASSERT(rb->Name == 0); 313 rb->Width = width; 314 rb->Height = height; 315 rb->_ActualFormat = internalFormat; 316 317 return GL_TRUE; 318} 319 320static void 321intel_resize_buffers(GLcontext *ctx, struct gl_framebuffer *fb, 322 GLuint width, GLuint height) 323{ 324 struct intel_framebuffer *intel_fb = (struct intel_framebuffer*)fb; 325 int i; 326 327 _mesa_resize_framebuffer(ctx, fb, width, height); 328 329 fb->Initialized = GL_TRUE; /* XXX remove someday */ 330 331 if (fb->Name != 0) { 332 return; 333 } 334 335 /* Make sure all window system renderbuffers are up to date */ 336 for (i = 0; i < 3; i++) { 337 struct gl_renderbuffer *rb = &intel_fb->color_rb[i]->Base; 338 339 /* only resize if size is changing */ 340 if (rb && (rb->Width != width || rb->Height != height)) { 341 rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height); 342 } 343 } 344} 345 346static GLboolean 347intel_nop_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb, 348 GLenum internalFormat, GLuint width, GLuint height) 349{ 350 _mesa_problem(ctx, "intel_op_alloc_storage should never be called."); 351 return GL_FALSE; 352} 353 354 355 356/** 357 * Create a new intel_renderbuffer which corresponds to an on-screen window, 358 * not a user-created renderbuffer. 359 * \param width the screen width 360 * \param height the screen height 361 */ 362struct intel_renderbuffer * 363intel_create_renderbuffer(GLenum intFormat, GLsizei width, GLsizei height, 364 int offset, int pitch, int cpp, void *map) 365{ 366 GET_CURRENT_CONTEXT(ctx); 367 368 struct intel_renderbuffer *irb; 369 const GLuint name = 0; 370 371 irb = CALLOC_STRUCT(intel_renderbuffer); 372 if (!irb) { 373 _mesa_error(ctx, GL_OUT_OF_MEMORY, "creating renderbuffer"); 374 return NULL; 375 } 376 377 _mesa_init_renderbuffer(&irb->Base, name); 378 irb->Base.ClassID = INTEL_RB_CLASS; 379 380 switch (intFormat) { 381 case GL_RGB5: 382 irb->Base._ActualFormat = GL_RGB5; 383 irb->Base._BaseFormat = GL_RGBA; 384 irb->Base.RedBits = 5; 385 irb->Base.GreenBits = 6; 386 irb->Base.BlueBits = 5; 387 irb->Base.DataType = GL_UNSIGNED_BYTE; 388 cpp = 2; 389 break; 390 case GL_RGBA8: 391 irb->Base._ActualFormat = GL_RGBA8; 392 irb->Base._BaseFormat = GL_RGBA; 393 irb->Base.RedBits = 8; 394 irb->Base.GreenBits = 8; 395 irb->Base.BlueBits = 8; 396 irb->Base.AlphaBits = 8; 397 irb->Base.DataType = GL_UNSIGNED_BYTE; 398 cpp = 4; 399 break; 400 case GL_STENCIL_INDEX8_EXT: 401 irb->Base._ActualFormat = GL_STENCIL_INDEX8_EXT; 402 irb->Base._BaseFormat = GL_STENCIL_INDEX; 403 irb->Base.StencilBits = 8; 404 irb->Base.DataType = GL_UNSIGNED_BYTE; 405 cpp = 1; 406 break; 407 case GL_DEPTH_COMPONENT16: 408 irb->Base._ActualFormat = GL_DEPTH_COMPONENT16; 409 irb->Base._BaseFormat = GL_DEPTH_COMPONENT; 410 irb->Base.DepthBits = 16; 411 irb->Base.DataType = GL_UNSIGNED_SHORT; 412 cpp = 2; 413 break; 414 case GL_DEPTH_COMPONENT24: 415 irb->Base._ActualFormat = GL_DEPTH24_STENCIL8_EXT; 416 irb->Base._BaseFormat = GL_DEPTH_COMPONENT; 417 irb->Base.DepthBits = 24; 418 irb->Base.DataType = GL_UNSIGNED_INT; 419 cpp = 4; 420 break; 421 case GL_DEPTH24_STENCIL8_EXT: 422 irb->Base._ActualFormat = GL_DEPTH24_STENCIL8_EXT; 423 irb->Base._BaseFormat = GL_DEPTH_STENCIL_EXT; 424 irb->Base.DepthBits = 24; 425 irb->Base.StencilBits = 8; 426 irb->Base.DataType = GL_UNSIGNED_INT_24_8_EXT; 427 cpp = 4; 428 break; 429 default: 430 _mesa_problem(NULL, 431 "Unexpected intFormat in intel_create_renderbuffer"); 432 return NULL; 433 } 434 435 irb->Base.InternalFormat = intFormat; 436 437 /* intel-specific methods */ 438 irb->Base.Delete = intel_delete_renderbuffer; 439 irb->Base.AllocStorage = intel_alloc_window_storage; 440 irb->Base.GetPointer = intel_get_pointer; 441 /* This sets the Get/PutRow/Value functions */ 442 intel_set_span_functions(&irb->Base); 443 444 irb->pfMap = map; 445 irb->pfPitch = pitch / cpp; /* in pixels */ 446 447#if 00 448 irb->region = intel_region_create_static(intel, 449 DRM_MM_TT, 450 offset, map, cpp, width, height); 451#endif 452 453 return irb; 454} 455 456 457/** 458 * Create a new renderbuffer object. 459 * Typically called via glBindRenderbufferEXT(). 460 */ 461static struct gl_renderbuffer * 462intel_new_renderbuffer(GLcontext * ctx, GLuint name) 463{ 464 /*struct intel_context *intel = intel_context(ctx); */ 465 struct intel_renderbuffer *irb; 466 467 irb = CALLOC_STRUCT(intel_renderbuffer); 468 if (!irb) { 469 _mesa_error(ctx, GL_OUT_OF_MEMORY, "creating renderbuffer"); 470 return NULL; 471 } 472 473 _mesa_init_renderbuffer(&irb->Base, name); 474 irb->Base.ClassID = INTEL_RB_CLASS; 475 476 /* intel-specific methods */ 477 irb->Base.Delete = intel_delete_renderbuffer; 478 irb->Base.AllocStorage = intel_alloc_renderbuffer_storage; 479 irb->Base.GetPointer = intel_get_pointer; 480 /* span routines set in alloc_storage function */ 481 482 return &irb->Base; 483} 484 485 486/** 487 * Called via glBindFramebufferEXT(). 488 */ 489static void 490intel_bind_framebuffer(GLcontext * ctx, GLenum target, 491 struct gl_framebuffer *fb, struct gl_framebuffer *fbread) 492{ 493 if (target == GL_FRAMEBUFFER_EXT || target == GL_DRAW_FRAMEBUFFER_EXT) { 494 intel_draw_buffer(ctx, fb); 495 /* Integer depth range depends on depth buffer bits */ 496 ctx->Driver.DepthRange(ctx, ctx->Viewport.Near, ctx->Viewport.Far); 497 } 498 else { 499 /* don't need to do anything if target == GL_READ_FRAMEBUFFER_EXT */ 500 } 501} 502 503 504/** 505 * Called via glFramebufferRenderbufferEXT(). 506 */ 507static void 508intel_framebuffer_renderbuffer(GLcontext * ctx, 509 struct gl_framebuffer *fb, 510 GLenum attachment, struct gl_renderbuffer *rb) 511{ 512 DBG("Intel FramebufferRenderbuffer %u %u\n", fb->Name, rb ? rb->Name : 0); 513 514 intelFlush(ctx); 515 516 _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb); 517 intel_draw_buffer(ctx, fb); 518} 519 520 521/** 522 * When glFramebufferTexture[123]D is called this function sets up the 523 * gl_renderbuffer wrapper around the texture image. 524 * This will have the region info needed for hardware rendering. 525 */ 526static struct intel_renderbuffer * 527intel_wrap_texture(GLcontext * ctx, struct gl_texture_image *texImage) 528{ 529 const GLuint name = ~0; /* not significant, but distinct for debugging */ 530 struct intel_renderbuffer *irb; 531 532 /* make an intel_renderbuffer to wrap the texture image */ 533 irb = CALLOC_STRUCT(intel_renderbuffer); 534 if (!irb) { 535 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture"); 536 return NULL; 537 } 538 539 _mesa_init_renderbuffer(&irb->Base, name); 540 irb->Base.ClassID = INTEL_RB_CLASS; 541 542 if (texImage->TexFormat == &_mesa_texformat_argb8888) { 543 irb->Base._ActualFormat = GL_RGBA8; 544 irb->Base._BaseFormat = GL_RGBA; 545 DBG("Render to RGBA8 texture OK\n"); 546 } 547 else if (texImage->TexFormat == &_mesa_texformat_rgb565) { 548 irb->Base._ActualFormat = GL_RGB5; 549 irb->Base._BaseFormat = GL_RGB; 550 DBG("Render to RGB5 texture OK\n"); 551 } 552 else if (texImage->TexFormat == &_mesa_texformat_z16) { 553 irb->Base._ActualFormat = GL_DEPTH_COMPONENT16; 554 irb->Base._BaseFormat = GL_DEPTH_COMPONENT; 555 DBG("Render to DEPTH16 texture OK\n"); 556 } 557 else { 558 DBG("Render to texture BAD FORMAT %d\n", 559 texImage->TexFormat->MesaFormat); 560 _mesa_free(irb); 561 return NULL; 562 } 563 564 irb->Base.InternalFormat = irb->Base._ActualFormat; 565 irb->Base.Width = texImage->Width; 566 irb->Base.Height = texImage->Height; 567 irb->Base.DataType = GL_UNSIGNED_BYTE; /* FBO XXX fix */ 568 irb->Base.RedBits = texImage->TexFormat->RedBits; 569 irb->Base.GreenBits = texImage->TexFormat->GreenBits; 570 irb->Base.BlueBits = texImage->TexFormat->BlueBits; 571 irb->Base.AlphaBits = texImage->TexFormat->AlphaBits; 572 irb->Base.DepthBits = texImage->TexFormat->DepthBits; 573 574 irb->Base.Delete = intel_delete_renderbuffer; 575 irb->Base.AllocStorage = intel_nop_alloc_storage; 576 intel_set_span_functions(&irb->Base); 577 578 irb->RenderToTexture = GL_TRUE; 579 580 return irb; 581} 582 583 584/** 585 * Called by glFramebufferTexture[123]DEXT() (and other places) to 586 * prepare for rendering into texture memory. This might be called 587 * many times to choose different texture levels, cube faces, etc 588 * before intel_finish_render_texture() is ever called. 589 */ 590static void 591intel_render_texture(GLcontext * ctx, 592 struct gl_framebuffer *fb, 593 struct gl_renderbuffer_attachment *att) 594{ 595 struct gl_texture_image *newImage 596 = att->Texture->Image[att->CubeMapFace][att->TextureLevel]; 597 struct intel_renderbuffer *irb = intel_renderbuffer(att->Renderbuffer); 598 struct intel_texture_image *intel_image; 599 GLuint imageOffset; 600 601 (void) fb; 602 603 ASSERT(newImage); 604 605 if (!irb) { 606 irb = intel_wrap_texture(ctx, newImage); 607 if (irb) { 608 /* bind the wrapper to the attachment point */ 609 _mesa_reference_renderbuffer(&att->Renderbuffer, &irb->Base); 610 } 611 else { 612 /* fallback to software rendering */ 613 _mesa_render_texture(ctx, fb, att); 614 return; 615 } 616 } 617 618 DBG("Begin render texture tid %x tex=%u w=%d h=%d refcount=%d\n", 619 _glthread_GetID(), 620 att->Texture->Name, newImage->Width, newImage->Height, 621 irb->Base.RefCount); 622 623 /* point the renderbufer's region to the texture image region */ 624 intel_image = intel_texture_image(newImage); 625 if (irb->region != intel_image->mt->region) { 626 if (irb->region) 627 intel_region_release(&irb->region); 628 intel_region_reference(&irb->region, intel_image->mt->region); 629 } 630 631 /* compute offset of the particular 2D image within the texture region */ 632 imageOffset = intel_miptree_image_offset(intel_image->mt, 633 att->CubeMapFace, 634 att->TextureLevel); 635 636 if (att->Texture->Target == GL_TEXTURE_3D) { 637 const GLuint *offsets = intel_miptree_depth_offsets(intel_image->mt, 638 att->TextureLevel); 639 imageOffset += offsets[att->Zoffset]; 640 } 641 642 /* store that offset in the region */ 643 intel_image->mt->region->draw_offset = imageOffset; 644 645 /* update drawing region, etc */ 646 intel_draw_buffer(ctx, fb); 647} 648 649 650/** 651 * Called by Mesa when rendering to a texture is done. 652 */ 653static void 654intel_finish_render_texture(GLcontext * ctx, 655 struct gl_renderbuffer_attachment *att) 656{ 657 struct intel_renderbuffer *irb = intel_renderbuffer(att->Renderbuffer); 658 659 DBG("End render texture (tid %x) tex %u\n", _glthread_GetID(), att->Texture->Name); 660 661 if (irb) { 662 /* just release the region */ 663 intel_region_release(&irb->region); 664 } 665 else if (att->Renderbuffer) { 666 /* software fallback */ 667 _mesa_finish_render_texture(ctx, att); 668 /* XXX FBO: Need to unmap the buffer (or in intelSpanRenderStart???) */ 669 } 670} 671 672 673/** 674 * Do one-time context initializations related to GL_EXT_framebuffer_object. 675 * Hook in device driver functions. 676 */ 677void 678intel_fbo_init(struct intel_context *intel) 679{ 680 intel->ctx.Driver.NewFramebuffer = intel_new_framebuffer; 681 intel->ctx.Driver.NewRenderbuffer = intel_new_renderbuffer; 682 intel->ctx.Driver.BindFramebuffer = intel_bind_framebuffer; 683 intel->ctx.Driver.FramebufferRenderbuffer = intel_framebuffer_renderbuffer; 684 intel->ctx.Driver.RenderTexture = intel_render_texture; 685 intel->ctx.Driver.FinishRenderTexture = intel_finish_render_texture; 686 intel->ctx.Driver.ResizeBuffers = intel_resize_buffers; 687} 688