Merge branch '7.8'
[profile/ivi/mesa.git] / src / gallium / state_trackers / glx / xlib / xm_st.c
1 /*
2  * Mesa 3-D graphics library
3  * Version:  7.9
4  *
5  * Copyright (C) 2010 LunarG Inc.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * Authors:
25  *    Chia-I Wu <olv@lunarg.com>
26  */
27
28 #include "util/u_memory.h"
29 #include "util/u_inlines.h"
30
31 #include "xm_api.h"
32 #include "xm_st.h"
33
34 struct xmesa_st_framebuffer {
35    XMesaDisplay display;
36    XMesaBuffer buffer;
37    struct pipe_screen *screen;
38
39    struct st_visual stvis;
40
41    unsigned texture_width, texture_height, texture_mask;
42    struct pipe_texture *textures[ST_ATTACHMENT_COUNT];
43
44    struct pipe_surface *display_surface;
45 };
46
47 static INLINE struct xmesa_st_framebuffer *
48 xmesa_st_framebuffer(struct st_framebuffer_iface *stfbi)
49 {
50    return (struct xmesa_st_framebuffer *) stfbi->st_manager_private;
51 }
52
53 /**
54  * Display an attachment to the xlib_drawable of the framebuffer.
55  */
56 static boolean
57 xmesa_st_framebuffer_display(struct st_framebuffer_iface *stfbi,
58                              enum st_attachment_type statt)
59 {
60    struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
61    struct pipe_texture *ptex = xstfb->textures[statt];
62    struct pipe_surface *psurf;
63
64    if (!ptex)
65       return TRUE;
66
67    psurf = xstfb->display_surface;
68    /* (re)allocate the surface for the texture to be displayed */
69    if (!psurf || psurf->texture != ptex) {
70       pipe_surface_reference(&xstfb->display_surface, NULL);
71
72       psurf = xstfb->screen->get_tex_surface(xstfb->screen,
73             ptex, 0, 0, 0, PIPE_BUFFER_USAGE_CPU_READ);
74       if (!psurf)
75          return FALSE;
76
77       xstfb->display_surface = psurf;
78    }
79
80    xstfb->screen->flush_frontbuffer(xstfb->screen, psurf, &xstfb->buffer->ws);
81
82    return TRUE;
83 }
84
85 /**
86  * Copy the contents between the attachments.
87  */
88 static void
89 xmesa_st_framebuffer_copy_textures(struct st_framebuffer_iface *stfbi,
90                                    enum st_attachment_type src_statt,
91                                    enum st_attachment_type dst_statt,
92                                    unsigned x, unsigned y,
93                                    unsigned width, unsigned height)
94 {
95    struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
96    struct pipe_texture *src_ptex = xstfb->textures[src_statt];
97    struct pipe_texture *dst_ptex = xstfb->textures[dst_statt];
98    struct pipe_surface *src, *dst;
99    struct pipe_context *pipe;
100
101    if (!src_ptex || !dst_ptex)
102       return;
103
104    pipe = xstfb->display->pipe;
105    if (!pipe) {
106       pipe = xstfb->screen->context_create(xstfb->screen, NULL);
107       if (!pipe)
108          return;
109       xstfb->display->pipe = pipe;
110    }
111
112    src = xstfb->screen->get_tex_surface(xstfb->screen,
113          src_ptex, 0, 0, 0, PIPE_BUFFER_USAGE_GPU_READ);
114    dst = xstfb->screen->get_tex_surface(xstfb->screen,
115          dst_ptex, 0, 0, 0, PIPE_BUFFER_USAGE_GPU_WRITE);
116
117    if (src && dst)
118       pipe->surface_copy(pipe, dst, x, y, src, x, y, width, height);
119
120    pipe_surface_reference(&src, NULL);
121    pipe_surface_reference(&dst, NULL);
122 }
123
124 /**
125  * Remove outdated textures and create the requested ones.
126  */
127 static void
128 xmesa_st_framebuffer_validate_textures(struct st_framebuffer_iface *stfbi,
129                                        unsigned width, unsigned height,
130                                        unsigned mask)
131 {
132    struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
133    struct pipe_texture templ;
134    unsigned i;
135
136    /* remove outdated textures */
137    if (xstfb->texture_width != width || xstfb->texture_height != height) {
138       for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
139          pipe_texture_reference(&xstfb->textures[i], NULL);
140    }
141
142    memset(&templ, 0, sizeof(templ));
143    templ.target = PIPE_TEXTURE_2D;
144    templ.width0 = width;
145    templ.height0 = height;
146    templ.depth0 = 1;
147    templ.last_level = 0;
148
149    for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
150       enum pipe_format format;
151       unsigned tex_usage;
152
153       /* the texture already exists or not requested */
154       if (xstfb->textures[i] || !(mask & (1 << i))) {
155          /* remember the texture */
156          if (xstfb->textures[i])
157             mask |= (1 << i);
158          continue;
159       }
160
161       switch (i) {
162       case ST_ATTACHMENT_FRONT_LEFT:
163       case ST_ATTACHMENT_BACK_LEFT:
164       case ST_ATTACHMENT_FRONT_RIGHT:
165       case ST_ATTACHMENT_BACK_RIGHT:
166          format = xstfb->stvis.color_format;
167          tex_usage = PIPE_TEXTURE_USAGE_DISPLAY_TARGET |
168                      PIPE_TEXTURE_USAGE_RENDER_TARGET;
169          break;
170       case ST_ATTACHMENT_DEPTH_STENCIL:
171          format = xstfb->stvis.depth_stencil_format;
172          tex_usage = PIPE_TEXTURE_USAGE_DEPTH_STENCIL;
173          break;
174       default:
175          format = PIPE_FORMAT_NONE;
176          break;
177       }
178
179       if (format != PIPE_FORMAT_NONE) {
180          templ.format = format;
181          templ.tex_usage = tex_usage;
182
183          xstfb->textures[i] =
184             xstfb->screen->texture_create(xstfb->screen, &templ);
185       }
186    }
187
188    xstfb->texture_width = width;
189    xstfb->texture_height = height;
190    xstfb->texture_mask = mask;
191 }
192
193 static boolean 
194 xmesa_st_framebuffer_validate(struct st_framebuffer_iface *stfbi,
195                               const enum st_attachment_type *statts,
196                               unsigned count,
197                               struct pipe_texture **out)
198 {
199    struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
200    unsigned statt_mask, new_mask, i;
201    boolean resized;
202
203    statt_mask = 0x0;
204    for (i = 0; i < count; i++)
205       statt_mask |= 1 << statts[i];
206    /* record newly allocated textures */
207    new_mask = statt_mask & ~xstfb->texture_mask;
208
209    resized = (xstfb->buffer->width != xstfb->texture_width ||
210               xstfb->buffer->height != xstfb->texture_height);
211
212    /* revalidate textures */
213    if (resized || new_mask) {
214       xmesa_st_framebuffer_validate_textures(stfbi,
215             xstfb->buffer->width, xstfb->buffer->height, statt_mask);
216
217       if (!resized) {
218          enum st_attachment_type back, front;
219
220          back = ST_ATTACHMENT_BACK_LEFT;
221          front = ST_ATTACHMENT_FRONT_LEFT;
222          /* copy the contents if front is newly allocated and back is not */
223          if ((statt_mask & (1 << back)) &&
224              (new_mask & (1 << front)) &&
225              !(new_mask & (1 << back))) {
226             xmesa_st_framebuffer_copy_textures(stfbi, back, front,
227                   0, 0, xstfb->texture_width, xstfb->texture_height);
228          }
229       }
230    }
231
232    for (i = 0; i < count; i++) {
233       out[i] = NULL;
234       pipe_texture_reference(&out[i], xstfb->textures[statts[i]]);
235    }
236
237    return TRUE;
238 }
239
240 static boolean
241 xmesa_st_framebuffer_flush_front(struct st_framebuffer_iface *stfbi,
242                                  enum st_attachment_type statt)
243 {
244    struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
245    boolean ret;
246
247    ret = xmesa_st_framebuffer_display(stfbi, statt);
248    if (ret)
249       xmesa_check_buffer_size(xstfb->buffer);
250
251    return ret;
252 }
253
254 struct st_framebuffer_iface *
255 xmesa_create_st_framebuffer(XMesaDisplay xmdpy, XMesaBuffer b)
256 {
257    struct st_framebuffer_iface *stfbi;
258    struct xmesa_st_framebuffer *xstfb;
259
260    assert(xmdpy->display == b->xm_visual->display);
261
262    stfbi = CALLOC_STRUCT(st_framebuffer_iface);
263    xstfb = CALLOC_STRUCT(xmesa_st_framebuffer);
264    if (!stfbi || !xstfb) {
265       if (stfbi)
266          FREE(stfbi);
267       if (xstfb)
268          FREE(xstfb);
269       return NULL;
270    }
271
272    xstfb->display = xmdpy;
273    xstfb->buffer = b;
274    xstfb->screen = xmdpy->screen;
275    xstfb->stvis = b->xm_visual->stvis;
276
277    stfbi->visual = &xstfb->stvis;
278    stfbi->flush_front = xmesa_st_framebuffer_flush_front;
279    stfbi->validate = xmesa_st_framebuffer_validate;
280    stfbi->st_manager_private = (void *) xstfb;
281
282    return stfbi;
283 }
284
285 void
286 xmesa_destroy_st_framebuffer(struct st_framebuffer_iface *stfbi)
287 {
288    struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
289    int i;
290
291    pipe_surface_reference(&xstfb->display_surface, NULL);
292
293    for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
294       pipe_texture_reference(&xstfb->textures[i], NULL);
295
296    FREE(xstfb);
297    FREE(stfbi);
298 }
299
300 void
301 xmesa_swap_st_framebuffer(struct st_framebuffer_iface *stfbi)
302 {
303    struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
304    boolean ret;
305
306    ret = xmesa_st_framebuffer_display(stfbi, ST_ATTACHMENT_BACK_LEFT);
307    if (ret) {
308       struct pipe_texture **front, **back, *tmp;
309
310       front = &xstfb->textures[ST_ATTACHMENT_FRONT_LEFT];
311       back = &xstfb->textures[ST_ATTACHMENT_BACK_LEFT];
312       /* swap textures only if the front texture has been allocated */
313       if (*front) {
314          tmp = *front;
315          *front = *back;
316          *back = tmp;
317       }
318
319       xmesa_check_buffer_size(xstfb->buffer);
320    }
321 }
322
323 void
324 xmesa_copy_st_framebuffer(struct st_framebuffer_iface *stfbi,
325                           enum st_attachment_type src,
326                           enum st_attachment_type dst,
327                           int x, int y, int w, int h)
328 {
329    xmesa_st_framebuffer_copy_textures(stfbi, src, dst, x, y, w, h);
330    if (dst == ST_ATTACHMENT_FRONT_LEFT)
331       xmesa_st_framebuffer_display(stfbi, dst);
332 }