1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 1999-2006 Brian Paul 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 "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included 14 * in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 26#include "glheader.h" 27 28#include "context.h" 29#include "bufferobj.h" 30#include "fbobject.h" 31#include "formats.h" 32#include "glformats.h" 33#include "mtypes.h" 34#include "renderbuffer.h" 35#include "util/u_memory.h" 36#include "util/u_inlines.h" 37 38#include "state_tracker/st_context.h" 39#include "state_tracker/st_format.h" 40 41/** 42 * Called by FBO code to choose a PIPE_FORMAT_ for drawing surfaces. 43 */ 44static enum pipe_format 45choose_renderbuffer_format(struct gl_context *ctx, 46 GLenum internalFormat, unsigned sample_count, 47 unsigned storage_sample_count) 48{ 49 unsigned bindings; 50 if (_mesa_is_depth_or_stencil_format(internalFormat)) 51 bindings = PIPE_BIND_DEPTH_STENCIL; 52 else 53 bindings = PIPE_BIND_RENDER_TARGET; 54 return st_choose_format(st_context(ctx), internalFormat, GL_NONE, GL_NONE, 55 PIPE_TEXTURE_2D, sample_count, 56 storage_sample_count, bindings, 57 false, false); 58} 59 60 61 62/** 63 * Delete a gl_framebuffer. 64 * This is the default function for renderbuffer->Delete(). 65 * Drivers which subclass gl_renderbuffer should probably implement their 66 * own delete function. But the driver might also call this function to 67 * free the object in the end. 68 */ 69static void 70delete_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb) 71{ 72 if (ctx) { 73 pipe_surface_release(ctx->pipe, &rb->surface_srgb); 74 pipe_surface_release(ctx->pipe, &rb->surface_linear); 75 } else { 76 pipe_surface_release_no_context(&rb->surface_srgb); 77 pipe_surface_release_no_context(&rb->surface_linear); 78 } 79 rb->surface = NULL; 80 pipe_resource_reference(&rb->texture, NULL); 81 free(rb->data); 82 free(rb->Label); 83 free(rb); 84} 85 86static GLboolean 87renderbuffer_alloc_sw_storage(struct gl_context *ctx, 88 struct gl_renderbuffer *rb, 89 GLenum internalFormat, 90 GLuint width, GLuint height) 91{ 92 enum pipe_format format; 93 size_t size; 94 95 free(rb->data); 96 rb->data = NULL; 97 98 if (internalFormat == GL_RGBA16_SNORM) { 99 /* Special case for software accum buffers. Otherwise, if the 100 * call to choose_renderbuffer_format() fails (because the 101 * driver doesn't support signed 16-bit/channel colors) we'd 102 * just return without allocating the software accum buffer. 103 */ 104 format = PIPE_FORMAT_R16G16B16A16_SNORM; 105 } 106 else { 107 format = choose_renderbuffer_format(ctx, internalFormat, 0, 0); 108 109 /* Not setting gl_renderbuffer::Format here will cause 110 * FRAMEBUFFER_UNSUPPORTED and ValidateFramebuffer will not be called. 111 */ 112 if (format == PIPE_FORMAT_NONE) { 113 return GL_TRUE; 114 } 115 } 116 117 rb->Format = st_pipe_format_to_mesa_format(format); 118 119 size = _mesa_format_image_size(rb->Format, width, height, 1); 120 rb->data = malloc(size); 121 return rb->data != NULL; 122} 123 124 125/** 126 * gl_renderbuffer::AllocStorage() 127 * This is called to allocate the original drawing surface, and 128 * during window resize. 129 */ 130static GLboolean 131renderbuffer_alloc_storage(struct gl_context * ctx, 132 struct gl_renderbuffer *rb, 133 GLenum internalFormat, 134 GLuint width, GLuint height) 135{ 136 struct st_context *st = st_context(ctx); 137 struct pipe_screen *screen = ctx->screen; 138 enum pipe_format format = PIPE_FORMAT_NONE; 139 struct pipe_resource templ; 140 141 /* init renderbuffer fields */ 142 rb->Width = width; 143 rb->Height = height; 144 rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat); 145 rb->defined = GL_FALSE; /* undefined contents now */ 146 147 if (rb->software) { 148 return renderbuffer_alloc_sw_storage(ctx, rb, internalFormat, 149 width, height); 150 } 151 152 /* Free the old surface and texture 153 */ 154 pipe_surface_reference(&rb->surface_srgb, NULL); 155 pipe_surface_reference(&rb->surface_linear, NULL); 156 rb->surface = NULL; 157 pipe_resource_reference(&rb->texture, NULL); 158 159 /* If an sRGB framebuffer is unsupported, sRGB formats behave like linear 160 * formats. 161 */ 162 if (!ctx->Extensions.EXT_sRGB) { 163 internalFormat = _mesa_get_linear_internalformat(internalFormat); 164 } 165 166 /* Handle multisample renderbuffers first. 167 * 168 * From ARB_framebuffer_object: 169 * If <samples> is zero, then RENDERBUFFER_SAMPLES is set to zero. 170 * Otherwise <samples> represents a request for a desired minimum 171 * number of samples. Since different implementations may support 172 * different sample counts for multisampled rendering, the actual 173 * number of samples allocated for the renderbuffer image is 174 * implementation dependent. However, the resulting value for 175 * RENDERBUFFER_SAMPLES is guaranteed to be greater than or equal 176 * to <samples> and no more than the next larger sample count supported 177 * by the implementation. 178 * 179 * Find the supported number of samples >= rb->NumSamples 180 */ 181 if (rb->NumSamples > 0) { 182 unsigned start, start_storage; 183 184 if (ctx->Const.MaxSamples > 1 && rb->NumSamples == 1) { 185 /* don't try num_samples = 1 with drivers that support real msaa */ 186 start = 2; 187 start_storage = 2; 188 } else { 189 start = rb->NumSamples; 190 start_storage = rb->NumStorageSamples; 191 } 192 193 if (ctx->Extensions.AMD_framebuffer_multisample_advanced) { 194 if (rb->_BaseFormat == GL_DEPTH_COMPONENT || 195 rb->_BaseFormat == GL_DEPTH_STENCIL || 196 rb->_BaseFormat == GL_STENCIL_INDEX) { 197 /* Find a supported depth-stencil format. */ 198 for (unsigned samples = start; 199 samples <= ctx->Const.MaxDepthStencilFramebufferSamples; 200 samples++) { 201 format = choose_renderbuffer_format(ctx, internalFormat, 202 samples, samples); 203 204 if (format != PIPE_FORMAT_NONE) { 205 rb->NumSamples = samples; 206 rb->NumStorageSamples = samples; 207 break; 208 } 209 } 210 } else { 211 /* Find a supported color format, samples >= storage_samples. */ 212 for (unsigned storage_samples = start_storage; 213 storage_samples <= ctx->Const.MaxColorFramebufferStorageSamples; 214 storage_samples++) { 215 for (unsigned samples = MAX2(start, storage_samples); 216 samples <= ctx->Const.MaxColorFramebufferSamples; 217 samples++) { 218 format = choose_renderbuffer_format(ctx, internalFormat, 219 samples, 220 storage_samples); 221 222 if (format != PIPE_FORMAT_NONE) { 223 rb->NumSamples = samples; 224 rb->NumStorageSamples = storage_samples; 225 goto found; 226 } 227 } 228 } 229 found:; 230 } 231 } else { 232 for (unsigned samples = start; samples <= ctx->Const.MaxSamples; 233 samples++) { 234 format = choose_renderbuffer_format(ctx, internalFormat, 235 samples, samples); 236 237 if (format != PIPE_FORMAT_NONE) { 238 rb->NumSamples = samples; 239 rb->NumStorageSamples = samples; 240 break; 241 } 242 } 243 } 244 } else { 245 format = choose_renderbuffer_format(ctx, internalFormat, 0, 0); 246 } 247 248 /* Not setting gl_renderbuffer::Format here will cause 249 * FRAMEBUFFER_UNSUPPORTED and ValidateFramebuffer will not be called. 250 */ 251 if (format == PIPE_FORMAT_NONE) { 252 return GL_TRUE; 253 } 254 255 rb->Format = st_pipe_format_to_mesa_format(format); 256 257 if (width == 0 || height == 0) { 258 /* if size is zero, nothing to allocate */ 259 return GL_TRUE; 260 } 261 262 /* Setup new texture template. 263 */ 264 memset(&templ, 0, sizeof(templ)); 265 templ.target = st->internal_target; 266 templ.format = format; 267 templ.width0 = width; 268 templ.height0 = height; 269 templ.depth0 = 1; 270 templ.array_size = 1; 271 templ.nr_samples = rb->NumSamples; 272 templ.nr_storage_samples = rb->NumStorageSamples; 273 274 if (util_format_is_depth_or_stencil(format)) { 275 templ.bind = PIPE_BIND_DEPTH_STENCIL; 276 } 277 else if (rb->Name != 0) { 278 /* this is a user-created renderbuffer */ 279 templ.bind = PIPE_BIND_RENDER_TARGET; 280 } 281 else { 282 /* this is a window-system buffer */ 283 templ.bind = (PIPE_BIND_DISPLAY_TARGET | 284 PIPE_BIND_RENDER_TARGET); 285 } 286 287 rb->texture = screen->resource_create(screen, &templ); 288 289 if (!rb->texture) 290 return FALSE; 291 292 _mesa_update_renderbuffer_surface(ctx, rb); 293 return rb->surface != NULL; 294} 295 296/** 297 * Initialize the fields of a gl_renderbuffer to default values. 298 */ 299void 300_mesa_init_renderbuffer(struct gl_renderbuffer *rb, GLuint name) 301{ 302 GET_CURRENT_CONTEXT(ctx); 303 304 rb->ClassID = 0; 305 rb->Name = name; 306 rb->RefCount = 1; 307 rb->Delete = delete_renderbuffer; 308 309 /* The rest of these should be set later by the caller of this function or 310 * the AllocStorage method: 311 */ 312 rb->AllocStorage = NULL; 313 314 rb->Width = 0; 315 rb->Height = 0; 316 rb->Depth = 0; 317 318 /* In GL 3, the initial format is GL_RGBA according to Table 6.26 319 * on page 302 of the GL 3.3 spec. 320 * 321 * In GLES 3, the initial format is GL_RGBA4 according to Table 6.15 322 * on page 258 of the GLES 3.0.4 spec. 323 * 324 * If the context is current, set the initial format based on the 325 * specs. If the context is not current, we cannot determine the 326 * API, so default to GL_RGBA. 327 */ 328 if (ctx && _mesa_is_gles(ctx)) { 329 rb->InternalFormat = GL_RGBA4; 330 } else { 331 rb->InternalFormat = GL_RGBA; 332 } 333 334 rb->Format = MESA_FORMAT_NONE; 335 336 rb->AllocStorage = renderbuffer_alloc_storage; 337} 338 339static void 340validate_and_init_renderbuffer_attachment(struct gl_framebuffer *fb, 341 gl_buffer_index bufferName, 342 struct gl_renderbuffer *rb) 343{ 344 assert(fb); 345 assert(rb); 346 assert(bufferName < BUFFER_COUNT); 347 348 /* There should be no previous renderbuffer on this attachment point, 349 * with the exception of depth/stencil since the same renderbuffer may 350 * be used for both. 351 */ 352 assert(bufferName == BUFFER_DEPTH || 353 bufferName == BUFFER_STENCIL || 354 fb->Attachment[bufferName].Renderbuffer == NULL); 355 356 /* winsys vs. user-created buffer cross check */ 357 if (_mesa_is_user_fbo(fb)) { 358 assert(rb->Name); 359 } 360 else { 361 assert(!rb->Name); 362 } 363 364 fb->Attachment[bufferName].Type = GL_RENDERBUFFER_EXT; 365 fb->Attachment[bufferName].Complete = GL_TRUE; 366} 367 368 369/** 370 * Attach a renderbuffer to a framebuffer. 371 * \param bufferName one of the BUFFER_x tokens 372 * 373 * This function avoids adding a reference and is therefore intended to be 374 * used with a freshly created renderbuffer. 375 */ 376void 377_mesa_attach_and_own_rb(struct gl_framebuffer *fb, 378 gl_buffer_index bufferName, 379 struct gl_renderbuffer *rb) 380{ 381 assert(rb->RefCount == 1); 382 383 validate_and_init_renderbuffer_attachment(fb, bufferName, rb); 384 385 _mesa_reference_renderbuffer(&fb->Attachment[bufferName].Renderbuffer, 386 NULL); 387 fb->Attachment[bufferName].Renderbuffer = rb; 388} 389 390/** 391 * Attach a renderbuffer to a framebuffer. 392 * \param bufferName one of the BUFFER_x tokens 393 */ 394void 395_mesa_attach_and_reference_rb(struct gl_framebuffer *fb, 396 gl_buffer_index bufferName, 397 struct gl_renderbuffer *rb) 398{ 399 validate_and_init_renderbuffer_attachment(fb, bufferName, rb); 400 _mesa_reference_renderbuffer(&fb->Attachment[bufferName].Renderbuffer, rb); 401} 402 403 404/** 405 * Remove the named renderbuffer from the given framebuffer. 406 * \param bufferName one of the BUFFER_x tokens 407 */ 408void 409_mesa_remove_renderbuffer(struct gl_framebuffer *fb, 410 gl_buffer_index bufferName) 411{ 412 assert(bufferName < BUFFER_COUNT); 413 _mesa_reference_renderbuffer(&fb->Attachment[bufferName].Renderbuffer, 414 NULL); 415} 416 417 418/** 419 * Set *ptr to point to rb. If *ptr points to another renderbuffer, 420 * dereference that buffer first. The new renderbuffer's refcount will 421 * be incremented. The old renderbuffer's refcount will be decremented. 422 * This is normally only called from the _mesa_reference_renderbuffer() macro 423 * when there's a real pointer change. 424 */ 425void 426_mesa_reference_renderbuffer_(struct gl_renderbuffer **ptr, 427 struct gl_renderbuffer *rb) 428{ 429 if (*ptr) { 430 /* Unreference the old renderbuffer */ 431 struct gl_renderbuffer *oldRb = *ptr; 432 433 assert(oldRb->RefCount > 0); 434 435 if (p_atomic_dec_zero(&oldRb->RefCount)) { 436 GET_CURRENT_CONTEXT(ctx); 437 oldRb->Delete(ctx, oldRb); 438 } 439 } 440 441 if (rb) { 442 /* reference new renderbuffer */ 443 p_atomic_inc(&rb->RefCount); 444 } 445 446 *ptr = rb; 447} 448 449void 450_mesa_map_renderbuffer(struct gl_context *ctx, 451 struct gl_renderbuffer *rb, 452 GLuint x, GLuint y, GLuint w, GLuint h, 453 GLbitfield mode, 454 GLubyte **mapOut, GLint *rowStrideOut, 455 bool flip_y) 456{ 457 struct pipe_context *pipe = ctx->pipe; 458 const GLboolean invert = flip_y; 459 GLuint y2; 460 GLubyte *map; 461 462 if (rb->software) { 463 /* software-allocated renderbuffer (probably an accum buffer) */ 464 if (rb->data) { 465 GLint bpp = _mesa_get_format_bytes(rb->Format); 466 GLint stride = _mesa_format_row_stride(rb->Format, 467 rb->Width); 468 *mapOut = (GLubyte *) rb->data + y * stride + x * bpp; 469 *rowStrideOut = stride; 470 } 471 else { 472 *mapOut = NULL; 473 *rowStrideOut = 0; 474 } 475 return; 476 } 477 478 /* Check for unexpected flags */ 479 assert((mode & ~(GL_MAP_READ_BIT | 480 GL_MAP_WRITE_BIT | 481 GL_MAP_INVALIDATE_RANGE_BIT)) == 0); 482 483 const enum pipe_map_flags transfer_flags = 484 _mesa_access_flags_to_transfer_flags(mode, false); 485 486 /* Note: y=0=bottom of buffer while y2=0=top of buffer. 487 * 'invert' will be true for window-system buffers and false for 488 * user-allocated renderbuffers and textures. 489 */ 490 if (invert) 491 y2 = rb->Height - y - h; 492 else 493 y2 = y; 494 495 map = pipe_texture_map(pipe, 496 rb->texture, 497 rb->surface->u.tex.level, 498 rb->surface->u.tex.first_layer, 499 transfer_flags, x, y2, w, h, &rb->transfer); 500 if (map) { 501 if (invert) { 502 *rowStrideOut = -(int) rb->transfer->stride; 503 map += (h - 1) * rb->transfer->stride; 504 } 505 else { 506 *rowStrideOut = rb->transfer->stride; 507 } 508 *mapOut = map; 509 } 510 else { 511 *mapOut = NULL; 512 *rowStrideOut = 0; 513 } 514} 515 516void 517_mesa_unmap_renderbuffer(struct gl_context *ctx, 518 struct gl_renderbuffer *rb) 519{ 520 struct pipe_context *pipe = ctx->pipe; 521 522 if (rb->software) { 523 /* software-allocated renderbuffer (probably an accum buffer) */ 524 return; 525 } 526 527 pipe_texture_unmap(pipe, rb->transfer); 528 rb->transfer = NULL; 529} 530 531void 532_mesa_regen_renderbuffer_surface(struct gl_context *ctx, 533 struct gl_renderbuffer *rb) 534{ 535 struct pipe_context *pipe = ctx->pipe; 536 struct pipe_resource *resource = rb->texture; 537 538 struct pipe_surface **psurf = 539 rb->surface_srgb ? &rb->surface_srgb : &rb->surface_linear; 540 struct pipe_surface *surf = *psurf; 541 /* create a new pipe_surface */ 542 struct pipe_surface surf_tmpl; 543 memset(&surf_tmpl, 0, sizeof(surf_tmpl)); 544 surf_tmpl.format = surf->format; 545 surf_tmpl.nr_samples = rb->rtt_nr_samples; 546 surf_tmpl.u.tex.level = surf->u.tex.level; 547 surf_tmpl.u.tex.first_layer = surf->u.tex.first_layer; 548 surf_tmpl.u.tex.last_layer = surf->u.tex.last_layer; 549 550 /* create -> destroy to avoid blowing up cached surfaces */ 551 surf = pipe->create_surface(pipe, resource, &surf_tmpl); 552 pipe_surface_release(pipe, psurf); 553 *psurf = surf; 554 555 rb->surface = *psurf; 556} 557 558/** 559 * Create or update the pipe_surface of a FBO renderbuffer. 560 * This is usually called after st_finalize_texture. 561 */ 562void 563_mesa_update_renderbuffer_surface(struct gl_context *ctx, 564 struct gl_renderbuffer *rb) 565{ 566 struct pipe_context *pipe = ctx->pipe; 567 struct pipe_resource *resource = rb->texture; 568 const struct gl_texture_object *stTexObj = NULL; 569 unsigned rtt_width = rb->Width; 570 unsigned rtt_height = rb->Height; 571 unsigned rtt_depth = rb->Depth; 572 573 /* 574 * For winsys fbo, it is possible that the renderbuffer is sRGB-capable but 575 * the format of rb->texture is linear (because we have no control over 576 * the format). Check rb->Format instead of rb->texture->format 577 * to determine if the rb is sRGB-capable. 578 */ 579 boolean enable_srgb = ctx->Color.sRGBEnabled && 580 _mesa_is_format_srgb(rb->Format); 581 enum pipe_format format = resource->format; 582 583 if (rb->is_rtt) { 584 stTexObj = rb->TexImage->TexObject; 585 if (stTexObj->surface_based) 586 format = stTexObj->surface_format; 587 } 588 589 format = enable_srgb ? util_format_srgb(format) : util_format_linear(format); 590 591 if (resource->target == PIPE_TEXTURE_1D_ARRAY) { 592 rtt_depth = rtt_height; 593 rtt_height = 1; 594 } 595 596 /* find matching mipmap level size */ 597 unsigned level; 598 for (level = 0; level <= resource->last_level; level++) { 599 if (u_minify(resource->width0, level) == rtt_width && 600 u_minify(resource->height0, level) == rtt_height && 601 (resource->target != PIPE_TEXTURE_3D || 602 u_minify(resource->depth0, level) == rtt_depth)) { 603 break; 604 } 605 } 606 assert(level <= resource->last_level); 607 608 /* determine the layer bounds */ 609 unsigned first_layer, last_layer; 610 if (rb->rtt_layered) { 611 first_layer = 0; 612 last_layer = util_max_layer(rb->texture, level); 613 } 614 else { 615 first_layer = 616 last_layer = rb->rtt_face + rb->rtt_slice; 617 } 618 619 /* Adjust for texture views */ 620 if (rb->is_rtt && resource->array_size > 1 && 621 stTexObj->Immutable) { 622 const struct gl_texture_object *tex = stTexObj; 623 first_layer += tex->Attrib.MinLayer; 624 if (!rb->rtt_layered) 625 last_layer += tex->Attrib.MinLayer; 626 else 627 last_layer = MIN2(first_layer + tex->Attrib.NumLayers - 1, 628 last_layer); 629 } 630 631 struct pipe_surface **psurf = 632 enable_srgb ? &rb->surface_srgb : &rb->surface_linear; 633 struct pipe_surface *surf = *psurf; 634 635 if (!surf || 636 surf->texture->nr_samples != rb->NumSamples || 637 surf->texture->nr_storage_samples != rb->NumStorageSamples || 638 surf->format != format || 639 surf->texture != resource || 640 surf->width != rtt_width || 641 surf->height != rtt_height || 642 surf->nr_samples != rb->rtt_nr_samples || 643 surf->u.tex.level != level || 644 surf->u.tex.first_layer != first_layer || 645 surf->u.tex.last_layer != last_layer) { 646 /* create a new pipe_surface */ 647 struct pipe_surface surf_tmpl; 648 memset(&surf_tmpl, 0, sizeof(surf_tmpl)); 649 surf_tmpl.format = format; 650 surf_tmpl.nr_samples = rb->rtt_nr_samples; 651 surf_tmpl.u.tex.level = level; 652 surf_tmpl.u.tex.first_layer = first_layer; 653 surf_tmpl.u.tex.last_layer = last_layer; 654 655 /* create -> destroy to avoid blowing up cached surfaces */ 656 struct pipe_surface *surf = pipe->create_surface(pipe, resource, &surf_tmpl); 657 pipe_surface_release(pipe, psurf); 658 *psurf = surf; 659 } 660 rb->surface = *psurf; 661} 662