st_cb_fbo.c revision 0a56a4968786bd93d9117af2a0a3bda13ea71c4d
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/renderbuffer.h" 41 42#include "pipe/p_context.h" 43#include "pipe/p_defines.h" 44#include "pipe/p_screen.h" 45#include "st_context.h" 46#include "st_cb_fbo.h" 47#include "st_cb_texture.h" 48#include "st_format.h" 49#include "st_public.h" 50#include "st_texture.h" 51 52 53 54/** 55 * Compute the renderbuffer's Red/Green/EtcBit fields from the pipe format. 56 */ 57static int 58init_renderbuffer_bits(struct st_renderbuffer *strb, 59 enum pipe_format pipeFormat) 60{ 61 struct pipe_format_info info; 62 63 if (!st_get_format_info( pipeFormat, &info )) { 64 assert( 0 ); 65 } 66 67 strb->Base._ActualFormat = info.base_format; 68 strb->Base.RedBits = info.red_bits; 69 strb->Base.GreenBits = info.green_bits; 70 strb->Base.BlueBits = info.blue_bits; 71 strb->Base.AlphaBits = info.alpha_bits; 72 strb->Base.DepthBits = info.depth_bits; 73 strb->Base.StencilBits = info.stencil_bits; 74 strb->Base.DataType = st_format_datatype(pipeFormat); 75 76 return info.size; 77} 78 79/** 80 * gl_renderbuffer::AllocStorage() 81 * This is called to allocate the original drawing surface, and 82 * during window resize. 83 */ 84static GLboolean 85st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb, 86 GLenum internalFormat, 87 GLuint width, GLuint height) 88{ 89 struct pipe_context *pipe = ctx->st->pipe; 90 struct st_renderbuffer *strb = st_renderbuffer(rb); 91 struct pipe_texture template; 92 unsigned surface_usage; 93 94 /* Free the old surface and texture 95 */ 96 pipe_surface_reference( &strb->surface, NULL ); 97 pipe_texture_reference( &strb->texture, NULL ); 98 99 /* Setup new texture template. 100 */ 101 memset(&template, 0, sizeof(template)); 102 template.target = PIPE_TEXTURE_2D; 103 if (strb->format != PIPE_FORMAT_NONE) { 104 template.format = strb->format; 105 } 106 else { 107 template.format = st_choose_renderbuffer_format(pipe, internalFormat); 108 } 109 pf_get_block(template.format, &template.block); 110 template.width[0] = width; 111 template.height[0] = height; 112 template.depth[0] = 1; 113 template.last_level = 0; 114 template.nr_samples = rb->NumSamples; 115 if (pf_is_depth_stencil(template.format)) { 116 template.tex_usage = PIPE_TEXTURE_USAGE_DEPTH_STENCIL; 117 } 118 else { 119 template.tex_usage = (PIPE_TEXTURE_USAGE_DISPLAY_TARGET | 120 PIPE_TEXTURE_USAGE_RENDER_TARGET); 121 } 122 123 /* init renderbuffer fields */ 124 strb->Base.Width = width; 125 strb->Base.Height = height; 126 init_renderbuffer_bits(strb, template.format); 127 128 /* Probably need dedicated flags for surface usage too: 129 */ 130 surface_usage = (PIPE_BUFFER_USAGE_GPU_READ | 131 PIPE_BUFFER_USAGE_GPU_WRITE); 132#if 0 133 PIPE_BUFFER_USAGE_CPU_READ | 134 PIPE_BUFFER_USAGE_CPU_WRITE); 135#endif 136 137 strb->texture = pipe->screen->texture_create( pipe->screen, 138 &template ); 139 140 /* Special path for accum buffers. 141 * 142 * Try a different surface format. Since accum buffers are s/w 143 * only for now, the surface pixel format doesn't really matter, 144 * only that the buffer is large enough. 145 */ 146 if (!strb->texture && template.format == DEFAULT_ACCUM_PIPE_FORMAT) 147 { 148 /* Actually, just setting this usage value should be sufficient 149 * to tell the driver to go ahead and allocate the buffer, even 150 * if HW doesn't support the format. 151 */ 152 template.tex_usage = 0; 153 surface_usage = (PIPE_BUFFER_USAGE_CPU_READ | 154 PIPE_BUFFER_USAGE_CPU_WRITE); 155 156 strb->texture = pipe->screen->texture_create( pipe->screen, 157 &template ); 158 159 } 160 161 if (!strb->texture) 162 return FALSE; 163 164 strb->surface = pipe->screen->get_tex_surface( pipe->screen, 165 strb->texture, 166 0, 0, 0, 167 surface_usage ); 168 169 assert(strb->surface->texture); 170 assert(strb->surface->format); 171 assert(strb->surface->width == width); 172 assert(strb->surface->height == height); 173 174 175 return strb->surface != NULL; 176} 177 178 179/** 180 * gl_renderbuffer::Delete() 181 */ 182static void 183st_renderbuffer_delete(struct gl_renderbuffer *rb) 184{ 185 struct st_renderbuffer *strb = st_renderbuffer(rb); 186 ASSERT(strb); 187 pipe_surface_reference(&strb->surface, NULL); 188 pipe_texture_reference(&strb->texture, NULL); 189 _mesa_free(strb); 190} 191 192 193/** 194 * gl_renderbuffer::GetPointer() 195 */ 196static void * 197null_get_pointer(GLcontext * ctx, struct gl_renderbuffer *rb, 198 GLint x, GLint y) 199{ 200 /* By returning NULL we force all software rendering to go through 201 * the span routines. 202 */ 203#if 0 204 assert(0); /* Should never get called with softpipe */ 205#endif 206 return NULL; 207} 208 209 210/** 211 * Called via ctx->Driver.NewFramebuffer() 212 */ 213static struct gl_framebuffer * 214st_new_framebuffer(GLcontext *ctx, GLuint name) 215{ 216 /* XXX not sure we need to subclass gl_framebuffer for pipe */ 217 return _mesa_new_framebuffer(ctx, name); 218} 219 220 221/** 222 * Called via ctx->Driver.NewRenderbuffer() 223 */ 224static struct gl_renderbuffer * 225st_new_renderbuffer(GLcontext *ctx, GLuint name) 226{ 227 struct st_renderbuffer *strb = ST_CALLOC_STRUCT(st_renderbuffer); 228 if (strb) { 229 _mesa_init_renderbuffer(&strb->Base, name); 230 strb->Base.Delete = st_renderbuffer_delete; 231 strb->Base.AllocStorage = st_renderbuffer_alloc_storage; 232 strb->Base.GetPointer = null_get_pointer; 233 strb->format = PIPE_FORMAT_NONE; 234 return &strb->Base; 235 } 236 return NULL; 237} 238 239 240/** 241 * Allocate a renderbuffer for a an on-screen window (not a user-created 242 * renderbuffer). The window system code determines the format. 243 */ 244struct gl_renderbuffer * 245st_new_renderbuffer_fb(enum pipe_format format, int samples) 246{ 247 struct st_renderbuffer *strb; 248 249 strb = ST_CALLOC_STRUCT(st_renderbuffer); 250 if (!strb) { 251 _mesa_error(NULL, GL_OUT_OF_MEMORY, "creating renderbuffer"); 252 return NULL; 253 } 254 255 _mesa_init_renderbuffer(&strb->Base, 0); 256 strb->Base.ClassID = 0x4242; /* just a unique value */ 257 strb->Base.NumSamples = samples; 258 strb->format = format; 259 260 switch (format) { 261 case PIPE_FORMAT_A8R8G8B8_UNORM: 262 case PIPE_FORMAT_B8G8R8A8_UNORM: 263 case PIPE_FORMAT_X8R8G8B8_UNORM: 264 case PIPE_FORMAT_B8G8R8X8_UNORM: 265 case PIPE_FORMAT_A1R5G5B5_UNORM: 266 case PIPE_FORMAT_A4R4G4B4_UNORM: 267 case PIPE_FORMAT_R5G6B5_UNORM: 268 strb->Base.InternalFormat = GL_RGBA; 269 strb->Base._BaseFormat = GL_RGBA; 270 break; 271 case PIPE_FORMAT_Z16_UNORM: 272 strb->Base.InternalFormat = GL_DEPTH_COMPONENT16; 273 strb->Base._BaseFormat = GL_DEPTH_COMPONENT; 274 break; 275 case PIPE_FORMAT_Z32_UNORM: 276 strb->Base.InternalFormat = GL_DEPTH_COMPONENT32; 277 strb->Base._BaseFormat = GL_DEPTH_COMPONENT; 278 break; 279 case PIPE_FORMAT_S8Z24_UNORM: 280 case PIPE_FORMAT_Z24S8_UNORM: 281 case PIPE_FORMAT_X8Z24_UNORM: 282 case PIPE_FORMAT_Z24X8_UNORM: 283 strb->Base.InternalFormat = GL_DEPTH24_STENCIL8_EXT; 284 strb->Base._BaseFormat = GL_DEPTH_STENCIL_EXT; 285 break; 286 case PIPE_FORMAT_S8_UNORM: 287 strb->Base.InternalFormat = GL_STENCIL_INDEX8_EXT; 288 strb->Base._BaseFormat = GL_STENCIL_INDEX; 289 break; 290 case DEFAULT_ACCUM_PIPE_FORMAT: /*PIPE_FORMAT_R16G16B16A16_SNORM*/ 291 strb->Base.InternalFormat = GL_RGBA16; 292 strb->Base._BaseFormat = GL_RGBA; 293 break; 294 default: 295 _mesa_problem(NULL, 296 "Unexpected format in st_new_renderbuffer_fb"); 297 return NULL; 298 } 299 300 /* st-specific methods */ 301 strb->Base.Delete = st_renderbuffer_delete; 302 strb->Base.AllocStorage = st_renderbuffer_alloc_storage; 303 strb->Base.GetPointer = null_get_pointer; 304 305 /* surface is allocated in st_renderbuffer_alloc_storage() */ 306 strb->surface = NULL; 307 308 return &strb->Base; 309} 310 311 312 313 314/** 315 * Called via ctx->Driver.BindFramebufferEXT(). 316 */ 317static void 318st_bind_framebuffer(GLcontext *ctx, GLenum target, 319 struct gl_framebuffer *fb, struct gl_framebuffer *fbread) 320{ 321 322} 323 324/** 325 * Called by ctx->Driver.FramebufferRenderbuffer 326 */ 327static void 328st_framebuffer_renderbuffer(GLcontext *ctx, 329 struct gl_framebuffer *fb, 330 GLenum attachment, 331 struct gl_renderbuffer *rb) 332{ 333 /* XXX no need for derivation? */ 334 _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb); 335} 336 337 338/** 339 * Called by ctx->Driver.RenderTexture 340 */ 341static void 342st_render_texture(GLcontext *ctx, 343 struct gl_framebuffer *fb, 344 struct gl_renderbuffer_attachment *att) 345{ 346 struct pipe_screen *screen = ctx->st->pipe->screen; 347 struct st_renderbuffer *strb; 348 struct gl_renderbuffer *rb; 349 struct pipe_texture *pt = st_get_texobj_texture(att->Texture); 350 struct st_texture_object *stObj; 351 const struct gl_texture_image *texImage = 352 att->Texture->Image[att->CubeMapFace][att->TextureLevel]; 353 354 if (!pt) 355 return; 356 357 /* create new renderbuffer which wraps the texture image */ 358 rb = st_new_renderbuffer(ctx, 0); 359 if (!rb) { 360 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture()"); 361 return; 362 } 363 364 _mesa_reference_renderbuffer(&att->Renderbuffer, rb); 365 assert(rb->RefCount == 1); 366 rb->AllocStorage = NULL; /* should not get called */ 367 strb = st_renderbuffer(rb); 368 369 assert(strb->Base.RefCount > 0); 370 371 /* get the texture for the texture object */ 372 stObj = st_texture_object(att->Texture); 373 374 /* point renderbuffer at texobject */ 375 strb->rtt = stObj; 376 strb->rtt_level = att->TextureLevel; 377 strb->rtt_face = att->CubeMapFace; 378 strb->rtt_slice = att->Zoffset; 379 380 rb->Width = texImage->Width2; 381 rb->Height = texImage->Height2; 382 /*printf("***** render to texture level %d: %d x %d\n", att->TextureLevel, rb->Width, rb->Height);*/ 383 384 /*printf("***** pipe texture %d x %d\n", pt->width[0], pt->height[0]);*/ 385 386 pipe_texture_reference( &strb->texture, pt ); 387 388 pipe_surface_reference(&strb->surface, NULL); 389 390 /* new surface for rendering into the texture */ 391 strb->surface = screen->get_tex_surface(screen, 392 strb->texture, 393 strb->rtt_face, 394 strb->rtt_level, 395 strb->rtt_slice, 396 PIPE_BUFFER_USAGE_GPU_READ | 397 PIPE_BUFFER_USAGE_GPU_WRITE); 398 399 init_renderbuffer_bits(strb, pt->format); 400 401 /* 402 printf("RENDER TO TEXTURE obj=%p pt=%p surf=%p %d x %d\n", 403 att->Texture, pt, strb->surface, rb->Width, rb->Height); 404 */ 405 406 /* Invalidate buffer state so that the pipe's framebuffer state 407 * gets updated. 408 * That's where the new renderbuffer (which we just created) gets 409 * passed to the pipe as a (color/depth) render target. 410 */ 411 st_invalidate_state(ctx, _NEW_BUFFERS); 412} 413 414 415/** 416 * Called via ctx->Driver.FinishRenderTexture. 417 */ 418static void 419st_finish_render_texture(GLcontext *ctx, 420 struct gl_renderbuffer_attachment *att) 421{ 422 struct st_renderbuffer *strb = st_renderbuffer(att->Renderbuffer); 423 424 if (!strb) 425 return; 426 427 st_flush( ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL ); 428 429 if (strb->surface) 430 pipe_surface_reference( &strb->surface, NULL ); 431 432 strb->rtt = NULL; 433 434 /* 435 printf("FINISH RENDER TO TEXTURE surf=%p\n", strb->surface); 436 */ 437 438 _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); 439 440 /* restore previous framebuffer state */ 441 st_invalidate_state(ctx, _NEW_BUFFERS); 442} 443 444 445/** 446 * Check that the framebuffer configuration is valid in terms of what 447 * the driver can support. 448 * 449 * For Gallium we only supports combined Z+stencil, not separate buffers. 450 */ 451static void 452st_validate_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb) 453{ 454 const struct gl_renderbuffer *depthRb = 455 fb->Attachment[BUFFER_DEPTH].Renderbuffer; 456 const struct gl_renderbuffer *stencilRb = 457 fb->Attachment[BUFFER_STENCIL].Renderbuffer; 458 459 if (stencilRb && depthRb && stencilRb != depthRb) { 460 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; 461 } 462} 463 464 465void st_init_fbo_functions(struct dd_function_table *functions) 466{ 467 functions->NewFramebuffer = st_new_framebuffer; 468 functions->NewRenderbuffer = st_new_renderbuffer; 469 functions->BindFramebuffer = st_bind_framebuffer; 470 functions->FramebufferRenderbuffer = st_framebuffer_renderbuffer; 471 functions->RenderTexture = st_render_texture; 472 functions->FinishRenderTexture = st_finish_render_texture; 473 functions->ValidateFramebuffer = st_validate_framebuffer; 474 /* no longer needed by core Mesa, drivers handle resizes... 475 functions->ResizeBuffers = st_resize_buffers; 476 */ 477} 478