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