st_cb_fbo.c revision 500e3af175cf8ef66bad23ae3b9e440670421ecd
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 "st_context.h" 45#include "st_cb_fbo.h" 46#include "st_cb_texture.h" 47#include "st_format.h" 48#include "st_public.h" 49 50 51 52/** 53 * gl_renderbuffer::AllocStorage() 54 */ 55static GLboolean 56st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb, 57 GLenum internalFormat, 58 GLuint width, GLuint height) 59{ 60 struct pipe_context *pipe = ctx->st->pipe; 61 struct st_renderbuffer *strb = st_renderbuffer(rb); 62 const GLuint pipeFormat 63 = st_choose_pipe_format(pipe, internalFormat, GL_NONE, GL_NONE); 64 const struct pipe_format_info *info = st_get_format_info(pipeFormat); 65 GLuint cpp; 66 GLbitfield flags = PIPE_SURFACE_FLAG_RENDER; /* want to render to surface */ 67 GLuint width2, height2; 68 69 assert(info); 70 if (!info) 71 return GL_FALSE; 72 73 switch (pipeFormat) { 74 case PIPE_FORMAT_S8_Z24: 75 strb->Base.DataType = GL_UNSIGNED_INT; 76 break; 77 default: 78 strb->Base.DataType = GL_UNSIGNED_BYTE; /* XXX fix */ 79 } 80 81 strb->Base._ActualFormat = info->base_format; 82 strb->Base.RedBits = info->red_bits; 83 strb->Base.GreenBits = info->green_bits; 84 strb->Base.BlueBits = info->blue_bits; 85 strb->Base.AlphaBits = info->alpha_bits; 86 strb->Base.DepthBits = info->depth_bits; 87 strb->Base.StencilBits = info->stencil_bits; 88 89 cpp = info->size; 90 91 if (!strb->surface) { 92 strb->surface = pipe->surface_alloc(pipe, pipeFormat); 93 assert(strb->surface); 94 if (!strb->surface) 95 return GL_FALSE; 96 } 97 98 /* free old region */ 99 if (strb->surface->region) { 100 pipe->region_release(pipe, &strb->surface->region); 101 } 102 103 /* Softpipe operates on quads, so pad dimensions to multiples of 2 */ 104 width2 = (width + 1) & ~1; 105 height2 = (height + 1) & ~1; 106 107 strb->surface->region = pipe->region_alloc(pipe, cpp, width2, height2, flags); 108 if (!strb->surface->region) 109 return GL_FALSE; /* out of memory, try s/w buffer? */ 110 111 ASSERT(strb->surface->region->buffer); 112 ASSERT(strb->surface->format); 113 114 strb->Base.Width = strb->surface->width = width; 115 strb->Base.Height = strb->surface->height = height; 116 117 return GL_TRUE; 118} 119 120 121/** 122 * gl_renderbuffer::Delete() 123 */ 124static void 125st_renderbuffer_delete(struct gl_renderbuffer *rb) 126{ 127 struct st_renderbuffer *strb = st_renderbuffer(rb); 128 GET_CURRENT_CONTEXT(ctx); 129 if (ctx) { 130 struct pipe_context *pipe = ctx->st->pipe; 131 ASSERT(strb); 132 if (strb && strb->surface) { 133 if (strb->surface->region) { 134 pipe->region_release(pipe, &strb->surface->region); 135 } 136 free(strb->surface); 137 } 138 } 139 else { 140 _mesa_warning(NULL, "st_renderbuffer_delete() called, but no current context"); 141 } 142 free(strb); 143} 144 145 146/** 147 * gl_renderbuffer::GetPointer() 148 */ 149static void * 150null_get_pointer(GLcontext * ctx, struct gl_renderbuffer *rb, 151 GLint x, GLint y) 152{ 153 /* By returning NULL we force all software rendering to go through 154 * the span routines. 155 */ 156#if 0 157 assert(0); /* Should never get called with softpipe */ 158#endif 159 return NULL; 160} 161 162 163/** 164 * Called via ctx->Driver.NewFramebuffer() 165 */ 166static struct gl_framebuffer * 167st_new_framebuffer(GLcontext *ctx, GLuint name) 168{ 169 /* XXX not sure we need to subclass gl_framebuffer for pipe */ 170 return _mesa_new_framebuffer(ctx, name); 171} 172 173 174/** 175 * Called via ctx->Driver.NewRenderbuffer() 176 */ 177static struct gl_renderbuffer * 178st_new_renderbuffer(GLcontext *ctx, GLuint name) 179{ 180 struct st_renderbuffer *strb = CALLOC_STRUCT(st_renderbuffer); 181 if (strb) { 182 _mesa_init_renderbuffer(&strb->Base, name); 183 strb->Base.Delete = st_renderbuffer_delete; 184 strb->Base.AllocStorage = st_renderbuffer_alloc_storage; 185 strb->Base.GetPointer = null_get_pointer; 186 return &strb->Base; 187 } 188 return NULL; 189} 190 191 192#if 000 193struct gl_renderbuffer * 194st_new_renderbuffer_fb(struct pipe_region *region, GLuint width, GLuint height) 195{ 196 struct st_renderbuffer *strb = CALLOC_STRUCT(st_renderbuffer); 197 if (!strb) 198 return; 199 200 _mesa_init_renderbuffer(&strb->Base, name); 201 strb->Base.Delete = st_renderbuffer_delete; 202 strb->Base.AllocStorage = st_renderbuffer_alloc_storage; 203 strb->Base.GetPointer = null_get_pointer; 204 strb->Base.Width = width; 205 strb->Base.Heigth = height; 206 207 strb->region = region; 208 209 return &strb->Base; 210} 211 212#else 213 214struct gl_renderbuffer * 215st_new_renderbuffer_fb(GLenum intFormat) 216{ 217 struct st_renderbuffer *strb; 218 219 strb = CALLOC_STRUCT(st_renderbuffer); 220 if (!strb) { 221 _mesa_error(NULL, GL_OUT_OF_MEMORY, "creating renderbuffer"); 222 return NULL; 223 } 224 225 _mesa_init_renderbuffer(&strb->Base, 0); 226 strb->Base.ClassID = 0x42; /* XXX temp */ 227 strb->Base.InternalFormat = intFormat; 228 229 switch (intFormat) { 230 case GL_RGB5: 231 case GL_RGBA8: 232 strb->Base._BaseFormat = GL_RGBA; 233 break; 234 case GL_DEPTH_COMPONENT16: 235 case GL_DEPTH_COMPONENT32: 236 strb->Base._BaseFormat = GL_DEPTH_COMPONENT; 237 break; 238 case GL_DEPTH24_STENCIL8_EXT: 239 strb->Base._BaseFormat = GL_DEPTH_STENCIL_EXT; 240 break; 241 case GL_STENCIL_INDEX8_EXT: 242 strb->Base._BaseFormat = GL_STENCIL_INDEX; 243 break; 244 default: 245 _mesa_problem(NULL, 246 "Unexpected intFormat in st_new_renderbuffer"); 247 return NULL; 248 } 249 250 /* st-specific methods */ 251 strb->Base.Delete = st_renderbuffer_delete; 252 strb->Base.AllocStorage = st_renderbuffer_alloc_storage; 253 strb->Base.GetPointer = null_get_pointer; 254 255 /* surface is allocate in alloc_renderbuffer_storage() */ 256 strb->surface = NULL; 257 258 return &strb->Base; 259} 260#endif 261 262 263 264/** 265 * Called via ctx->Driver.BindFramebufferEXT(). 266 */ 267static void 268st_bind_framebuffer(GLcontext *ctx, GLenum target, 269 struct gl_framebuffer *fb, struct gl_framebuffer *fbread) 270{ 271 272} 273 274/** 275 * Called by ctx->Driver.FramebufferRenderbuffer 276 */ 277static void 278st_framebuffer_renderbuffer(GLcontext *ctx, 279 struct gl_framebuffer *fb, 280 GLenum attachment, 281 struct gl_renderbuffer *rb) 282{ 283 /* XXX no need for derivation? */ 284 _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb); 285} 286 287 288/** 289 * Called by ctx->Driver.RenderTexture 290 */ 291static void 292st_render_texture(GLcontext *ctx, 293 struct gl_framebuffer *fb, 294 struct gl_renderbuffer_attachment *att) 295{ 296 struct st_context *st = ctx->st; 297 struct st_renderbuffer *strb; 298 struct gl_renderbuffer *rb; 299 struct pipe_context *pipe = st->pipe; 300 struct pipe_mipmap_tree *mt; 301 302 assert(!att->Renderbuffer); 303 304 /* create new renderbuffer which wraps the texture image */ 305 rb = st_new_renderbuffer(ctx, 0); 306 if (!rb) { 307 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture()"); 308 return; 309 } 310 311 _mesa_reference_renderbuffer(&att->Renderbuffer, rb); 312 assert(rb->RefCount == 1); 313 rb->AllocStorage = NULL; /* should not get called */ 314 strb = st_renderbuffer(rb); 315 316 /* get the mipmap tree for the texture */ 317 mt = st_get_texobj_mipmap_tree(att->Texture); 318 assert(mt); 319 assert(mt->level[0].width); 320 321 rb->Width = mt->level[0].width; 322 rb->Height = mt->level[0].height; 323 324 /* the renderbuffer's surface is inside the mipmap_tree: */ 325 strb->surface = pipe->get_tex_surface(pipe, mt, 326 att->CubeMapFace, 327 att->TextureLevel, 328 att->Zoffset); 329 assert(strb->surface); 330 331 /* 332 printf("RENDER TO TEXTURE obj=%p mt=%p surf=%p %d x %d\n", 333 att->Texture, mt, strb->surface, rb->Width, rb->Height); 334 */ 335 336 /* Invalidate buffer state so that the pipe's framebuffer state 337 * gets updated. 338 * That's where the new renderbuffer (which we just created) gets 339 * passed to the pipe as a (color/depth) render target. 340 */ 341 st_invalidate_state(ctx, _NEW_BUFFERS); 342} 343 344 345/** 346 * Called via ctx->Driver.FinishRenderTexture. 347 */ 348static void 349st_finish_render_texture(GLcontext *ctx, 350 struct gl_renderbuffer_attachment *att) 351{ 352 struct st_renderbuffer *strb = st_renderbuffer(att->Renderbuffer); 353 354 assert(strb); 355 356 ctx->st->pipe->flush(ctx->st->pipe, 0x0); 357 358 /* 359 printf("FINISH RENDER TO TEXTURE surf=%p\n", strb->surface); 360 */ 361 362 pipe_surface_reference(&strb->surface, NULL); 363 364 _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); 365 366 /* restore previous framebuffer state */ 367 st_invalidate_state(ctx, _NEW_BUFFERS); 368} 369 370 371 372void st_init_fbo_functions(struct dd_function_table *functions) 373{ 374 functions->NewFramebuffer = st_new_framebuffer; 375 functions->NewRenderbuffer = st_new_renderbuffer; 376 functions->BindFramebuffer = st_bind_framebuffer; 377 functions->FramebufferRenderbuffer = st_framebuffer_renderbuffer; 378 functions->RenderTexture = st_render_texture; 379 functions->FinishRenderTexture = st_finish_render_texture; 380 /* no longer needed by core Mesa, drivers handle resizes... 381 functions->ResizeBuffers = st_resize_buffers; 382 */ 383} 384