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 map_count;
65   unsigned stride; /**< because we get stride at create */
66   void *ptr;
67};
68
69static INLINE struct wrapper_sw_winsys *
70wrapper_sw_winsys(struct sw_winsys *ws)
71{
72   return (struct wrapper_sw_winsys *)ws;
73}
74
75static INLINE struct wrapper_sw_displaytarget *
76wrapper_sw_displaytarget(struct sw_displaytarget *dt)
77{
78   return (struct wrapper_sw_displaytarget *)dt;
79}
80
81
82/*
83 * Functions
84 */
85
86
87static boolean
88wsw_dt_get_stride(struct wrapper_sw_displaytarget *wdt, unsigned *stride)
89{
90   struct pipe_context *pipe = wdt->winsys->pipe;
91   struct pipe_resource *tex = wdt->tex;
92   struct pipe_transfer *tr;
93
94   tr = pipe_get_transfer(pipe, tex, 0, 0,
95                          PIPE_TRANSFER_READ_WRITE,
96                          0, 0, wdt->tex->width0, wdt->tex->height0);
97   if (!tr)
98      return FALSE;
99
100   *stride = tr->stride;
101   wdt->stride = tr->stride;
102
103   pipe->transfer_destroy(pipe, tr);
104
105   return TRUE;
106}
107
108static struct sw_displaytarget *
109wsw_dt_wrap_texture(struct wrapper_sw_winsys *wsw,
110                    struct pipe_resource *tex, unsigned *stride)
111{
112   struct wrapper_sw_displaytarget *wdt = CALLOC_STRUCT(wrapper_sw_displaytarget);
113   if (!wdt)
114      goto err_unref;
115
116   wdt->tex = tex;
117   wdt->winsys = wsw;
118
119   if (!wsw_dt_get_stride(wdt, stride))
120      goto err_free;
121
122   return (struct sw_displaytarget *)wdt;
123
124err_free:
125   FREE(wdt);
126err_unref:
127   pipe_resource_reference(&tex, NULL);
128   return NULL;
129}
130
131static struct sw_displaytarget *
132wsw_dt_create(struct sw_winsys *ws,
133              unsigned bind,
134              enum pipe_format format,
135              unsigned width, unsigned height,
136              unsigned alignment,
137              unsigned *stride)
138{
139   struct wrapper_sw_winsys *wsw = wrapper_sw_winsys(ws);
140   struct pipe_resource templ;
141   struct pipe_resource *tex;
142
143   /*
144    * XXX Why don't we just get the template.
145    */
146   memset(&templ, 0, sizeof(templ));
147   templ.target = wsw->target;
148   templ.width0 = width;
149   templ.height0 = height;
150   templ.depth0 = 1;
151   templ.array_size = 1;
152   templ.format = format;
153   templ.bind = bind;
154
155   /* XXX alignment: we can't do anything about this */
156
157   tex = wsw->screen->resource_create(wsw->screen, &templ);
158   if (!tex)
159      return NULL;
160
161   return wsw_dt_wrap_texture(wsw, tex, stride);
162}
163
164static struct sw_displaytarget *
165wsw_dt_from_handle(struct sw_winsys *ws,
166                   const struct pipe_resource *templ,
167                   struct winsys_handle *whandle,
168                   unsigned *stride)
169{
170   struct wrapper_sw_winsys *wsw = wrapper_sw_winsys(ws);
171   struct pipe_resource *tex;
172
173   tex = wsw->screen->resource_from_handle(wsw->screen, templ, whandle);
174   if (!tex)
175      return NULL;
176
177   return wsw_dt_wrap_texture(wsw, tex, stride);
178}
179
180static boolean
181wsw_dt_get_handle(struct sw_winsys *ws,
182                  struct sw_displaytarget *dt,
183                  struct winsys_handle *whandle)
184{
185   struct wrapper_sw_winsys *wsw = wrapper_sw_winsys(ws);
186   struct wrapper_sw_displaytarget *wdt = wrapper_sw_displaytarget(dt);
187   struct pipe_resource *tex = wdt->tex;
188
189   return wsw->screen->resource_get_handle(wsw->screen, tex, whandle);
190}
191
192static void *
193wsw_dt_map(struct sw_winsys *ws,
194           struct sw_displaytarget *dt,
195           unsigned flags)
196{
197   struct wrapper_sw_displaytarget *wdt = wrapper_sw_displaytarget(dt);
198   struct pipe_context *pipe = wdt->winsys->pipe;
199   struct pipe_resource *tex = wdt->tex;
200   struct pipe_transfer *tr;
201   void *ptr;
202
203   if (!wdt->map_count) {
204
205      assert(!wdt->transfer);
206
207      tr = pipe_get_transfer(pipe, tex, 0, 0,
208                             PIPE_TRANSFER_READ_WRITE,
209                             0, 0, wdt->tex->width0, wdt->tex->height0);
210      if (!tr)
211         return NULL;
212
213      ptr = pipe->transfer_map(pipe, tr);
214      if (!ptr)
215        goto err;
216
217      wdt->transfer = tr;
218      wdt->ptr = ptr;
219
220      /* XXX Handle this case */
221      assert(tr->stride == wdt->stride);
222   }
223
224   wdt->map_count++;
225
226   return wdt->ptr;
227
228err:
229   pipe->transfer_destroy(pipe, tr);
230   return NULL;
231}
232
233static void
234wsw_dt_unmap(struct sw_winsys *ws,
235             struct sw_displaytarget *dt)
236{
237   struct wrapper_sw_displaytarget *wdt = wrapper_sw_displaytarget(dt);
238   struct pipe_context *pipe = wdt->winsys->pipe;
239
240   assert(wdt->transfer);
241
242   wdt->map_count--;
243
244   if (wdt->map_count)
245      return;
246
247   pipe->transfer_unmap(pipe, wdt->transfer);
248   pipe->transfer_destroy(pipe, wdt->transfer);
249   pipe->flush(pipe, NULL);
250   wdt->transfer = NULL;
251}
252
253static void
254wsw_dt_destroy(struct sw_winsys *ws,
255               struct sw_displaytarget *dt)
256{
257   struct wrapper_sw_displaytarget *wdt = wrapper_sw_displaytarget(dt);
258
259   pipe_resource_reference(&wdt->tex, NULL);
260
261   FREE(wdt);
262}
263
264static void
265wsw_destroy(struct sw_winsys *ws)
266{
267   struct wrapper_sw_winsys *wsw = wrapper_sw_winsys(ws);
268
269   wsw->pipe->destroy(wsw->pipe);
270   wsw->screen->destroy(wsw->screen);
271
272   FREE(wsw);
273}
274
275struct sw_winsys *
276wrapper_sw_winsys_wrap_pipe_screen(struct pipe_screen *screen)
277{
278   struct wrapper_sw_winsys *wsw = CALLOC_STRUCT(wrapper_sw_winsys);
279
280   if (!wsw)
281      goto err;
282
283   wsw->base.displaytarget_create = wsw_dt_create;
284   wsw->base.displaytarget_from_handle = wsw_dt_from_handle;
285   wsw->base.displaytarget_get_handle = wsw_dt_get_handle;
286   wsw->base.displaytarget_map = wsw_dt_map;
287   wsw->base.displaytarget_unmap = wsw_dt_unmap;
288   wsw->base.displaytarget_destroy = wsw_dt_destroy;
289   wsw->base.destroy = wsw_destroy;
290
291   wsw->screen = screen;
292   wsw->pipe = screen->context_create(screen, NULL);
293   if (!wsw->pipe)
294      goto err_free;
295
296   if(screen->get_param(screen, PIPE_CAP_NPOT_TEXTURES))
297      wsw->target = PIPE_TEXTURE_2D;
298   else
299      wsw->target = PIPE_TEXTURE_RECT;
300
301   return &wsw->base;
302
303err_free:
304   FREE(wsw);
305err:
306   return NULL;
307}
308
309struct pipe_screen *
310wrapper_sw_winsys_dewrap_pipe_screen(struct sw_winsys *ws)
311{
312   struct wrapper_sw_winsys *wsw = wrapper_sw_winsys(ws);
313   struct pipe_screen *screen = wsw->screen;
314
315   wsw->pipe->destroy(wsw->pipe);
316   /* don't destroy the screen its needed later on */
317
318   FREE(wsw);
319   return screen;
320}
321