wrapper_sw_winsys.c revision 4c7001462607e6e99e474d6271dd481d3f8f201c
1/**********************************************************
2 * Copyright 2010 VMware, Inc.  All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 *
24 **********************************************************/
25
26
27#include "wrapper_sw_winsys.h"
28
29#include "pipe/p_format.h"
30#include "pipe/p_state.h"
31
32#include "state_tracker/sw_winsys.h"
33
34#include "util/u_memory.h"
35#include "util/u_inlines.h"
36
37/*
38 * This code wraps a pipe_screen and exposes a sw_winsys interface for use
39 * with software resterizers. This code is used by the DRM based winsys to
40 * allow access to the drm driver.
41 *
42 * We must borrow the whole stack because only the pipe screen knows how
43 * to decode the content of a buffer. Or how to create a buffer that
44 * can still be used by drivers using real hardware (as the case is
45 * with software st/xorg but hw st/dri).
46 *
47 * We also need a pipe context for the transfers.
48 */
49
50struct wrapper_sw_winsys
51{
52   struct sw_winsys base;
53   struct pipe_screen *screen;
54   struct pipe_context *pipe;
55   enum pipe_texture_target target;
56};
57
58struct wrapper_sw_displaytarget
59{
60   struct wrapper_sw_winsys *winsys;
61   struct pipe_resource *tex;
62   struct pipe_transfer *transfer;
63
64   unsigned width;
65   unsigned height;
66   unsigned map_count;
67   unsigned stride; /**< because we give stride at create */
68   void *ptr;
69};
70
71static INLINE struct wrapper_sw_winsys *
72wrapper_sw_winsys(struct sw_winsys *ws)
73{
74   return (struct wrapper_sw_winsys *)ws;
75}
76
77static INLINE struct wrapper_sw_displaytarget *
78wrapper_sw_displaytarget(struct sw_displaytarget *dt)
79{
80   return (struct wrapper_sw_displaytarget *)dt;
81}
82
83
84/*
85 * Functions
86 */
87
88
89static boolean
90wsw_dt_get_stride(struct wrapper_sw_displaytarget *wdt, unsigned *stride)
91{
92   struct pipe_context *pipe = wdt->winsys->pipe;
93   struct pipe_resource *tex = wdt->tex;
94   struct pipe_transfer *tr;
95
96   tr = pipe_get_transfer(pipe, tex, 0, 0,
97                          PIPE_TRANSFER_READ_WRITE,
98                          0, 0, wdt->width, wdt->height);
99   if (!tr)
100      return FALSE;
101
102   *stride = tr->stride;
103   wdt->stride = tr->stride;
104
105   pipe->transfer_destroy(pipe, tr);
106
107   return TRUE;
108}
109
110static struct sw_displaytarget *
111wsw_dt_wrap_texture(struct wrapper_sw_winsys *wsw,
112                    struct pipe_resource *tex, unsigned *stride)
113{
114   struct wrapper_sw_displaytarget *wdt = CALLOC_STRUCT(wrapper_sw_displaytarget);
115   if (!wdt)
116      goto err_unref;
117
118   wdt->tex = tex;
119   wdt->winsys = wsw;
120
121   if (!wsw_dt_get_stride(wdt, stride))
122      goto err_free;
123
124   return (struct sw_displaytarget *)wdt;
125
126err_free:
127   FREE(wdt);
128err_unref:
129   pipe_resource_reference(&tex, NULL);
130   return NULL;
131}
132
133static struct sw_displaytarget *
134wsw_dt_create(struct sw_winsys *ws,
135              unsigned bind,
136              enum pipe_format format,
137              unsigned width, unsigned height,
138              unsigned alignment,
139              unsigned *stride)
140{
141   struct wrapper_sw_winsys *wsw = wrapper_sw_winsys(ws);
142   struct pipe_resource templ;
143   struct pipe_resource *tex;
144
145   /*
146    * XXX Why don't we just get the template.
147    */
148   memset(&templ, 0, sizeof(templ));
149   templ.target = wsw->target;
150   templ.width0 = width;
151   templ.height0 = height;
152   templ.depth0 = 1;
153   templ.array_size = 1;
154   templ.format = format;
155   templ.bind = bind;
156
157   /* XXX alignment: we can't do anything about this */
158
159   tex = wsw->screen->resource_create(wsw->screen, &templ);
160   if (!tex)
161      return NULL;
162
163   return wsw_dt_wrap_texture(wsw, tex, stride);
164}
165
166static struct sw_displaytarget *
167wsw_dt_from_handle(struct sw_winsys *ws,
168                   const struct pipe_resource *templ,
169                   struct winsys_handle *whandle,
170                   unsigned *stride)
171{
172   struct wrapper_sw_winsys *wsw = wrapper_sw_winsys(ws);
173   struct pipe_resource *tex;
174
175   tex = wsw->screen->resource_from_handle(wsw->screen, templ, whandle);
176   if (!tex)
177      return NULL;
178
179   return wsw_dt_wrap_texture(wsw, tex, stride);
180}
181
182static boolean
183wsw_dt_get_handle(struct sw_winsys *ws,
184                  struct sw_displaytarget *dt,
185                  struct winsys_handle *whandle)
186{
187   struct wrapper_sw_winsys *wsw = wrapper_sw_winsys(ws);
188   struct wrapper_sw_displaytarget *wdt = wrapper_sw_displaytarget(dt);
189   struct pipe_resource *tex = wdt->tex;
190
191   return wsw->screen->resource_get_handle(wsw->screen, tex, whandle);
192}
193
194static void *
195wsw_dt_map(struct sw_winsys *ws,
196           struct sw_displaytarget *dt,
197           unsigned flags)
198{
199   struct wrapper_sw_displaytarget *wdt = wrapper_sw_displaytarget(dt);
200   struct pipe_context *pipe = wdt->winsys->pipe;
201   struct pipe_resource *tex = wdt->tex;
202   struct pipe_transfer *tr;
203   void *ptr;
204
205   if (!wdt->map_count) {
206
207      assert(!wdt->transfer);
208
209      tr = pipe_get_transfer(pipe, tex, 0, 0,
210                             PIPE_TRANSFER_READ_WRITE,
211                             0, 0, wdt->width, wdt->height);
212      if (!tr)
213         return NULL;
214
215      ptr = pipe->transfer_map(pipe, tr);
216      if (!ptr)
217        goto err;
218
219      wdt->transfer = tr;
220      wdt->ptr = ptr;
221
222      /* XXX Handle this case */
223      assert(tr->stride == wdt->stride);
224   }
225
226   wdt->map_count++;
227
228   return wdt->ptr;
229
230err:
231   pipe->transfer_destroy(pipe, tr);
232   return NULL;
233}
234
235static void
236wsw_dt_unmap(struct sw_winsys *ws,
237             struct sw_displaytarget *dt)
238{
239   struct wrapper_sw_displaytarget *wdt = wrapper_sw_displaytarget(dt);
240   struct pipe_context *pipe = wdt->winsys->pipe;
241
242   assert(wdt->transfer);
243
244   wdt->map_count--;
245
246   if (wdt->map_count)
247      return;
248
249   pipe->transfer_unmap(pipe, wdt->transfer);
250   pipe->transfer_destroy(pipe, wdt->transfer);
251   wdt->transfer = NULL;
252}
253
254static void
255wsw_dt_destroy(struct sw_winsys *ws,
256               struct sw_displaytarget *dt)
257{
258   struct wrapper_sw_displaytarget *wdt = wrapper_sw_displaytarget(dt);
259
260   pipe_resource_reference(&wdt->tex, NULL);
261
262   FREE(wdt);
263}
264
265static void
266wsw_destroy(struct sw_winsys *ws)
267{
268   struct wrapper_sw_winsys *wsw = wrapper_sw_winsys(ws);
269
270   wsw->pipe->destroy(wsw->pipe);
271   wsw->screen->destroy(wsw->screen);
272
273   FREE(wsw);
274}
275
276struct sw_winsys *
277wrapper_sw_winsys_wrap_pipe_screen(struct pipe_screen *screen)
278{
279   struct wrapper_sw_winsys *wsw = CALLOC_STRUCT(wrapper_sw_winsys);
280
281   if (!wsw)
282      goto err;
283
284   wsw->base.displaytarget_create = wsw_dt_create;
285   wsw->base.displaytarget_from_handle = wsw_dt_from_handle;
286   wsw->base.displaytarget_get_handle = wsw_dt_get_handle;
287   wsw->base.displaytarget_map = wsw_dt_map;
288   wsw->base.displaytarget_unmap = wsw_dt_unmap;
289   wsw->base.displaytarget_destroy = wsw_dt_destroy;
290   wsw->base.destroy = wsw_destroy;
291
292   wsw->screen = screen;
293   wsw->pipe = screen->context_create(screen, NULL);
294   if (!wsw->pipe)
295      goto err_free;
296
297   if(screen->get_param(screen, PIPE_CAP_NPOT_TEXTURES))
298      wsw->target = PIPE_TEXTURE_2D;
299   else
300      wsw->target = PIPE_TEXTURE_RECT;
301
302   return &wsw->base;
303
304err_free:
305   FREE(wsw);
306err:
307   return NULL;
308}
309
310struct pipe_screen *
311wrapper_sw_winsys_dewrap_pipe_screen(struct sw_winsys *ws)
312{
313   struct wrapper_sw_winsys *wsw = wrapper_sw_winsys(ws);
314   struct pipe_screen *screen = wsw->screen;
315
316   wsw->pipe->destroy(wsw->pipe);
317   /* don't destroy the screen its needed later on */
318
319   FREE(wsw);
320   return screen;
321}
322