intel_fbo.c revision b7b2791c6bea6ad0db76fdad9a217aa1efffea93
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/macros.h" 31#include "main/mtypes.h" 32#include "main/fbobject.h" 33#include "main/framebuffer.h" 34#include "main/renderbuffer.h" 35#include "main/context.h" 36#include "main/texrender.h" 37#include "drivers/common/meta.h" 38 39#include "intel_context.h" 40#include "intel_batchbuffer.h" 41#include "intel_buffers.h" 42#include "intel_fbo.h" 43#include "intel_mipmap_tree.h" 44#include "intel_regions.h" 45#include "intel_tex.h" 46#include "intel_span.h" 47 48#define FILE_DEBUG_FLAG DEBUG_FBO 49 50 51/** 52 * Create a new framebuffer object. 53 */ 54static struct gl_framebuffer * 55intel_new_framebuffer(struct gl_context * ctx, GLuint name) 56{ 57 /* Only drawable state in intel_framebuffer at this time, just use Mesa's 58 * class 59 */ 60 return _mesa_new_framebuffer(ctx, name); 61} 62 63 64/** Called by gl_renderbuffer::Delete() */ 65static void 66intel_delete_renderbuffer(struct gl_renderbuffer *rb) 67{ 68 GET_CURRENT_CONTEXT(ctx); 69 struct intel_context *intel = intel_context(ctx); 70 struct intel_renderbuffer *irb = intel_renderbuffer(rb); 71 72 ASSERT(irb); 73 74 if (intel && irb->region) { 75 intel_region_release(&irb->region); 76 } 77 78 free(irb); 79} 80 81 82/** 83 * Return a pointer to a specific pixel in a renderbuffer. 84 */ 85static void * 86intel_get_pointer(struct gl_context * ctx, struct gl_renderbuffer *rb, 87 GLint x, GLint y) 88{ 89 /* By returning NULL we force all software rendering to go through 90 * the span routines. 91 */ 92 return NULL; 93} 94 95 96/** 97 * Called via glRenderbufferStorageEXT() to set the format and allocate 98 * storage for a user-created renderbuffer. 99 */ 100static GLboolean 101intel_alloc_renderbuffer_storage(struct gl_context * ctx, struct gl_renderbuffer *rb, 102 GLenum internalFormat, 103 GLuint width, GLuint height) 104{ 105 struct intel_context *intel = intel_context(ctx); 106 struct intel_renderbuffer *irb = intel_renderbuffer(rb); 107 int cpp, tiling; 108 109 ASSERT(rb->Name != 0); 110 111 switch (internalFormat) { 112 default: 113 /* Use the same format-choice logic as for textures. 114 * Renderbuffers aren't any different from textures for us, 115 * except they're less useful because you can't texture with 116 * them. 117 */ 118 rb->Format = intelChooseTextureFormat(ctx, internalFormat, 119 GL_NONE, GL_NONE); 120 break; 121 case GL_STENCIL_INDEX: 122 case GL_STENCIL_INDEX1_EXT: 123 case GL_STENCIL_INDEX4_EXT: 124 case GL_STENCIL_INDEX8_EXT: 125 case GL_STENCIL_INDEX16_EXT: 126 /* These aren't actual texture formats, so force them here. */ 127 rb->Format = MESA_FORMAT_S8_Z24; 128 break; 129 } 130 131 rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat); 132 rb->DataType = intel_mesa_format_to_rb_datatype(rb->Format); 133 cpp = _mesa_get_format_bytes(rb->Format); 134 135 intel_flush(ctx); 136 137 /* free old region */ 138 if (irb->region) { 139 intel_region_release(&irb->region); 140 } 141 142 /* allocate new memory region/renderbuffer */ 143 144 /* alloc hardware renderbuffer */ 145 DBG("Allocating %d x %d Intel RBO\n", width, height); 146 147 tiling = I915_TILING_NONE; 148 149 /* Gen6 requires depth must be tiling */ 150 if (intel->gen >= 6 && rb->Format == MESA_FORMAT_S8_Z24) 151 tiling = I915_TILING_Y; 152 153 irb->region = intel_region_alloc(intel->intelScreen, tiling, cpp, 154 width, height, GL_TRUE); 155 if (!irb->region) 156 return GL_FALSE; /* out of memory? */ 157 158 ASSERT(irb->region->buffer); 159 160 rb->Width = width; 161 rb->Height = height; 162 163 return GL_TRUE; 164} 165 166 167#if FEATURE_OES_EGL_image 168static void 169intel_image_target_renderbuffer_storage(struct gl_context *ctx, 170 struct gl_renderbuffer *rb, 171 void *image_handle) 172{ 173 struct intel_context *intel = intel_context(ctx); 174 struct intel_renderbuffer *irb; 175 __DRIscreen *screen; 176 __DRIimage *image; 177 178 screen = intel->intelScreen->driScrnPriv; 179 image = screen->dri2.image->lookupEGLImage(screen, image_handle, 180 screen->loaderPrivate); 181 if (image == NULL) 182 return; 183 184 irb = intel_renderbuffer(rb); 185 if (irb->region) 186 intel_region_release(&irb->region); 187 intel_region_reference(&irb->region, image->region); 188 189 rb->InternalFormat = image->internal_format; 190 rb->Width = image->region->width; 191 rb->Height = image->region->height; 192 rb->Format = image->format; 193 rb->DataType = image->data_type; 194 rb->_BaseFormat = _mesa_base_fbo_format(&intel->ctx, 195 image->internal_format); 196} 197#endif 198 199/** 200 * Called for each hardware renderbuffer when a _window_ is resized. 201 * Just update fields. 202 * Not used for user-created renderbuffers! 203 */ 204static GLboolean 205intel_alloc_window_storage(struct gl_context * ctx, struct gl_renderbuffer *rb, 206 GLenum internalFormat, GLuint width, GLuint height) 207{ 208 ASSERT(rb->Name == 0); 209 rb->Width = width; 210 rb->Height = height; 211 rb->InternalFormat = internalFormat; 212 213 return GL_TRUE; 214} 215 216 217static void 218intel_resize_buffers(struct gl_context *ctx, struct gl_framebuffer *fb, 219 GLuint width, GLuint height) 220{ 221 int i; 222 223 _mesa_resize_framebuffer(ctx, fb, width, height); 224 225 fb->Initialized = GL_TRUE; /* XXX remove someday */ 226 227 if (fb->Name != 0) { 228 return; 229 } 230 231 232 /* Make sure all window system renderbuffers are up to date */ 233 for (i = BUFFER_FRONT_LEFT; i <= BUFFER_BACK_RIGHT; i++) { 234 struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer; 235 236 /* only resize if size is changing */ 237 if (rb && (rb->Width != width || rb->Height != height)) { 238 rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height); 239 } 240 } 241} 242 243 244/** Dummy function for gl_renderbuffer::AllocStorage() */ 245static GLboolean 246intel_nop_alloc_storage(struct gl_context * ctx, struct gl_renderbuffer *rb, 247 GLenum internalFormat, GLuint width, GLuint height) 248{ 249 _mesa_problem(ctx, "intel_op_alloc_storage should never be called."); 250 return GL_FALSE; 251} 252 253 254void 255intel_renderbuffer_set_region(struct intel_context *intel, 256 struct intel_renderbuffer *rb, 257 struct intel_region *region) 258{ 259 struct intel_region *old; 260 261 old = rb->region; 262 rb->region = NULL; 263 intel_region_reference(&rb->region, region); 264 intel_region_release(&old); 265} 266 267 268/** 269 * Create a new intel_renderbuffer which corresponds to an on-screen window, 270 * not a user-created renderbuffer. 271 */ 272struct intel_renderbuffer * 273intel_create_renderbuffer(gl_format format) 274{ 275 GET_CURRENT_CONTEXT(ctx); 276 277 struct intel_renderbuffer *irb; 278 279 irb = CALLOC_STRUCT(intel_renderbuffer); 280 if (!irb) { 281 _mesa_error(ctx, GL_OUT_OF_MEMORY, "creating renderbuffer"); 282 return NULL; 283 } 284 285 _mesa_init_renderbuffer(&irb->Base, 0); 286 irb->Base.ClassID = INTEL_RB_CLASS; 287 288 switch (format) { 289 case MESA_FORMAT_RGB565: 290 irb->Base._BaseFormat = GL_RGB; 291 break; 292 case MESA_FORMAT_XRGB8888: 293 irb->Base._BaseFormat = GL_RGB; 294 break; 295 case MESA_FORMAT_ARGB8888: 296 irb->Base._BaseFormat = GL_RGBA; 297 break; 298 case MESA_FORMAT_Z16: 299 irb->Base._BaseFormat = GL_DEPTH_COMPONENT; 300 break; 301 case MESA_FORMAT_X8_Z24: 302 irb->Base._BaseFormat = GL_DEPTH_COMPONENT; 303 break; 304 case MESA_FORMAT_S8_Z24: 305 irb->Base._BaseFormat = GL_DEPTH_STENCIL; 306 break; 307 case MESA_FORMAT_A8: 308 irb->Base._BaseFormat = GL_ALPHA; 309 break; 310 case MESA_FORMAT_R8: 311 irb->Base._BaseFormat = GL_RED; 312 break; 313 case MESA_FORMAT_RG88: 314 irb->Base._BaseFormat = GL_RG; 315 break; 316 default: 317 _mesa_problem(NULL, 318 "Unexpected intFormat in intel_create_renderbuffer"); 319 free(irb); 320 return NULL; 321 } 322 323 irb->Base.Format = format; 324 irb->Base.InternalFormat = irb->Base._BaseFormat; 325 irb->Base.DataType = intel_mesa_format_to_rb_datatype(format); 326 327 /* intel-specific methods */ 328 irb->Base.Delete = intel_delete_renderbuffer; 329 irb->Base.AllocStorage = intel_alloc_window_storage; 330 irb->Base.GetPointer = intel_get_pointer; 331 332 return irb; 333} 334 335 336/** 337 * Create a new renderbuffer object. 338 * Typically called via glBindRenderbufferEXT(). 339 */ 340static struct gl_renderbuffer * 341intel_new_renderbuffer(struct gl_context * ctx, GLuint name) 342{ 343 /*struct intel_context *intel = intel_context(ctx); */ 344 struct intel_renderbuffer *irb; 345 346 irb = CALLOC_STRUCT(intel_renderbuffer); 347 if (!irb) { 348 _mesa_error(ctx, GL_OUT_OF_MEMORY, "creating renderbuffer"); 349 return NULL; 350 } 351 352 _mesa_init_renderbuffer(&irb->Base, name); 353 irb->Base.ClassID = INTEL_RB_CLASS; 354 355 /* intel-specific methods */ 356 irb->Base.Delete = intel_delete_renderbuffer; 357 irb->Base.AllocStorage = intel_alloc_renderbuffer_storage; 358 irb->Base.GetPointer = intel_get_pointer; 359 /* span routines set in alloc_storage function */ 360 361 return &irb->Base; 362} 363 364 365/** 366 * Called via glBindFramebufferEXT(). 367 */ 368static void 369intel_bind_framebuffer(struct gl_context * ctx, GLenum target, 370 struct gl_framebuffer *fb, struct gl_framebuffer *fbread) 371{ 372 if (target == GL_FRAMEBUFFER_EXT || target == GL_DRAW_FRAMEBUFFER_EXT) { 373 intel_draw_buffer(ctx, fb); 374 } 375 else { 376 /* don't need to do anything if target == GL_READ_FRAMEBUFFER_EXT */ 377 } 378} 379 380 381/** 382 * Called via glFramebufferRenderbufferEXT(). 383 */ 384static void 385intel_framebuffer_renderbuffer(struct gl_context * ctx, 386 struct gl_framebuffer *fb, 387 GLenum attachment, struct gl_renderbuffer *rb) 388{ 389 DBG("Intel FramebufferRenderbuffer %u %u\n", fb->Name, rb ? rb->Name : 0); 390 391 intel_flush(ctx); 392 393 _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb); 394 intel_draw_buffer(ctx, fb); 395} 396 397 398static GLboolean 399intel_update_wrapper(struct gl_context *ctx, struct intel_renderbuffer *irb, 400 struct gl_texture_image *texImage) 401{ 402 if (!intel_span_supports_format(texImage->TexFormat)) { 403 DBG("Render to texture BAD FORMAT %s\n", 404 _mesa_get_format_name(texImage->TexFormat)); 405 return GL_FALSE; 406 } else { 407 DBG("Render to texture %s\n", _mesa_get_format_name(texImage->TexFormat)); 408 } 409 410 irb->Base.Format = texImage->TexFormat; 411 irb->Base.DataType = intel_mesa_format_to_rb_datatype(texImage->TexFormat); 412 irb->Base.InternalFormat = texImage->InternalFormat; 413 irb->Base._BaseFormat = _mesa_base_fbo_format(ctx, irb->Base.InternalFormat); 414 irb->Base.Width = texImage->Width; 415 irb->Base.Height = texImage->Height; 416 417 irb->Base.Delete = intel_delete_renderbuffer; 418 irb->Base.AllocStorage = intel_nop_alloc_storage; 419 420 return GL_TRUE; 421} 422 423 424/** 425 * When glFramebufferTexture[123]D is called this function sets up the 426 * gl_renderbuffer wrapper around the texture image. 427 * This will have the region info needed for hardware rendering. 428 */ 429static struct intel_renderbuffer * 430intel_wrap_texture(struct gl_context * ctx, struct gl_texture_image *texImage) 431{ 432 const GLuint name = ~0; /* not significant, but distinct for debugging */ 433 struct intel_renderbuffer *irb; 434 435 /* make an intel_renderbuffer to wrap the texture image */ 436 irb = CALLOC_STRUCT(intel_renderbuffer); 437 if (!irb) { 438 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture"); 439 return NULL; 440 } 441 442 _mesa_init_renderbuffer(&irb->Base, name); 443 irb->Base.ClassID = INTEL_RB_CLASS; 444 445 if (!intel_update_wrapper(ctx, irb, texImage)) { 446 free(irb); 447 return NULL; 448 } 449 450 return irb; 451} 452 453 454/** 455 * Called by glFramebufferTexture[123]DEXT() (and other places) to 456 * prepare for rendering into texture memory. This might be called 457 * many times to choose different texture levels, cube faces, etc 458 * before intel_finish_render_texture() is ever called. 459 */ 460static void 461intel_render_texture(struct gl_context * ctx, 462 struct gl_framebuffer *fb, 463 struct gl_renderbuffer_attachment *att) 464{ 465 struct gl_texture_image *newImage 466 = att->Texture->Image[att->CubeMapFace][att->TextureLevel]; 467 struct intel_renderbuffer *irb = intel_renderbuffer(att->Renderbuffer); 468 struct intel_texture_image *intel_image; 469 GLuint dst_x, dst_y; 470 471 (void) fb; 472 473 ASSERT(newImage); 474 475 intel_image = intel_texture_image(newImage); 476 if (!intel_image->mt) { 477 /* Fallback on drawing to a texture that doesn't have a miptree 478 * (has a border, width/height 0, etc.) 479 */ 480 _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); 481 _mesa_render_texture(ctx, fb, att); 482 return; 483 } 484 else if (!irb) { 485 irb = intel_wrap_texture(ctx, newImage); 486 if (irb) { 487 /* bind the wrapper to the attachment point */ 488 _mesa_reference_renderbuffer(&att->Renderbuffer, &irb->Base); 489 } 490 else { 491 /* fallback to software rendering */ 492 _mesa_render_texture(ctx, fb, att); 493 return; 494 } 495 } 496 497 if (!intel_update_wrapper(ctx, irb, newImage)) { 498 _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); 499 _mesa_render_texture(ctx, fb, att); 500 return; 501 } 502 503 DBG("Begin render texture tid %lx tex=%u w=%d h=%d refcount=%d\n", 504 _glthread_GetID(), 505 att->Texture->Name, newImage->Width, newImage->Height, 506 irb->Base.RefCount); 507 508 /* point the renderbufer's region to the texture image region */ 509 if (irb->region != intel_image->mt->region) { 510 if (irb->region) 511 intel_region_release(&irb->region); 512 intel_region_reference(&irb->region, intel_image->mt->region); 513 } 514 515 /* compute offset of the particular 2D image within the texture region */ 516 intel_miptree_get_image_offset(intel_image->mt, 517 att->TextureLevel, 518 att->CubeMapFace, 519 att->Zoffset, 520 &dst_x, &dst_y); 521 522 intel_image->mt->region->draw_offset = (dst_y * intel_image->mt->region->pitch + 523 dst_x) * intel_image->mt->cpp; 524 intel_image->mt->region->draw_x = dst_x; 525 intel_image->mt->region->draw_y = dst_y; 526 intel_image->used_as_render_target = GL_TRUE; 527 528 /* update drawing region, etc */ 529 intel_draw_buffer(ctx, fb); 530} 531 532 533/** 534 * Called by Mesa when rendering to a texture is done. 535 */ 536static void 537intel_finish_render_texture(struct gl_context * ctx, 538 struct gl_renderbuffer_attachment *att) 539{ 540 struct intel_context *intel = intel_context(ctx); 541 struct gl_texture_object *tex_obj = att->Texture; 542 struct gl_texture_image *image = 543 tex_obj->Image[att->CubeMapFace][att->TextureLevel]; 544 struct intel_texture_image *intel_image = intel_texture_image(image); 545 546 DBG("Finish render texture tid %lx tex=%u\n", 547 _glthread_GetID(), att->Texture->Name); 548 549 /* Flag that this image may now be validated into the object's miptree. */ 550 if (intel_image) 551 intel_image->used_as_render_target = GL_FALSE; 552 553 /* Since we've (probably) rendered to the texture and will (likely) use 554 * it in the texture domain later on in this batchbuffer, flush the 555 * batch. Once again, we wish for a domain tracker in libdrm to cover 556 * usage inside of a batchbuffer like GEM does in the kernel. 557 */ 558 intel_batchbuffer_emit_mi_flush(intel->batch); 559} 560 561/** 562 * Do additional "completeness" testing of a framebuffer object. 563 */ 564static void 565intel_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) 566{ 567 const struct intel_renderbuffer *depthRb = 568 intel_get_renderbuffer(fb, BUFFER_DEPTH); 569 const struct intel_renderbuffer *stencilRb = 570 intel_get_renderbuffer(fb, BUFFER_STENCIL); 571 int i; 572 573 if (depthRb && stencilRb && stencilRb != depthRb) { 574 if (fb->Attachment[BUFFER_DEPTH].Type == GL_TEXTURE && 575 fb->Attachment[BUFFER_STENCIL].Type == GL_TEXTURE && 576 (fb->Attachment[BUFFER_DEPTH].Texture->Name == 577 fb->Attachment[BUFFER_STENCIL].Texture->Name)) { 578 /* OK */ 579 } else { 580 /* we only support combined depth/stencil buffers, not separate 581 * stencil buffers. 582 */ 583 DBG("Only supports combined depth/stencil (found %s, %s)\n", 584 depthRb ? _mesa_get_format_name(depthRb->Base.Format): "NULL", 585 stencilRb ? _mesa_get_format_name(stencilRb->Base.Format): "NULL"); 586 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; 587 } 588 } 589 590 for (i = 0; i < Elements(fb->Attachment); i++) { 591 struct gl_renderbuffer *rb; 592 struct intel_renderbuffer *irb; 593 594 if (fb->Attachment[i].Type == GL_NONE) 595 continue; 596 597 /* A supported attachment will have a Renderbuffer set either 598 * from being a Renderbuffer or being a texture that got the 599 * intel_wrap_texture() treatment. 600 */ 601 rb = fb->Attachment[i].Renderbuffer; 602 if (rb == NULL) { 603 DBG("attachment without renderbuffer\n"); 604 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; 605 continue; 606 } 607 608 irb = intel_renderbuffer(rb); 609 if (irb == NULL) { 610 DBG("software rendering renderbuffer\n"); 611 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; 612 continue; 613 } 614 615 if (!intel_span_supports_format(irb->Base.Format)) { 616 DBG("Unsupported texture/renderbuffer format attached: %s\n", 617 _mesa_get_format_name(irb->Base.Format)); 618 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; 619 } 620 } 621} 622 623 624/** 625 * Do one-time context initializations related to GL_EXT_framebuffer_object. 626 * Hook in device driver functions. 627 */ 628void 629intel_fbo_init(struct intel_context *intel) 630{ 631 intel->ctx.Driver.NewFramebuffer = intel_new_framebuffer; 632 intel->ctx.Driver.NewRenderbuffer = intel_new_renderbuffer; 633 intel->ctx.Driver.BindFramebuffer = intel_bind_framebuffer; 634 intel->ctx.Driver.FramebufferRenderbuffer = intel_framebuffer_renderbuffer; 635 intel->ctx.Driver.RenderTexture = intel_render_texture; 636 intel->ctx.Driver.FinishRenderTexture = intel_finish_render_texture; 637 intel->ctx.Driver.ResizeBuffers = intel_resize_buffers; 638 intel->ctx.Driver.ValidateFramebuffer = intel_validate_framebuffer; 639 intel->ctx.Driver.BlitFramebuffer = _mesa_meta_BlitFramebuffer; 640 641#if FEATURE_OES_EGL_image 642 intel->ctx.Driver.EGLImageTargetRenderbufferStorage = 643 intel_image_target_renderbuffer_storage; 644#endif 645} 646