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