d3c43bbc68a7b180532b380c164021d71a764d12
[profile/ivi/mesa.git] / src / mesa / state_tracker / st_framebuffer.c
1 /**************************************************************************
2  * 
3  * Copyright 2003 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 #include "main/imports.h"
30 #include "main/buffers.h"
31 #include "main/context.h"
32 #include "main/framebuffer.h"
33 #include "main/renderbuffer.h"
34 #include "st_context.h"
35 #include "st_cb_fbo.h"
36 #include "st_public.h"
37 #include "pipe/p_defines.h"
38 #include "util/u_inlines.h"
39
40
41 struct st_framebuffer *
42 st_create_framebuffer( const __GLcontextModes *visual,
43                        enum pipe_format colorFormat,
44                        enum pipe_format depthFormat,
45                        enum pipe_format stencilFormat,
46                        uint width, uint height,
47                        void *private)
48 {
49    struct st_framebuffer *stfb = ST_CALLOC_STRUCT(st_framebuffer);
50    if (stfb) {
51       int samples = st_get_msaa();
52       int i;
53
54       if (visual->sampleBuffers)
55          samples = visual->samples;
56
57       _mesa_initialize_window_framebuffer(&stfb->Base, visual);
58
59       if (visual->doubleBufferMode) {
60          struct gl_renderbuffer *rb
61             = st_new_renderbuffer_fb(colorFormat, samples, FALSE);
62          _mesa_add_renderbuffer(&stfb->Base, BUFFER_BACK_LEFT, rb);
63       }
64       else {
65          /* Only allocate front buffer right now if we're single buffered.
66           * If double-buffered, allocate front buffer on demand later.
67           * See check_create_front_buffers() and st_set_framebuffer_surface().
68           */
69          struct gl_renderbuffer *rb
70             = st_new_renderbuffer_fb(colorFormat, samples, FALSE);
71          _mesa_add_renderbuffer(&stfb->Base, BUFFER_FRONT_LEFT, rb);
72       }
73
74       if (depthFormat == stencilFormat && depthFormat != PIPE_FORMAT_NONE) {
75          /* combined depth/stencil buffer */
76          struct gl_renderbuffer *depthStencilRb
77             = st_new_renderbuffer_fb(depthFormat, samples, FALSE);
78          /* note: bind RB to two attachment points */
79          _mesa_add_renderbuffer(&stfb->Base, BUFFER_DEPTH, depthStencilRb);
80          _mesa_add_renderbuffer(&stfb->Base, BUFFER_STENCIL, depthStencilRb);
81       }
82       else {
83          /* separate depth and/or stencil */
84
85          if (visual->depthBits == 32) {
86             /* 32-bit depth buffer */
87             struct gl_renderbuffer *depthRb
88                = st_new_renderbuffer_fb(depthFormat, samples, FALSE);
89             _mesa_add_renderbuffer(&stfb->Base, BUFFER_DEPTH, depthRb);
90          }
91          else if (visual->depthBits == 24) {
92             /* 24-bit depth buffer, ignore stencil bits */
93             struct gl_renderbuffer *depthRb
94                = st_new_renderbuffer_fb(depthFormat, samples, FALSE);
95             _mesa_add_renderbuffer(&stfb->Base, BUFFER_DEPTH, depthRb);
96          }
97          else if (visual->depthBits > 0) {
98             /* 16-bit depth buffer */
99             struct gl_renderbuffer *depthRb
100                = st_new_renderbuffer_fb(depthFormat, samples, FALSE);
101             _mesa_add_renderbuffer(&stfb->Base, BUFFER_DEPTH, depthRb);
102          }
103
104          if (visual->stencilBits > 0) {
105             /* 8-bit stencil */
106             struct gl_renderbuffer *stencilRb
107                = st_new_renderbuffer_fb(stencilFormat, samples, FALSE);
108             _mesa_add_renderbuffer(&stfb->Base, BUFFER_STENCIL, stencilRb);
109          }
110       }
111
112       if (visual->accumRedBits > 0) {
113          /* 16-bit/channel accum */
114          /* TODO: query the pipe screen for accumulation buffer format support */
115          struct gl_renderbuffer *accumRb
116             = st_new_renderbuffer_fb(PIPE_FORMAT_R16G16B16A16_SNORM, 0, TRUE);
117          _mesa_add_renderbuffer(&stfb->Base, BUFFER_ACCUM, accumRb);
118       }
119
120       for (i = 0; i < visual->numAuxBuffers; i++) {
121          struct gl_renderbuffer *aux
122             = st_new_renderbuffer_fb(colorFormat, 0, FALSE);
123          _mesa_add_renderbuffer(&stfb->Base, BUFFER_AUX0 + i, aux);
124       }
125
126       stfb->Base.Initialized = GL_TRUE;
127       stfb->InitWidth = width;
128       stfb->InitHeight = height;
129       stfb->Private = private;
130    }
131    return stfb;
132 }
133
134
135 void st_resize_framebuffer( struct st_framebuffer *stfb,
136                             uint width, uint height )
137 {
138    if (stfb->Base.Width != width || stfb->Base.Height != height) {
139       GET_CURRENT_CONTEXT(ctx);
140       if (ctx) {
141          _mesa_check_init_viewport(ctx, width, height);
142
143          _mesa_resize_framebuffer(ctx, &stfb->Base, width, height);
144
145          assert(stfb->Base.Width == width);
146          assert(stfb->Base.Height == height);
147       }
148    }
149 }
150
151
152 void st_unreference_framebuffer( struct st_framebuffer *stfb )
153 {
154    _mesa_reference_framebuffer((struct gl_framebuffer **) &stfb, NULL);
155 }
156
157
158
159 /**
160  * Set/replace a framebuffer surface.
161  * The user of the state tracker can use this instead of
162  * st_resize_framebuffer() to provide new surfaces when a window is resized.
163  * \param surfIndex  an ST_SURFACE_x index
164  */
165 void
166 st_set_framebuffer_surface(struct st_framebuffer *stfb,
167                            uint surfIndex, struct pipe_surface *surf)
168 {
169    GET_CURRENT_CONTEXT(ctx);
170    struct st_renderbuffer *strb;
171
172    /* sanity checks */
173    assert(ST_SURFACE_FRONT_LEFT == BUFFER_FRONT_LEFT);
174    assert(ST_SURFACE_BACK_LEFT == BUFFER_BACK_LEFT);
175    assert(ST_SURFACE_FRONT_RIGHT == BUFFER_FRONT_RIGHT);
176    assert(ST_SURFACE_BACK_RIGHT == BUFFER_BACK_RIGHT);
177    assert(ST_SURFACE_DEPTH == BUFFER_DEPTH);
178
179    assert(surfIndex < BUFFER_COUNT);
180
181    strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer);
182
183    if (!strb) {
184       /* create new renderbuffer for this surface now */
185       const GLuint numSamples = stfb->Base.Visual.samples;
186       struct gl_renderbuffer *rb =
187          st_new_renderbuffer_fb(surf->format, numSamples, FALSE);
188       if (!rb) {
189          /* out of memory */
190          _mesa_warning(ctx, "Out of memory allocating renderbuffer");
191          return;
192       }
193       _mesa_add_renderbuffer(&stfb->Base, surfIndex, rb);
194       strb = st_renderbuffer(rb);
195    }
196
197    /* replace the renderbuffer's surface/texture pointers */
198    pipe_surface_reference( &strb->surface, surf );
199    pipe_texture_reference( &strb->texture, surf->texture );
200    pipe_sampler_view_reference(&strb->sampler_view, NULL);
201
202    if (ctx) {
203       /* If ctx isn't set, we've likely not made current yet.
204        * But when we do, we need to start setting this dirty bit
205        * to ensure the renderbuffer attachements are up-to-date
206        * via update_framebuffer.
207        * Core Mesa's state validation will update the parent framebuffer's
208        * size info, etc.
209        */
210       ctx->st->dirty.st |= ST_NEW_FRAMEBUFFER;
211       ctx->NewState |= _NEW_BUFFERS;
212    }
213
214    /* update renderbuffer's width/height */
215    strb->Base.Width = surf->width;
216    strb->Base.Height = surf->height;
217 }
218
219
220
221 /**
222  * Return the pipe_surface for the given renderbuffer.
223  */
224 int
225 st_get_framebuffer_surface(struct st_framebuffer *stfb, uint surfIndex, struct pipe_surface **surface)
226 {
227    struct st_renderbuffer *strb;
228
229    assert(surfIndex <= ST_SURFACE_DEPTH);
230
231    /* sanity checks, ST tokens should match Mesa tokens */
232    assert(ST_SURFACE_FRONT_LEFT == BUFFER_FRONT_LEFT);
233    assert(ST_SURFACE_BACK_RIGHT == BUFFER_BACK_RIGHT);
234
235    strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer);
236    if (strb) {
237       *surface = strb->surface;
238       return GL_TRUE;
239    }
240
241    *surface = NULL;
242    return GL_FALSE;
243 }
244
245 int
246 st_get_framebuffer_texture(struct st_framebuffer *stfb, uint surfIndex, struct pipe_texture **texture)
247 {
248    struct st_renderbuffer *strb;
249
250    assert(surfIndex <= ST_SURFACE_DEPTH);
251
252    /* sanity checks, ST tokens should match Mesa tokens */
253    assert(ST_SURFACE_FRONT_LEFT == BUFFER_FRONT_LEFT);
254    assert(ST_SURFACE_BACK_RIGHT == BUFFER_BACK_RIGHT);
255
256    strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer);
257    if (strb) {
258       *texture = strb->texture;
259       return GL_TRUE;
260    }
261
262    *texture = NULL;
263    return GL_FALSE;
264 }
265
266 /**
267  * This function is to be called prior to SwapBuffers on the given
268  * framebuffer.  It checks if the current context is bound to the framebuffer
269  * and flushes rendering if needed.
270  */
271 void
272 st_notify_swapbuffers(struct st_framebuffer *stfb)
273 {
274    GET_CURRENT_CONTEXT(ctx);
275
276    if (ctx && ctx->DrawBuffer == &stfb->Base) {
277       st_flush( ctx->st, 
278                 PIPE_FLUSH_RENDER_CACHE | 
279                 PIPE_FLUSH_SWAPBUFFERS |
280                 PIPE_FLUSH_FRAME,
281                 NULL );
282       if (st_renderbuffer(stfb->Base.Attachment[BUFFER_BACK_LEFT].Renderbuffer))
283          ctx->st->frontbuffer_status = FRONT_STATUS_COPY_OF_BACK;
284    }
285 }
286
287
288 /**
289  * Swap the front/back color buffers.  Exchange the front/back pointers
290  * and update some derived state.
291  * No need to call st_notify_swapbuffers() first.
292  *
293  * For a single-buffered framebuffer, no swap occurs, but we still return
294  * the pointer(s) to the front color buffer(s).
295  *
296  * \param front_left  returns pointer to front-left renderbuffer after swap
297  * \param front_right  returns pointer to front-right renderbuffer after swap
298  */
299 void
300 st_swapbuffers(struct st_framebuffer *stfb,
301                struct pipe_surface **front_left,
302                struct pipe_surface **front_right)
303 {
304    struct gl_framebuffer *fb = &stfb->Base;
305
306    GET_CURRENT_CONTEXT(ctx);
307
308    if (ctx && ctx->DrawBuffer == &stfb->Base) {
309       st_flush( ctx->st, 
310                 PIPE_FLUSH_RENDER_CACHE | 
311                 PIPE_FLUSH_SWAPBUFFERS |
312                 PIPE_FLUSH_FRAME,
313                 NULL );
314    }
315
316    if (!fb->Visual.doubleBufferMode) {
317       /* single buffer mode - return pointers to front surfaces */
318       if (front_left) {
319          struct st_renderbuffer *strb =
320             st_renderbuffer(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer);
321          *front_left = strb->surface;
322       }
323       if (front_right) {
324          struct st_renderbuffer *strb =
325             st_renderbuffer(fb->Attachment[BUFFER_FRONT_RIGHT].Renderbuffer);
326          *front_right = strb ? strb->surface : NULL;
327       }
328       return;
329    }
330
331    /* swap left buffers */
332    if (fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer &&
333        fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer) {
334       struct gl_renderbuffer *rbTemp;
335       rbTemp = fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer;
336       fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer =
337          fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer;
338       fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer = rbTemp;
339       if (front_left) {
340          struct st_renderbuffer *strb =
341             st_renderbuffer(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer);
342          *front_left = strb->surface;
343       }
344       /* mark back buffer contents as undefined */
345       {
346          struct st_renderbuffer *back =
347             st_renderbuffer(fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer);
348          back->defined = GL_FALSE;
349       }
350    }
351    else {
352       /* no front buffer, display the back buffer */
353       if (front_left) {
354          struct st_renderbuffer *strb =
355             st_renderbuffer(fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer);
356          *front_left = strb->surface;
357       }
358    }
359
360    /* swap right buffers (for stereo) */
361    if (fb->Attachment[BUFFER_FRONT_RIGHT].Renderbuffer &&
362        fb->Attachment[BUFFER_BACK_RIGHT].Renderbuffer) {
363       struct gl_renderbuffer *rbTemp;
364       rbTemp = fb->Attachment[BUFFER_FRONT_RIGHT].Renderbuffer;
365       fb->Attachment[BUFFER_FRONT_RIGHT].Renderbuffer =
366          fb->Attachment[BUFFER_BACK_RIGHT].Renderbuffer;
367       fb->Attachment[BUFFER_BACK_RIGHT].Renderbuffer = rbTemp;
368       if (front_right) {
369          struct st_renderbuffer *strb =
370             st_renderbuffer(fb->Attachment[BUFFER_FRONT_RIGHT].Renderbuffer);
371          *front_right = strb->surface;
372       }
373       /* mark back buffer contents as undefined */
374       {
375          struct st_renderbuffer *back =
376             st_renderbuffer(fb->Attachment[BUFFER_BACK_RIGHT].Renderbuffer);
377          back->defined = GL_FALSE;
378       }
379    }
380    else {
381       /* no front right buffer, display back right buffer (if exists) */
382       if (front_right) {
383          struct st_renderbuffer *strb =
384             st_renderbuffer(fb->Attachment[BUFFER_BACK_RIGHT].Renderbuffer);
385          *front_right = strb ? strb->surface : NULL;
386       }
387    }
388
389    /* Update the _ColorDrawBuffers[] array and _ColorReadBuffer pointer */
390    _mesa_update_framebuffer(ctx);
391
392    /* Make sure we draw into the new back surface */
393    st_invalidate_state(ctx, _NEW_BUFFERS);
394 }
395
396
397 void *st_framebuffer_private( struct st_framebuffer *stfb )
398 {
399    return stfb->Private;
400 }
401
402 void st_get_framebuffer_dimensions( struct st_framebuffer *stfb,
403                                     uint *width,
404                                     uint *height)
405 {
406    *width = stfb->Base.Width;
407    *height = stfb->Base.Height;
408 }