135c4bbdfSmrg/*
235c4bbdfSmrg * Copyright © 2014 Keith Packard
335c4bbdfSmrg *
435c4bbdfSmrg * Permission to use, copy, modify, distribute, and sell this software and its
535c4bbdfSmrg * documentation for any purpose is hereby granted without fee, provided that
635c4bbdfSmrg * the above copyright notice appear in all copies and that both that copyright
735c4bbdfSmrg * notice and this permission notice appear in supporting documentation, and
835c4bbdfSmrg * that the name of the copyright holders not be used in advertising or
935c4bbdfSmrg * publicity pertaining to distribution of the software without specific,
1035c4bbdfSmrg * written prior permission.  The copyright holders make no representations
1135c4bbdfSmrg * about the suitability of this software for any purpose.  It is provided "as
1235c4bbdfSmrg * is" without express or implied warranty.
1335c4bbdfSmrg *
1435c4bbdfSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1535c4bbdfSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1635c4bbdfSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1735c4bbdfSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1835c4bbdfSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1935c4bbdfSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
2035c4bbdfSmrg * OF THIS SOFTWARE.
2135c4bbdfSmrg */
2235c4bbdfSmrg
2335c4bbdfSmrg#include "glamor_priv.h"
2435c4bbdfSmrg#include "glamor_transfer.h"
2535c4bbdfSmrg
2635c4bbdfSmrg/*
2735c4bbdfSmrg * Write a region of bits into a pixmap
2835c4bbdfSmrg */
2935c4bbdfSmrgvoid
3035c4bbdfSmrgglamor_upload_boxes(PixmapPtr pixmap, BoxPtr in_boxes, int in_nbox,
3135c4bbdfSmrg                    int dx_src, int dy_src,
3235c4bbdfSmrg                    int dx_dst, int dy_dst,
3335c4bbdfSmrg                    uint8_t *bits, uint32_t byte_stride)
3435c4bbdfSmrg{
3535c4bbdfSmrg    ScreenPtr                   screen = pixmap->drawable.pScreen;
3635c4bbdfSmrg    glamor_screen_private       *glamor_priv = glamor_get_screen_private(screen);
3735c4bbdfSmrg    glamor_pixmap_private       *priv = glamor_get_pixmap_private(pixmap);
3835c4bbdfSmrg    int                         box_index;
3935c4bbdfSmrg    int                         bytes_per_pixel = pixmap->drawable.bitsPerPixel >> 3;
40ed6184dfSmrg    const struct glamor_format *f = glamor_format_for_pixmap(pixmap);
4135c4bbdfSmrg
4235c4bbdfSmrg    glamor_make_current(glamor_priv);
4335c4bbdfSmrg
4435c4bbdfSmrg    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
4535c4bbdfSmrg
4635c4bbdfSmrg    if (glamor_priv->has_unpack_subimage)
4735c4bbdfSmrg        glPixelStorei(GL_UNPACK_ROW_LENGTH, byte_stride / bytes_per_pixel);
4835c4bbdfSmrg
4935c4bbdfSmrg    glamor_pixmap_loop(priv, box_index) {
5035c4bbdfSmrg        BoxPtr                  box = glamor_pixmap_box_at(priv, box_index);
5135c4bbdfSmrg        glamor_pixmap_fbo       *fbo = glamor_pixmap_fbo_at(priv, box_index);
5235c4bbdfSmrg        BoxPtr                  boxes = in_boxes;
5335c4bbdfSmrg        int                     nbox = in_nbox;
5435c4bbdfSmrg
5535c4bbdfSmrg        glamor_bind_texture(glamor_priv, GL_TEXTURE0, fbo, TRUE);
5635c4bbdfSmrg
5735c4bbdfSmrg        while (nbox--) {
5835c4bbdfSmrg
5935c4bbdfSmrg            /* compute drawable coordinates */
6035c4bbdfSmrg            int x1 = MAX(boxes->x1 + dx_dst, box->x1);
6135c4bbdfSmrg            int x2 = MIN(boxes->x2 + dx_dst, box->x2);
6235c4bbdfSmrg            int y1 = MAX(boxes->y1 + dy_dst, box->y1);
6335c4bbdfSmrg            int y2 = MIN(boxes->y2 + dy_dst, box->y2);
6435c4bbdfSmrg
6535c4bbdfSmrg            size_t ofs = (y1 - dy_dst + dy_src) * byte_stride;
6635c4bbdfSmrg            ofs += (x1 - dx_dst + dx_src) * bytes_per_pixel;
6735c4bbdfSmrg
6835c4bbdfSmrg            boxes++;
6935c4bbdfSmrg
7035c4bbdfSmrg            if (x2 <= x1 || y2 <= y1)
7135c4bbdfSmrg                continue;
7235c4bbdfSmrg
7335c4bbdfSmrg            if (glamor_priv->has_unpack_subimage ||
7435c4bbdfSmrg                x2 - x1 == byte_stride / bytes_per_pixel) {
7535c4bbdfSmrg                glTexSubImage2D(GL_TEXTURE_2D, 0,
7635c4bbdfSmrg                                x1 - box->x1, y1 - box->y1,
7735c4bbdfSmrg                                x2 - x1, y2 - y1,
78ed6184dfSmrg                                f->format, f->type,
7935c4bbdfSmrg                                bits + ofs);
8035c4bbdfSmrg            } else {
8135c4bbdfSmrg                for (; y1 < y2; y1++, ofs += byte_stride)
8235c4bbdfSmrg                    glTexSubImage2D(GL_TEXTURE_2D, 0,
8335c4bbdfSmrg                                    x1 - box->x1, y1 - box->y1,
8435c4bbdfSmrg                                    x2 - x1, 1,
85ed6184dfSmrg                                    f->format, f->type,
8635c4bbdfSmrg                                    bits + ofs);
8735c4bbdfSmrg            }
8835c4bbdfSmrg        }
8935c4bbdfSmrg    }
9035c4bbdfSmrg
9135c4bbdfSmrg    if (glamor_priv->has_unpack_subimage)
9235c4bbdfSmrg        glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
9335c4bbdfSmrg}
9435c4bbdfSmrg
9535c4bbdfSmrg/*
9635c4bbdfSmrg * Upload a region of data
9735c4bbdfSmrg */
9835c4bbdfSmrg
9935c4bbdfSmrgvoid
10035c4bbdfSmrgglamor_upload_region(PixmapPtr pixmap, RegionPtr region,
10135c4bbdfSmrg                     int region_x, int region_y,
10235c4bbdfSmrg                     uint8_t *bits, uint32_t byte_stride)
10335c4bbdfSmrg{
10435c4bbdfSmrg    glamor_upload_boxes(pixmap, RegionRects(region), RegionNumRects(region),
10535c4bbdfSmrg                        -region_x, -region_y,
10635c4bbdfSmrg                        0, 0,
10735c4bbdfSmrg                        bits, byte_stride);
10835c4bbdfSmrg}
10935c4bbdfSmrg
11035c4bbdfSmrg/*
11135c4bbdfSmrg * Take the data in the pixmap and stuff it back into the FBO
11235c4bbdfSmrg */
11335c4bbdfSmrgvoid
11435c4bbdfSmrgglamor_upload_pixmap(PixmapPtr pixmap)
11535c4bbdfSmrg{
11635c4bbdfSmrg    BoxRec box;
11735c4bbdfSmrg
11835c4bbdfSmrg    box.x1 = 0;
11935c4bbdfSmrg    box.x2 = pixmap->drawable.width;
12035c4bbdfSmrg    box.y1 = 0;
12135c4bbdfSmrg    box.y2 = pixmap->drawable.height;
12235c4bbdfSmrg    glamor_upload_boxes(pixmap, &box, 1, 0, 0, 0, 0,
12335c4bbdfSmrg                        pixmap->devPrivate.ptr, pixmap->devKind);
12435c4bbdfSmrg}
12535c4bbdfSmrg
12635c4bbdfSmrg/*
12735c4bbdfSmrg * Read stuff from the pixmap FBOs and write to memory
12835c4bbdfSmrg */
12935c4bbdfSmrgvoid
13035c4bbdfSmrgglamor_download_boxes(PixmapPtr pixmap, BoxPtr in_boxes, int in_nbox,
13135c4bbdfSmrg                      int dx_src, int dy_src,
13235c4bbdfSmrg                      int dx_dst, int dy_dst,
13335c4bbdfSmrg                      uint8_t *bits, uint32_t byte_stride)
13435c4bbdfSmrg{
13535c4bbdfSmrg    ScreenPtr screen = pixmap->drawable.pScreen;
13635c4bbdfSmrg    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
13735c4bbdfSmrg    glamor_pixmap_private *priv = glamor_get_pixmap_private(pixmap);
13835c4bbdfSmrg    int box_index;
13935c4bbdfSmrg    int bytes_per_pixel = pixmap->drawable.bitsPerPixel >> 3;
140ed6184dfSmrg    const struct glamor_format *f = glamor_format_for_pixmap(pixmap);
14135c4bbdfSmrg
14235c4bbdfSmrg    glamor_make_current(glamor_priv);
14335c4bbdfSmrg
14435c4bbdfSmrg    glPixelStorei(GL_PACK_ALIGNMENT, 4);
14535c4bbdfSmrg    if (glamor_priv->has_pack_subimage)
14635c4bbdfSmrg        glPixelStorei(GL_PACK_ROW_LENGTH, byte_stride / bytes_per_pixel);
14735c4bbdfSmrg
14835c4bbdfSmrg    glamor_pixmap_loop(priv, box_index) {
14935c4bbdfSmrg        BoxPtr                  box = glamor_pixmap_box_at(priv, box_index);
15035c4bbdfSmrg        glamor_pixmap_fbo       *fbo = glamor_pixmap_fbo_at(priv, box_index);
15135c4bbdfSmrg        BoxPtr                  boxes = in_boxes;
15235c4bbdfSmrg        int                     nbox = in_nbox;
15335c4bbdfSmrg
15435c4bbdfSmrg        /* This should not be called on GLAMOR_FBO_NO_FBO-allocated pixmaps. */
15535c4bbdfSmrg        assert(fbo->fb);
15635c4bbdfSmrg        glBindFramebuffer(GL_FRAMEBUFFER, fbo->fb);
15735c4bbdfSmrg
15835c4bbdfSmrg        while (nbox--) {
15935c4bbdfSmrg
16035c4bbdfSmrg            /* compute drawable coordinates */
16135c4bbdfSmrg            int                     x1 = MAX(boxes->x1 + dx_src, box->x1);
16235c4bbdfSmrg            int                     x2 = MIN(boxes->x2 + dx_src, box->x2);
16335c4bbdfSmrg            int                     y1 = MAX(boxes->y1 + dy_src, box->y1);
16435c4bbdfSmrg            int                     y2 = MIN(boxes->y2 + dy_src, box->y2);
16535c4bbdfSmrg            size_t ofs = (y1 - dy_src + dy_dst) * byte_stride;
16635c4bbdfSmrg            ofs += (x1 - dx_src + dx_dst) * bytes_per_pixel;
16735c4bbdfSmrg
16835c4bbdfSmrg            boxes++;
16935c4bbdfSmrg
17035c4bbdfSmrg            if (x2 <= x1 || y2 <= y1)
17135c4bbdfSmrg                continue;
17235c4bbdfSmrg
17335c4bbdfSmrg            if (glamor_priv->has_pack_subimage ||
17435c4bbdfSmrg                x2 - x1 == byte_stride / bytes_per_pixel) {
175ed6184dfSmrg                glReadPixels(x1 - box->x1, y1 - box->y1, x2 - x1, y2 - y1, f->format, f->type, bits + ofs);
17635c4bbdfSmrg            } else {
17735c4bbdfSmrg                for (; y1 < y2; y1++, ofs += byte_stride)
178ed6184dfSmrg                    glReadPixels(x1 - box->x1, y1 - box->y1, x2 - x1, 1, f->format, f->type, bits + ofs);
17935c4bbdfSmrg            }
18035c4bbdfSmrg        }
18135c4bbdfSmrg    }
18235c4bbdfSmrg    if (glamor_priv->has_pack_subimage)
18335c4bbdfSmrg        glPixelStorei(GL_PACK_ROW_LENGTH, 0);
18435c4bbdfSmrg}
18535c4bbdfSmrg
18635c4bbdfSmrg/*
18735c4bbdfSmrg * Read data from the pixmap FBO
18835c4bbdfSmrg */
18935c4bbdfSmrgvoid
19035c4bbdfSmrgglamor_download_rect(PixmapPtr pixmap, int x, int y, int w, int h, uint8_t *bits)
19135c4bbdfSmrg{
19235c4bbdfSmrg    BoxRec      box;
19335c4bbdfSmrg
19435c4bbdfSmrg    box.x1 = x;
19535c4bbdfSmrg    box.x2 = x + w;
19635c4bbdfSmrg    box.y1 = y;
19735c4bbdfSmrg    box.y2 = y + h;
19835c4bbdfSmrg
19935c4bbdfSmrg    glamor_download_boxes(pixmap, &box, 1, 0, 0, -x, -y,
20035c4bbdfSmrg                          bits, PixmapBytePad(w, pixmap->drawable.depth));
20135c4bbdfSmrg}
20235c4bbdfSmrg
20335c4bbdfSmrg/*
20435c4bbdfSmrg * Pull the data from the FBO down to the pixmap
20535c4bbdfSmrg */
20635c4bbdfSmrgvoid
20735c4bbdfSmrgglamor_download_pixmap(PixmapPtr pixmap)
20835c4bbdfSmrg{
20935c4bbdfSmrg    BoxRec      box;
21035c4bbdfSmrg
21135c4bbdfSmrg    box.x1 = 0;
21235c4bbdfSmrg    box.x2 = pixmap->drawable.width;
21335c4bbdfSmrg    box.y1 = 0;
21435c4bbdfSmrg    box.y2 = pixmap->drawable.height;
21535c4bbdfSmrg
21635c4bbdfSmrg    glamor_download_boxes(pixmap, &box, 1, 0, 0, 0, 0,
21735c4bbdfSmrg                          pixmap->devPrivate.ptr, pixmap->devKind);
21835c4bbdfSmrg}
219