OSDN Git Service

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