st_cb_fbo.c revision 9d4ab9a663d4088ec553edaae0eeafb746d2490d
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 60static GLboolean 61st_renderbuffer_alloc_sw_storage(struct gl_context * ctx, 62 struct gl_renderbuffer *rb, 63 GLenum internalFormat, 64 GLuint width, GLuint height) 65{ 66 struct pipe_screen *screen = st_context(ctx)->pipe->screen; 67 struct st_renderbuffer *strb = st_renderbuffer(rb); 68 enum pipe_format format; 69 size_t size; 70 71 free(strb->data); 72 strb->data = NULL; 73 74 if (internalFormat == GL_RGBA16_SNORM) { 75 /* Special case for software accum buffers. Otherwise, if the 76 * call to st_choose_renderbuffer_format() fails (because the 77 * driver doesn't support signed 16-bit/channel colors) we'd 78 * just return without allocating the software accum buffer. 79 */ 80 format = PIPE_FORMAT_R16G16B16A16_SNORM; 81 } 82 else { 83 format = st_choose_renderbuffer_format(screen, internalFormat, 0); 84 85 /* Not setting gl_renderbuffer::Format here will cause 86 * FRAMEBUFFER_UNSUPPORTED and ValidateFramebuffer will not be called. 87 */ 88 if (format == PIPE_FORMAT_NONE) { 89 return GL_TRUE; 90 } 91 } 92 93 strb->Base.Format = st_pipe_format_to_mesa_format(format); 94 95 size = _mesa_format_image_size(strb->Base.Format, width, height, 1); 96 strb->data = malloc(size); 97 return strb->data != NULL; 98} 99 100 101/** 102 * gl_renderbuffer::AllocStorage() 103 * This is called to allocate the original drawing surface, and 104 * during window resize. 105 */ 106static GLboolean 107st_renderbuffer_alloc_storage(struct gl_context * ctx, 108 struct gl_renderbuffer *rb, 109 GLenum internalFormat, 110 GLuint width, GLuint height) 111{ 112 struct st_context *st = st_context(ctx); 113 struct pipe_context *pipe = st->pipe; 114 struct pipe_screen *screen = st->pipe->screen; 115 struct st_renderbuffer *strb = st_renderbuffer(rb); 116 enum pipe_format format = PIPE_FORMAT_NONE; 117 struct pipe_surface surf_tmpl; 118 struct pipe_resource templ; 119 120 /* init renderbuffer fields */ 121 strb->Base.Width = width; 122 strb->Base.Height = height; 123 strb->Base._BaseFormat = _mesa_base_fbo_format(ctx, internalFormat); 124 strb->defined = GL_FALSE; /* undefined contents now */ 125 126 if (strb->software) { 127 return st_renderbuffer_alloc_sw_storage(ctx, rb, internalFormat, 128 width, height); 129 } 130 131 /* Free the old surface and texture 132 */ 133 pipe_surface_reference( &strb->surface, NULL ); 134 pipe_resource_reference( &strb->texture, NULL ); 135 136 /* Handle multisample renderbuffers first. 137 * 138 * From ARB_framebuffer_object: 139 * If <samples> is zero, then RENDERBUFFER_SAMPLES is set to zero. 140 * Otherwise <samples> represents a request for a desired minimum 141 * number of samples. Since different implementations may support 142 * different sample counts for multisampled rendering, the actual 143 * number of samples allocated for the renderbuffer image is 144 * implementation dependent. However, the resulting value for 145 * RENDERBUFFER_SAMPLES is guaranteed to be greater than or equal 146 * to <samples> and no more than the next larger sample count supported 147 * by the implementation. 148 * 149 * So let's find the supported number of samples closest to NumSamples. 150 * (NumSamples == 1) is treated the same as (NumSamples == 0). 151 */ 152 if (rb->NumSamples > 1) { 153 unsigned i; 154 155 for (i = rb->NumSamples; i <= ctx->Const.MaxSamples; i++) { 156 format = st_choose_renderbuffer_format(screen, internalFormat, i); 157 158 if (format != PIPE_FORMAT_NONE) { 159 rb->NumSamples = i; 160 break; 161 } 162 } 163 } else { 164 format = st_choose_renderbuffer_format(screen, internalFormat, 0); 165 } 166 167 /* Not setting gl_renderbuffer::Format here will cause 168 * FRAMEBUFFER_UNSUPPORTED and ValidateFramebuffer will not be called. 169 */ 170 if (format == PIPE_FORMAT_NONE) { 171 return GL_TRUE; 172 } 173 174 strb->Base.Format = st_pipe_format_to_mesa_format(format); 175 176 if (width == 0 || height == 0) { 177 /* if size is zero, nothing to allocate */ 178 return GL_TRUE; 179 } 180 181 /* Setup new texture template. 182 */ 183 memset(&templ, 0, sizeof(templ)); 184 templ.target = st->internal_target; 185 templ.format = format; 186 templ.width0 = width; 187 templ.height0 = height; 188 templ.depth0 = 1; 189 templ.array_size = 1; 190 templ.nr_samples = rb->NumSamples; 191 if (util_format_is_depth_or_stencil(format)) { 192 templ.bind = PIPE_BIND_DEPTH_STENCIL; 193 } 194 else if (strb->Base.Name != 0) { 195 /* this is a user-created renderbuffer */ 196 templ.bind = PIPE_BIND_RENDER_TARGET; 197 } 198 else { 199 /* this is a window-system buffer */ 200 templ.bind = (PIPE_BIND_DISPLAY_TARGET | 201 PIPE_BIND_RENDER_TARGET); 202 } 203 204 strb->texture = screen->resource_create(screen, &templ); 205 206 if (!strb->texture) 207 return FALSE; 208 209 u_surface_default_template(&surf_tmpl, strb->texture, templ.bind); 210 strb->surface = pipe->create_surface(pipe, 211 strb->texture, 212 &surf_tmpl); 213 if (strb->surface) { 214 assert(strb->surface->texture); 215 assert(strb->surface->format); 216 assert(strb->surface->width == width); 217 assert(strb->surface->height == height); 218 } 219 220 return strb->surface != NULL; 221} 222 223 224/** 225 * gl_renderbuffer::Delete() 226 */ 227static void 228st_renderbuffer_delete(struct gl_context *ctx, struct gl_renderbuffer *rb) 229{ 230 struct st_renderbuffer *strb = st_renderbuffer(rb); 231 ASSERT(strb); 232 pipe_surface_reference(&strb->surface, NULL); 233 pipe_resource_reference(&strb->texture, NULL); 234 free(strb->data); 235 _mesa_delete_renderbuffer(ctx, rb); 236} 237 238 239/** 240 * Called via ctx->Driver.NewFramebuffer() 241 */ 242static struct gl_framebuffer * 243st_new_framebuffer(struct gl_context *ctx, GLuint name) 244{ 245 /* XXX not sure we need to subclass gl_framebuffer for pipe */ 246 return _mesa_new_framebuffer(ctx, name); 247} 248 249 250/** 251 * Called via ctx->Driver.NewRenderbuffer() 252 */ 253static struct gl_renderbuffer * 254st_new_renderbuffer(struct gl_context *ctx, GLuint name) 255{ 256 struct st_renderbuffer *strb = ST_CALLOC_STRUCT(st_renderbuffer); 257 if (strb) { 258 assert(name != 0); 259 _mesa_init_renderbuffer(&strb->Base, name); 260 strb->Base.Delete = st_renderbuffer_delete; 261 strb->Base.AllocStorage = st_renderbuffer_alloc_storage; 262 return &strb->Base; 263 } 264 return NULL; 265} 266 267 268/** 269 * Allocate a renderbuffer for a an on-screen window (not a user-created 270 * renderbuffer). The window system code determines the format. 271 */ 272struct gl_renderbuffer * 273st_new_renderbuffer_fb(enum pipe_format format, int samples, boolean sw) 274{ 275 struct st_renderbuffer *strb; 276 277 strb = ST_CALLOC_STRUCT(st_renderbuffer); 278 if (!strb) { 279 _mesa_error(NULL, GL_OUT_OF_MEMORY, "creating renderbuffer"); 280 return NULL; 281 } 282 283 _mesa_init_renderbuffer(&strb->Base, 0); 284 strb->Base.ClassID = 0x4242; /* just a unique value */ 285 strb->Base.NumSamples = samples; 286 strb->Base.Format = st_pipe_format_to_mesa_format(format); 287 strb->Base._BaseFormat = _mesa_get_format_base_format(strb->Base.Format); 288 strb->software = sw; 289 290 switch (format) { 291 case PIPE_FORMAT_R8G8B8A8_UNORM: 292 case PIPE_FORMAT_B8G8R8A8_UNORM: 293 case PIPE_FORMAT_A8R8G8B8_UNORM: 294 strb->Base.InternalFormat = GL_RGBA8; 295 break; 296 case PIPE_FORMAT_R8G8B8X8_UNORM: 297 case PIPE_FORMAT_B8G8R8X8_UNORM: 298 case PIPE_FORMAT_X8R8G8B8_UNORM: 299 strb->Base.InternalFormat = GL_RGB8; 300 break; 301 case PIPE_FORMAT_B5G5R5A1_UNORM: 302 strb->Base.InternalFormat = GL_RGB5_A1; 303 break; 304 case PIPE_FORMAT_B4G4R4A4_UNORM: 305 strb->Base.InternalFormat = GL_RGBA4; 306 break; 307 case PIPE_FORMAT_B5G6R5_UNORM: 308 strb->Base.InternalFormat = GL_RGB565; 309 break; 310 case PIPE_FORMAT_Z16_UNORM: 311 strb->Base.InternalFormat = GL_DEPTH_COMPONENT16; 312 break; 313 case PIPE_FORMAT_Z32_UNORM: 314 strb->Base.InternalFormat = GL_DEPTH_COMPONENT32; 315 break; 316 case PIPE_FORMAT_Z24_UNORM_S8_UINT: 317 case PIPE_FORMAT_S8_UINT_Z24_UNORM: 318 case PIPE_FORMAT_Z24X8_UNORM: 319 case PIPE_FORMAT_X8Z24_UNORM: 320 strb->Base.InternalFormat = GL_DEPTH24_STENCIL8_EXT; 321 break; 322 case PIPE_FORMAT_S8_UINT: 323 strb->Base.InternalFormat = GL_STENCIL_INDEX8_EXT; 324 break; 325 case PIPE_FORMAT_R16G16B16A16_SNORM: 326 /* accum buffer */ 327 strb->Base.InternalFormat = GL_RGBA16_SNORM; 328 break; 329 case PIPE_FORMAT_R8_UNORM: 330 strb->Base.InternalFormat = GL_R8; 331 break; 332 case PIPE_FORMAT_R8G8_UNORM: 333 strb->Base.InternalFormat = GL_RG8; 334 break; 335 case PIPE_FORMAT_R16_UNORM: 336 strb->Base.InternalFormat = GL_R16; 337 break; 338 case PIPE_FORMAT_R16G16_UNORM: 339 strb->Base.InternalFormat = GL_RG16; 340 break; 341 case PIPE_FORMAT_R32G32B32A32_FLOAT: 342 strb->Base.InternalFormat = GL_RGBA32F; 343 break; 344 case PIPE_FORMAT_R16G16B16A16_FLOAT: 345 strb->Base.InternalFormat = GL_RGBA16F; 346 break; 347 default: 348 _mesa_problem(NULL, 349 "Unexpected format %s in st_new_renderbuffer_fb", 350 util_format_name(format)); 351 free(strb); 352 return NULL; 353 } 354 355 /* st-specific methods */ 356 strb->Base.Delete = st_renderbuffer_delete; 357 strb->Base.AllocStorage = st_renderbuffer_alloc_storage; 358 359 /* surface is allocated in st_renderbuffer_alloc_storage() */ 360 strb->surface = NULL; 361 362 return &strb->Base; 363} 364 365 366/** 367 * Called via ctx->Driver.BindFramebufferEXT(). 368 */ 369static void 370st_bind_framebuffer(struct gl_context *ctx, GLenum target, 371 struct gl_framebuffer *fb, struct gl_framebuffer *fbread) 372{ 373 /* no-op */ 374} 375 376 377/** 378 * Called by ctx->Driver.RenderTexture 379 */ 380static void 381st_render_texture(struct gl_context *ctx, 382 struct gl_framebuffer *fb, 383 struct gl_renderbuffer_attachment *att) 384{ 385 struct st_context *st = st_context(ctx); 386 struct pipe_context *pipe = st->pipe; 387 struct st_renderbuffer *strb; 388 struct gl_renderbuffer *rb; 389 struct pipe_resource *pt; 390 struct st_texture_object *stObj; 391 const struct gl_texture_image *texImage; 392 struct pipe_surface surf_tmpl; 393 394 if (!st_finalize_texture(ctx, pipe, att->Texture)) 395 return; 396 397 pt = st_get_texobj_resource(att->Texture); 398 assert(pt); 399 400 /* get pointer to texture image we're rendeing to */ 401 texImage = _mesa_get_attachment_teximage(att); 402 403 /* create new renderbuffer which wraps the texture image. 404 * Use the texture's name as the renderbuffer's name so that we have 405 * something that's non-zero (to determine vertical orientation) and 406 * possibly helpful for debugging. 407 */ 408 rb = st_new_renderbuffer(ctx, att->Texture->Name); 409 if (!rb) { 410 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture()"); 411 return; 412 } 413 414 _mesa_reference_renderbuffer(&att->Renderbuffer, rb); 415 assert(rb->RefCount == 1); 416 rb->AllocStorage = NULL; /* should not get called */ 417 strb = st_renderbuffer(rb); 418 419 assert(strb->Base.RefCount > 0); 420 421 /* get the texture for the texture object */ 422 stObj = st_texture_object(att->Texture); 423 424 /* point renderbuffer at texobject */ 425 strb->rtt = stObj; 426 strb->rtt_level = att->TextureLevel; 427 strb->rtt_face = att->CubeMapFace; 428 strb->rtt_slice = att->Zoffset; 429 430 rb->Width = texImage->Width2; 431 rb->Height = texImage->Height2; 432 rb->_BaseFormat = texImage->_BaseFormat; 433 rb->InternalFormat = texImage->InternalFormat; 434 435 pipe_resource_reference( &strb->texture, pt ); 436 437 pipe_surface_reference(&strb->surface, NULL); 438 439 assert(strb->rtt_level <= strb->texture->last_level); 440 441 /* new surface for rendering into the texture */ 442 memset(&surf_tmpl, 0, sizeof(surf_tmpl)); 443 surf_tmpl.format = ctx->Color.sRGBEnabled 444 ? strb->texture->format : util_format_linear(strb->texture->format); 445 surf_tmpl.usage = PIPE_BIND_RENDER_TARGET; 446 surf_tmpl.u.tex.level = strb->rtt_level; 447 surf_tmpl.u.tex.first_layer = strb->rtt_face + strb->rtt_slice; 448 surf_tmpl.u.tex.last_layer = strb->rtt_face + strb->rtt_slice; 449 strb->surface = pipe->create_surface(pipe, 450 strb->texture, 451 &surf_tmpl); 452 453 strb->Base.Format = st_pipe_format_to_mesa_format(pt->format); 454 455 /* Invalidate buffer state so that the pipe's framebuffer state 456 * gets updated. 457 * That's where the new renderbuffer (which we just created) gets 458 * passed to the pipe as a (color/depth) render target. 459 */ 460 st_invalidate_state(ctx, _NEW_BUFFERS); 461 462 463 /* Need to trigger a call to update_framebuffer() since we just 464 * attached a new renderbuffer. 465 */ 466 ctx->NewState |= _NEW_BUFFERS; 467} 468 469 470/** 471 * Called via ctx->Driver.FinishRenderTexture. 472 */ 473static void 474st_finish_render_texture(struct gl_context *ctx, 475 struct gl_renderbuffer_attachment *att) 476{ 477 struct st_renderbuffer *strb = st_renderbuffer(att->Renderbuffer); 478 479 if (!strb) 480 return; 481 482 strb->rtt = NULL; 483 484 /* restore previous framebuffer state */ 485 st_invalidate_state(ctx, _NEW_BUFFERS); 486} 487 488 489/** Debug helper */ 490static void 491st_fbo_invalid(const char *reason) 492{ 493 if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) { 494 _mesa_debug(NULL, "Invalid FBO: %s\n", reason); 495 } 496} 497 498 499/** 500 * Validate a renderbuffer attachment for a particular set of bindings. 501 */ 502static GLboolean 503st_validate_attachment(struct gl_context *ctx, 504 struct pipe_screen *screen, 505 const struct gl_renderbuffer_attachment *att, 506 unsigned bindings) 507{ 508 const struct st_texture_object *stObj = st_texture_object(att->Texture); 509 enum pipe_format format; 510 gl_format texFormat; 511 GLboolean valid; 512 513 /* Only validate texture attachments for now, since 514 * st_renderbuffer_alloc_storage makes sure that 515 * the format is supported. 516 */ 517 if (att->Type != GL_TEXTURE) 518 return GL_TRUE; 519 520 if (!stObj) 521 return GL_FALSE; 522 523 format = stObj->pt->format; 524 texFormat = _mesa_get_attachment_teximage_const(att)->TexFormat; 525 526 /* If the encoding is sRGB and sRGB rendering cannot be enabled, 527 * check for linear format support instead. 528 * Later when we create a surface, we change the format to a linear one. */ 529 if (!ctx->Extensions.EXT_framebuffer_sRGB && 530 _mesa_get_format_color_encoding(texFormat) == GL_SRGB) { 531 const gl_format linearFormat = _mesa_get_srgb_format_linear(texFormat); 532 format = st_mesa_format_to_pipe_format(linearFormat); 533 } 534 535 valid = screen->is_format_supported(screen, format, 536 PIPE_TEXTURE_2D, 537 stObj->pt->nr_samples, bindings); 538 if (!valid) { 539 st_fbo_invalid("Invalid format"); 540 } 541 542 return valid; 543} 544 545 546/** 547 * Check if two renderbuffer attachments name a combined depth/stencil 548 * renderbuffer. 549 */ 550GLboolean 551st_is_depth_stencil_combined(const struct gl_renderbuffer_attachment *depth, 552 const struct gl_renderbuffer_attachment *stencil) 553{ 554 assert(depth && stencil); 555 556 if (depth->Type == stencil->Type) { 557 if (depth->Type == GL_RENDERBUFFER_EXT && 558 depth->Renderbuffer == stencil->Renderbuffer) 559 return GL_TRUE; 560 561 if (depth->Type == GL_TEXTURE && 562 depth->Texture == stencil->Texture) 563 return GL_TRUE; 564 } 565 566 return GL_FALSE; 567} 568 569 570/** 571 * Check that the framebuffer configuration is valid in terms of what 572 * the driver can support. 573 * 574 * For Gallium we only supports combined Z+stencil, not separate buffers. 575 */ 576static void 577st_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) 578{ 579 struct st_context *st = st_context(ctx); 580 struct pipe_screen *screen = st->pipe->screen; 581 const struct gl_renderbuffer_attachment *depth = 582 &fb->Attachment[BUFFER_DEPTH]; 583 const struct gl_renderbuffer_attachment *stencil = 584 &fb->Attachment[BUFFER_STENCIL]; 585 GLuint i; 586 enum pipe_format first_format = PIPE_FORMAT_NONE; 587 boolean mixed_formats = 588 screen->get_param(screen, PIPE_CAP_MIXED_COLORBUFFER_FORMATS) != 0; 589 590 if (depth->Type && stencil->Type && depth->Type != stencil->Type) { 591 st_fbo_invalid("Different Depth/Stencil buffer formats"); 592 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; 593 return; 594 } 595 if (depth->Type == GL_RENDERBUFFER_EXT && 596 stencil->Type == GL_RENDERBUFFER_EXT && 597 depth->Renderbuffer != stencil->Renderbuffer) { 598 st_fbo_invalid("Separate Depth/Stencil buffers"); 599 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; 600 return; 601 } 602 if (depth->Type == GL_TEXTURE && 603 stencil->Type == GL_TEXTURE && 604 depth->Texture != stencil->Texture) { 605 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; 606 st_fbo_invalid("Different Depth/Stencil textures"); 607 return; 608 } 609 610 if (!st_validate_attachment(ctx, 611 screen, 612 depth, 613 PIPE_BIND_DEPTH_STENCIL)) { 614 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; 615 return; 616 } 617 if (!st_validate_attachment(ctx, 618 screen, 619 stencil, 620 PIPE_BIND_DEPTH_STENCIL)) { 621 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; 622 return; 623 } 624 for (i = 0; i < ctx->Const.MaxColorAttachments; i++) { 625 struct gl_renderbuffer_attachment *att = 626 &fb->Attachment[BUFFER_COLOR0 + i]; 627 enum pipe_format format; 628 629 if (!st_validate_attachment(ctx, 630 screen, 631 att, 632 PIPE_BIND_RENDER_TARGET)) { 633 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; 634 return; 635 } 636 637 if (!mixed_formats) { 638 /* Disallow mixed formats. */ 639 if (att->Type != GL_NONE) { 640 format = st_renderbuffer(att->Renderbuffer)->surface->format; 641 } else { 642 continue; 643 } 644 645 if (first_format == PIPE_FORMAT_NONE) { 646 first_format = format; 647 } else if (format != first_format) { 648 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; 649 st_fbo_invalid("Mixed color formats"); 650 return; 651 } 652 } 653 } 654} 655 656 657/** 658 * Called via glDrawBuffer. 659 */ 660static void 661st_DrawBuffers(struct gl_context *ctx, GLsizei count, const GLenum *buffers) 662{ 663 struct st_context *st = st_context(ctx); 664 struct gl_framebuffer *fb = ctx->DrawBuffer; 665 GLuint i; 666 667 (void) count; 668 (void) buffers; 669 670 /* add the renderbuffers on demand */ 671 for (i = 0; i < fb->_NumColorDrawBuffers; i++) { 672 gl_buffer_index idx = fb->_ColorDrawBufferIndexes[i]; 673 st_manager_add_color_renderbuffer(st, fb, idx); 674 } 675} 676 677 678/** 679 * Called via glReadBuffer. 680 */ 681static void 682st_ReadBuffer(struct gl_context *ctx, GLenum buffer) 683{ 684 struct st_context *st = st_context(ctx); 685 struct gl_framebuffer *fb = ctx->ReadBuffer; 686 687 (void) buffer; 688 689 /* add the renderbuffer on demand */ 690 st_manager_add_color_renderbuffer(st, fb, fb->_ColorReadBufferIndex); 691} 692 693 694 695/** 696 * Called via ctx->Driver.MapRenderbuffer. 697 */ 698static void 699st_MapRenderbuffer(struct gl_context *ctx, 700 struct gl_renderbuffer *rb, 701 GLuint x, GLuint y, GLuint w, GLuint h, 702 GLbitfield mode, 703 GLubyte **mapOut, GLint *rowStrideOut) 704{ 705 struct st_context *st = st_context(ctx); 706 struct st_renderbuffer *strb = st_renderbuffer(rb); 707 struct pipe_context *pipe = st->pipe; 708 const GLboolean invert = rb->Name == 0; 709 unsigned usage; 710 GLuint y2; 711 712 if (strb->software) { 713 /* software-allocated renderbuffer (probably an accum buffer) */ 714 if (strb->data) { 715 GLint bpp = _mesa_get_format_bytes(strb->Base.Format); 716 GLint stride = _mesa_format_row_stride(strb->Base.Format, 717 strb->Base.Width); 718 *mapOut = (GLubyte *) strb->data + y * stride + x * bpp; 719 *rowStrideOut = stride; 720 } 721 else { 722 *mapOut = NULL; 723 *rowStrideOut = 0; 724 } 725 return; 726 } 727 728 usage = 0x0; 729 if (mode & GL_MAP_READ_BIT) 730 usage |= PIPE_TRANSFER_READ; 731 if (mode & GL_MAP_WRITE_BIT) 732 usage |= PIPE_TRANSFER_WRITE; 733 if (mode & GL_MAP_INVALIDATE_RANGE_BIT) 734 usage |= PIPE_TRANSFER_DISCARD_RANGE; 735 736 /* Note: y=0=bottom of buffer while y2=0=top of buffer. 737 * 'invert' will be true for window-system buffers and false for 738 * user-allocated renderbuffers and textures. 739 */ 740 if (invert) 741 y2 = strb->Base.Height - y - h; 742 else 743 y2 = y; 744 745 strb->transfer = pipe_get_transfer(pipe, 746 strb->texture, 747 strb->rtt_level, 748 strb->rtt_face + strb->rtt_slice, 749 usage, x, y2, w, h); 750 if (strb->transfer) { 751 GLubyte *map = pipe_transfer_map(pipe, strb->transfer); 752 if (invert) { 753 *rowStrideOut = -strb->transfer->stride; 754 map += (h - 1) * strb->transfer->stride; 755 } 756 else { 757 *rowStrideOut = strb->transfer->stride; 758 } 759 *mapOut = map; 760 } 761 else { 762 *mapOut = NULL; 763 *rowStrideOut = 0; 764 } 765} 766 767 768/** 769 * Called via ctx->Driver.UnmapRenderbuffer. 770 */ 771static void 772st_UnmapRenderbuffer(struct gl_context *ctx, 773 struct gl_renderbuffer *rb) 774{ 775 struct st_context *st = st_context(ctx); 776 struct st_renderbuffer *strb = st_renderbuffer(rb); 777 struct pipe_context *pipe = st->pipe; 778 779 if (strb->software) { 780 /* software-allocated renderbuffer (probably an accum buffer) */ 781 return; 782 } 783 784 pipe_transfer_unmap(pipe, strb->transfer); 785 pipe->transfer_destroy(pipe, strb->transfer); 786 strb->transfer = NULL; 787} 788 789 790 791void st_init_fbo_functions(struct dd_function_table *functions) 792{ 793#if FEATURE_EXT_framebuffer_object 794 functions->NewFramebuffer = st_new_framebuffer; 795 functions->NewRenderbuffer = st_new_renderbuffer; 796 functions->BindFramebuffer = st_bind_framebuffer; 797 functions->FramebufferRenderbuffer = _mesa_framebuffer_renderbuffer; 798 functions->RenderTexture = st_render_texture; 799 functions->FinishRenderTexture = st_finish_render_texture; 800 functions->ValidateFramebuffer = st_validate_framebuffer; 801#endif 802 803 functions->DrawBuffers = st_DrawBuffers; 804 functions->ReadBuffer = st_ReadBuffer; 805 806 functions->MapRenderbuffer = st_MapRenderbuffer; 807 functions->UnmapRenderbuffer = st_UnmapRenderbuffer; 808} 809 810 811