static void
glamor_glyphs_flush(CARD8 op, PicturePtr src, PicturePtr dst,
                   glamor_program *prog,
                   struct glamor_glyph_atlas *atlas, int nglyph)
{
    DrawablePtr drawable = dst->pDrawable;
    glamor_screen_private *glamor_priv = glamor_get_screen_private(drawable->pScreen);
    PixmapPtr atlas_pixmap = atlas->atlas;
    glamor_pixmap_private *atlas_priv = glamor_get_pixmap_private(atlas_pixmap);
    glamor_pixmap_fbo *atlas_fbo = glamor_pixmap_fbo_at(atlas_priv, 0, 0);
    PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
    glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
    int box_x, box_y;
    int off_x, off_y;

    glamor_put_vbo_space(drawable->pScreen);

    glEnable(GL_SCISSOR_TEST);
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, atlas_fbo->tex);

    for (;;) {
        if (!glamor_use_program_render(prog, op, src, dst))
            break;

        glUniform1i(prog->atlas_uniform, 1);

        glamor_pixmap_loop(pixmap_priv, box_x, box_y) {
            BoxPtr box = RegionRects(dst->pCompositeClip);
            int nbox = RegionNumRects(dst->pCompositeClip);

            glamor_set_destination_drawable(drawable, box_x, box_y, TRUE, FALSE, prog->matrix_uniform, &off_x, &off_y);

            /* Run over the clip list, drawing the glyphs
             * in each box
             */

            while (nbox--) {
                glScissor(box->x1 + off_x,
                          box->y1 + off_y,
                          box->x2 - box->x1,
                          box->y2 - box->y1);
                box++;

                if (glamor_glyph_use_130(glamor_priv))
                    glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, nglyph);
                else
                    glamor_glDrawArrays_GL_QUADS(glamor_priv, nglyph);
            }
        }
        if (prog->alpha != glamor_program_alpha_ca_first)
            break;
        prog++;
    }
