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 50 struct 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 58 struct 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 69 static inline struct wrapper_sw_winsys * 70 wrapper_sw_winsys(struct sw_winsys *ws) 71 { 72 return (struct wrapper_sw_winsys *)ws; 73 } 74 75 static inline struct wrapper_sw_displaytarget * 76 wrapper_sw_displaytarget(struct sw_displaytarget *dt) 77 { 78 return (struct wrapper_sw_displaytarget *)dt; 79 } 80 81 82 /* 83 * Functions 84 */ 85 86 87 static boolean 88 wsw_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 100 static boolean 101 wsw_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 122 static struct sw_displaytarget * 123 wsw_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 138 err_free: 139 FREE(wdt); 140 err_unref: 141 pipe_resource_reference(&tex, NULL); 142 return NULL; 143 } 144 145 static struct sw_displaytarget * 146 wsw_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 179 static struct sw_displaytarget * 180 wsw_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 196 static boolean 197 wsw_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 209 static void * 210 wsw_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 241 err: 242 pipe->transfer_unmap(pipe, tr); 243 return NULL; 244 } 245 246 static void 247 wsw_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 265 static void 266 wsw_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 276 static void 277 wsw_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 287 struct sw_winsys * 288 wrapper_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 316 err_free: 317 FREE(wsw); 318 err: 319 return NULL; 320 } 321 322 struct pipe_screen * 323 wrapper_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