• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Mesa 3-D graphics library
3  *
4  * Copyright (C) 2010 LunarG Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  *
24  * Authors:
25  *    Chia-I Wu <olv@lunarg.com>
26  */
27 
28 #include "xm_api.h"
29 #include "xm_st.h"
30 
31 #include "util/u_inlines.h"
32 #include "util/u_atomic.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    enum pipe_texture_target target;
41 
42    unsigned texture_width, texture_height, texture_mask;
43    struct pipe_resource *textures[ST_ATTACHMENT_COUNT];
44 
45    struct pipe_resource *display_resource;
46 };
47 
48 
49 static inline struct xmesa_st_framebuffer *
xmesa_st_framebuffer(struct st_framebuffer_iface * stfbi)50 xmesa_st_framebuffer(struct st_framebuffer_iface *stfbi)
51 {
52    return (struct xmesa_st_framebuffer *) stfbi->st_manager_private;
53 }
54 
55 
56 /**
57  * Display (present) an attachment to the xlib_drawable of the framebuffer.
58  */
59 static boolean
xmesa_st_framebuffer_display(struct st_framebuffer_iface * stfbi,enum st_attachment_type statt)60 xmesa_st_framebuffer_display(struct st_framebuffer_iface *stfbi,
61                              enum st_attachment_type statt)
62 {
63    struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
64    struct pipe_resource *ptex = xstfb->textures[statt];
65    struct pipe_resource *pres;
66 
67    if (!ptex)
68       return TRUE;
69 
70    pres = xstfb->display_resource;
71    /* (re)allocate the surface for the texture to be displayed */
72    if (!pres || pres != ptex) {
73       pipe_resource_reference(&xstfb->display_resource, ptex);
74       pres = xstfb->display_resource;
75    }
76 
77    xstfb->screen->flush_frontbuffer(xstfb->screen, pres, 0, 0, &xstfb->buffer->ws, NULL);
78    return TRUE;
79 }
80 
81 
82 /**
83  * Copy the contents between the attachments.
84  */
85 static void
xmesa_st_framebuffer_copy_textures(struct st_framebuffer_iface * stfbi,enum st_attachment_type src_statt,enum st_attachment_type dst_statt,unsigned x,unsigned y,unsigned width,unsigned height)86 xmesa_st_framebuffer_copy_textures(struct st_framebuffer_iface *stfbi,
87                                    enum st_attachment_type src_statt,
88                                    enum st_attachment_type dst_statt,
89                                    unsigned x, unsigned y,
90                                    unsigned width, unsigned height)
91 {
92    struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
93    struct pipe_resource *src_ptex = xstfb->textures[src_statt];
94    struct pipe_resource *dst_ptex = xstfb->textures[dst_statt];
95    struct pipe_box src_box;
96    struct pipe_context *pipe;
97 
98    if (!src_ptex || !dst_ptex)
99       return;
100 
101    pipe = xmesa_get_context(stfbi);
102 
103    u_box_2d(x, y, width, height, &src_box);
104 
105    if (src_ptex && dst_ptex)
106       pipe->resource_copy_region(pipe, dst_ptex, 0, x, y, 0,
107                                  src_ptex, 0, &src_box);
108 }
109 
110 
111 /**
112  * Remove outdated textures and create the requested ones.
113  * This is a helper used during framebuffer validation.
114  */
115 boolean
xmesa_st_framebuffer_validate_textures(struct st_framebuffer_iface * stfbi,unsigned width,unsigned height,unsigned mask)116 xmesa_st_framebuffer_validate_textures(struct st_framebuffer_iface *stfbi,
117                                        unsigned width, unsigned height,
118                                        unsigned mask)
119 {
120    struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
121    struct pipe_resource templ;
122    enum st_attachment_type i;
123 
124    /* remove outdated textures */
125    if (xstfb->texture_width != width || xstfb->texture_height != height) {
126       for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
127          pipe_resource_reference(&xstfb->textures[i], NULL);
128    }
129 
130    memset(&templ, 0, sizeof(templ));
131    templ.target = xstfb->target;
132    templ.width0 = width;
133    templ.height0 = height;
134    templ.depth0 = 1;
135    templ.array_size = 1;
136    templ.last_level = 0;
137    templ.nr_samples = xstfb->stvis.samples;
138 
139    for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
140       enum pipe_format format;
141       unsigned bind;
142 
143       /* the texture already exists or not requested */
144       if (xstfb->textures[i] || !(mask & (1 << i))) {
145          /* remember the texture */
146          if (xstfb->textures[i])
147             mask |= (1 << i);
148          continue;
149       }
150 
151       switch (i) {
152       case ST_ATTACHMENT_FRONT_LEFT:
153       case ST_ATTACHMENT_BACK_LEFT:
154       case ST_ATTACHMENT_FRONT_RIGHT:
155       case ST_ATTACHMENT_BACK_RIGHT:
156          format = xstfb->stvis.color_format;
157          bind = PIPE_BIND_DISPLAY_TARGET |
158                      PIPE_BIND_RENDER_TARGET;
159          break;
160       case ST_ATTACHMENT_DEPTH_STENCIL:
161          format = xstfb->stvis.depth_stencil_format;
162          bind = PIPE_BIND_DEPTH_STENCIL;
163          break;
164       default:
165          format = PIPE_FORMAT_NONE;
166          break;
167       }
168 
169       if (format != PIPE_FORMAT_NONE) {
170          templ.format = format;
171          templ.bind = bind;
172 
173          xstfb->textures[i] =
174             xstfb->screen->resource_create(xstfb->screen, &templ);
175          if (!xstfb->textures[i])
176             return FALSE;
177       }
178    }
179 
180    xstfb->texture_width = width;
181    xstfb->texture_height = height;
182    xstfb->texture_mask = mask;
183 
184    return TRUE;
185 }
186 
187 
188 /**
189  * Check that a framebuffer's attachments match the window's size.
190  *
191  * Called via st_framebuffer_iface::validate()
192  *
193  * \param statts  array of framebuffer attachments
194  * \param count  number of framebuffer attachments in statts[]
195  * \param out  returns resources for each of the attachments
196  */
197 static boolean
xmesa_st_framebuffer_validate(struct st_context_iface * stctx,struct st_framebuffer_iface * stfbi,const enum st_attachment_type * statts,unsigned count,struct pipe_resource ** out)198 xmesa_st_framebuffer_validate(struct st_context_iface *stctx,
199                               struct st_framebuffer_iface *stfbi,
200                               const enum st_attachment_type *statts,
201                               unsigned count,
202                               struct pipe_resource **out)
203 {
204    struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
205    unsigned statt_mask, new_mask, i;
206    boolean resized;
207    boolean ret;
208 
209    /* build mask of ST_ATTACHMENT bits */
210    statt_mask = 0x0;
211    for (i = 0; i < count; i++)
212       statt_mask |= 1 << statts[i];
213 
214    /* record newly allocated textures */
215    new_mask = statt_mask & ~xstfb->texture_mask;
216 
217    /* If xmesa_strict_invalidate is not set, we will not yet have
218     * called XGetGeometry().  Do so here:
219     */
220    if (!xmesa_strict_invalidate)
221       xmesa_check_buffer_size(xstfb->buffer);
222 
223    resized = (xstfb->buffer->width != xstfb->texture_width ||
224               xstfb->buffer->height != xstfb->texture_height);
225 
226    /* revalidate textures */
227    if (resized || new_mask) {
228       ret = xmesa_st_framebuffer_validate_textures(stfbi,
229                   xstfb->buffer->width, xstfb->buffer->height, statt_mask);
230       if (!ret)
231          return ret;
232 
233       if (!resized) {
234          enum st_attachment_type back, front;
235 
236          back = ST_ATTACHMENT_BACK_LEFT;
237          front = ST_ATTACHMENT_FRONT_LEFT;
238          /* copy the contents if front is newly allocated and back is not */
239          if ((statt_mask & (1 << back)) &&
240              (new_mask & (1 << front)) &&
241              !(new_mask & (1 << back))) {
242             xmesa_st_framebuffer_copy_textures(stfbi, back, front,
243                   0, 0, xstfb->texture_width, xstfb->texture_height);
244          }
245       }
246    }
247 
248    for (i = 0; i < count; i++)
249       pipe_resource_reference(&out[i], xstfb->textures[statts[i]]);
250 
251    return TRUE;
252 }
253 
254 
255 /**
256  * Called via st_framebuffer_iface::flush_front()
257  */
258 static boolean
xmesa_st_framebuffer_flush_front(struct st_context_iface * stctx,struct st_framebuffer_iface * stfbi,enum st_attachment_type statt)259 xmesa_st_framebuffer_flush_front(struct st_context_iface *stctx,
260                                  struct st_framebuffer_iface *stfbi,
261                                  enum st_attachment_type statt)
262 {
263    struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
264    boolean ret;
265 
266    ret = xmesa_st_framebuffer_display(stfbi, statt);
267 
268    if (ret && xmesa_strict_invalidate)
269       xmesa_check_buffer_size(xstfb->buffer);
270 
271    return ret;
272 }
273 
274 static uint32_t xmesa_stfbi_ID = 0;
275 
276 struct st_framebuffer_iface *
xmesa_create_st_framebuffer(XMesaDisplay xmdpy,XMesaBuffer b)277 xmesa_create_st_framebuffer(XMesaDisplay xmdpy, XMesaBuffer b)
278 {
279    struct st_framebuffer_iface *stfbi;
280    struct xmesa_st_framebuffer *xstfb;
281 
282    assert(xmdpy->display == b->xm_visual->display);
283 
284    stfbi = CALLOC_STRUCT(st_framebuffer_iface);
285    xstfb = CALLOC_STRUCT(xmesa_st_framebuffer);
286    if (!stfbi || !xstfb) {
287       free(stfbi);
288       free(xstfb);
289       return NULL;
290    }
291 
292    xstfb->display = xmdpy;
293    xstfb->buffer = b;
294    xstfb->screen = xmdpy->screen;
295    xstfb->stvis = b->xm_visual->stvis;
296    if (xstfb->screen->get_param(xstfb->screen, PIPE_CAP_NPOT_TEXTURES))
297       xstfb->target = PIPE_TEXTURE_2D;
298    else
299       xstfb->target = PIPE_TEXTURE_RECT;
300 
301    stfbi->visual = &xstfb->stvis;
302    stfbi->flush_front = xmesa_st_framebuffer_flush_front;
303    stfbi->validate = xmesa_st_framebuffer_validate;
304    stfbi->ID = p_atomic_inc_return(&xmesa_stfbi_ID);
305    stfbi->state_manager = xmdpy->smapi;
306    p_atomic_set(&stfbi->stamp, 1);
307    stfbi->st_manager_private = (void *) xstfb;
308 
309    return stfbi;
310 }
311 
312 
313 void
xmesa_destroy_st_framebuffer(struct st_framebuffer_iface * stfbi)314 xmesa_destroy_st_framebuffer(struct st_framebuffer_iface *stfbi)
315 {
316    struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
317    int i;
318 
319    pipe_resource_reference(&xstfb->display_resource, NULL);
320 
321    for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
322       pipe_resource_reference(&xstfb->textures[i], NULL);
323 
324    free(xstfb);
325    free(stfbi);
326 }
327 
328 
329 /**
330  * Return the pipe_surface which corresponds to the given
331  * framebuffer attachment.
332  */
333 struct pipe_resource *
xmesa_get_framebuffer_resource(struct st_framebuffer_iface * stfbi,enum st_attachment_type att)334 xmesa_get_framebuffer_resource(struct st_framebuffer_iface *stfbi,
335                                enum st_attachment_type att)
336 {
337    struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
338    return xstfb->textures[att];
339 }
340 
341 
342 void
xmesa_swap_st_framebuffer(struct st_framebuffer_iface * stfbi)343 xmesa_swap_st_framebuffer(struct st_framebuffer_iface *stfbi)
344 {
345    struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
346    boolean ret;
347 
348    ret = xmesa_st_framebuffer_display(stfbi, ST_ATTACHMENT_BACK_LEFT);
349    if (ret) {
350       struct pipe_resource **front, **back, *tmp;
351 
352       front = &xstfb->textures[ST_ATTACHMENT_FRONT_LEFT];
353       back = &xstfb->textures[ST_ATTACHMENT_BACK_LEFT];
354       /* swap textures only if the front texture has been allocated */
355       if (*front) {
356          tmp = *front;
357          *front = *back;
358          *back = tmp;
359 
360          /* the current context should validate the buffer after swapping */
361          if (!xmesa_strict_invalidate)
362             xmesa_notify_invalid_buffer(xstfb->buffer);
363       }
364 
365       if (xmesa_strict_invalidate)
366 	 xmesa_check_buffer_size(xstfb->buffer);
367    }
368 }
369 
370 
371 void
xmesa_copy_st_framebuffer(struct st_framebuffer_iface * stfbi,enum st_attachment_type src,enum st_attachment_type dst,int x,int y,int w,int h)372 xmesa_copy_st_framebuffer(struct st_framebuffer_iface *stfbi,
373                           enum st_attachment_type src,
374                           enum st_attachment_type dst,
375                           int x, int y, int w, int h)
376 {
377    xmesa_st_framebuffer_copy_textures(stfbi, src, dst, x, y, w, h);
378    if (dst == ST_ATTACHMENT_FRONT_LEFT)
379       xmesa_st_framebuffer_display(stfbi, dst);
380 }
381 
382 
383 struct pipe_resource*
xmesa_get_attachment(struct st_framebuffer_iface * stfbi,enum st_attachment_type st_attachment)384 xmesa_get_attachment(struct st_framebuffer_iface *stfbi,
385                      enum st_attachment_type st_attachment)
386 {
387    struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
388    struct pipe_resource *res;
389 
390    res = xstfb->textures[st_attachment];
391    return res;
392 }
393 
394 
395 struct pipe_context*
xmesa_get_context(struct st_framebuffer_iface * stfbi)396 xmesa_get_context(struct st_framebuffer_iface *stfbi)
397 {
398    struct pipe_context *pipe;
399    struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
400 
401    pipe = xstfb->display->pipe;
402    if (!pipe) {
403       pipe = xstfb->screen->context_create(xstfb->screen, NULL, 0);
404       if (!pipe)
405          return NULL;
406       xstfb->display->pipe = pipe;
407    }
408    return pipe;
409 }
410