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