drisw: use getImageShm() if available
[mesa.git] / src / gallium / state_trackers / dri / drisw.c
1 /**************************************************************************
2 *
3 * Copyright 2009, VMware, Inc.
4 * All Rights Reserved.
5 * Copyright 2010 George Sapountzis <gsapountzis@gmail.com>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
17 * of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 **************************************************************************/
28
29 #include "util/u_format.h"
30 #include "util/u_memory.h"
31 #include "util/u_inlines.h"
32 #include "util/u_box.h"
33 #include "pipe/p_context.h"
34 #include "pipe-loader/pipe_loader.h"
35 #include "state_tracker/drisw_api.h"
36 #include "state_tracker/st_context.h"
37
38 #include "dri_screen.h"
39 #include "dri_context.h"
40 #include "dri_drawable.h"
41 #include "dri_helpers.h"
42 #include "dri_query_renderer.h"
43
44 DEBUG_GET_ONCE_BOOL_OPTION(swrast_no_present, "SWRAST_NO_PRESENT", FALSE);
45 static boolean swrast_no_present = FALSE;
46
47 static inline void
48 get_drawable_info(__DRIdrawable *dPriv, int *x, int *y, int *w, int *h)
49 {
50 __DRIscreen *sPriv = dPriv->driScreenPriv;
51 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
52
53 loader->getDrawableInfo(dPriv,
54 x, y, w, h,
55 dPriv->loaderPrivate);
56 }
57
58 static inline void
59 put_image(__DRIdrawable *dPriv, void *data, unsigned width, unsigned height)
60 {
61 __DRIscreen *sPriv = dPriv->driScreenPriv;
62 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
63
64 loader->putImage(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP,
65 0, 0, width, height,
66 data, dPriv->loaderPrivate);
67 }
68
69 static inline void
70 put_image2(__DRIdrawable *dPriv, void *data, int x, int y,
71 unsigned width, unsigned height, unsigned stride)
72 {
73 __DRIscreen *sPriv = dPriv->driScreenPriv;
74 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
75
76 loader->putImage2(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP,
77 x, y, width, height, stride,
78 data, dPriv->loaderPrivate);
79 }
80
81 static inline void
82 put_image_shm(__DRIdrawable *dPriv, int shmid, char *shmaddr,
83 unsigned offset, int x, int y,
84 unsigned width, unsigned height, unsigned stride)
85 {
86 __DRIscreen *sPriv = dPriv->driScreenPriv;
87 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
88
89 loader->putImageShm(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP,
90 x, y, width, height, stride,
91 shmid, shmaddr, offset, dPriv->loaderPrivate);
92 }
93
94 static inline void
95 get_image(__DRIdrawable *dPriv, int x, int y, int width, int height, void *data)
96 {
97 __DRIscreen *sPriv = dPriv->driScreenPriv;
98 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
99
100 loader->getImage(dPriv,
101 x, y, width, height,
102 data, dPriv->loaderPrivate);
103 }
104
105 static inline void
106 get_image2(__DRIdrawable *dPriv, int x, int y, int width, int height, int stride, void *data)
107 {
108 __DRIscreen *sPriv = dPriv->driScreenPriv;
109 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
110
111 /* getImage2 support is only in version 3 or newer */
112 if (loader->base.version < 3)
113 return;
114
115 loader->getImage2(dPriv,
116 x, y, width, height, stride,
117 data, dPriv->loaderPrivate);
118 }
119
120 static inline bool
121 get_image_shm(__DRIdrawable *dPriv, int x, int y, int width, int height,
122 struct pipe_resource *res)
123 {
124 __DRIscreen *sPriv = dPriv->driScreenPriv;
125 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
126 struct winsys_handle whandle;
127
128 whandle.type = WINSYS_HANDLE_TYPE_SHMID;
129
130 if (loader->base.version < 4 || !loader->getImageShm)
131 return FALSE;
132
133 if (!res->screen->resource_get_handle(res->screen, NULL, res, &whandle, PIPE_HANDLE_USAGE_WRITE))
134 return FALSE;
135
136 loader->getImageShm(dPriv, x, y, width, height, whandle.handle, dPriv->loaderPrivate);
137 return TRUE;
138 }
139
140 static void
141 drisw_update_drawable_info(struct dri_drawable *drawable)
142 {
143 __DRIdrawable *dPriv = drawable->dPriv;
144 int x, y;
145
146 get_drawable_info(dPriv, &x, &y, &dPriv->w, &dPriv->h);
147 }
148
149 static void
150 drisw_get_image(struct dri_drawable *drawable,
151 int x, int y, unsigned width, unsigned height, unsigned stride,
152 void *data)
153 {
154 __DRIdrawable *dPriv = drawable->dPriv;
155 int draw_x, draw_y, draw_w, draw_h;
156
157 get_drawable_info(dPriv, &draw_x, &draw_y, &draw_w, &draw_h);
158 get_image2(dPriv, x, y, draw_w, draw_h, stride, data);
159 }
160
161 static void
162 drisw_put_image(struct dri_drawable *drawable,
163 void *data, unsigned width, unsigned height)
164 {
165 __DRIdrawable *dPriv = drawable->dPriv;
166
167 put_image(dPriv, data, width, height);
168 }
169
170 static void
171 drisw_put_image2(struct dri_drawable *drawable,
172 void *data, int x, int y, unsigned width, unsigned height,
173 unsigned stride)
174 {
175 __DRIdrawable *dPriv = drawable->dPriv;
176
177 put_image2(dPriv, data, x, y, width, height, stride);
178 }
179
180 static inline void
181 drisw_put_image_shm(struct dri_drawable *drawable,
182 int shmid, char *shmaddr, unsigned offset,
183 int x, int y, unsigned width, unsigned height,
184 unsigned stride)
185 {
186 __DRIdrawable *dPriv = drawable->dPriv;
187
188 put_image_shm(dPriv, shmid, shmaddr, offset, x, y, width, height, stride);
189 }
190
191 static inline void
192 drisw_present_texture(__DRIdrawable *dPriv,
193 struct pipe_resource *ptex, struct pipe_box *sub_box)
194 {
195 struct dri_drawable *drawable = dri_drawable(dPriv);
196 struct dri_screen *screen = dri_screen(drawable->sPriv);
197
198 if (swrast_no_present)
199 return;
200
201 screen->base.screen->flush_frontbuffer(screen->base.screen, ptex, 0, 0, drawable, sub_box);
202 }
203
204 static inline void
205 drisw_invalidate_drawable(__DRIdrawable *dPriv)
206 {
207 struct dri_drawable *drawable = dri_drawable(dPriv);
208
209 drawable->texture_stamp = dPriv->lastStamp - 1;
210
211 p_atomic_inc(&drawable->base.stamp);
212 }
213
214 static inline void
215 drisw_copy_to_front(__DRIdrawable * dPriv,
216 struct pipe_resource *ptex)
217 {
218 drisw_present_texture(dPriv, ptex, NULL);
219
220 drisw_invalidate_drawable(dPriv);
221 }
222
223 /*
224 * Backend functions for st_framebuffer interface and swap_buffers.
225 */
226
227 static void
228 drisw_swap_buffers(__DRIdrawable *dPriv)
229 {
230 struct dri_context *ctx = dri_get_current(dPriv->driScreenPriv);
231 struct dri_drawable *drawable = dri_drawable(dPriv);
232 struct pipe_resource *ptex;
233
234 if (!ctx)
235 return;
236
237 ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT];
238
239 if (ptex) {
240 if (ctx->pp)
241 pp_run(ctx->pp, ptex, ptex, drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]);
242
243 ctx->st->flush(ctx->st, ST_FLUSH_FRONT, NULL);
244
245 drisw_copy_to_front(dPriv, ptex);
246 }
247 }
248
249 static void
250 drisw_copy_sub_buffer(__DRIdrawable *dPriv, int x, int y,
251 int w, int h)
252 {
253 struct dri_context *ctx = dri_get_current(dPriv->driScreenPriv);
254 struct dri_drawable *drawable = dri_drawable(dPriv);
255 struct pipe_resource *ptex;
256 struct pipe_box box;
257 if (!ctx)
258 return;
259
260 ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT];
261
262 if (ptex) {
263 if (ctx->pp && drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL])
264 pp_run(ctx->pp, ptex, ptex, drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]);
265
266 ctx->st->flush(ctx->st, ST_FLUSH_FRONT, NULL);
267
268 u_box_2d(x, dPriv->h - y - h, w, h, &box);
269 drisw_present_texture(dPriv, ptex, &box);
270 }
271 }
272
273 static void
274 drisw_flush_frontbuffer(struct dri_context *ctx,
275 struct dri_drawable *drawable,
276 enum st_attachment_type statt)
277 {
278 struct pipe_resource *ptex;
279
280 if (!ctx)
281 return;
282
283 ptex = drawable->textures[statt];
284
285 if (ptex) {
286 drisw_copy_to_front(ctx->dPriv, ptex);
287 }
288 }
289
290 /**
291 * Allocate framebuffer attachments.
292 *
293 * During fixed-size operation, the function keeps allocating new attachments
294 * as they are requested. Unused attachments are not removed, not until the
295 * framebuffer is resized or destroyed.
296 */
297 static void
298 drisw_allocate_textures(struct dri_context *stctx,
299 struct dri_drawable *drawable,
300 const enum st_attachment_type *statts,
301 unsigned count)
302 {
303 struct dri_screen *screen = dri_screen(drawable->sPriv);
304 const __DRIswrastLoaderExtension *loader = drawable->dPriv->driScreenPriv->swrast_loader;
305 struct pipe_resource templ;
306 unsigned width, height;
307 boolean resized;
308 unsigned i;
309
310 width = drawable->dPriv->w;
311 height = drawable->dPriv->h;
312
313 resized = (drawable->old_w != width ||
314 drawable->old_h != height);
315
316 /* remove outdated textures */
317 if (resized) {
318 for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
319 pipe_resource_reference(&drawable->textures[i], NULL);
320 }
321
322 memset(&templ, 0, sizeof(templ));
323 templ.target = screen->target;
324 templ.width0 = width;
325 templ.height0 = height;
326 templ.depth0 = 1;
327 templ.array_size = 1;
328 templ.last_level = 0;
329
330 for (i = 0; i < count; i++) {
331 enum pipe_format format;
332 unsigned bind;
333
334 /* the texture already exists or not requested */
335 if (drawable->textures[statts[i]])
336 continue;
337
338 dri_drawable_get_format(drawable, statts[i], &format, &bind);
339
340 /* if we don't do any present, no need for display targets */
341 if (statts[i] != ST_ATTACHMENT_DEPTH_STENCIL && !swrast_no_present)
342 bind |= PIPE_BIND_DISPLAY_TARGET;
343
344 if (format == PIPE_FORMAT_NONE)
345 continue;
346
347 templ.format = format;
348 templ.bind = bind;
349
350 if (statts[i] == ST_ATTACHMENT_FRONT_LEFT &&
351 screen->base.screen->resource_create_front &&
352 loader->base.version >= 3) {
353 drawable->textures[statts[i]] =
354 screen->base.screen->resource_create_front(screen->base.screen, &templ, (const void *)drawable);
355 } else
356 drawable->textures[statts[i]] =
357 screen->base.screen->resource_create(screen->base.screen, &templ);
358 }
359
360 drawable->old_w = width;
361 drawable->old_h = height;
362 }
363
364 static void
365 drisw_update_tex_buffer(struct dri_drawable *drawable,
366 struct dri_context *ctx,
367 struct pipe_resource *res)
368 {
369 __DRIdrawable *dPriv = drawable->dPriv;
370
371 struct st_context *st_ctx = (struct st_context *)ctx->st;
372 struct pipe_context *pipe = st_ctx->pipe;
373 struct pipe_transfer *transfer;
374 char *map;
375 int x, y, w, h;
376 int ximage_stride, line;
377 int cpp = util_format_get_blocksize(res->format);
378
379 get_drawable_info(dPriv, &x, &y, &w, &h);
380
381 map = pipe_transfer_map(pipe, res,
382 0, 0, // level, layer,
383 PIPE_TRANSFER_WRITE,
384 x, y, w, h, &transfer);
385
386 /* Copy the Drawable content to the mapped texture buffer */
387 if (!get_image_shm(dPriv, x, y, w, h, res))
388 get_image(dPriv, x, y, w, h, map);
389
390 /* The pipe transfer has a pitch rounded up to the nearest 64 pixels.
391 get_image() has a pitch rounded up to 4 bytes. */
392 ximage_stride = ((w * cpp) + 3) & -4;
393 for (line = h-1; line; --line) {
394 memmove(&map[line * transfer->stride],
395 &map[line * ximage_stride],
396 ximage_stride);
397 }
398
399 pipe_transfer_unmap(pipe, transfer);
400 }
401
402 static __DRIimageExtension driSWImageExtension = {
403 .base = { __DRI_IMAGE, 6 },
404
405 .createImageFromRenderbuffer = dri2_create_image_from_renderbuffer,
406 .createImageFromTexture = dri2_create_from_texture,
407 .destroyImage = dri2_destroy_image,
408 };
409
410 /*
411 * Backend function for init_screen.
412 */
413
414 static const __DRIextension *drisw_screen_extensions[] = {
415 &driTexBufferExtension.base,
416 &dri2RendererQueryExtension.base,
417 &dri2ConfigQueryExtension.base,
418 &dri2FenceExtension.base,
419 &dri2NoErrorExtension.base,
420 &driSWImageExtension.base,
421 &dri2FlushControlExtension.base,
422 NULL
423 };
424
425 static struct drisw_loader_funcs drisw_lf = {
426 .get_image = drisw_get_image,
427 .put_image = drisw_put_image,
428 .put_image2 = drisw_put_image2
429 };
430
431 static const __DRIconfig **
432 drisw_init_screen(__DRIscreen * sPriv)
433 {
434 const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
435 const __DRIconfig **configs;
436 struct dri_screen *screen;
437 struct pipe_screen *pscreen = NULL;
438
439 screen = CALLOC_STRUCT(dri_screen);
440 if (!screen)
441 return NULL;
442
443 screen->sPriv = sPriv;
444 screen->fd = -1;
445
446 swrast_no_present = debug_get_option_swrast_no_present();
447
448 sPriv->driverPrivate = (void *)screen;
449 sPriv->extensions = drisw_screen_extensions;
450 if (loader->base.version >= 4) {
451 if (loader->putImageShm)
452 drisw_lf.put_image_shm = drisw_put_image_shm;
453 }
454
455 if (pipe_loader_sw_probe_dri(&screen->dev, &drisw_lf)) {
456 dri_init_options(screen);
457
458 pscreen = pipe_loader_create_screen(screen->dev);
459 }
460
461 if (!pscreen)
462 goto fail;
463
464 configs = dri_init_screen_helper(screen, pscreen);
465 if (!configs)
466 goto fail;
467
468 screen->lookup_egl_image = dri2_lookup_egl_image;
469
470 return configs;
471 fail:
472 dri_destroy_screen_helper(screen);
473 if (screen->dev)
474 pipe_loader_release(&screen->dev, 1);
475 FREE(screen);
476 return NULL;
477 }
478
479 static boolean
480 drisw_create_buffer(__DRIscreen * sPriv,
481 __DRIdrawable * dPriv,
482 const struct gl_config * visual, boolean isPixmap)
483 {
484 struct dri_drawable *drawable = NULL;
485
486 if (!dri_create_buffer(sPriv, dPriv, visual, isPixmap))
487 return FALSE;
488
489 drawable = dPriv->driverPrivate;
490
491 drawable->allocate_textures = drisw_allocate_textures;
492 drawable->update_drawable_info = drisw_update_drawable_info;
493 drawable->flush_frontbuffer = drisw_flush_frontbuffer;
494 drawable->update_tex_buffer = drisw_update_tex_buffer;
495
496 return TRUE;
497 }
498
499 /**
500 * DRI driver virtual function table.
501 *
502 * DRI versions differ in their implementation of init_screen and swap_buffers.
503 */
504 const struct __DriverAPIRec galliumsw_driver_api = {
505 .InitScreen = drisw_init_screen,
506 .DestroyScreen = dri_destroy_screen,
507 .CreateContext = dri_create_context,
508 .DestroyContext = dri_destroy_context,
509 .CreateBuffer = drisw_create_buffer,
510 .DestroyBuffer = dri_destroy_buffer,
511 .SwapBuffers = drisw_swap_buffers,
512 .MakeCurrent = dri_make_current,
513 .UnbindContext = dri_unbind_context,
514 .CopySubBuffer = drisw_copy_sub_buffer,
515 };
516
517 /* This is the table of extensions that the loader will dlsym() for. */
518 const __DRIextension *galliumsw_driver_extensions[] = {
519 &driCoreExtension.base,
520 &driSWRastExtension.base,
521 &driCopySubBufferExtension.base,
522 &gallium_config_options.base,
523 NULL
524 };
525
526 /* vim: set sw=3 ts=8 sts=3 expandtab: */