• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 /* TODO:
30  *
31  * xshm / EGLImage:
32  *
33  * Allow the loaders to use the XSHM extension. It probably requires callbacks
34  * for createImage/destroyImage similar to DRI2 getBuffers.
35  */
36 
37 #include "util/u_format.h"
38 #include "util/u_memory.h"
39 #include "util/u_inlines.h"
40 #include "util/u_box.h"
41 #include "pipe/p_context.h"
42 #include "pipe-loader/pipe_loader.h"
43 #include "state_tracker/drisw_api.h"
44 #include "state_tracker/st_context.h"
45 
46 #include "dri_screen.h"
47 #include "dri_context.h"
48 #include "dri_drawable.h"
49 #include "dri_helpers.h"
50 #include "dri_query_renderer.h"
51 
52 DEBUG_GET_ONCE_BOOL_OPTION(swrast_no_present, "SWRAST_NO_PRESENT", FALSE);
53 static boolean swrast_no_present = FALSE;
54 
55 static inline void
get_drawable_info(__DRIdrawable * dPriv,int * x,int * y,int * w,int * h)56 get_drawable_info(__DRIdrawable *dPriv, int *x, int *y, int *w, int *h)
57 {
58    __DRIscreen *sPriv = dPriv->driScreenPriv;
59    const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
60 
61    loader->getDrawableInfo(dPriv,
62                            x, y, w, h,
63                            dPriv->loaderPrivate);
64 }
65 
66 static inline void
put_image(__DRIdrawable * dPriv,void * data,unsigned width,unsigned height)67 put_image(__DRIdrawable *dPriv, void *data, unsigned width, unsigned height)
68 {
69    __DRIscreen *sPriv = dPriv->driScreenPriv;
70    const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
71 
72    loader->putImage(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP,
73                     0, 0, width, height,
74                     data, dPriv->loaderPrivate);
75 }
76 
77 static inline void
put_image2(__DRIdrawable * dPriv,void * data,int x,int y,unsigned width,unsigned height,unsigned stride)78 put_image2(__DRIdrawable *dPriv, void *data, int x, int y,
79            unsigned width, unsigned height, unsigned stride)
80 {
81    __DRIscreen *sPriv = dPriv->driScreenPriv;
82    const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
83 
84    loader->putImage2(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP,
85                      x, y, width, height, stride,
86                      data, dPriv->loaderPrivate);
87 }
88 
89 static inline void
get_image(__DRIdrawable * dPriv,int x,int y,int width,int height,void * data)90 get_image(__DRIdrawable *dPriv, int x, int y, int width, int height, void *data)
91 {
92    __DRIscreen *sPriv = dPriv->driScreenPriv;
93    const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
94 
95    loader->getImage(dPriv,
96                     x, y, width, height,
97                     data, dPriv->loaderPrivate);
98 }
99 
100 static inline void
get_image2(__DRIdrawable * dPriv,int x,int y,int width,int height,int stride,void * data)101 get_image2(__DRIdrawable *dPriv, int x, int y, int width, int height, int stride, void *data)
102 {
103    __DRIscreen *sPriv = dPriv->driScreenPriv;
104    const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
105 
106    /* getImage2 support is only in version 3 or newer */
107    if (loader->base.version < 3)
108       return;
109 
110    loader->getImage2(dPriv,
111                      x, y, width, height, stride,
112                      data, dPriv->loaderPrivate);
113 }
114 
115 static void
drisw_update_drawable_info(struct dri_drawable * drawable)116 drisw_update_drawable_info(struct dri_drawable *drawable)
117 {
118    __DRIdrawable *dPriv = drawable->dPriv;
119    int x, y;
120 
121    get_drawable_info(dPriv, &x, &y, &dPriv->w, &dPriv->h);
122 }
123 
124 static void
drisw_get_image(struct dri_drawable * drawable,int x,int y,unsigned width,unsigned height,unsigned stride,void * data)125 drisw_get_image(struct dri_drawable *drawable,
126                 int x, int y, unsigned width, unsigned height, unsigned stride,
127                 void *data)
128 {
129    __DRIdrawable *dPriv = drawable->dPriv;
130    int draw_x, draw_y, draw_w, draw_h;
131 
132    get_drawable_info(dPriv, &draw_x, &draw_y, &draw_w, &draw_h);
133    get_image2(dPriv, x, y, draw_w, draw_h, stride, data);
134 }
135 
136 static void
drisw_put_image(struct dri_drawable * drawable,void * data,unsigned width,unsigned height)137 drisw_put_image(struct dri_drawable *drawable,
138                 void *data, unsigned width, unsigned height)
139 {
140    __DRIdrawable *dPriv = drawable->dPriv;
141 
142    put_image(dPriv, data, width, height);
143 }
144 
145 static void
drisw_put_image2(struct dri_drawable * drawable,void * data,int x,int y,unsigned width,unsigned height,unsigned stride)146 drisw_put_image2(struct dri_drawable *drawable,
147                  void *data, int x, int y, unsigned width, unsigned height,
148                  unsigned stride)
149 {
150    __DRIdrawable *dPriv = drawable->dPriv;
151 
152    put_image2(dPriv, data, x, y, width, height, stride);
153 }
154 
155 static inline void
drisw_present_texture(__DRIdrawable * dPriv,struct pipe_resource * ptex,struct pipe_box * sub_box)156 drisw_present_texture(__DRIdrawable *dPriv,
157                       struct pipe_resource *ptex, struct pipe_box *sub_box)
158 {
159    struct dri_drawable *drawable = dri_drawable(dPriv);
160    struct dri_screen *screen = dri_screen(drawable->sPriv);
161 
162    if (swrast_no_present)
163       return;
164 
165    screen->base.screen->flush_frontbuffer(screen->base.screen, ptex, 0, 0, drawable, sub_box);
166 }
167 
168 static inline void
drisw_invalidate_drawable(__DRIdrawable * dPriv)169 drisw_invalidate_drawable(__DRIdrawable *dPriv)
170 {
171    struct dri_drawable *drawable = dri_drawable(dPriv);
172 
173    drawable->texture_stamp = dPriv->lastStamp - 1;
174 
175    p_atomic_inc(&drawable->base.stamp);
176 }
177 
178 static inline void
drisw_copy_to_front(__DRIdrawable * dPriv,struct pipe_resource * ptex)179 drisw_copy_to_front(__DRIdrawable * dPriv,
180                     struct pipe_resource *ptex)
181 {
182    drisw_present_texture(dPriv, ptex, NULL);
183 
184    drisw_invalidate_drawable(dPriv);
185 }
186 
187 /*
188  * Backend functions for st_framebuffer interface and swap_buffers.
189  */
190 
191 static void
drisw_swap_buffers(__DRIdrawable * dPriv)192 drisw_swap_buffers(__DRIdrawable *dPriv)
193 {
194    struct dri_context *ctx = dri_get_current(dPriv->driScreenPriv);
195    struct dri_drawable *drawable = dri_drawable(dPriv);
196    struct pipe_resource *ptex;
197 
198    if (!ctx)
199       return;
200 
201    ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT];
202 
203    if (ptex) {
204       if (ctx->pp)
205          pp_run(ctx->pp, ptex, ptex, drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]);
206 
207       ctx->st->flush(ctx->st, ST_FLUSH_FRONT, NULL);
208 
209       drisw_copy_to_front(dPriv, ptex);
210    }
211 }
212 
213 static void
drisw_copy_sub_buffer(__DRIdrawable * dPriv,int x,int y,int w,int h)214 drisw_copy_sub_buffer(__DRIdrawable *dPriv, int x, int y,
215                       int w, int h)
216 {
217    struct dri_context *ctx = dri_get_current(dPriv->driScreenPriv);
218    struct dri_drawable *drawable = dri_drawable(dPriv);
219    struct pipe_resource *ptex;
220    struct pipe_box box;
221    if (!ctx)
222       return;
223 
224    ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT];
225 
226    if (ptex) {
227       if (ctx->pp && drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL])
228          pp_run(ctx->pp, ptex, ptex, drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]);
229 
230       ctx->st->flush(ctx->st, ST_FLUSH_FRONT, NULL);
231 
232       u_box_2d(x, dPriv->h - y - h, w, h, &box);
233       drisw_present_texture(dPriv, ptex, &box);
234    }
235 }
236 
237 static void
drisw_flush_frontbuffer(struct dri_context * ctx,struct dri_drawable * drawable,enum st_attachment_type statt)238 drisw_flush_frontbuffer(struct dri_context *ctx,
239                         struct dri_drawable *drawable,
240                         enum st_attachment_type statt)
241 {
242    struct pipe_resource *ptex;
243 
244    if (!ctx)
245       return;
246 
247    ptex = drawable->textures[statt];
248 
249    if (ptex) {
250       drisw_copy_to_front(ctx->dPriv, ptex);
251    }
252 }
253 
254 /**
255  * Allocate framebuffer attachments.
256  *
257  * During fixed-size operation, the function keeps allocating new attachments
258  * as they are requested. Unused attachments are not removed, not until the
259  * framebuffer is resized or destroyed.
260  */
261 static void
drisw_allocate_textures(struct dri_context * stctx,struct dri_drawable * drawable,const enum st_attachment_type * statts,unsigned count)262 drisw_allocate_textures(struct dri_context *stctx,
263                         struct dri_drawable *drawable,
264                         const enum st_attachment_type *statts,
265                         unsigned count)
266 {
267    struct dri_screen *screen = dri_screen(drawable->sPriv);
268    const __DRIswrastLoaderExtension *loader = drawable->dPriv->driScreenPriv->swrast_loader;
269    struct pipe_resource templ;
270    unsigned width, height;
271    boolean resized;
272    unsigned i;
273 
274    width  = drawable->dPriv->w;
275    height = drawable->dPriv->h;
276 
277    resized = (drawable->old_w != width ||
278               drawable->old_h != height);
279 
280    /* remove outdated textures */
281    if (resized) {
282       for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
283          pipe_resource_reference(&drawable->textures[i], NULL);
284    }
285 
286    memset(&templ, 0, sizeof(templ));
287    templ.target = screen->target;
288    templ.width0 = width;
289    templ.height0 = height;
290    templ.depth0 = 1;
291    templ.array_size = 1;
292    templ.last_level = 0;
293 
294    for (i = 0; i < count; i++) {
295       enum pipe_format format;
296       unsigned bind;
297 
298       /* the texture already exists or not requested */
299       if (drawable->textures[statts[i]])
300          continue;
301 
302       dri_drawable_get_format(drawable, statts[i], &format, &bind);
303 
304       /* if we don't do any present, no need for display targets */
305       if (statts[i] != ST_ATTACHMENT_DEPTH_STENCIL && !swrast_no_present)
306          bind |= PIPE_BIND_DISPLAY_TARGET;
307 
308       if (format == PIPE_FORMAT_NONE)
309          continue;
310 
311       templ.format = format;
312       templ.bind = bind;
313 
314       if (statts[i] == ST_ATTACHMENT_FRONT_LEFT &&
315           screen->base.screen->resource_create_front &&
316           loader->base.version >= 3) {
317          drawable->textures[statts[i]] =
318             screen->base.screen->resource_create_front(screen->base.screen, &templ, (const void *)drawable);
319       } else
320          drawable->textures[statts[i]] =
321             screen->base.screen->resource_create(screen->base.screen, &templ);
322    }
323 
324    drawable->old_w = width;
325    drawable->old_h = height;
326 }
327 
328 static void
drisw_update_tex_buffer(struct dri_drawable * drawable,struct dri_context * ctx,struct pipe_resource * res)329 drisw_update_tex_buffer(struct dri_drawable *drawable,
330                         struct dri_context *ctx,
331                         struct pipe_resource *res)
332 {
333    __DRIdrawable *dPriv = drawable->dPriv;
334 
335    struct st_context *st_ctx = (struct st_context *)ctx->st;
336    struct pipe_context *pipe = st_ctx->pipe;
337    struct pipe_transfer *transfer;
338    char *map;
339    int x, y, w, h;
340    int ximage_stride, line;
341    int cpp = util_format_get_blocksize(res->format);
342 
343    get_drawable_info(dPriv, &x, &y, &w, &h);
344 
345    map = pipe_transfer_map(pipe, res,
346                            0, 0, // level, layer,
347                            PIPE_TRANSFER_WRITE,
348                            x, y, w, h, &transfer);
349 
350    /* Copy the Drawable content to the mapped texture buffer */
351    get_image(dPriv, x, y, w, h, map);
352 
353    /* The pipe transfer has a pitch rounded up to the nearest 64 pixels.
354       get_image() has a pitch rounded up to 4 bytes.  */
355    ximage_stride = ((w * cpp) + 3) & -4;
356    for (line = h-1; line; --line) {
357       memmove(&map[line * transfer->stride],
358               &map[line * ximage_stride],
359               ximage_stride);
360    }
361 
362    pipe_transfer_unmap(pipe, transfer);
363 }
364 
365 static __DRIimageExtension driSWImageExtension = {
366     .base = { __DRI_IMAGE, 6 },
367 
368     .createImageFromRenderbuffer  = dri2_create_image_from_renderbuffer,
369     .createImageFromTexture = dri2_create_from_texture,
370     .destroyImage = dri2_destroy_image,
371 };
372 
373 /*
374  * Backend function for init_screen.
375  */
376 
377 static const __DRIextension *drisw_screen_extensions[] = {
378    &driTexBufferExtension.base,
379    &dri2RendererQueryExtension.base,
380    &dri2ConfigQueryExtension.base,
381    &dri2FenceExtension.base,
382    &dri2NoErrorExtension.base,
383    &driSWImageExtension.base,
384    &dri2FlushControlExtension.base,
385    NULL
386 };
387 
388 static struct drisw_loader_funcs drisw_lf = {
389    .get_image = drisw_get_image,
390    .put_image = drisw_put_image,
391    .put_image2 = drisw_put_image2
392 };
393 
394 static const __DRIconfig **
drisw_init_screen(__DRIscreen * sPriv)395 drisw_init_screen(__DRIscreen * sPriv)
396 {
397    const __DRIconfig **configs;
398    struct dri_screen *screen;
399    struct pipe_screen *pscreen = NULL;
400 
401    screen = CALLOC_STRUCT(dri_screen);
402    if (!screen)
403       return NULL;
404 
405    screen->sPriv = sPriv;
406    screen->fd = -1;
407 
408    swrast_no_present = debug_get_option_swrast_no_present();
409 
410    sPriv->driverPrivate = (void *)screen;
411    sPriv->extensions = drisw_screen_extensions;
412 
413    if (pipe_loader_sw_probe_dri(&screen->dev, &drisw_lf)) {
414       dri_init_options(screen);
415 
416       pscreen = pipe_loader_create_screen(screen->dev);
417    }
418 
419    if (!pscreen)
420       goto fail;
421 
422    configs = dri_init_screen_helper(screen, pscreen);
423    if (!configs)
424       goto fail;
425 
426    screen->lookup_egl_image = dri2_lookup_egl_image;
427 
428    return configs;
429 fail:
430    dri_destroy_screen_helper(screen);
431    if (screen->dev)
432       pipe_loader_release(&screen->dev, 1);
433    FREE(screen);
434    return NULL;
435 }
436 
437 static boolean
drisw_create_buffer(__DRIscreen * sPriv,__DRIdrawable * dPriv,const struct gl_config * visual,boolean isPixmap)438 drisw_create_buffer(__DRIscreen * sPriv,
439                     __DRIdrawable * dPriv,
440                     const struct gl_config * visual, boolean isPixmap)
441 {
442    struct dri_drawable *drawable = NULL;
443 
444    if (!dri_create_buffer(sPriv, dPriv, visual, isPixmap))
445       return FALSE;
446 
447    drawable = dPriv->driverPrivate;
448 
449    drawable->allocate_textures = drisw_allocate_textures;
450    drawable->update_drawable_info = drisw_update_drawable_info;
451    drawable->flush_frontbuffer = drisw_flush_frontbuffer;
452    drawable->update_tex_buffer = drisw_update_tex_buffer;
453 
454    return TRUE;
455 }
456 
457 /**
458  * DRI driver virtual function table.
459  *
460  * DRI versions differ in their implementation of init_screen and swap_buffers.
461  */
462 const struct __DriverAPIRec galliumsw_driver_api = {
463    .InitScreen = drisw_init_screen,
464    .DestroyScreen = dri_destroy_screen,
465    .CreateContext = dri_create_context,
466    .DestroyContext = dri_destroy_context,
467    .CreateBuffer = drisw_create_buffer,
468    .DestroyBuffer = dri_destroy_buffer,
469    .SwapBuffers = drisw_swap_buffers,
470    .MakeCurrent = dri_make_current,
471    .UnbindContext = dri_unbind_context,
472    .CopySubBuffer = drisw_copy_sub_buffer,
473 };
474 
475 /* This is the table of extensions that the loader will dlsym() for. */
476 const __DRIextension *galliumsw_driver_extensions[] = {
477     &driCoreExtension.base,
478     &driSWRastExtension.base,
479     &driCopySubBufferExtension.base,
480     &gallium_config_options.base,
481     NULL
482 };
483 
484 /* vim: set sw=3 ts=8 sts=3 expandtab: */
485