st_cb_fbo.c revision 4f58d9af9addb1506a1b2abc7dd8012147772b78
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_inlines.h" 45#include "pipe/p_winsys.h" 46#include "st_context.h" 47#include "st_cb_fbo.h" 48#include "st_cb_texture.h" 49#include "st_format.h" 50#include "st_public.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/** 81 * gl_renderbuffer::AllocStorage() 82 */ 83static GLboolean 84st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb, 85 GLenum internalFormat, 86 GLuint width, GLuint height) 87{ 88 struct pipe_context *pipe = ctx->st->pipe; 89 struct st_renderbuffer *strb = st_renderbuffer(rb); 90 uint type = strb->screenSurface ? PIPE_SCREEN_SURFACE : PIPE_SURFACE; 91 const enum pipe_format pipeFormat 92 = st_choose_pipe_format(pipe, internalFormat, GL_NONE, GL_NONE, type); 93 GLuint cpp; 94 GLbitfield flags = 0x0; /* XXX needed? */ 95 96 cpp = init_renderbuffer_bits(strb, pipeFormat); 97 assert(cpp); 98 99 if (strb->surface && strb->surface->format != pipeFormat) { 100 /* need to change surface types, free this surface */ 101 pipe_surface_reference(&strb->surface, NULL); 102 assert(strb->surface == NULL); 103 } 104 105 if (!strb->surface) { 106 strb->surface = pipe->winsys->surface_alloc(pipe->winsys, pipeFormat); 107 assert(strb->surface); 108 if (!strb->surface) 109 return GL_FALSE; 110 strb->surface->cpp = cpp; 111 } 112 113 strb->surface->pitch = pipe->winsys->surface_pitch(pipe->winsys, cpp, 114 width, flags); 115 116 /* loop here since mapping is refcounted */ 117 while (strb->surface->map) 118 pipe_surface_unmap(strb->surface); 119 if (strb->surface->buffer) 120 pipe->winsys->buffer_reference(pipe->winsys, &strb->surface->buffer, 121 NULL); 122 123 strb->surface->buffer = pipe->winsys->buffer_create(pipe->winsys, 32, 0, 0); 124 if (!strb->surface->buffer) 125 return GL_FALSE; /* out of memory, try s/w buffer? */ 126 127 pipe->winsys->buffer_data(pipe->winsys, strb->surface->buffer, 128 strb->surface->pitch * cpp * height, NULL, 129 PIPE_BUFFER_USAGE_PIXEL); 130 131 ASSERT(strb->surface->buffer); 132 ASSERT(strb->surface->format); 133 134 strb->Base.Width = strb->surface->width = width; 135 strb->Base.Height = strb->surface->height = height; 136 137 return GL_TRUE; 138} 139 140 141/** 142 * gl_renderbuffer::Delete() 143 */ 144static void 145st_renderbuffer_delete(struct gl_renderbuffer *rb) 146{ 147 struct st_renderbuffer *strb = st_renderbuffer(rb); 148 ASSERT(strb); 149 if (strb->surface) { 150 struct pipe_winsys *ws = strb->surface->winsys; 151 ws->surface_release(ws, &strb->surface); 152 } 153 free(strb); 154} 155 156 157/** 158 * gl_renderbuffer::GetPointer() 159 */ 160static void * 161null_get_pointer(GLcontext * ctx, struct gl_renderbuffer *rb, 162 GLint x, GLint y) 163{ 164 /* By returning NULL we force all software rendering to go through 165 * the span routines. 166 */ 167#if 0 168 assert(0); /* Should never get called with softpipe */ 169#endif 170 return NULL; 171} 172 173 174/** 175 * Called via ctx->Driver.NewFramebuffer() 176 */ 177static struct gl_framebuffer * 178st_new_framebuffer(GLcontext *ctx, GLuint name) 179{ 180 /* XXX not sure we need to subclass gl_framebuffer for pipe */ 181 return _mesa_new_framebuffer(ctx, name); 182} 183 184 185/** 186 * Called via ctx->Driver.NewRenderbuffer() 187 */ 188static struct gl_renderbuffer * 189st_new_renderbuffer(GLcontext *ctx, GLuint name) 190{ 191 struct st_renderbuffer *strb = CALLOC_STRUCT(st_renderbuffer); 192 if (strb) { 193 _mesa_init_renderbuffer(&strb->Base, name); 194 strb->Base.Delete = st_renderbuffer_delete; 195 strb->Base.AllocStorage = st_renderbuffer_alloc_storage; 196 strb->Base.GetPointer = null_get_pointer; 197 return &strb->Base; 198 } 199 return NULL; 200} 201 202 203/** 204 * Allocate a renderbuffer for a an on-screen window (not a user-created 205 * renderbuffer). The window system code determines the internal format. 206 * \param screenSurface indicates if the renderbuffer is a front/back color 207 * buffer that'll be displayed/copied to the screen 208 */ 209struct gl_renderbuffer * 210st_new_renderbuffer_fb(GLenum intFormat, GLboolean screenSurface) 211{ 212 struct st_renderbuffer *strb; 213 214 strb = CALLOC_STRUCT(st_renderbuffer); 215 if (!strb) { 216 _mesa_error(NULL, GL_OUT_OF_MEMORY, "creating renderbuffer"); 217 return NULL; 218 } 219 220 _mesa_init_renderbuffer(&strb->Base, 0); 221 strb->Base.ClassID = 0x4242; /* just a unique value */ 222 strb->Base.InternalFormat = intFormat; 223 strb->screenSurface = screenSurface; 224 225 switch (intFormat) { 226 case GL_RGB5: 227 case GL_RGBA8: 228 case GL_RGBA16: 229 strb->Base._BaseFormat = GL_RGBA; 230 break; 231 case GL_DEPTH_COMPONENT16: 232 case GL_DEPTH_COMPONENT32: 233 strb->Base._BaseFormat = GL_DEPTH_COMPONENT; 234 break; 235 case GL_DEPTH24_STENCIL8_EXT: 236 strb->Base._BaseFormat = GL_DEPTH_STENCIL_EXT; 237 break; 238 case GL_STENCIL_INDEX8_EXT: 239 strb->Base._BaseFormat = GL_STENCIL_INDEX; 240 break; 241 default: 242 _mesa_problem(NULL, 243 "Unexpected intFormat in st_new_renderbuffer"); 244 return NULL; 245 } 246 247 /* st-specific methods */ 248 strb->Base.Delete = st_renderbuffer_delete; 249 strb->Base.AllocStorage = st_renderbuffer_alloc_storage; 250 strb->Base.GetPointer = null_get_pointer; 251 252 /* surface is allocated in st_renderbuffer_alloc_storage() */ 253 strb->surface = NULL; 254 255 return &strb->Base; 256} 257 258 259 260/** 261 * Called via ctx->Driver.BindFramebufferEXT(). 262 */ 263static void 264st_bind_framebuffer(GLcontext *ctx, GLenum target, 265 struct gl_framebuffer *fb, struct gl_framebuffer *fbread) 266{ 267 268} 269 270/** 271 * Called by ctx->Driver.FramebufferRenderbuffer 272 */ 273static void 274st_framebuffer_renderbuffer(GLcontext *ctx, 275 struct gl_framebuffer *fb, 276 GLenum attachment, 277 struct gl_renderbuffer *rb) 278{ 279 /* XXX no need for derivation? */ 280 _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb); 281} 282 283 284/** 285 * Called by ctx->Driver.RenderTexture 286 */ 287static void 288st_render_texture(GLcontext *ctx, 289 struct gl_framebuffer *fb, 290 struct gl_renderbuffer_attachment *att) 291{ 292 struct st_context *st = ctx->st; 293 struct st_renderbuffer *strb; 294 struct gl_renderbuffer *rb; 295 struct pipe_context *pipe = st->pipe; 296 struct pipe_texture *pt; 297 298 assert(!att->Renderbuffer); 299 300 /* create new renderbuffer which wraps the texture image */ 301 rb = st_new_renderbuffer(ctx, 0); 302 if (!rb) { 303 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture()"); 304 return; 305 } 306 307 _mesa_reference_renderbuffer(&att->Renderbuffer, rb); 308 assert(rb->RefCount == 1); 309 rb->AllocStorage = NULL; /* should not get called */ 310 strb = st_renderbuffer(rb); 311 312 /* get the texture for the texture object */ 313 pt = st_get_texobj_texture(att->Texture); 314 assert(pt); 315 assert(pt->width[att->TextureLevel]); 316 317 rb->Width = pt->width[att->TextureLevel]; 318 rb->Height = pt->height[att->TextureLevel]; 319 320 /* the renderbuffer's surface is inside the texture */ 321 strb->surface = pipe->get_tex_surface(pipe, pt, 322 att->CubeMapFace, 323 att->TextureLevel, 324 att->Zoffset); 325 assert(strb->surface); 326 327 init_renderbuffer_bits(strb, pt->format); 328 329 /* 330 printf("RENDER TO TEXTURE obj=%p pt=%p surf=%p %d x %d\n", 331 att->Texture, pt, strb->surface, rb->Width, rb->Height); 332 */ 333 334 /* Invalidate buffer state so that the pipe's framebuffer state 335 * gets updated. 336 * That's where the new renderbuffer (which we just created) gets 337 * passed to the pipe as a (color/depth) render target. 338 */ 339 st_invalidate_state(ctx, _NEW_BUFFERS); 340} 341 342 343/** 344 * Called via ctx->Driver.FinishRenderTexture. 345 */ 346static void 347st_finish_render_texture(GLcontext *ctx, 348 struct gl_renderbuffer_attachment *att) 349{ 350 struct st_renderbuffer *strb = st_renderbuffer(att->Renderbuffer); 351 352 assert(strb); 353 354 ctx->st->pipe->flush(ctx->st->pipe, 0x0); 355 356 /* 357 printf("FINISH RENDER TO TEXTURE surf=%p\n", strb->surface); 358 */ 359 360 pipe_surface_reference(&strb->surface, NULL); 361 362 _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); 363 364 /* restore previous framebuffer state */ 365 st_invalidate_state(ctx, _NEW_BUFFERS); 366} 367 368 369 370void st_init_fbo_functions(struct dd_function_table *functions) 371{ 372 functions->NewFramebuffer = st_new_framebuffer; 373 functions->NewRenderbuffer = st_new_renderbuffer; 374 functions->BindFramebuffer = st_bind_framebuffer; 375 functions->FramebufferRenderbuffer = st_framebuffer_renderbuffer; 376 functions->RenderTexture = st_render_texture; 377 functions->FinishRenderTexture = st_finish_render_texture; 378 /* no longer needed by core Mesa, drivers handle resizes... 379 functions->ResizeBuffers = st_resize_buffers; 380 */ 381} 382