gallium: tex surface checkpoint
[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_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 #include "st_texture.h"
52
53
54
55 /**
56 * Compute the renderbuffer's Red/Green/EtcBit fields from the pipe format.
57 */
58 static int
59 init_renderbuffer_bits(struct st_renderbuffer *strb,
60 enum pipe_format pipeFormat)
61 {
62 struct pipe_format_info info;
63
64 if (!st_get_format_info( pipeFormat, &info )) {
65 assert( 0 );
66 }
67
68 strb->Base._ActualFormat = info.base_format;
69 strb->Base.RedBits = info.red_bits;
70 strb->Base.GreenBits = info.green_bits;
71 strb->Base.BlueBits = info.blue_bits;
72 strb->Base.AlphaBits = info.alpha_bits;
73 strb->Base.DepthBits = info.depth_bits;
74 strb->Base.StencilBits = info.stencil_bits;
75 strb->Base.DataType = st_format_datatype(pipeFormat);
76
77 return info.size;
78 }
79
80
81 /**
82 * gl_renderbuffer::AllocStorage()
83 * This is called to allocate the original drawing surface, and
84 * during window resize.
85 */
86 static GLboolean
87 st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
88 GLenum internalFormat,
89 GLuint width, GLuint height)
90 {
91 struct pipe_context *pipe = ctx->st->pipe;
92 struct st_renderbuffer *strb = st_renderbuffer(rb);
93 enum pipe_format pipeFormat;
94 unsigned flags = (PIPE_BUFFER_USAGE_CPU_WRITE |
95 PIPE_BUFFER_USAGE_CPU_READ |
96 PIPE_BUFFER_USAGE_GPU_WRITE |
97 PIPE_BUFFER_USAGE_GPU_READ);
98 int ret;
99
100 pipe_surface_reference( &strb->surface, NULL );
101
102 if (!strb->surface) {
103 /* first time surface creation */
104 strb->surface = pipe->winsys->surface_alloc(pipe->winsys);
105 assert(strb->surface);
106 assert(strb->surface->refcount);
107 assert(strb->surface->winsys);
108 if (!strb->surface)
109 return GL_FALSE;
110 }
111 #if 0
112 else if (strb->surface->buffer) {
113 /* release/discard the old surface buffer */
114 pipe_reference_buffer(pipe, &strb->surface->buffer, NULL);
115 }
116 #else
117 else {
118 assert(0);
119 }
120 #endif
121 /* Determine surface format here */
122 if (strb->format != PIPE_FORMAT_NONE) {
123 assert(strb->format != 0);
124 /* we'll hit this for front/back color bufs */
125 pipeFormat = strb->format;
126 }
127 else {
128 pipeFormat = st_choose_renderbuffer_format(pipe, internalFormat);
129 }
130
131 init_renderbuffer_bits(strb, pipeFormat);
132
133 ret = pipe->winsys->surface_alloc_storage(pipe->winsys,
134 strb->surface,
135 width,
136 height,
137 pipeFormat,
138 flags);
139 if (ret || !strb->surface->buffer) {
140 if (pipeFormat == DEFAULT_ACCUM_PIPE_FORMAT) {
141 /* Accum buffer. Try a different surface format. Since accum
142 * buffers are s/w only for now, the surface pixel format doesn't
143 * really matter, only that the buffer is large enough.
144 */
145 int sz, mult;
146 enum pipe_format accum_format;
147
148 /* allocate a buffer of (typically) double height to get 64bpp */
149 accum_format = st_choose_renderbuffer_format(pipe, GL_RGBA);
150 sz = pf_get_size(accum_format);
151 mult = pf_get_size(DEFAULT_ACCUM_PIPE_FORMAT) / sz;
152
153 ret = pipe->winsys->surface_alloc_storage(pipe->winsys,
154 strb->surface,
155 width, height * mult,
156 accum_format, flags);
157 if (ret)
158 return GL_FALSE; /* we've _really_ failed */
159
160 }
161 else {
162 return GL_FALSE; /* out of memory, try s/w buffer? */
163 }
164 }
165
166 ASSERT(strb->surface->buffer);
167 ASSERT(strb->surface->format);
168 ASSERT(strb->surface->cpp);
169 ASSERT(strb->surface->width == width);
170 /*ASSERT(strb->surface->height == height);*/
171 ASSERT(strb->surface->pitch);
172
173 strb->Base.Width = width;
174 strb->Base.Height = height;
175
176 return GL_TRUE;
177 }
178
179
180 /**
181 * gl_renderbuffer::Delete()
182 */
183 static void
184 st_renderbuffer_delete(struct gl_renderbuffer *rb)
185 {
186 struct st_renderbuffer *strb = st_renderbuffer(rb);
187 ASSERT(strb);
188 if (strb->surface) {
189 struct pipe_winsys *ws = strb->surface->winsys;
190 ws->surface_release(ws, &strb->surface);
191 }
192 free(strb);
193 }
194
195
196 /**
197 * gl_renderbuffer::GetPointer()
198 */
199 static void *
200 null_get_pointer(GLcontext * ctx, struct gl_renderbuffer *rb,
201 GLint x, GLint y)
202 {
203 /* By returning NULL we force all software rendering to go through
204 * the span routines.
205 */
206 #if 0
207 assert(0); /* Should never get called with softpipe */
208 #endif
209 return NULL;
210 }
211
212
213 /**
214 * Called via ctx->Driver.NewFramebuffer()
215 */
216 static struct gl_framebuffer *
217 st_new_framebuffer(GLcontext *ctx, GLuint name)
218 {
219 /* XXX not sure we need to subclass gl_framebuffer for pipe */
220 return _mesa_new_framebuffer(ctx, name);
221 }
222
223
224 /**
225 * Called via ctx->Driver.NewRenderbuffer()
226 */
227 static struct gl_renderbuffer *
228 st_new_renderbuffer(GLcontext *ctx, GLuint name)
229 {
230 struct st_renderbuffer *strb = CALLOC_STRUCT(st_renderbuffer);
231 if (strb) {
232 _mesa_init_renderbuffer(&strb->Base, name);
233 strb->Base.Delete = st_renderbuffer_delete;
234 strb->Base.AllocStorage = st_renderbuffer_alloc_storage;
235 strb->Base.GetPointer = null_get_pointer;
236 strb->format = PIPE_FORMAT_NONE;
237 return &strb->Base;
238 }
239 return NULL;
240 }
241
242
243 /**
244 * Allocate a renderbuffer for a an on-screen window (not a user-created
245 * renderbuffer). The window system code determines the format.
246 */
247 struct gl_renderbuffer *
248 st_new_renderbuffer_fb(enum pipe_format format)
249 {
250 struct st_renderbuffer *strb;
251
252 strb = CALLOC_STRUCT(st_renderbuffer);
253 if (!strb) {
254 _mesa_error(NULL, GL_OUT_OF_MEMORY, "creating renderbuffer");
255 return NULL;
256 }
257
258 _mesa_init_renderbuffer(&strb->Base, 0);
259 strb->Base.ClassID = 0x4242; /* just a unique value */
260 strb->format = format;
261
262 switch (format) {
263 case PIPE_FORMAT_A8R8G8B8_UNORM:
264 case PIPE_FORMAT_B8G8R8A8_UNORM:
265 case PIPE_FORMAT_X8R8G8B8_UNORM:
266 case PIPE_FORMAT_B8G8R8X8_UNORM:
267 case PIPE_FORMAT_A1R5G5B5_UNORM:
268 case PIPE_FORMAT_A4R4G4B4_UNORM:
269 case PIPE_FORMAT_R5G6B5_UNORM:
270 strb->Base.InternalFormat = GL_RGBA;
271 strb->Base._BaseFormat = GL_RGBA;
272 break;
273 case PIPE_FORMAT_Z16_UNORM:
274 strb->Base.InternalFormat = GL_DEPTH_COMPONENT16;
275 strb->Base._BaseFormat = GL_DEPTH_COMPONENT;
276 break;
277 case PIPE_FORMAT_Z32_UNORM:
278 strb->Base.InternalFormat = GL_DEPTH_COMPONENT32;
279 strb->Base._BaseFormat = GL_DEPTH_COMPONENT;
280 break;
281 case PIPE_FORMAT_S8Z24_UNORM:
282 case PIPE_FORMAT_Z24S8_UNORM:
283 case PIPE_FORMAT_X8Z24_UNORM:
284 case PIPE_FORMAT_Z24X8_UNORM:
285 strb->Base.InternalFormat = GL_DEPTH24_STENCIL8_EXT;
286 strb->Base._BaseFormat = GL_DEPTH_STENCIL_EXT;
287 break;
288 case PIPE_FORMAT_S8_UNORM:
289 strb->Base.InternalFormat = GL_STENCIL_INDEX8_EXT;
290 strb->Base._BaseFormat = GL_STENCIL_INDEX;
291 break;
292 case DEFAULT_ACCUM_PIPE_FORMAT: /*PIPE_FORMAT_R16G16B16A16_SNORM*/
293 strb->Base.InternalFormat = GL_RGBA16;
294 strb->Base._BaseFormat = GL_RGBA;
295 break;
296 default:
297 _mesa_problem(NULL,
298 "Unexpected format in st_new_renderbuffer_fb");
299 return NULL;
300 }
301
302 /* st-specific methods */
303 strb->Base.Delete = st_renderbuffer_delete;
304 strb->Base.AllocStorage = st_renderbuffer_alloc_storage;
305 strb->Base.GetPointer = null_get_pointer;
306
307 /* surface is allocated in st_renderbuffer_alloc_storage() */
308 strb->surface = NULL;
309
310 return &strb->Base;
311 }
312
313
314
315
316 /**
317 * Called via ctx->Driver.BindFramebufferEXT().
318 */
319 static void
320 st_bind_framebuffer(GLcontext *ctx, GLenum target,
321 struct gl_framebuffer *fb, struct gl_framebuffer *fbread)
322 {
323
324 }
325
326 /**
327 * Called by ctx->Driver.FramebufferRenderbuffer
328 */
329 static void
330 st_framebuffer_renderbuffer(GLcontext *ctx,
331 struct gl_framebuffer *fb,
332 GLenum attachment,
333 struct gl_renderbuffer *rb)
334 {
335 /* XXX no need for derivation? */
336 _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb);
337 }
338
339
340 /**
341 * Called by ctx->Driver.RenderTexture
342 */
343 static void
344 st_render_texture(GLcontext *ctx,
345 struct gl_framebuffer *fb,
346 struct gl_renderbuffer_attachment *att)
347 {
348 struct st_context *st = ctx->st;
349 struct st_renderbuffer *strb;
350 struct gl_renderbuffer *rb;
351 struct pipe_context *pipe = st->pipe;
352 struct pipe_screen *screen = pipe->screen;
353 struct pipe_texture *pt;
354
355 assert(!att->Renderbuffer);
356
357 /* create new renderbuffer which wraps the texture image */
358 rb = st_new_renderbuffer(ctx, 0);
359 if (!rb) {
360 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture()");
361 return;
362 }
363
364 _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
365 assert(rb->RefCount == 1);
366 rb->AllocStorage = NULL; /* should not get called */
367 strb = st_renderbuffer(rb);
368
369 /* get the texture for the texture object */
370 pt = st_get_texobj_texture(att->Texture);
371 assert(pt);
372 assert(pt->width[att->TextureLevel]);
373
374 rb->Width = pt->width[att->TextureLevel];
375 rb->Height = pt->height[att->TextureLevel];
376
377 /* the renderbuffer's surface is inside the texture */
378 strb->surface = screen->get_tex_surface(screen, pt,
379 att->CubeMapFace,
380 att->TextureLevel,
381 att->Zoffset,
382 PIPE_BUFFER_USAGE_CPU_READ |
383 PIPE_BUFFER_USAGE_CPU_WRITE |
384 PIPE_BUFFER_USAGE_GPU_READ |
385 PIPE_BUFFER_USAGE_GPU_WRITE);
386 assert(strb->surface);
387 assert(screen->is_format_supported(screen, strb->surface->format, PIPE_TEXTURE));
388 assert(screen->is_format_supported(screen, strb->surface->format, PIPE_SURFACE));
389
390 init_renderbuffer_bits(strb, pt->format);
391
392 /*
393 printf("RENDER TO TEXTURE obj=%p pt=%p surf=%p %d x %d\n",
394 att->Texture, pt, strb->surface, rb->Width, rb->Height);
395 */
396
397 /* Invalidate buffer state so that the pipe's framebuffer state
398 * gets updated.
399 * That's where the new renderbuffer (which we just created) gets
400 * passed to the pipe as a (color/depth) render target.
401 */
402 st_invalidate_state(ctx, _NEW_BUFFERS);
403 }
404
405
406 /**
407 * Called via ctx->Driver.FinishRenderTexture.
408 */
409 static void
410 st_finish_render_texture(GLcontext *ctx,
411 struct gl_renderbuffer_attachment *att)
412 {
413 struct pipe_screen *screen = ctx->st->pipe->screen;
414 struct st_renderbuffer *strb = st_renderbuffer(att->Renderbuffer);
415
416 assert(strb);
417
418 ctx->st->pipe->flush(ctx->st->pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
419
420 screen->tex_surface_release( screen, &strb->surface );
421
422 /*
423 printf("FINISH RENDER TO TEXTURE surf=%p\n", strb->surface);
424 */
425
426 _mesa_reference_renderbuffer(&att->Renderbuffer, NULL);
427
428 /* restore previous framebuffer state */
429 st_invalidate_state(ctx, _NEW_BUFFERS);
430 }
431
432
433
434 void st_init_fbo_functions(struct dd_function_table *functions)
435 {
436 functions->NewFramebuffer = st_new_framebuffer;
437 functions->NewRenderbuffer = st_new_renderbuffer;
438 functions->BindFramebuffer = st_bind_framebuffer;
439 functions->FramebufferRenderbuffer = st_framebuffer_renderbuffer;
440 functions->RenderTexture = st_render_texture;
441 functions->FinishRenderTexture = st_finish_render_texture;
442 /* no longer needed by core Mesa, drivers handle resizes...
443 functions->ResizeBuffers = st_resize_buffers;
444 */
445 }