void
glamor_set_destination_drawable(DrawablePtr     drawable,
                                int             box_index,
                                Bool            do_drawable_translate,
                                Bool            center_offset,
                                GLint           matrix_uniform_location,
                                int             *p_off_x,
                                int             *p_off_y)
{
    ScreenPtr screen = drawable->pScreen;
    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
    PixmapPtr pixmap = glamor_get_drawable_pixmap(drawable);
    glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
    int off_x, off_y;
    BoxPtr box = glamor_pixmap_box_at(pixmap_priv, box_index);
    int w = box->x2 - box->x1;
    int h = box->y2 - box->y1;
    float scale_x = 2.0f / (float) w;
    float scale_y = 2.0f / (float) h;
    float center_adjust = 0.0f;

    glamor_get_drawable_deltas(drawable, pixmap, &off_x, &off_y);

    off_x -= box->x1;
    off_y -= box->y1;

    if (p_off_x) {
        *p_off_x = off_x;
        *p_off_y = off_y;
    }

    /* A tricky computation to find the right value for the two linear functions
     * that transform rendering coordinates to pixmap coordinates
     *
     *  pixmap_x = render_x + drawable->x + off_x
     *  pixmap_y = render_y + drawable->y + off_y
     *
     *  gl_x = pixmap_x * 2 / width - 1
     *  gl_y = pixmap_y * 2 / height - 1
     *
     *  gl_x = (render_x + drawable->x + off_x) * 2 / width - 1
     *
     *  gl_x = (render_x) * 2 / width + (drawable->x + off_x) * 2 / width - 1
     */

    if (do_drawable_translate) {
        off_x += drawable->x;
        off_y += drawable->y;
    }

    /*
     * To get GL_POINTS drawn in the right spot, we need to adjust the
     * coordinates by 1/2 a pixel.
     */
    if (center_offset)
        center_adjust = 0.5f;

    glUniform4f(matrix_uniform_location,
                scale_x, (off_x + center_adjust) * scale_x - 1.0f,
                scale_y, (off_y + center_adjust) * scale_y - 1.0f);

    glamor_set_destination_pixmap_fbo(glamor_priv, glamor_pixmap_fbo_at(pixmap_priv, box_index),
                                      0, 0, w, h);
}
static Bool
glamor_copy_fbo_fbo_draw(DrawablePtr src,
                         DrawablePtr dst,
                         GCPtr gc,
                         BoxPtr box,
                         int nbox,
                         int dx,
                         int dy,
                         Bool reverse,
                         Bool upsidedown,
                         Pixel bitplane,
                         void *closure)
{
    ScreenPtr screen = dst->pScreen;
    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
    PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
    PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
    glamor_pixmap_private *src_priv = glamor_get_pixmap_private(src_pixmap);
    glamor_pixmap_private *dst_priv = glamor_get_pixmap_private(dst_pixmap);
    int src_box_index, dst_box_index;
    int dst_off_x, dst_off_y;
    int src_off_x, src_off_y;
    GLshort *v;
    char *vbo_offset;
    struct copy_args args;
    glamor_program *prog;
    const glamor_facet *copy_facet;
    int n;

    glamor_make_current(glamor_priv);

    if (gc && !glamor_set_planemask(gc->depth, gc->planemask))
        goto bail_ctx;

    if (!glamor_set_alu(screen, gc ? gc->alu : GXcopy))
        goto bail_ctx;

    if (bitplane) {
        prog = &glamor_priv->copy_plane_prog;
        copy_facet = &glamor_facet_copyplane;
    } else {
        prog = &glamor_priv->copy_area_prog;
        copy_facet = &glamor_facet_copyarea;
    }

    if (prog->failed)
        goto bail_ctx;

    if (!prog->prog) {
        if (!glamor_build_program(screen, prog,
                                  copy_facet, NULL, NULL, NULL))
            goto bail_ctx;
    }

    args.src_pixmap = src_pixmap;
    args.bitplane = bitplane;

    /* Set up the vertex buffers for the points */

    v = glamor_get_vbo_space(dst->pScreen, nbox * 8 * sizeof (int16_t), &vbo_offset);

    glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
    glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_SHORT, GL_FALSE,
                          2 * sizeof (GLshort), vbo_offset);

    for (n = 0; n < nbox; n++) {
        v[0] = box->x1; v[1] = box->y1;
        v[2] = box->x1; v[3] = box->y2;
        v[4] = box->x2; v[5] = box->y2;
        v[6] = box->x2; v[7] = box->y1;
        v += 8;
        box++;
    }

    glamor_put_vbo_space(screen);

    glamor_get_drawable_deltas(src, src_pixmap, &src_off_x, &src_off_y);

    glEnable(GL_SCISSOR_TEST);

    glamor_pixmap_loop(src_priv, src_box_index) {
        BoxPtr src_box = glamor_pixmap_box_at(src_priv, src_box_index);

        args.dx = dx + src_off_x - src_box->x1;
        args.dy = dy + src_off_y - src_box->y1;
        args.src = glamor_pixmap_fbo_at(src_priv, src_box_index);

        if (!glamor_use_program(dst_pixmap, gc, prog, &args))
            goto bail_ctx;

        glamor_pixmap_loop(dst_priv, dst_box_index) {
            glamor_set_destination_drawable(dst, dst_box_index, FALSE, FALSE,
                                            prog->matrix_uniform,
                                            &dst_off_x, &dst_off_y);

            glScissor(dst_off_x - args.dx,
                      dst_off_y - args.dy,
                      src_box->x2 - src_box->x1,
                      src_box->y2 - src_box->y1);

            glamor_glDrawArrays_GL_QUADS(glamor_priv, nbox);
        }
/*
 * Write a region of bits into a pixmap
 */
void
glamor_upload_boxes(PixmapPtr pixmap, BoxPtr in_boxes, int in_nbox,
                    int dx_src, int dy_src,
                    int dx_dst, int dy_dst,
                    uint8_t *bits, uint32_t byte_stride)
{
    ScreenPtr                   screen = pixmap->drawable.pScreen;
    glamor_screen_private       *glamor_priv = glamor_get_screen_private(screen);
    glamor_pixmap_private       *priv = glamor_get_pixmap_private(pixmap);
    int                         box_index;
    int                         bytes_per_pixel = pixmap->drawable.bitsPerPixel >> 3;
    GLenum                      type;
    GLenum                      format;

    glamor_format_for_pixmap(pixmap, &format, &type);

    glamor_make_current(glamor_priv);

    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);

    if (glamor_priv->has_unpack_subimage)
        glPixelStorei(GL_UNPACK_ROW_LENGTH, byte_stride / bytes_per_pixel);

    glamor_pixmap_loop(priv, box_index) {
        BoxPtr                  box = glamor_pixmap_box_at(priv, box_index);
        glamor_pixmap_fbo       *fbo = glamor_pixmap_fbo_at(priv, box_index);
        BoxPtr                  boxes = in_boxes;
        int                     nbox = in_nbox;

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, fbo->tex);

        while (nbox--) {

            /* compute drawable coordinates */
            int x1 = MAX(boxes->x1 + dx_dst, box->x1);
            int x2 = MIN(boxes->x2 + dx_dst, box->x2);
            int y1 = MAX(boxes->y1 + dy_dst, box->y1);
            int y2 = MIN(boxes->y2 + dy_dst, box->y2);

            size_t ofs = (y1 - dy_dst + dy_src) * byte_stride;
            ofs += (x1 - dx_dst + dx_src) * bytes_per_pixel;

            boxes++;

            if (x2 <= x1 || y2 <= y1)
                continue;

            if (glamor_priv->has_unpack_subimage ||
                x2 - x1 == byte_stride / bytes_per_pixel) {
                glTexSubImage2D(GL_TEXTURE_2D, 0,
                                x1 - box->x1, y1 - box->y1,
                                x2 - x1, y2 - y1,
                                format, type,
                                bits + ofs);
            } else {
                for (; y1 < y2; y1++, ofs += byte_stride)
                    glTexSubImage2D(GL_TEXTURE_2D, 0,
                                    x1 - box->x1, y1 - box->y1,
                                    x2 - x1, 1,
                                    format, type,
                                    bits + ofs);
            }
        }
    }