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