st_cb_fbo.c revision ef9a619ba9c49e27ac3fd1c2925ae6b288cd4a09
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/renderbuffer.h" 42 43#include "pipe/p_context.h" 44#include "pipe/p_defines.h" 45#include "pipe/p_screen.h" 46#include "st_context.h" 47#include "st_cb_fbo.h" 48#include "st_cb_flush.h" 49#include "st_format.h" 50#include "st_texture.h" 51#include "st_manager.h" 52 53#include "util/u_format.h" 54#include "util/u_inlines.h" 55 56 57/** 58 * gl_renderbuffer::AllocStorage() 59 * This is called to allocate the original drawing surface, and 60 * during window resize. 61 */ 62static GLboolean 63st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb, 64 GLenum internalFormat, 65 GLuint width, GLuint height) 66{ 67 struct pipe_screen *screen = ctx->st->pipe->screen; 68 struct st_renderbuffer *strb = st_renderbuffer(rb); 69 enum pipe_format format; 70 71 if (strb->format != PIPE_FORMAT_NONE) 72 format = strb->format; 73 else 74 format = st_choose_renderbuffer_format(screen, internalFormat); 75 76 /* init renderbuffer fields */ 77 strb->Base.Width = width; 78 strb->Base.Height = height; 79 strb->Base.Format = st_pipe_format_to_mesa_format(format); 80 strb->Base.DataType = st_format_datatype(format); 81 82 strb->defined = GL_FALSE; /* undefined contents now */ 83 84 if (strb->software) { 85 size_t size; 86 87 free(strb->data); 88 89 assert(strb->format != PIPE_FORMAT_NONE); 90 91 strb->stride = util_format_get_stride(strb->format, width); 92 size = util_format_get_2d_size(strb->format, strb->stride, height); 93 94 strb->data = malloc(size); 95 96 return strb->data != NULL; 97 } 98 else { 99 struct pipe_resource template; 100 101 /* Free the old surface and texture 102 */ 103 pipe_surface_reference( &strb->surface, NULL ); 104 pipe_resource_reference( &strb->texture, NULL ); 105 pipe_sampler_view_reference(&strb->sampler_view, NULL); 106 107 /* Setup new texture template. 108 */ 109 memset(&template, 0, sizeof(template)); 110 template.target = PIPE_TEXTURE_2D; 111 template.format = format; 112 template.width0 = width; 113 template.height0 = height; 114 template.depth0 = 1; 115 template.last_level = 0; 116 template.nr_samples = rb->NumSamples; 117 if (util_format_is_depth_or_stencil(format)) { 118 template.bind = PIPE_BIND_DEPTH_STENCIL; 119 } 120 else { 121 template.bind = (PIPE_BIND_DISPLAY_TARGET | 122 PIPE_BIND_RENDER_TARGET); 123 } 124 125 strb->texture = screen->resource_create(screen, &template); 126 127 if (!strb->texture) 128 return FALSE; 129 130 strb->surface = screen->get_tex_surface(screen, 131 strb->texture, 132 0, 0, 0, 133 template.bind); 134 if (strb->surface) { 135 assert(strb->surface->texture); 136 assert(strb->surface->format); 137 assert(strb->surface->width == width); 138 assert(strb->surface->height == height); 139 } 140 141 return strb->surface != NULL; 142 } 143} 144 145 146/** 147 * gl_renderbuffer::Delete() 148 */ 149static void 150st_renderbuffer_delete(struct gl_renderbuffer *rb) 151{ 152 struct st_renderbuffer *strb = st_renderbuffer(rb); 153 ASSERT(strb); 154 pipe_surface_reference(&strb->surface, NULL); 155 pipe_resource_reference(&strb->texture, NULL); 156 pipe_sampler_view_reference(&strb->sampler_view, NULL); 157 free(strb->data); 158 free(strb); 159} 160 161 162/** 163 * gl_renderbuffer::GetPointer() 164 */ 165static void * 166null_get_pointer(GLcontext * ctx, struct gl_renderbuffer *rb, 167 GLint x, GLint y) 168{ 169 /* By returning NULL we force all software rendering to go through 170 * the span routines. 171 */ 172#if 0 173 assert(0); /* Should never get called with softpipe */ 174#endif 175 return NULL; 176} 177 178 179/** 180 * Called via ctx->Driver.NewFramebuffer() 181 */ 182static struct gl_framebuffer * 183st_new_framebuffer(GLcontext *ctx, GLuint name) 184{ 185 /* XXX not sure we need to subclass gl_framebuffer for pipe */ 186 return _mesa_new_framebuffer(ctx, name); 187} 188 189 190/** 191 * Called via ctx->Driver.NewRenderbuffer() 192 */ 193static struct gl_renderbuffer * 194st_new_renderbuffer(GLcontext *ctx, GLuint name) 195{ 196 struct st_renderbuffer *strb = ST_CALLOC_STRUCT(st_renderbuffer); 197 if (strb) { 198 _mesa_init_renderbuffer(&strb->Base, name); 199 strb->Base.Delete = st_renderbuffer_delete; 200 strb->Base.AllocStorage = st_renderbuffer_alloc_storage; 201 strb->Base.GetPointer = null_get_pointer; 202 strb->format = PIPE_FORMAT_NONE; 203 return &strb->Base; 204 } 205 return NULL; 206} 207 208 209/** 210 * Allocate a renderbuffer for a an on-screen window (not a user-created 211 * renderbuffer). The window system code determines the format. 212 */ 213struct gl_renderbuffer * 214st_new_renderbuffer_fb(enum pipe_format format, int samples, boolean sw) 215{ 216 struct st_renderbuffer *strb; 217 218 strb = ST_CALLOC_STRUCT(st_renderbuffer); 219 if (!strb) { 220 _mesa_error(NULL, GL_OUT_OF_MEMORY, "creating renderbuffer"); 221 return NULL; 222 } 223 224 _mesa_init_renderbuffer(&strb->Base, 0); 225 strb->Base.ClassID = 0x4242; /* just a unique value */ 226 strb->Base.NumSamples = samples; 227 strb->Base.Format = st_pipe_format_to_mesa_format(format); 228 strb->Base.DataType = st_format_datatype(format); 229 strb->format = format; 230 strb->software = sw; 231 232 switch (format) { 233 case PIPE_FORMAT_B8G8R8A8_UNORM: 234 case PIPE_FORMAT_A8R8G8B8_UNORM: 235 case PIPE_FORMAT_B8G8R8X8_UNORM: 236 case PIPE_FORMAT_X8R8G8B8_UNORM: 237 case PIPE_FORMAT_B5G5R5A1_UNORM: 238 case PIPE_FORMAT_B4G4R4A4_UNORM: 239 case PIPE_FORMAT_B5G6R5_UNORM: 240 strb->Base.InternalFormat = GL_RGBA; 241 break; 242 case PIPE_FORMAT_Z16_UNORM: 243 strb->Base.InternalFormat = GL_DEPTH_COMPONENT16; 244 break; 245 case PIPE_FORMAT_Z32_UNORM: 246 strb->Base.InternalFormat = GL_DEPTH_COMPONENT32; 247 break; 248 case PIPE_FORMAT_Z24_UNORM_S8_USCALED: 249 case PIPE_FORMAT_S8_USCALED_Z24_UNORM: 250 case PIPE_FORMAT_Z24X8_UNORM: 251 case PIPE_FORMAT_X8Z24_UNORM: 252 strb->Base.InternalFormat = GL_DEPTH24_STENCIL8_EXT; 253 break; 254 case PIPE_FORMAT_S8_USCALED: 255 strb->Base.InternalFormat = GL_STENCIL_INDEX8_EXT; 256 break; 257 case PIPE_FORMAT_R16G16B16A16_SNORM: 258 strb->Base.InternalFormat = GL_RGBA16; 259 break; 260 default: 261 _mesa_problem(NULL, 262 "Unexpected format in st_new_renderbuffer_fb"); 263 free(strb); 264 return NULL; 265 } 266 267 /* st-specific methods */ 268 strb->Base.Delete = st_renderbuffer_delete; 269 strb->Base.AllocStorage = st_renderbuffer_alloc_storage; 270 strb->Base.GetPointer = null_get_pointer; 271 272 /* surface is allocated in st_renderbuffer_alloc_storage() */ 273 strb->surface = NULL; 274 275 return &strb->Base; 276} 277 278 279 280 281/** 282 * Called via ctx->Driver.BindFramebufferEXT(). 283 */ 284static void 285st_bind_framebuffer(GLcontext *ctx, GLenum target, 286 struct gl_framebuffer *fb, struct gl_framebuffer *fbread) 287{ 288 289} 290 291/** 292 * Called by ctx->Driver.FramebufferRenderbuffer 293 */ 294static void 295st_framebuffer_renderbuffer(GLcontext *ctx, 296 struct gl_framebuffer *fb, 297 GLenum attachment, 298 struct gl_renderbuffer *rb) 299{ 300 /* XXX no need for derivation? */ 301 _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb); 302} 303 304 305/** 306 * Called by ctx->Driver.RenderTexture 307 */ 308static void 309st_render_texture(GLcontext *ctx, 310 struct gl_framebuffer *fb, 311 struct gl_renderbuffer_attachment *att) 312{ 313 struct pipe_screen *screen = ctx->st->pipe->screen; 314 struct st_renderbuffer *strb; 315 struct gl_renderbuffer *rb; 316 struct pipe_resource *pt = st_get_texobj_texture(att->Texture); 317 struct st_texture_object *stObj; 318 const struct gl_texture_image *texImage; 319 GLint pt_level; 320 321 /* When would this fail? Perhaps assert? */ 322 if (!pt) 323 return; 324 325 /* The first gallium texture level = Mesa BaseLevel */ 326 pt_level = MAX2(0, (GLint) att->TextureLevel - att->Texture->BaseLevel); 327 texImage = att->Texture->Image[att->CubeMapFace][pt_level]; 328 329 /* create new renderbuffer which wraps the texture image */ 330 rb = st_new_renderbuffer(ctx, 0); 331 if (!rb) { 332 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture()"); 333 return; 334 } 335 336 _mesa_reference_renderbuffer(&att->Renderbuffer, rb); 337 assert(rb->RefCount == 1); 338 rb->AllocStorage = NULL; /* should not get called */ 339 strb = st_renderbuffer(rb); 340 341 assert(strb->Base.RefCount > 0); 342 343 /* get the texture for the texture object */ 344 stObj = st_texture_object(att->Texture); 345 346 /* point renderbuffer at texobject */ 347 strb->rtt = stObj; 348 strb->rtt_level = pt_level; 349 strb->rtt_face = att->CubeMapFace; 350 strb->rtt_slice = att->Zoffset; 351 352 rb->Width = texImage->Width2; 353 rb->Height = texImage->Height2; 354 rb->_BaseFormat = texImage->_BaseFormat; 355 /*printf("***** render to texture level %d: %d x %d\n", att->TextureLevel, rb->Width, rb->Height);*/ 356 357 /*printf("***** pipe texture %d x %d\n", pt->width0, pt->height0);*/ 358 359 pipe_resource_reference( &strb->texture, pt ); 360 361 pipe_surface_reference(&strb->surface, NULL); 362 363 pipe_sampler_view_reference(&strb->sampler_view, st_get_texture_sampler_view(stObj)); 364 365 assert(strb->rtt_level <= strb->texture->last_level); 366 367 /* new surface for rendering into the texture */ 368 strb->surface = screen->get_tex_surface(screen, 369 strb->texture, 370 strb->rtt_face, 371 strb->rtt_level, 372 strb->rtt_slice, 373 PIPE_BIND_RENDER_TARGET); 374 375 strb->format = pt->format; 376 377 strb->Base.Format = st_pipe_format_to_mesa_format(pt->format); 378 strb->Base.DataType = st_format_datatype(pt->format); 379 380 /* 381 printf("RENDER TO TEXTURE obj=%p pt=%p surf=%p %d x %d\n", 382 att->Texture, pt, strb->surface, rb->Width, rb->Height); 383 */ 384 385 /* Invalidate buffer state so that the pipe's framebuffer state 386 * gets updated. 387 * That's where the new renderbuffer (which we just created) gets 388 * passed to the pipe as a (color/depth) render target. 389 */ 390 st_invalidate_state(ctx, _NEW_BUFFERS); 391} 392 393 394/** 395 * Called via ctx->Driver.FinishRenderTexture. 396 */ 397static void 398st_finish_render_texture(GLcontext *ctx, 399 struct gl_renderbuffer_attachment *att) 400{ 401 struct st_renderbuffer *strb = st_renderbuffer(att->Renderbuffer); 402 403 if (!strb) 404 return; 405 406 st_flush( ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL ); 407 408 strb->rtt = NULL; 409 410 /* 411 printf("FINISH RENDER TO TEXTURE surf=%p\n", strb->surface); 412 */ 413 414 /* restore previous framebuffer state */ 415 st_invalidate_state(ctx, _NEW_BUFFERS); 416} 417 418 419/** 420 * Validate a renderbuffer attachment for a particular usage. 421 */ 422 423static GLboolean 424st_validate_attachment(struct pipe_screen *screen, 425 const struct gl_renderbuffer_attachment *att, 426 GLuint usage) 427{ 428 const struct st_texture_object *stObj = 429 st_texture_object(att->Texture); 430 431 /** 432 * Only validate texture attachments for now, since 433 * st_renderbuffer_alloc_storage makes sure that 434 * the format is supported. 435 */ 436 437 if (att->Type != GL_TEXTURE) 438 return GL_TRUE; 439 440 if (!stObj) 441 return GL_FALSE; 442 443 return screen->is_format_supported(screen, stObj->pt->format, 444 PIPE_TEXTURE_2D, 445 usage, 0); 446} 447 448/** 449 * Check that the framebuffer configuration is valid in terms of what 450 * the driver can support. 451 * 452 * For Gallium we only supports combined Z+stencil, not separate buffers. 453 */ 454static void 455st_validate_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb) 456{ 457 struct pipe_screen *screen = ctx->st->pipe->screen; 458 const struct gl_renderbuffer *depthRb = 459 fb->Attachment[BUFFER_DEPTH].Renderbuffer; 460 const struct gl_renderbuffer *stencilRb = 461 fb->Attachment[BUFFER_STENCIL].Renderbuffer; 462 GLuint i; 463 464 if (stencilRb && depthRb && stencilRb != depthRb) { 465 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; 466 return; 467 } 468 469 if (!st_validate_attachment(screen, 470 &fb->Attachment[BUFFER_DEPTH], 471 PIPE_BIND_DEPTH_STENCIL)) { 472 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; 473 return; 474 } 475 if (!st_validate_attachment(screen, 476 &fb->Attachment[BUFFER_STENCIL], 477 PIPE_BIND_DEPTH_STENCIL)) { 478 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; 479 return; 480 } 481 for (i = 0; i < ctx->Const.MaxColorAttachments; i++) { 482 if (!st_validate_attachment(screen, 483 &fb->Attachment[BUFFER_COLOR0 + i], 484 PIPE_BIND_RENDER_TARGET)) { 485 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; 486 return; 487 } 488 } 489} 490 491 492/** 493 * Called via glDrawBuffer. 494 */ 495static void 496st_DrawBuffers(GLcontext *ctx, GLsizei count, const GLenum *buffers) 497{ 498 GLframebuffer *fb = ctx->DrawBuffer; 499 GLuint i; 500 501 (void) count; 502 (void) buffers; 503 504 /* add the renderbuffers on demand */ 505 for (i = 0; i < fb->_NumColorDrawBuffers; i++) { 506 gl_buffer_index idx = fb->_ColorDrawBufferIndexes[i]; 507 st_manager_add_color_renderbuffer(ctx->st, fb, idx); 508 } 509} 510 511 512/** 513 * Called via glReadBuffer. 514 */ 515static void 516st_ReadBuffer(GLcontext *ctx, GLenum buffer) 517{ 518 GLframebuffer *fb = ctx->ReadBuffer; 519 520 (void) buffer; 521 522 /* add the renderbuffer on demand */ 523 st_manager_add_color_renderbuffer(ctx->st, fb, fb->_ColorReadBufferIndex); 524} 525 526 527void st_init_fbo_functions(struct dd_function_table *functions) 528{ 529 functions->NewFramebuffer = st_new_framebuffer; 530 functions->NewRenderbuffer = st_new_renderbuffer; 531 functions->BindFramebuffer = st_bind_framebuffer; 532 functions->FramebufferRenderbuffer = st_framebuffer_renderbuffer; 533 functions->RenderTexture = st_render_texture; 534 functions->FinishRenderTexture = st_finish_render_texture; 535 functions->ValidateFramebuffer = st_validate_framebuffer; 536 /* no longer needed by core Mesa, drivers handle resizes... 537 functions->ResizeBuffers = st_resize_buffers; 538 */ 539 540 functions->DrawBuffers = st_DrawBuffers; 541 functions->ReadBuffer = st_ReadBuffer; 542} 543 544struct pipe_sampler_view * 545st_renderbuffer_get_sampler_view(struct st_renderbuffer *rb, 546 struct pipe_context *pipe) 547{ 548 if (!rb->sampler_view) { 549 rb->sampler_view = st_create_texture_sampler_view(pipe, rb->texture); 550 } 551 552 return rb->sampler_view; 553} 554