radeon_fbo.c revision 77e6fb17d96ed9d9b3c2f52999e93da12a466405
1/************************************************************************** 2 * 3 * Copyright 2008 Red Hat Inc. 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/enums.h" 33#include "main/fbobject.h" 34#include "main/framebuffer.h" 35#include "main/renderbuffer.h" 36#include "main/context.h" 37#include "main/texrender.h" 38#include "drivers/common/meta.h" 39 40#include "radeon_common.h" 41#include "radeon_mipmap_tree.h" 42 43#define FILE_DEBUG_FLAG RADEON_TEXTURE 44#define DBG(...) do { \ 45 if (RADEON_DEBUG & FILE_DEBUG_FLAG) \ 46 _mesa_printf(__VA_ARGS__); \ 47} while(0) 48 49static struct gl_framebuffer * 50radeon_new_framebuffer(GLcontext *ctx, GLuint name) 51{ 52 return _mesa_new_framebuffer(ctx, name); 53} 54 55static void 56radeon_delete_renderbuffer(struct gl_renderbuffer *rb) 57{ 58 struct radeon_renderbuffer *rrb = radeon_renderbuffer(rb); 59 60 radeon_print(RADEON_TEXTURE, RADEON_TRACE, 61 "%s(rb %p, rrb %p) \n", 62 __func__, rb, rrb); 63 64 ASSERT(rrb); 65 66 if (rrb && rrb->bo) { 67 radeon_bo_unref(rrb->bo); 68 } 69 _mesa_free(rrb); 70} 71 72static void * 73radeon_get_pointer(GLcontext *ctx, struct gl_renderbuffer *rb, 74 GLint x, GLint y) 75{ 76 radeon_print(RADEON_TEXTURE, RADEON_TRACE, 77 "%s(%p, rb %p) \n", 78 __func__, ctx, rb); 79 80 return NULL; 81} 82 83/** 84 * Called via glRenderbufferStorageEXT() to set the format and allocate 85 * storage for a user-created renderbuffer. 86 */ 87static GLboolean 88radeon_alloc_renderbuffer_storage(GLcontext * ctx, struct gl_renderbuffer *rb, 89 GLenum internalFormat, 90 GLuint width, GLuint height) 91{ 92 struct radeon_context *radeon = RADEON_CONTEXT(ctx); 93 struct radeon_renderbuffer *rrb = radeon_renderbuffer(rb); 94 GLboolean software_buffer = GL_FALSE; 95 int cpp; 96 97 radeon_print(RADEON_TEXTURE, RADEON_TRACE, 98 "%s(%p, rb %p) \n", 99 __func__, ctx, rb); 100 101 ASSERT(rb->Name != 0); 102 switch (internalFormat) { 103 case GL_R3_G3_B2: 104 case GL_RGB4: 105 case GL_RGB5: 106 rb->Format = _dri_texformat_rgb565; 107 rb->DataType = GL_UNSIGNED_BYTE; 108 cpp = 2; 109 break; 110 case GL_RGB: 111 case GL_RGB8: 112 case GL_RGB10: 113 case GL_RGB12: 114 case GL_RGB16: 115 rb->Format = _dri_texformat_argb8888; 116 rb->DataType = GL_UNSIGNED_BYTE; 117 cpp = 4; 118 break; 119 case GL_RGBA: 120 case GL_RGBA2: 121 case GL_RGBA4: 122 case GL_RGB5_A1: 123 case GL_RGBA8: 124 case GL_RGB10_A2: 125 case GL_RGBA12: 126 case GL_RGBA16: 127 rb->Format = _dri_texformat_argb8888; 128 rb->DataType = GL_UNSIGNED_BYTE; 129 cpp = 4; 130 break; 131 case GL_STENCIL_INDEX: 132 case GL_STENCIL_INDEX1_EXT: 133 case GL_STENCIL_INDEX4_EXT: 134 case GL_STENCIL_INDEX8_EXT: 135 case GL_STENCIL_INDEX16_EXT: 136 /* alloc a depth+stencil buffer */ 137 rb->Format = MESA_FORMAT_S8_Z24; 138 rb->DataType = GL_UNSIGNED_INT_24_8_EXT; 139 cpp = 4; 140 break; 141 case GL_DEPTH_COMPONENT16: 142 rb->Format = MESA_FORMAT_Z16; 143 rb->DataType = GL_UNSIGNED_SHORT; 144 cpp = 2; 145 break; 146 case GL_DEPTH_COMPONENT: 147 case GL_DEPTH_COMPONENT24: 148 case GL_DEPTH_COMPONENT32: 149 rb->Format = MESA_FORMAT_X8_Z24; 150 rb->DataType = GL_UNSIGNED_INT; 151 cpp = 4; 152 break; 153 case GL_DEPTH_STENCIL_EXT: 154 case GL_DEPTH24_STENCIL8_EXT: 155 rb->Format = MESA_FORMAT_S8_Z24; 156 rb->DataType = GL_UNSIGNED_INT_24_8_EXT; 157 cpp = 4; 158 break; 159 default: 160 _mesa_problem(ctx, 161 "Unexpected format in radeon_alloc_renderbuffer_storage"); 162 return GL_FALSE; 163 } 164 165 rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat); 166 167 if (ctx->Driver.Flush) 168 ctx->Driver.Flush(ctx); /* +r6/r7 */ 169 170 if (rrb->bo) 171 radeon_bo_unref(rrb->bo); 172 173 174 if (software_buffer) { 175 return _mesa_soft_renderbuffer_storage(ctx, rb, internalFormat, 176 width, height); 177 } 178 else { 179 uint32_t size; 180 uint32_t pitch = ((cpp * width + 63) & ~63) / cpp; 181 182 if (RADEON_DEBUG & RADEON_MEMORY) 183 fprintf(stderr,"Allocating %d x %d radeon RBO (pitch %d)\n", width, 184 height, pitch); 185 186 size = pitch * height * cpp; 187 rrb->pitch = pitch * cpp; 188 rrb->cpp = cpp; 189 rrb->bo = radeon_bo_open(radeon->radeonScreen->bom, 190 0, 191 size, 192 0, 193 RADEON_GEM_DOMAIN_VRAM, 194 0); 195 rb->Width = width; 196 rb->Height = height; 197 return GL_TRUE; 198 } 199 200} 201 202 203/** 204 * Called for each hardware renderbuffer when a _window_ is resized. 205 * Just update fields. 206 * Not used for user-created renderbuffers! 207 */ 208static GLboolean 209radeon_alloc_window_storage(GLcontext * ctx, struct gl_renderbuffer *rb, 210 GLenum internalFormat, GLuint width, GLuint height) 211{ 212 ASSERT(rb->Name == 0); 213 rb->Width = width; 214 rb->Height = height; 215 rb->InternalFormat = internalFormat; 216 radeon_print(RADEON_TEXTURE, RADEON_TRACE, 217 "%s(%p, rb %p) \n", 218 __func__, ctx, rb); 219 220 221 return GL_TRUE; 222} 223 224 225static void 226radeon_resize_buffers(GLcontext *ctx, struct gl_framebuffer *fb, 227 GLuint width, GLuint height) 228{ 229 struct radeon_framebuffer *radeon_fb = (struct radeon_framebuffer*)fb; 230 int i; 231 232 radeon_print(RADEON_TEXTURE, RADEON_TRACE, 233 "%s(%p, fb %p) \n", 234 __func__, ctx, fb); 235 236 _mesa_resize_framebuffer(ctx, fb, width, height); 237 238 fb->Initialized = GL_TRUE; /* XXX remove someday */ 239 240 if (fb->Name != 0) { 241 return; 242 } 243 244 /* Make sure all window system renderbuffers are up to date */ 245 for (i = 0; i < 2; i++) { 246 struct gl_renderbuffer *rb = &radeon_fb->color_rb[i]->base; 247 248 /* only resize if size is changing */ 249 if (rb && (rb->Width != width || rb->Height != height)) { 250 rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height); 251 } 252 } 253} 254 255 256/** Dummy function for gl_renderbuffer::AllocStorage() */ 257static GLboolean 258radeon_nop_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb, 259 GLenum internalFormat, GLuint width, GLuint height) 260{ 261 _mesa_problem(ctx, "radeon_op_alloc_storage should never be called."); 262 return GL_FALSE; 263} 264 265 266/** 267 * Create a renderbuffer for a window's color, depth and/or stencil buffer. 268 * Not used for user-created renderbuffers. 269 */ 270struct radeon_renderbuffer * 271radeon_create_renderbuffer(gl_format format, __DRIdrawable *driDrawPriv) 272{ 273 struct radeon_renderbuffer *rrb; 274 275 rrb = CALLOC_STRUCT(radeon_renderbuffer); 276 277 radeon_print(RADEON_TEXTURE, RADEON_TRACE, 278 "%s( rrb %p ) \n", 279 __func__, rrb); 280 281 if (!rrb) 282 return NULL; 283 284 _mesa_init_renderbuffer(&rrb->base, 0); 285 rrb->base.ClassID = RADEON_RB_CLASS; 286 287 rrb->base.Format = format; 288 289 switch (format) { 290 case MESA_FORMAT_RGB565: 291 assert(_mesa_little_endian()); 292 rrb->base.DataType = GL_UNSIGNED_BYTE; 293 rrb->base._BaseFormat = GL_RGB; 294 break; 295 case MESA_FORMAT_RGB565_REV: 296 assert(!_mesa_little_endian()); 297 rrb->base.DataType = GL_UNSIGNED_BYTE; 298 rrb->base._BaseFormat = GL_RGB; 299 break; 300 case MESA_FORMAT_XRGB8888: 301 assert(_mesa_little_endian()); 302 rrb->base.DataType = GL_UNSIGNED_BYTE; 303 rrb->base._BaseFormat = GL_RGB; 304 break; 305 case MESA_FORMAT_XRGB8888_REV: 306 assert(!_mesa_little_endian()); 307 rrb->base.DataType = GL_UNSIGNED_BYTE; 308 rrb->base._BaseFormat = GL_RGB; 309 break; 310 case MESA_FORMAT_ARGB8888: 311 assert(_mesa_little_endian()); 312 rrb->base.DataType = GL_UNSIGNED_BYTE; 313 rrb->base._BaseFormat = GL_RGBA; 314 break; 315 case MESA_FORMAT_ARGB8888_REV: 316 assert(!_mesa_little_endian()); 317 rrb->base.DataType = GL_UNSIGNED_BYTE; 318 rrb->base._BaseFormat = GL_RGBA; 319 break; 320 case MESA_FORMAT_S8: 321 rrb->base.DataType = GL_UNSIGNED_BYTE; 322 rrb->base._BaseFormat = GL_STENCIL_INDEX; 323 break; 324 case MESA_FORMAT_Z16: 325 rrb->base.DataType = GL_UNSIGNED_SHORT; 326 rrb->base._BaseFormat = GL_DEPTH_COMPONENT; 327 break; 328 case MESA_FORMAT_X8_Z24: 329 rrb->base.DataType = GL_UNSIGNED_INT; 330 rrb->base._BaseFormat = GL_DEPTH_COMPONENT; 331 break; 332 case MESA_FORMAT_S8_Z24: 333 rrb->base.DataType = GL_UNSIGNED_INT_24_8_EXT; 334 rrb->base._BaseFormat = GL_DEPTH_STENCIL; 335 break; 336 default: 337 fprintf(stderr, "%s: Unknown format %s\n", 338 __FUNCTION__, _mesa_get_format_name(format)); 339 _mesa_delete_renderbuffer(&rrb->base); 340 return NULL; 341 } 342 343 rrb->dPriv = driDrawPriv; 344 rrb->base.InternalFormat = _mesa_get_format_base_format(format); 345 346 rrb->base.Delete = radeon_delete_renderbuffer; 347 rrb->base.AllocStorage = radeon_alloc_window_storage; 348 rrb->base.GetPointer = radeon_get_pointer; 349 350 rrb->bo = NULL; 351 return rrb; 352} 353 354static struct gl_renderbuffer * 355radeon_new_renderbuffer(GLcontext * ctx, GLuint name) 356{ 357 struct radeon_renderbuffer *rrb; 358 359 rrb = CALLOC_STRUCT(radeon_renderbuffer); 360 361 radeon_print(RADEON_TEXTURE, RADEON_TRACE, 362 "%s(%p, rrb %p) \n", 363 __func__, ctx, rrb); 364 365 if (!rrb) 366 return NULL; 367 368 _mesa_init_renderbuffer(&rrb->base, name); 369 rrb->base.ClassID = RADEON_RB_CLASS; 370 371 rrb->base.Delete = radeon_delete_renderbuffer; 372 rrb->base.AllocStorage = radeon_alloc_renderbuffer_storage; 373 rrb->base.GetPointer = radeon_get_pointer; 374 375 return &rrb->base; 376} 377 378static void 379radeon_bind_framebuffer(GLcontext * ctx, GLenum target, 380 struct gl_framebuffer *fb, struct gl_framebuffer *fbread) 381{ 382 radeon_print(RADEON_TEXTURE, RADEON_TRACE, 383 "%s(%p, fb %p, target %s) \n", 384 __func__, ctx, fb, 385 _mesa_lookup_enum_by_nr(target)); 386 387 if (target == GL_FRAMEBUFFER_EXT || target == GL_DRAW_FRAMEBUFFER_EXT) { 388 radeon_draw_buffer(ctx, fb); 389 } 390 else { 391 /* don't need to do anything if target == GL_READ_FRAMEBUFFER_EXT */ 392 } 393} 394 395static void 396radeon_framebuffer_renderbuffer(GLcontext * ctx, 397 struct gl_framebuffer *fb, 398 GLenum attachment, struct gl_renderbuffer *rb) 399{ 400 401 if (ctx->Driver.Flush) 402 ctx->Driver.Flush(ctx); /* +r6/r7 */ 403 404 radeon_print(RADEON_TEXTURE, RADEON_TRACE, 405 "%s(%p, fb %p, rb %p) \n", 406 __func__, ctx, fb, rb); 407 408 _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb); 409 radeon_draw_buffer(ctx, fb); 410} 411 412 413/* TODO: According to EXT_fbo spec internal format of texture image 414 * once set during glTexImage call, should be preserved when 415 * attaching image to renderbuffer. When HW doesn't support 416 * rendering to format of attached image, set framebuffer 417 * completeness accordingly in radeon_validate_framebuffer (issue #79). 418 */ 419static GLboolean 420radeon_update_wrapper(GLcontext *ctx, struct radeon_renderbuffer *rrb, 421 struct gl_texture_image *texImage) 422{ 423 int retry = 0; 424 gl_format texFormat; 425 426 radeon_print(RADEON_TEXTURE, RADEON_TRACE, 427 "%s(%p, rrb %p, texImage %p) \n", 428 __func__, ctx, rrb, texImage); 429 430restart: 431 if (texImage->TexFormat == _dri_texformat_argb8888) { 432 rrb->base.DataType = GL_UNSIGNED_BYTE; 433 DBG("Render to RGBA8 texture OK\n"); 434 } 435 else if (texImage->TexFormat == _dri_texformat_rgb565) { 436 rrb->base.DataType = GL_UNSIGNED_BYTE; 437 DBG("Render to RGB5 texture OK\n"); 438 } 439 else if (texImage->TexFormat == _dri_texformat_argb1555) { 440 rrb->base.DataType = GL_UNSIGNED_BYTE; 441 DBG("Render to ARGB1555 texture OK\n"); 442 } 443 else if (texImage->TexFormat == _dri_texformat_argb4444) { 444 rrb->base.DataType = GL_UNSIGNED_BYTE; 445 DBG("Render to ARGB4444 texture OK\n"); 446 } 447 else if (texImage->TexFormat == MESA_FORMAT_Z16) { 448 rrb->base.DataType = GL_UNSIGNED_SHORT; 449 DBG("Render to DEPTH16 texture OK\n"); 450 } 451 else if (texImage->TexFormat == MESA_FORMAT_S8_Z24) { 452 rrb->base.DataType = GL_UNSIGNED_INT_24_8_EXT; 453 DBG("Render to DEPTH_STENCIL texture OK\n"); 454 } 455 else { 456 /* try redoing the FBO */ 457 if (retry == 1) { 458 DBG("Render to texture BAD FORMAT %d\n", 459 texImage->TexFormat); 460 return GL_FALSE; 461 } 462 /* XXX why is the tex format being set here? 463 * I think this can be removed. 464 */ 465 texImage->TexFormat = radeonChooseTextureFormat(ctx, texImage->InternalFormat, 0, 466 _mesa_get_format_datatype(texImage->TexFormat), 467 1); 468 469 retry++; 470 goto restart; 471 } 472 473 texFormat = texImage->TexFormat; 474 475 rrb->base.Format = texFormat; 476 477 rrb->cpp = _mesa_get_format_bytes(texFormat); 478 rrb->pitch = texImage->Width * rrb->cpp; 479 rrb->base.InternalFormat = texImage->InternalFormat; 480 rrb->base._BaseFormat = _mesa_base_fbo_format(ctx, rrb->base.InternalFormat); 481 482 rrb->base.Width = texImage->Width; 483 rrb->base.Height = texImage->Height; 484 485 rrb->base.Delete = radeon_delete_renderbuffer; 486 rrb->base.AllocStorage = radeon_nop_alloc_storage; 487 488 return GL_TRUE; 489} 490 491 492static struct radeon_renderbuffer * 493radeon_wrap_texture(GLcontext * ctx, struct gl_texture_image *texImage) 494{ 495 const GLuint name = ~0; /* not significant, but distinct for debugging */ 496 struct radeon_renderbuffer *rrb; 497 498 /* make an radeon_renderbuffer to wrap the texture image */ 499 rrb = CALLOC_STRUCT(radeon_renderbuffer); 500 501 radeon_print(RADEON_TEXTURE, RADEON_TRACE, 502 "%s(%p, rrb %p, texImage %p) \n", 503 __func__, ctx, rrb, texImage); 504 505 if (!rrb) { 506 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture"); 507 return NULL; 508 } 509 510 _mesa_init_renderbuffer(&rrb->base, name); 511 rrb->base.ClassID = RADEON_RB_CLASS; 512 513 if (!radeon_update_wrapper(ctx, rrb, texImage)) { 514 _mesa_free(rrb); 515 return NULL; 516 } 517 518 return rrb; 519 520} 521static void 522radeon_render_texture(GLcontext * ctx, 523 struct gl_framebuffer *fb, 524 struct gl_renderbuffer_attachment *att) 525{ 526 struct gl_texture_image *newImage 527 = att->Texture->Image[att->CubeMapFace][att->TextureLevel]; 528 struct radeon_renderbuffer *rrb = radeon_renderbuffer(att->Renderbuffer); 529 radeon_texture_image *radeon_image; 530 GLuint imageOffset; 531 532 radeon_print(RADEON_TEXTURE, RADEON_TRACE, 533 "%s(%p, fb %p, rrb %p, att %p)\n", 534 __func__, ctx, fb, rrb, att); 535 536 (void) fb; 537 538 ASSERT(newImage); 539 540 if (newImage->Border != 0) { 541 /* Fallback on drawing to a texture with a border, which won't have a 542 * miptree. 543 */ 544 _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); 545 _mesa_render_texture(ctx, fb, att); 546 return; 547 } 548 else if (!rrb) { 549 rrb = radeon_wrap_texture(ctx, newImage); 550 if (rrb) { 551 /* bind the wrapper to the attachment point */ 552 _mesa_reference_renderbuffer(&att->Renderbuffer, &rrb->base); 553 } 554 else { 555 /* fallback to software rendering */ 556 _mesa_render_texture(ctx, fb, att); 557 return; 558 } 559 } 560 561 if (!radeon_update_wrapper(ctx, rrb, newImage)) { 562 _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); 563 _mesa_render_texture(ctx, fb, att); 564 return; 565 } 566 567 DBG("Begin render texture tid %x tex=%u w=%d h=%d refcount=%d\n", 568 _glthread_GetID(), 569 att->Texture->Name, newImage->Width, newImage->Height, 570 rrb->base.RefCount); 571 572 /* point the renderbufer's region to the texture image region */ 573 radeon_image = (radeon_texture_image *)newImage; 574 if (rrb->bo != radeon_image->mt->bo) { 575 if (rrb->bo) 576 radeon_bo_unref(rrb->bo); 577 rrb->bo = radeon_image->mt->bo; 578 radeon_bo_ref(rrb->bo); 579 } 580 581 /* compute offset of the particular 2D image within the texture region */ 582 imageOffset = radeon_miptree_image_offset(radeon_image->mt, 583 att->CubeMapFace, 584 att->TextureLevel); 585 586 if (att->Texture->Target == GL_TEXTURE_3D) { 587 imageOffset += radeon_image->mt->levels[att->TextureLevel].rowstride * 588 radeon_image->mt->levels[att->TextureLevel].height * 589 att->Zoffset; 590 } 591 592 /* store that offset in the region, along with the correct pitch for 593 * the image we are rendering to */ 594 rrb->draw_offset = imageOffset; 595 rrb->pitch = radeon_image->mt->levels[att->TextureLevel].rowstride; 596 597 /* update drawing region, etc */ 598 radeon_draw_buffer(ctx, fb); 599} 600 601static void 602radeon_finish_render_texture(GLcontext * ctx, 603 struct gl_renderbuffer_attachment *att) 604{ 605 606} 607static void 608radeon_validate_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb) 609{ 610} 611 612void radeon_fbo_init(struct radeon_context *radeon) 613{ 614 radeon->glCtx->Driver.NewFramebuffer = radeon_new_framebuffer; 615 radeon->glCtx->Driver.NewRenderbuffer = radeon_new_renderbuffer; 616 radeon->glCtx->Driver.BindFramebuffer = radeon_bind_framebuffer; 617 radeon->glCtx->Driver.FramebufferRenderbuffer = radeon_framebuffer_renderbuffer; 618 radeon->glCtx->Driver.RenderTexture = radeon_render_texture; 619 radeon->glCtx->Driver.FinishRenderTexture = radeon_finish_render_texture; 620 radeon->glCtx->Driver.ResizeBuffers = radeon_resize_buffers; 621 radeon->glCtx->Driver.ValidateFramebuffer = radeon_validate_framebuffer; 622 radeon->glCtx->Driver.BlitFramebuffer = _mesa_meta_BlitFramebuffer; 623} 624 625 626void radeon_renderbuffer_set_bo(struct radeon_renderbuffer *rb, 627 struct radeon_bo *bo) 628{ 629 struct radeon_bo *old; 630 old = rb->bo; 631 rb->bo = bo; 632 radeon_bo_ref(bo); 633 if (old) 634 radeon_bo_unref(old); 635} 636