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