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