st_cb_fbo.c revision de414f491526610bb260c73805c81ba413388e20
1/************************************************************************** 2 * 3 * Copyright 2007 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/** 30 * Framebuffer/renderbuffer functions. 31 * 32 * \author Brian Paul 33 */ 34 35 36#include "main/imports.h" 37#include "main/context.h" 38#include "main/fbobject.h" 39#include "main/framebuffer.h" 40#include "main/macros.h" 41#include "main/mfeatures.h" 42#include "main/renderbuffer.h" 43 44#include "pipe/p_context.h" 45#include "pipe/p_defines.h" 46#include "pipe/p_screen.h" 47#include "st_context.h" 48#include "st_cb_fbo.h" 49#include "st_cb_flush.h" 50#include "st_cb_texture.h" 51#include "st_format.h" 52#include "st_texture.h" 53#include "st_manager.h" 54 55#include "util/u_format.h" 56#include "util/u_inlines.h" 57#include "util/u_surface.h" 58 59 60/** 61 * gl_renderbuffer::AllocStorage() 62 * This is called to allocate the original drawing surface, and 63 * during window resize. 64 */ 65static GLboolean 66st_renderbuffer_alloc_storage(struct gl_context * ctx, 67 struct gl_renderbuffer *rb, 68 GLenum internalFormat, 69 GLuint width, GLuint height) 70{ 71 struct st_context *st = st_context(ctx); 72 struct pipe_context *pipe = st->pipe; 73 struct pipe_screen *screen = st->pipe->screen; 74 struct st_renderbuffer *strb = st_renderbuffer(rb); 75 enum pipe_format format; 76 struct pipe_surface surf_tmpl; 77 78 format = st_choose_renderbuffer_format(screen, internalFormat, 79 rb->NumSamples); 80 81 if (format == PIPE_FORMAT_NONE) { 82 return FALSE; 83 } 84 85 /* init renderbuffer fields */ 86 strb->Base.Width = width; 87 strb->Base.Height = height; 88 strb->Base.Format = st_pipe_format_to_mesa_format(format); 89 strb->Base._BaseFormat = _mesa_base_fbo_format(ctx, internalFormat); 90 strb->Base.DataType = st_format_datatype(format); 91 strb->format = format; 92 93 strb->defined = GL_FALSE; /* undefined contents now */ 94 95 if (strb->software) { 96 size_t size; 97 98 free(strb->data); 99 100 assert(strb->format != PIPE_FORMAT_NONE); 101 102 strb->stride = util_format_get_stride(strb->format, width); 103 size = util_format_get_2d_size(strb->format, strb->stride, height); 104 105 strb->data = malloc(size); 106 107 return strb->data != NULL; 108 } 109 else { 110 struct pipe_resource template; 111 112 /* Free the old surface and texture 113 */ 114 pipe_surface_reference( &strb->surface, NULL ); 115 pipe_resource_reference( &strb->texture, NULL ); 116 117 /* Setup new texture template. 118 */ 119 memset(&template, 0, sizeof(template)); 120 template.target = st->internal_target; 121 template.format = format; 122 template.width0 = width; 123 template.height0 = height; 124 template.depth0 = 1; 125 template.array_size = 1; 126 template.last_level = 0; 127 template.nr_samples = rb->NumSamples; 128 if (util_format_is_depth_or_stencil(format)) { 129 template.bind = PIPE_BIND_DEPTH_STENCIL; 130 } 131 else { 132 template.bind = (PIPE_BIND_DISPLAY_TARGET | 133 PIPE_BIND_RENDER_TARGET); 134 } 135 136 strb->texture = screen->resource_create(screen, &template); 137 138 if (!strb->texture) 139 return FALSE; 140 141 memset(&surf_tmpl, 0, sizeof(surf_tmpl)); 142 u_surface_default_template(&surf_tmpl, strb->texture, template.bind); 143 strb->surface = pipe->create_surface(pipe, 144 strb->texture, 145 &surf_tmpl); 146 if (strb->surface) { 147 assert(strb->surface->texture); 148 assert(strb->surface->format); 149 assert(strb->surface->width == width); 150 assert(strb->surface->height == height); 151 } 152 153 return strb->surface != NULL; 154 } 155} 156 157 158/** 159 * gl_renderbuffer::Delete() 160 */ 161static void 162st_renderbuffer_delete(struct gl_renderbuffer *rb) 163{ 164 struct st_renderbuffer *strb = st_renderbuffer(rb); 165 ASSERT(strb); 166 pipe_surface_reference(&strb->surface, NULL); 167 pipe_resource_reference(&strb->texture, NULL); 168 free(strb->data); 169 free(strb); 170} 171 172 173/** 174 * gl_renderbuffer::GetPointer() 175 */ 176static void * 177null_get_pointer(struct gl_context * ctx, struct gl_renderbuffer *rb, 178 GLint x, GLint y) 179{ 180 /* By returning NULL we force all software rendering to go through 181 * the span routines. 182 */ 183#if 0 184 assert(0); /* Should never get called with softpipe */ 185#endif 186 return NULL; 187} 188 189 190/** 191 * Called via ctx->Driver.NewFramebuffer() 192 */ 193static struct gl_framebuffer * 194st_new_framebuffer(struct gl_context *ctx, GLuint name) 195{ 196 /* XXX not sure we need to subclass gl_framebuffer for pipe */ 197 return _mesa_new_framebuffer(ctx, name); 198} 199 200 201/** 202 * Called via ctx->Driver.NewRenderbuffer() 203 */ 204static struct gl_renderbuffer * 205st_new_renderbuffer(struct gl_context *ctx, GLuint name) 206{ 207 struct st_renderbuffer *strb = ST_CALLOC_STRUCT(st_renderbuffer); 208 if (strb) { 209 _mesa_init_renderbuffer(&strb->Base, name); 210 strb->Base.Delete = st_renderbuffer_delete; 211 strb->Base.AllocStorage = st_renderbuffer_alloc_storage; 212 strb->Base.GetPointer = null_get_pointer; 213 strb->format = PIPE_FORMAT_NONE; 214 return &strb->Base; 215 } 216 return NULL; 217} 218 219 220/** 221 * Allocate a renderbuffer for a an on-screen window (not a user-created 222 * renderbuffer). The window system code determines the format. 223 */ 224struct gl_renderbuffer * 225st_new_renderbuffer_fb(enum pipe_format format, int samples, boolean sw) 226{ 227 struct st_renderbuffer *strb; 228 229 strb = ST_CALLOC_STRUCT(st_renderbuffer); 230 if (!strb) { 231 _mesa_error(NULL, GL_OUT_OF_MEMORY, "creating renderbuffer"); 232 return NULL; 233 } 234 235 _mesa_init_renderbuffer(&strb->Base, 0); 236 strb->Base.ClassID = 0x4242; /* just a unique value */ 237 strb->Base.NumSamples = samples; 238 strb->Base.Format = st_pipe_format_to_mesa_format(format); 239 strb->Base._BaseFormat = _mesa_get_format_base_format(strb->Base.Format); 240 strb->Base.DataType = st_format_datatype(format); 241 strb->format = format; 242 strb->software = sw; 243 244 switch (format) { 245 case PIPE_FORMAT_R8G8B8A8_UNORM: 246 case PIPE_FORMAT_B8G8R8A8_UNORM: 247 case PIPE_FORMAT_A8R8G8B8_UNORM: 248 case PIPE_FORMAT_R8G8B8X8_UNORM: 249 case PIPE_FORMAT_B8G8R8X8_UNORM: 250 case PIPE_FORMAT_X8R8G8B8_UNORM: 251 case PIPE_FORMAT_B5G5R5A1_UNORM: 252 case PIPE_FORMAT_B4G4R4A4_UNORM: 253 case PIPE_FORMAT_B5G6R5_UNORM: 254 strb->Base.InternalFormat = GL_RGBA; 255 break; 256 case PIPE_FORMAT_Z16_UNORM: 257 strb->Base.InternalFormat = GL_DEPTH_COMPONENT16; 258 break; 259 case PIPE_FORMAT_Z32_UNORM: 260 strb->Base.InternalFormat = GL_DEPTH_COMPONENT32; 261 break; 262 case PIPE_FORMAT_Z24_UNORM_S8_USCALED: 263 case PIPE_FORMAT_S8_USCALED_Z24_UNORM: 264 case PIPE_FORMAT_Z24X8_UNORM: 265 case PIPE_FORMAT_X8Z24_UNORM: 266 strb->Base.InternalFormat = GL_DEPTH24_STENCIL8_EXT; 267 break; 268 case PIPE_FORMAT_S8_USCALED: 269 strb->Base.InternalFormat = GL_STENCIL_INDEX8_EXT; 270 break; 271 case PIPE_FORMAT_R16G16B16A16_SNORM: 272 /* accum buffer */ 273 strb->Base.InternalFormat = GL_RGBA16_SNORM; 274 break; 275 case PIPE_FORMAT_R8_UNORM: 276 strb->Base.InternalFormat = GL_R8; 277 break; 278 case PIPE_FORMAT_R8G8_UNORM: 279 strb->Base.InternalFormat = GL_RG8; 280 break; 281 case PIPE_FORMAT_R16_UNORM: 282 strb->Base.InternalFormat = GL_R16; 283 break; 284 case PIPE_FORMAT_R16G16_UNORM: 285 strb->Base.InternalFormat = GL_RG16; 286 break; 287 default: 288 _mesa_problem(NULL, 289 "Unexpected format in st_new_renderbuffer_fb"); 290 free(strb); 291 return NULL; 292 } 293 294 /* st-specific methods */ 295 strb->Base.Delete = st_renderbuffer_delete; 296 strb->Base.AllocStorage = st_renderbuffer_alloc_storage; 297 strb->Base.GetPointer = null_get_pointer; 298 299 /* surface is allocated in st_renderbuffer_alloc_storage() */ 300 strb->surface = NULL; 301 302 return &strb->Base; 303} 304 305 306 307 308/** 309 * Called via ctx->Driver.BindFramebufferEXT(). 310 */ 311static void 312st_bind_framebuffer(struct gl_context *ctx, GLenum target, 313 struct gl_framebuffer *fb, struct gl_framebuffer *fbread) 314{ 315 316} 317 318/** 319 * Called by ctx->Driver.FramebufferRenderbuffer 320 */ 321static void 322st_framebuffer_renderbuffer(struct gl_context *ctx, 323 struct gl_framebuffer *fb, 324 GLenum attachment, 325 struct gl_renderbuffer *rb) 326{ 327 /* XXX no need for derivation? */ 328 _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb); 329} 330 331 332/** 333 * Called by ctx->Driver.RenderTexture 334 */ 335static void 336st_render_texture(struct gl_context *ctx, 337 struct gl_framebuffer *fb, 338 struct gl_renderbuffer_attachment *att) 339{ 340 struct st_context *st = st_context(ctx); 341 struct pipe_context *pipe = st->pipe; 342 struct st_renderbuffer *strb; 343 struct gl_renderbuffer *rb; 344 struct pipe_resource *pt; 345 struct st_texture_object *stObj; 346 const struct gl_texture_image *texImage; 347 struct pipe_surface surf_tmpl; 348 349 if (!st_finalize_texture(ctx, pipe, att->Texture)) 350 return; 351 352 pt = st_get_texobj_resource(att->Texture); 353 assert(pt); 354 355 /* get pointer to texture image we're rendeing to */ 356 texImage = _mesa_get_attachment_teximage(att); 357 358 /* create new renderbuffer which wraps the texture image */ 359 rb = st_new_renderbuffer(ctx, 0); 360 if (!rb) { 361 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture()"); 362 return; 363 } 364 365 _mesa_reference_renderbuffer(&att->Renderbuffer, rb); 366 assert(rb->RefCount == 1); 367 rb->AllocStorage = NULL; /* should not get called */ 368 strb = st_renderbuffer(rb); 369 370 assert(strb->Base.RefCount > 0); 371 372 /* get the texture for the texture object */ 373 stObj = st_texture_object(att->Texture); 374 375 /* point renderbuffer at texobject */ 376 strb->rtt = stObj; 377 strb->rtt_level = att->TextureLevel; 378 strb->rtt_face = att->CubeMapFace; 379 strb->rtt_slice = att->Zoffset; 380 381 rb->Width = texImage->Width2; 382 rb->Height = texImage->Height2; 383 rb->_BaseFormat = texImage->_BaseFormat; 384 /*printf("***** render to texture level %d: %d x %d\n", att->TextureLevel, rb->Width, rb->Height);*/ 385 386 /*printf("***** pipe texture %d x %d\n", pt->width0, pt->height0);*/ 387 388 pipe_resource_reference( &strb->texture, pt ); 389 390 pipe_surface_reference(&strb->surface, NULL); 391 392 assert(strb->rtt_level <= strb->texture->last_level); 393 394 /* new surface for rendering into the texture */ 395 memset(&surf_tmpl, 0, sizeof(surf_tmpl)); 396 surf_tmpl.format = ctx->Color.sRGBEnabled ? strb->texture->format : util_format_linear(strb->texture->format); 397 surf_tmpl.usage = PIPE_BIND_RENDER_TARGET; 398 surf_tmpl.u.tex.level = strb->rtt_level; 399 surf_tmpl.u.tex.first_layer = strb->rtt_face + strb->rtt_slice; 400 surf_tmpl.u.tex.last_layer = strb->rtt_face + strb->rtt_slice; 401 strb->surface = pipe->create_surface(pipe, 402 strb->texture, 403 &surf_tmpl); 404 405 strb->format = pt->format; 406 407 strb->Base.Format = st_pipe_format_to_mesa_format(pt->format); 408 strb->Base.DataType = st_format_datatype(pt->format); 409 410 /* 411 printf("RENDER TO TEXTURE obj=%p pt=%p surf=%p %d x %d\n", 412 att->Texture, pt, strb->surface, rb->Width, rb->Height); 413 */ 414 415 /* Invalidate buffer state so that the pipe's framebuffer state 416 * gets updated. 417 * That's where the new renderbuffer (which we just created) gets 418 * passed to the pipe as a (color/depth) render target. 419 */ 420 st_invalidate_state(ctx, _NEW_BUFFERS); 421} 422 423 424/** 425 * Called via ctx->Driver.FinishRenderTexture. 426 */ 427static void 428st_finish_render_texture(struct gl_context *ctx, 429 struct gl_renderbuffer_attachment *att) 430{ 431 struct st_renderbuffer *strb = st_renderbuffer(att->Renderbuffer); 432 433 if (!strb) 434 return; 435 436 strb->rtt = NULL; 437 438 /* 439 printf("FINISH RENDER TO TEXTURE surf=%p\n", strb->surface); 440 */ 441 442 /* restore previous framebuffer state */ 443 st_invalidate_state(ctx, _NEW_BUFFERS); 444} 445 446 447/** 448 * Validate a renderbuffer attachment for a particular set of bindings. 449 */ 450static GLboolean 451st_validate_attachment(struct gl_context *ctx, 452 struct pipe_screen *screen, 453 const struct gl_renderbuffer_attachment *att, 454 unsigned bindings) 455{ 456 const struct st_texture_object *stObj = st_texture_object(att->Texture); 457 enum pipe_format format; 458 gl_format texFormat; 459 460 /* Only validate texture attachments for now, since 461 * st_renderbuffer_alloc_storage makes sure that 462 * the format is supported. 463 */ 464 if (att->Type != GL_TEXTURE) 465 return GL_TRUE; 466 467 if (!stObj) 468 return GL_FALSE; 469 470 format = stObj->pt->format; 471 texFormat = _mesa_get_attachment_teximage_const(att)->TexFormat; 472 473 /* If the encoding is sRGB and sRGB rendering cannot be enabled, 474 * check for linear format support instead. 475 * Later when we create a surface, we change the format to a linear one. */ 476 if (!ctx->Const.sRGBCapable && 477 _mesa_get_format_color_encoding(texFormat) == GL_SRGB) { 478 const gl_format linearFormat = _mesa_get_srgb_format_linear(texFormat); 479 format = st_mesa_format_to_pipe_format(linearFormat); 480 } 481 482 return screen->is_format_supported(screen, format, 483 PIPE_TEXTURE_2D, 484 stObj->pt->nr_samples, bindings); 485} 486 487 488/** 489 * Check if two renderbuffer attachments name a combined depth/stencil 490 * renderbuffer. 491 */ 492GLboolean 493st_is_depth_stencil_combined(const struct gl_renderbuffer_attachment *depth, 494 const struct gl_renderbuffer_attachment *stencil) 495{ 496 assert(depth && stencil); 497 498 if (depth->Type == stencil->Type) { 499 if (depth->Type == GL_RENDERBUFFER_EXT && 500 depth->Renderbuffer == stencil->Renderbuffer) 501 return GL_TRUE; 502 503 if (depth->Type == GL_TEXTURE && 504 depth->Texture == stencil->Texture) 505 return GL_TRUE; 506 } 507 508 return GL_FALSE; 509} 510 511 512/** 513 * Check that the framebuffer configuration is valid in terms of what 514 * the driver can support. 515 * 516 * For Gallium we only supports combined Z+stencil, not separate buffers. 517 */ 518static void 519st_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) 520{ 521 struct st_context *st = st_context(ctx); 522 struct pipe_screen *screen = st->pipe->screen; 523 const struct gl_renderbuffer_attachment *depth = 524 &fb->Attachment[BUFFER_DEPTH]; 525 const struct gl_renderbuffer_attachment *stencil = 526 &fb->Attachment[BUFFER_STENCIL]; 527 GLuint i; 528 enum pipe_format first_format = PIPE_FORMAT_NONE; 529 boolean mixed_formats = 530 screen->get_param(screen, PIPE_CAP_MIXED_COLORBUFFER_FORMATS) != 0; 531 532 if (depth->Type && stencil->Type && depth->Type != stencil->Type) { 533 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; 534 return; 535 } 536 if (depth->Type == GL_RENDERBUFFER_EXT && 537 stencil->Type == GL_RENDERBUFFER_EXT && 538 depth->Renderbuffer != stencil->Renderbuffer) { 539 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; 540 return; 541 } 542 if (depth->Type == GL_TEXTURE && 543 stencil->Type == GL_TEXTURE && 544 depth->Texture != stencil->Texture) { 545 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; 546 return; 547 } 548 549 if (!st_validate_attachment(ctx, 550 screen, 551 depth, 552 PIPE_BIND_DEPTH_STENCIL)) { 553 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; 554 return; 555 } 556 if (!st_validate_attachment(ctx, 557 screen, 558 stencil, 559 PIPE_BIND_DEPTH_STENCIL)) { 560 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; 561 return; 562 } 563 for (i = 0; i < ctx->Const.MaxColorAttachments; i++) { 564 struct gl_renderbuffer_attachment *att = 565 &fb->Attachment[BUFFER_COLOR0 + i]; 566 enum pipe_format format; 567 568 if (!st_validate_attachment(ctx, 569 screen, 570 att, 571 PIPE_BIND_RENDER_TARGET)) { 572 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; 573 return; 574 } 575 576 if (!mixed_formats) { 577 /* Disallow mixed formats. */ 578 if (att->Type != GL_NONE) { 579 format = st_renderbuffer(att->Renderbuffer)->surface->format; 580 } else { 581 continue; 582 } 583 584 if (first_format == PIPE_FORMAT_NONE) { 585 first_format = format; 586 } else if (format != first_format) { 587 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; 588 return; 589 } 590 } 591 } 592} 593 594 595/** 596 * Called via glDrawBuffer. 597 */ 598static void 599st_DrawBuffers(struct gl_context *ctx, GLsizei count, const GLenum *buffers) 600{ 601 struct st_context *st = st_context(ctx); 602 struct gl_framebuffer *fb = ctx->DrawBuffer; 603 GLuint i; 604 605 (void) count; 606 (void) buffers; 607 608 /* add the renderbuffers on demand */ 609 for (i = 0; i < fb->_NumColorDrawBuffers; i++) { 610 gl_buffer_index idx = fb->_ColorDrawBufferIndexes[i]; 611 st_manager_add_color_renderbuffer(st, fb, idx); 612 } 613} 614 615 616/** 617 * Called via glReadBuffer. 618 */ 619static void 620st_ReadBuffer(struct gl_context *ctx, GLenum buffer) 621{ 622 struct st_context *st = st_context(ctx); 623 struct gl_framebuffer *fb = ctx->ReadBuffer; 624 625 (void) buffer; 626 627 /* add the renderbuffer on demand */ 628 st_manager_add_color_renderbuffer(st, fb, fb->_ColorReadBufferIndex); 629} 630 631 632void st_init_fbo_functions(struct dd_function_table *functions) 633{ 634#if FEATURE_EXT_framebuffer_object 635 functions->NewFramebuffer = st_new_framebuffer; 636 functions->NewRenderbuffer = st_new_renderbuffer; 637 functions->BindFramebuffer = st_bind_framebuffer; 638 functions->FramebufferRenderbuffer = st_framebuffer_renderbuffer; 639 functions->RenderTexture = st_render_texture; 640 functions->FinishRenderTexture = st_finish_render_texture; 641 functions->ValidateFramebuffer = st_validate_framebuffer; 642#endif 643 /* no longer needed by core Mesa, drivers handle resizes... 644 functions->ResizeBuffers = st_resize_buffers; 645 */ 646 647 functions->DrawBuffers = st_DrawBuffers; 648 functions->ReadBuffer = st_ReadBuffer; 649} 650 651 652