stw_st.c revision 210218bb96fce822ad58df6b6fdd41350c6fbdf8
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#include "state_tracker/st_gl_api.h" /* for st_gl_api_create */
31
32#include "stw_st.h"
33#include "stw_device.h"
34#include "stw_framebuffer.h"
35#include "stw_pixelformat.h"
36
37struct stw_st_framebuffer {
38   struct st_framebuffer_iface base;
39
40   struct stw_framebuffer *fb;
41   struct st_visual stvis;
42
43   struct pipe_resource *textures[ST_ATTACHMENT_COUNT];
44   unsigned texture_width, texture_height;
45   unsigned texture_mask;
46
47   struct pipe_surface *front_surface, *back_surface;
48};
49
50static INLINE struct stw_st_framebuffer *
51stw_st_framebuffer(struct st_framebuffer_iface *stfb)
52{
53   return (struct stw_st_framebuffer *) stfb;
54}
55
56/**
57 * Remove outdated textures and create the requested ones.
58 */
59static void
60stw_st_framebuffer_validate_locked(struct st_framebuffer_iface *stfb,
61                                   unsigned width, unsigned height,
62                                   unsigned mask)
63{
64   struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
65   struct pipe_resource templ;
66   unsigned i;
67
68   /* remove outdated surface */
69   pipe_surface_reference(&stwfb->front_surface, NULL);
70   pipe_surface_reference(&stwfb->back_surface, NULL);
71
72   /* remove outdated textures */
73   if (stwfb->texture_width != width || stwfb->texture_height != height) {
74      for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
75         pipe_resource_reference(&stwfb->textures[i], NULL);
76   }
77
78   memset(&templ, 0, sizeof(templ));
79   templ.target = PIPE_TEXTURE_2D;
80   templ.width0 = width;
81   templ.height0 = height;
82   templ.depth0 = 1;
83   templ.last_level = 0;
84
85   for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
86      enum pipe_format format;
87      unsigned bind;
88
89      /* the texture already exists or not requested */
90      if (stwfb->textures[i] || !(mask & (1 << i))) {
91         /* remember the texture */
92         if (stwfb->textures[i])
93            mask |= (1 << i);
94         continue;
95      }
96
97      switch (i) {
98      case ST_ATTACHMENT_FRONT_LEFT:
99      case ST_ATTACHMENT_BACK_LEFT:
100         format = stwfb->stvis.color_format;
101         bind = PIPE_BIND_DISPLAY_TARGET |
102                PIPE_BIND_RENDER_TARGET;
103         break;
104      case ST_ATTACHMENT_DEPTH_STENCIL:
105         format = stwfb->stvis.depth_stencil_format;
106         bind = PIPE_BIND_DEPTH_STENCIL;
107         break;
108      default:
109         format = PIPE_FORMAT_NONE;
110         break;
111      }
112
113      if (format != PIPE_FORMAT_NONE) {
114         templ.format = format;
115         templ.bind = bind;
116
117         stwfb->textures[i] =
118            stw_dev->screen->resource_create(stw_dev->screen, &templ);
119      }
120   }
121
122   stwfb->texture_width = width;
123   stwfb->texture_height = height;
124   stwfb->texture_mask = mask;
125}
126
127static boolean
128stw_st_framebuffer_validate(struct st_framebuffer_iface *stfb,
129                            const enum st_attachment_type *statts,
130                            unsigned count,
131                            struct pipe_resource **out)
132{
133   struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
134   unsigned statt_mask, i;
135
136   statt_mask = 0x0;
137   for (i = 0; i < count; i++)
138      statt_mask |= 1 << statts[i];
139
140   pipe_mutex_lock(stwfb->fb->mutex);
141
142   if (stwfb->fb->must_resize || (statt_mask & ~stwfb->texture_mask)) {
143      stw_st_framebuffer_validate_locked(&stwfb->base,
144            stwfb->fb->width, stwfb->fb->height, statt_mask);
145      stwfb->fb->must_resize = FALSE;
146   }
147
148   for (i = 0; i < count; i++) {
149      out[i] = NULL;
150      pipe_resource_reference(&out[i], stwfb->textures[statts[i]]);
151   }
152
153   stw_framebuffer_release(stwfb->fb);
154
155   return TRUE;
156}
157
158static struct pipe_surface *
159get_present_surface_locked(struct st_framebuffer_iface *stfb,
160                           enum st_attachment_type statt)
161{
162   struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
163   struct pipe_resource *ptex;
164   struct pipe_surface *psurf, **cache;
165
166   ptex = stwfb->textures[statt];
167   if (!ptex)
168      return NULL;
169
170   psurf = NULL;
171
172   switch (statt) {
173   case ST_ATTACHMENT_FRONT_LEFT:
174      cache = &stwfb->front_surface;
175      break;
176   case ST_ATTACHMENT_BACK_LEFT:
177      cache = &stwfb->back_surface;
178      break;
179   default:
180      cache = &psurf;
181      break;
182   }
183
184   if (!*cache) {
185      *cache = stw_dev->screen->get_tex_surface(stw_dev->screen,
186            ptex, 0, 0, 0,
187            PIPE_BIND_DISPLAY_TARGET |
188            PIPE_BIND_RENDER_TARGET);
189   }
190
191   if (psurf != *cache)
192      pipe_surface_reference(&psurf, *cache);
193
194   return psurf;
195}
196
197/**
198 * Present an attachment of the framebuffer.
199 */
200static boolean
201stw_st_framebuffer_present_locked(struct st_framebuffer_iface *stfb,
202                                  enum st_attachment_type statt)
203{
204   struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
205   struct pipe_surface *psurf;
206
207   psurf = get_present_surface_locked(&stwfb->base, statt);
208   if (psurf) {
209      stw_framebuffer_present_locked(stwfb->fb->hDC, stwfb->fb, psurf);
210      pipe_surface_reference(&psurf, NULL);
211   }
212
213   return TRUE;
214}
215
216static boolean
217stw_st_framebuffer_flush_front(struct st_framebuffer_iface *stfb,
218                               enum st_attachment_type statt)
219{
220   struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
221
222   pipe_mutex_lock(stwfb->fb->mutex);
223
224   return stw_st_framebuffer_present_locked(&stwfb->base, statt);
225}
226
227/**
228 * Create a framebuffer interface.
229 */
230struct st_framebuffer_iface *
231stw_st_create_framebuffer(struct stw_framebuffer *fb)
232{
233   struct stw_st_framebuffer *stwfb;
234
235   stwfb = CALLOC_STRUCT(stw_st_framebuffer);
236   if (!stwfb)
237      return NULL;
238
239   stwfb->fb = fb;
240   stwfb->stvis = fb->pfi->stvis;
241
242   stwfb->base.visual = &stwfb->stvis;
243   stwfb->base.flush_front = stw_st_framebuffer_flush_front;
244   stwfb->base.validate = stw_st_framebuffer_validate;
245
246   return &stwfb->base;
247}
248
249/**
250 * Destroy a framebuffer interface.
251 */
252void
253stw_st_destroy_framebuffer_locked(struct st_framebuffer_iface *stfb)
254{
255   struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
256   int i;
257
258   pipe_surface_reference(&stwfb->front_surface, NULL);
259   pipe_surface_reference(&stwfb->back_surface, NULL);
260
261   for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
262      pipe_resource_reference(&stwfb->textures[i], NULL);
263
264   FREE(stwfb);
265}
266
267/**
268 * Swap the buffers of the given framebuffer.
269 */
270boolean
271stw_st_swap_framebuffer_locked(struct st_framebuffer_iface *stfb)
272{
273   struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
274   unsigned front = ST_ATTACHMENT_FRONT_LEFT, back = ST_ATTACHMENT_BACK_LEFT;
275   struct pipe_resource *ptex;
276   struct pipe_surface *psurf;
277   unsigned mask;
278
279   /* swap the textures */
280   ptex = stwfb->textures[front];
281   stwfb->textures[front] = stwfb->textures[back];
282   stwfb->textures[back] = ptex;
283
284   /* swap the surfaces */
285   psurf = stwfb->front_surface;
286   stwfb->front_surface = stwfb->back_surface;
287   stwfb->back_surface = psurf;
288
289   /* convert to mask */
290   front = 1 << front;
291   back = 1 << back;
292
293   /* swap the bits in mask */
294   mask = stwfb->texture_mask & ~(front | back);
295   if (stwfb->texture_mask & front)
296      mask |= back;
297   if (stwfb->texture_mask & back)
298      mask |= front;
299   stwfb->texture_mask = mask;
300
301   front = ST_ATTACHMENT_FRONT_LEFT;
302   return stw_st_framebuffer_present_locked(&stwfb->base, front);
303}
304
305/**
306 * Create an st_api of the state tracker.
307 */
308struct st_api *
309stw_st_create_api(void)
310{
311   return st_gl_api_create();
312}
313