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