xm_st.c revision 813c58d77e21cb59adb914b4b4ee26be758ff0ea
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
34struct xmesa_st_framebuffer {
35   struct pipe_screen *screen;
36   XMesaBuffer buffer;
37
38   struct st_visual stvis;
39
40   unsigned texture_width, texture_height;
41   struct pipe_texture *textures[ST_ATTACHMENT_COUNT];
42
43   struct pipe_surface *display_surface;
44};
45
46static INLINE struct xmesa_st_framebuffer *
47xmesa_st_framebuffer(struct st_framebuffer_iface *stfbi)
48{
49   return (struct xmesa_st_framebuffer *) stfbi->st_manager_private;
50}
51
52/**
53 * Display an attachment to the xlib_drawable of the framebuffer.
54 */
55static boolean
56xmesa_st_framebuffer_display(struct st_framebuffer_iface *stfbi,
57                             enum st_attachment_type statt)
58{
59   struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
60   struct pipe_texture *ptex = xstfb->textures[statt];
61   struct pipe_surface *psurf;
62
63   if (!ptex)
64      return TRUE;
65
66   psurf = xstfb->display_surface;
67   /* (re)allocate the surface for the texture to be displayed */
68   if (!psurf || psurf->texture != ptex) {
69      pipe_surface_reference(&xstfb->display_surface, NULL);
70
71      psurf = xstfb->screen->get_tex_surface(xstfb->screen,
72            ptex, 0, 0, 0, PIPE_BUFFER_USAGE_CPU_READ);
73      if (!psurf)
74         return FALSE;
75
76      xstfb->display_surface = psurf;
77   }
78
79   xstfb->screen->flush_frontbuffer(xstfb->screen, psurf, &xstfb->buffer->ws);
80
81   return TRUE;
82}
83
84/**
85 * Remove outdated textures and create the requested ones.
86 */
87static void
88xmesa_st_framebuffer_validate_textures(struct st_framebuffer_iface *stfbi,
89                                       const enum st_attachment_type *statts,
90                                       unsigned count)
91{
92   struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
93   struct pipe_texture templ;
94   unsigned request_mask, i;
95
96   request_mask = 0;
97   for (i = 0; i < count; i++)
98      request_mask |= 1 << statts[i];
99
100   memset(&templ, 0, sizeof(templ));
101   templ.target = PIPE_TEXTURE_2D;
102   templ.width0 = xstfb->texture_width;
103   templ.height0 = xstfb->texture_height;
104   templ.depth0 = 1;
105   templ.last_level = 0;
106
107   for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
108      struct pipe_texture *ptex = xstfb->textures[i];
109      enum pipe_format format;
110      unsigned tex_usage;
111
112      /* remove outdated textures */
113      if (ptex && (ptex->width0 != xstfb->texture_width ||
114                   ptex->height0 != xstfb->texture_height)) {
115         pipe_texture_reference(&xstfb->textures[i], NULL);
116         ptex = NULL;
117      }
118
119      /* the texture already exists or not requested */
120      if (ptex || !(request_mask & (1 << i)))
121         continue;
122
123      switch (i) {
124      case ST_ATTACHMENT_FRONT_LEFT:
125      case ST_ATTACHMENT_BACK_LEFT:
126      case ST_ATTACHMENT_FRONT_RIGHT:
127      case ST_ATTACHMENT_BACK_RIGHT:
128         format = xstfb->stvis.color_format;
129         tex_usage = PIPE_TEXTURE_USAGE_DISPLAY_TARGET |
130                     PIPE_TEXTURE_USAGE_RENDER_TARGET;
131         break;
132      case ST_ATTACHMENT_DEPTH_STENCIL:
133         format = xstfb->stvis.depth_stencil_format;
134         tex_usage = PIPE_TEXTURE_USAGE_DEPTH_STENCIL;
135         break;
136      default:
137         format = PIPE_FORMAT_NONE;
138         break;
139      }
140
141      if (format != PIPE_FORMAT_NONE) {
142         templ.format = format;
143         templ.tex_usage = tex_usage;
144
145         xstfb->textures[i] =
146            xstfb->screen->texture_create(xstfb->screen, &templ);
147      }
148   }
149}
150
151static boolean
152xmesa_st_framebuffer_validate(struct st_framebuffer_iface *stfbi,
153                              const enum st_attachment_type *statts,
154                              unsigned count,
155                              struct pipe_texture **out)
156{
157   struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
158   unsigned i;
159
160   /* revalidate textures */
161   if (xstfb->buffer->width != xstfb->texture_width ||
162       xstfb->buffer->height != xstfb->texture_height) {
163      xstfb->texture_width = xstfb->buffer->width;
164      xstfb->texture_height = xstfb->buffer->height;
165
166      xmesa_st_framebuffer_validate_textures(stfbi, statts, count);
167   }
168
169   for (i = 0; i < count; i++) {
170      out[i] = NULL;
171      pipe_texture_reference(&out[i], xstfb->textures[statts[i]]);
172   }
173
174   return TRUE;
175}
176
177static boolean
178xmesa_st_framebuffer_flush_front(struct st_framebuffer_iface *stfbi,
179                                 enum st_attachment_type statt)
180{
181   struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
182   boolean ret;
183
184   ret = xmesa_st_framebuffer_display(stfbi, statt);
185   if (ret)
186      xmesa_check_buffer_size(xstfb->buffer);
187
188   return ret;
189}
190
191struct st_framebuffer_iface *
192xmesa_create_st_framebuffer(struct pipe_screen *screen, XMesaBuffer b)
193{
194   struct st_framebuffer_iface *stfbi;
195   struct xmesa_st_framebuffer *xstfb;
196
197   stfbi = CALLOC_STRUCT(st_framebuffer_iface);
198   xstfb = CALLOC_STRUCT(xmesa_st_framebuffer);
199   if (!stfbi || !xstfb) {
200      if (stfbi)
201         FREE(stfbi);
202      if (xstfb)
203         FREE(xstfb);
204      return NULL;
205   }
206
207   xstfb->screen = screen;
208   xstfb->buffer = b;
209   xstfb->stvis = b->xm_visual->stvis;
210
211   stfbi->visual = &xstfb->stvis;
212   stfbi->flush_front = xmesa_st_framebuffer_flush_front;
213   stfbi->validate = xmesa_st_framebuffer_validate;
214   stfbi->st_manager_private = (void *) xstfb;
215
216   return stfbi;
217}
218
219void
220xmesa_destroy_st_framebuffer(struct st_framebuffer_iface *stfbi)
221{
222   struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
223   int i;
224
225   pipe_surface_reference(&xstfb->display_surface, NULL);
226
227   for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
228      pipe_texture_reference(&xstfb->textures[i], NULL);
229
230   FREE(xstfb);
231   FREE(stfbi);
232}
233
234void
235xmesa_swap_st_framebuffer(struct st_framebuffer_iface *stfbi)
236{
237   struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
238   boolean ret;
239
240   ret = xmesa_st_framebuffer_display(stfbi, ST_ATTACHMENT_BACK_LEFT);
241   if (ret) {
242      struct pipe_texture **front, **back, *tmp;
243
244      front = &xstfb->textures[ST_ATTACHMENT_FRONT_LEFT];
245      back = &xstfb->textures[ST_ATTACHMENT_BACK_LEFT];
246      /* swap textures only if the front texture has been allocated */
247      if (*front) {
248         tmp = *front;
249         *front = *back;
250         *back = tmp;
251      }
252
253      xmesa_check_buffer_size(xstfb->buffer);
254   }
255}
256
257void
258xmesa_copy_st_framebuffer(struct st_framebuffer_iface *stfbi,
259                          enum st_attachment_type src,
260                          enum st_attachment_type dst,
261                          int x, int y, int w, int h)
262{
263   /* TODO */
264}
265