1/*
2 * Copyright © 2014 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission.  The copyright holders make no representations
11 * about the suitability of this software for any purpose.  It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23#include "glamor_priv.h"
24#include "glamor_transfer.h"
25#include "glamor_transform.h"
26
27/*
28 * PutImage. Only does ZPixmap right now as other formats are quite a bit harder
29 */
30
31static Bool
32glamor_put_image_gl(DrawablePtr drawable, GCPtr gc, int depth, int x, int y,
33                    int w, int h, int leftPad, int format, char *bits)
34{
35    ScreenPtr screen = drawable->pScreen;
36    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
37    PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
38    glamor_pixmap_private *pixmap_priv;
39    uint32_t    byte_stride = PixmapBytePad(w, drawable->depth);
40    RegionRec   region;
41    BoxRec      box;
42    int         off_x, off_y;
43
44    pixmap_priv = glamor_get_pixmap_private(pixmap);
45
46    if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
47        return FALSE;
48
49    if (gc->alu != GXcopy)
50        goto bail;
51
52    if (!glamor_pm_is_solid(gc->depth, gc->planemask))
53        goto bail;
54
55    if (format == XYPixmap && drawable->depth == 1 && leftPad == 0)
56        format = ZPixmap;
57
58    if (format != ZPixmap)
59        goto bail;
60
61    x += drawable->x;
62    y += drawable->y;
63    box.x1 = x;
64    box.y1 = y;
65    box.x2 = box.x1 + w;
66    box.y2 = box.y1 + h;
67    RegionInit(&region, &box, 1);
68    RegionIntersect(&region, &region, gc->pCompositeClip);
69
70    glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y);
71    if (off_x || off_y) {
72        x += off_x;
73        y += off_y;
74        RegionTranslate(&region, off_x, off_y);
75    }
76
77    glamor_make_current(glamor_priv);
78
79    glamor_upload_region(pixmap, &region, x, y, (uint8_t *) bits, byte_stride);
80
81    RegionUninit(&region);
82    return TRUE;
83bail:
84    return FALSE;
85}
86
87static void
88glamor_put_image_bail(DrawablePtr drawable, GCPtr gc, int depth, int x, int y,
89                      int w, int h, int leftPad, int format, char *bits)
90{
91    if (glamor_prepare_access_box(drawable, GLAMOR_ACCESS_RW, x, y, w, h))
92        fbPutImage(drawable, gc, depth, x, y, w, h, leftPad, format, bits);
93    glamor_finish_access(drawable);
94}
95
96void
97glamor_put_image(DrawablePtr drawable, GCPtr gc, int depth, int x, int y,
98                 int w, int h, int leftPad, int format, char *bits)
99{
100    if (glamor_put_image_gl(drawable, gc, depth, x, y, w, h, leftPad, format, bits))
101        return;
102    glamor_put_image_bail(drawable, gc, depth, x, y, w, h, leftPad, format, bits);
103}
104
105static Bool
106glamor_get_image_gl(DrawablePtr drawable, int x, int y, int w, int h,
107                    unsigned int format, unsigned long plane_mask, char *d)
108{
109    PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
110    glamor_pixmap_private *pixmap_priv;
111    uint32_t    byte_stride = PixmapBytePad(w, drawable->depth);
112    BoxRec      box;
113    int         off_x, off_y;
114
115    pixmap_priv = glamor_get_pixmap_private(pixmap);
116    if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv))
117        goto bail;
118
119    if (format != ZPixmap)
120        goto bail;
121
122    glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y);
123    box.x1 = x;
124    box.x2 = x + w;
125    box.y1 = y;
126    box.y2 = y + h;
127    glamor_download_boxes(pixmap, &box, 1,
128                          drawable->x + off_x, drawable->y + off_y,
129                          -x, -y,
130                          (uint8_t *) d, byte_stride);
131
132    if (!glamor_pm_is_solid(drawable->depth, plane_mask)) {
133        FbStip pm = fbReplicatePixel(plane_mask, drawable->bitsPerPixel);
134        FbStip *dst = (void *)d;
135        uint32_t dstStride = byte_stride / sizeof(FbStip);
136
137        for (int i = 0; i < dstStride * h; i++)
138            dst[i] &= pm;
139    }
140
141    return TRUE;
142bail:
143    return FALSE;
144}
145
146static void
147glamor_get_image_bail(DrawablePtr drawable, int x, int y, int w, int h,
148                      unsigned int format, unsigned long plane_mask, char *d)
149{
150    if (glamor_prepare_access_box(drawable, GLAMOR_ACCESS_RO, x, y, w, h))
151        fbGetImage(drawable, x, y, w, h, format, plane_mask, d);
152    glamor_finish_access(drawable);
153}
154
155void
156glamor_get_image(DrawablePtr drawable, int x, int y, int w, int h,
157                 unsigned int format, unsigned long plane_mask, char *d)
158{
159    if (glamor_get_image_gl(drawable, x, y, w, h, format, plane_mask, d))
160        return;
161    glamor_get_image_bail(drawable, x, y, w, h, format, plane_mask, d);
162}
163