794 lines
26 KiB
C
794 lines
26 KiB
C
/*
|
|
* Copyright © 2014 Keith Packard
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
* documentation for any purpose is hereby granted without fee, provided that
|
|
* the above copyright notice appear in all copies and that both that copyright
|
|
* notice and this permission notice appear in supporting documentation, and
|
|
* that the name of the copyright holders not be used in advertising or
|
|
* publicity pertaining to distribution of the software without specific,
|
|
* written prior permission. The copyright holders make no representations
|
|
* about the suitability of this software for any purpose. It is provided "as
|
|
* is" without express or implied warranty.
|
|
*
|
|
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
|
* OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#include "glamor_priv.h"
|
|
#include "glamor_transfer.h"
|
|
#include "glamor_prepare.h"
|
|
#include "glamor_transform.h"
|
|
|
|
struct copy_args {
|
|
PixmapPtr src_pixmap;
|
|
glamor_pixmap_fbo *src;
|
|
uint32_t bitplane;
|
|
int dx, dy;
|
|
};
|
|
|
|
static Bool
|
|
use_copyarea(PixmapPtr dst, GCPtr gc, glamor_program *prog, void *arg)
|
|
{
|
|
struct copy_args *args = arg;
|
|
glamor_pixmap_fbo *src = args->src;
|
|
|
|
glamor_bind_texture(glamor_get_screen_private(dst->drawable.pScreen),
|
|
GL_TEXTURE0, src, TRUE);
|
|
|
|
glUniform2f(prog->fill_offset_uniform, args->dx, args->dy);
|
|
glUniform2f(prog->fill_size_inv_uniform, 1.0f/src->width, 1.0f/src->height);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static const glamor_facet glamor_facet_copyarea = {
|
|
"copy_area",
|
|
.vs_vars = "attribute vec2 primitive;\n",
|
|
.vs_exec = (GLAMOR_POS(gl_Position, primitive.xy)
|
|
" fill_pos = (fill_offset + primitive.xy) * fill_size_inv;\n"),
|
|
.fs_exec = " gl_FragColor = texture2D(sampler, fill_pos);\n",
|
|
.locations = glamor_program_location_fillsamp | glamor_program_location_fillpos,
|
|
.use = use_copyarea,
|
|
};
|
|
|
|
/*
|
|
* Configure the copy plane program for the current operation
|
|
*/
|
|
|
|
static Bool
|
|
use_copyplane(PixmapPtr dst, GCPtr gc, glamor_program *prog, void *arg)
|
|
{
|
|
struct copy_args *args = arg;
|
|
glamor_pixmap_fbo *src = args->src;
|
|
|
|
glamor_bind_texture(glamor_get_screen_private(dst->drawable.pScreen),
|
|
GL_TEXTURE0, src, TRUE);
|
|
|
|
glUniform2f(prog->fill_offset_uniform, args->dx, args->dy);
|
|
glUniform2f(prog->fill_size_inv_uniform, 1.0f/src->width, 1.0f/src->height);
|
|
|
|
glamor_set_color(dst, gc->fgPixel, prog->fg_uniform);
|
|
glamor_set_color(dst, gc->bgPixel, prog->bg_uniform);
|
|
|
|
/* XXX handle 2 10 10 10 and 1555 formats; presumably the pixmap private knows this? */
|
|
switch (args->src_pixmap->drawable.depth) {
|
|
case 30:
|
|
glUniform4ui(prog->bitplane_uniform,
|
|
(args->bitplane >> 20) & 0x3ff,
|
|
(args->bitplane >> 10) & 0x3ff,
|
|
(args->bitplane ) & 0x3ff,
|
|
0);
|
|
|
|
glUniform4f(prog->bitmul_uniform, 0x3ff, 0x3ff, 0x3ff, 0);
|
|
break;
|
|
case 24:
|
|
glUniform4ui(prog->bitplane_uniform,
|
|
(args->bitplane >> 16) & 0xff,
|
|
(args->bitplane >> 8) & 0xff,
|
|
(args->bitplane ) & 0xff,
|
|
0);
|
|
|
|
glUniform4f(prog->bitmul_uniform, 0xff, 0xff, 0xff, 0);
|
|
break;
|
|
case 32:
|
|
glUniform4ui(prog->bitplane_uniform,
|
|
(args->bitplane >> 16) & 0xff,
|
|
(args->bitplane >> 8) & 0xff,
|
|
(args->bitplane ) & 0xff,
|
|
(args->bitplane >> 24) & 0xff);
|
|
|
|
glUniform4f(prog->bitmul_uniform, 0xff, 0xff, 0xff, 0xff);
|
|
break;
|
|
case 16:
|
|
glUniform4ui(prog->bitplane_uniform,
|
|
(args->bitplane >> 11) & 0x1f,
|
|
(args->bitplane >> 5) & 0x3f,
|
|
(args->bitplane ) & 0x1f,
|
|
0);
|
|
|
|
glUniform4f(prog->bitmul_uniform, 0x1f, 0x3f, 0x1f, 0);
|
|
break;
|
|
case 15:
|
|
glUniform4ui(prog->bitplane_uniform,
|
|
(args->bitplane >> 10) & 0x1f,
|
|
(args->bitplane >> 5) & 0x1f,
|
|
(args->bitplane ) & 0x1f,
|
|
0);
|
|
|
|
glUniform4f(prog->bitmul_uniform, 0x1f, 0x1f, 0x1f, 0);
|
|
break;
|
|
case 8:
|
|
glUniform4ui(prog->bitplane_uniform,
|
|
0, 0, 0, args->bitplane);
|
|
glUniform4f(prog->bitmul_uniform, 0, 0, 0, 0xff);
|
|
break;
|
|
case 1:
|
|
glUniform4ui(prog->bitplane_uniform,
|
|
0, 0, 0, args->bitplane);
|
|
glUniform4f(prog->bitmul_uniform, 0, 0, 0, 0xff);
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static const glamor_facet glamor_facet_copyplane = {
|
|
"copy_plane",
|
|
.version = 130,
|
|
.vs_vars = "attribute vec2 primitive;\n",
|
|
.vs_exec = (GLAMOR_POS(gl_Position, (primitive.xy))
|
|
" fill_pos = (fill_offset + primitive.xy) * fill_size_inv;\n"),
|
|
.fs_exec = (" uvec4 bits = uvec4(round(texture2D(sampler, fill_pos) * bitmul));\n"
|
|
" if ((bits & bitplane) != uvec4(0,0,0,0))\n"
|
|
" gl_FragColor = fg;\n"
|
|
" else\n"
|
|
" gl_FragColor = bg;\n"),
|
|
.locations = glamor_program_location_fillsamp|glamor_program_location_fillpos|glamor_program_location_fg|glamor_program_location_bg|glamor_program_location_bitplane,
|
|
.use = use_copyplane,
|
|
};
|
|
|
|
/*
|
|
* When all else fails, pull the bits out of the GPU and do the
|
|
* operation with fb
|
|
*/
|
|
|
|
static void
|
|
glamor_copy_bail(DrawablePtr src,
|
|
DrawablePtr dst,
|
|
GCPtr gc,
|
|
BoxPtr box,
|
|
int nbox,
|
|
int dx,
|
|
int dy,
|
|
Bool reverse,
|
|
Bool upsidedown,
|
|
Pixel bitplane,
|
|
void *closure)
|
|
{
|
|
if (glamor_prepare_access(dst, GLAMOR_ACCESS_RW) && glamor_prepare_access(src, GLAMOR_ACCESS_RO)) {
|
|
if (bitplane) {
|
|
if (src->bitsPerPixel > 1)
|
|
fbCopyNto1(src, dst, gc, box, nbox, dx, dy,
|
|
reverse, upsidedown, bitplane, closure);
|
|
else
|
|
fbCopy1toN(src, dst, gc, box, nbox, dx, dy,
|
|
reverse, upsidedown, bitplane, closure);
|
|
} else {
|
|
fbCopyNtoN(src, dst, gc, box, nbox, dx, dy,
|
|
reverse, upsidedown, bitplane, closure);
|
|
}
|
|
}
|
|
glamor_finish_access(dst);
|
|
glamor_finish_access(src);
|
|
}
|
|
|
|
/**
|
|
* Implements CopyPlane and CopyArea from the CPU to the GPU by using
|
|
* the source as a texture and painting that into the destination.
|
|
*
|
|
* This requires that source and dest are different textures, or that
|
|
* (if the copy area doesn't overlap), GL_NV_texture_barrier is used
|
|
* to ensure that the caches are flushed at the right times.
|
|
*/
|
|
static Bool
|
|
glamor_copy_cpu_fbo(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 dst_pixmap = glamor_get_drawable_pixmap(dst);
|
|
int dst_xoff, dst_yoff;
|
|
|
|
if (gc && gc->alu != GXcopy)
|
|
goto bail;
|
|
|
|
if (gc && !glamor_pm_is_solid(gc->depth, gc->planemask))
|
|
goto bail;
|
|
|
|
glamor_make_current(glamor_priv);
|
|
|
|
if (!glamor_prepare_access(src, GLAMOR_ACCESS_RO))
|
|
goto bail;
|
|
|
|
glamor_get_drawable_deltas(dst, dst_pixmap, &dst_xoff, &dst_yoff);
|
|
|
|
if (bitplane) {
|
|
FbBits *tmp_bits;
|
|
FbStride tmp_stride;
|
|
int tmp_bpp;
|
|
int tmp_xoff, tmp_yoff;
|
|
|
|
PixmapPtr tmp_pix = fbCreatePixmap(screen, dst_pixmap->drawable.width,
|
|
dst_pixmap->drawable.height,
|
|
dst->depth, 0);
|
|
|
|
if (!tmp_pix) {
|
|
glamor_finish_access(src);
|
|
goto bail;
|
|
}
|
|
|
|
tmp_pix->drawable.x = dst_xoff;
|
|
tmp_pix->drawable.y = dst_yoff;
|
|
|
|
fbGetDrawable(&tmp_pix->drawable, tmp_bits, tmp_stride, tmp_bpp, tmp_xoff,
|
|
tmp_yoff);
|
|
|
|
if (src->bitsPerPixel > 1)
|
|
fbCopyNto1(src, &tmp_pix->drawable, gc, box, nbox, dx, dy,
|
|
reverse, upsidedown, bitplane, closure);
|
|
else
|
|
fbCopy1toN(src, &tmp_pix->drawable, gc, box, nbox, dx, dy,
|
|
reverse, upsidedown, bitplane, closure);
|
|
|
|
glamor_upload_boxes(dst_pixmap, box, nbox, tmp_xoff, tmp_yoff,
|
|
dst_xoff, dst_yoff, (uint8_t *) tmp_bits,
|
|
tmp_stride * sizeof(FbBits));
|
|
fbDestroyPixmap(tmp_pix);
|
|
} else {
|
|
FbBits *src_bits;
|
|
FbStride src_stride;
|
|
int src_bpp;
|
|
int src_xoff, src_yoff;
|
|
|
|
fbGetDrawable(src, src_bits, src_stride, src_bpp, src_xoff, src_yoff);
|
|
glamor_upload_boxes(dst_pixmap, box, nbox, src_xoff + dx, src_yoff + dy,
|
|
dst_xoff, dst_yoff,
|
|
(uint8_t *) src_bits, src_stride * sizeof (FbBits));
|
|
}
|
|
glamor_finish_access(src);
|
|
|
|
return TRUE;
|
|
|
|
bail:
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* Implements CopyArea from the GPU to the CPU using glReadPixels from the
|
|
* source FBO.
|
|
*/
|
|
static Bool
|
|
glamor_copy_fbo_cpu(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);
|
|
FbBits *dst_bits;
|
|
FbStride dst_stride;
|
|
int dst_bpp;
|
|
int src_xoff, src_yoff;
|
|
int dst_xoff, dst_yoff;
|
|
|
|
if (gc && gc->alu != GXcopy)
|
|
goto bail;
|
|
|
|
if (gc && !glamor_pm_is_solid(gc->depth, gc->planemask))
|
|
goto bail;
|
|
|
|
glamor_make_current(glamor_priv);
|
|
|
|
if (!glamor_prepare_access(dst, GLAMOR_ACCESS_RW))
|
|
goto bail;
|
|
|
|
glamor_get_drawable_deltas(src, src_pixmap, &src_xoff, &src_yoff);
|
|
|
|
fbGetDrawable(dst, dst_bits, dst_stride, dst_bpp, dst_xoff, dst_yoff);
|
|
|
|
glamor_download_boxes(src_pixmap, box, nbox, src_xoff + dx, src_yoff + dy,
|
|
dst_xoff, dst_yoff,
|
|
(uint8_t *) dst_bits, dst_stride * sizeof (FbBits));
|
|
glamor_finish_access(dst);
|
|
|
|
return TRUE;
|
|
|
|
bail:
|
|
return FALSE;
|
|
}
|
|
|
|
/* Include the enums here for the moment, to keep from needing to bump epoxy. */
|
|
#ifndef GL_TILE_RASTER_ORDER_FIXED_MESA
|
|
#define GL_TILE_RASTER_ORDER_FIXED_MESA 0x8BB8
|
|
#define GL_TILE_RASTER_ORDER_INCREASING_X_MESA 0x8BB9
|
|
#define GL_TILE_RASTER_ORDER_INCREASING_Y_MESA 0x8BBA
|
|
#endif
|
|
|
|
/*
|
|
* Copy from GPU to GPU by using the source
|
|
* as a texture and painting that into the destination
|
|
*/
|
|
|
|
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;
|
|
Bool ret = FALSE;
|
|
BoxRec bounds = glamor_no_rendering_bounds();
|
|
|
|
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 && !glamor_priv->can_copyplane)
|
|
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);
|
|
|
|
if (src_pixmap == dst_pixmap && glamor_priv->has_mesa_tile_raster_order) {
|
|
glEnable(GL_TILE_RASTER_ORDER_FIXED_MESA);
|
|
if (dx >= 0)
|
|
glEnable(GL_TILE_RASTER_ORDER_INCREASING_X_MESA);
|
|
else
|
|
glDisable(GL_TILE_RASTER_ORDER_INCREASING_X_MESA);
|
|
if (dy >= 0)
|
|
glEnable(GL_TILE_RASTER_ORDER_INCREASING_Y_MESA);
|
|
else
|
|
glDisable(GL_TILE_RASTER_ORDER_INCREASING_Y_MESA);
|
|
}
|
|
|
|
glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
|
|
glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_SHORT, GL_FALSE,
|
|
2 * sizeof (GLshort), vbo_offset);
|
|
|
|
if (nbox < 100) {
|
|
bounds = glamor_start_rendering_bounds();
|
|
for (int i = 0; i < nbox; i++)
|
|
glamor_bounds_union_box(&bounds, &box[i]);
|
|
}
|
|
|
|
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) {
|
|
BoxRec scissor = {
|
|
.x1 = max(-args.dx, bounds.x1),
|
|
.y1 = max(-args.dy, bounds.y1),
|
|
.x2 = min(-args.dx + src_box->x2 - src_box->x1, bounds.x2),
|
|
.y2 = min(-args.dy + src_box->y2 - src_box->y1, bounds.y2),
|
|
};
|
|
if (scissor.x1 >= scissor.x2 || scissor.y1 >= scissor.y2)
|
|
continue;
|
|
|
|
if (!glamor_set_destination_drawable(dst, dst_box_index, FALSE, FALSE,
|
|
prog->matrix_uniform,
|
|
&dst_off_x, &dst_off_y))
|
|
goto bail_ctx;
|
|
|
|
glScissor(scissor.x1 + dst_off_x,
|
|
scissor.y1 + dst_off_y,
|
|
scissor.x2 - scissor.x1,
|
|
scissor.y2 - scissor.y1);
|
|
|
|
glamor_glDrawArrays_GL_QUADS(glamor_priv, nbox);
|
|
}
|
|
}
|
|
|
|
ret = TRUE;
|
|
|
|
bail_ctx:
|
|
if (src_pixmap == dst_pixmap && glamor_priv->has_mesa_tile_raster_order) {
|
|
glDisable(GL_TILE_RASTER_ORDER_FIXED_MESA);
|
|
}
|
|
glDisable(GL_SCISSOR_TEST);
|
|
glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Copies from the GPU to the GPU using a temporary pixmap in between,
|
|
* to correctly handle overlapping copies.
|
|
*/
|
|
|
|
static Bool
|
|
glamor_copy_fbo_fbo_temp(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 tmp_pixmap;
|
|
BoxRec bounds;
|
|
int n;
|
|
BoxPtr tmp_box;
|
|
|
|
if (nbox == 0)
|
|
return TRUE;
|
|
|
|
/* Sanity check state to avoid getting halfway through and bailing
|
|
* at the last second. Might be nice to have checks that didn't
|
|
* involve setting state.
|
|
*/
|
|
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;
|
|
|
|
/* Find the size of the area to copy
|
|
*/
|
|
bounds = box[0];
|
|
for (n = 1; n < nbox; n++) {
|
|
bounds.x1 = min(bounds.x1, box[n].x1);
|
|
bounds.x2 = max(bounds.x2, box[n].x2);
|
|
bounds.y1 = min(bounds.y1, box[n].y1);
|
|
bounds.y2 = max(bounds.y2, box[n].y2);
|
|
}
|
|
|
|
/* Allocate a suitable temporary pixmap
|
|
*/
|
|
tmp_pixmap = glamor_create_pixmap(screen,
|
|
bounds.x2 - bounds.x1,
|
|
bounds.y2 - bounds.y1,
|
|
src->depth, 0);
|
|
if (!tmp_pixmap)
|
|
goto bail;
|
|
|
|
tmp_box = calloc(nbox, sizeof (BoxRec));
|
|
if (!tmp_box)
|
|
goto bail_pixmap;
|
|
|
|
/* Convert destination boxes into tmp pixmap boxes
|
|
*/
|
|
for (n = 0; n < nbox; n++) {
|
|
tmp_box[n].x1 = box[n].x1 - bounds.x1;
|
|
tmp_box[n].x2 = box[n].x2 - bounds.x1;
|
|
tmp_box[n].y1 = box[n].y1 - bounds.y1;
|
|
tmp_box[n].y2 = box[n].y2 - bounds.y1;
|
|
}
|
|
|
|
if (!glamor_copy_fbo_fbo_draw(src,
|
|
&tmp_pixmap->drawable,
|
|
NULL,
|
|
tmp_box,
|
|
nbox,
|
|
dx + bounds.x1,
|
|
dy + bounds.y1,
|
|
FALSE, FALSE,
|
|
0, NULL))
|
|
goto bail_box;
|
|
|
|
if (!glamor_copy_fbo_fbo_draw(&tmp_pixmap->drawable,
|
|
dst,
|
|
gc,
|
|
box,
|
|
nbox,
|
|
-bounds.x1,
|
|
-bounds.y1,
|
|
FALSE, FALSE,
|
|
bitplane, closure))
|
|
goto bail_box;
|
|
|
|
free(tmp_box);
|
|
|
|
glamor_destroy_pixmap(tmp_pixmap);
|
|
|
|
return TRUE;
|
|
bail_box:
|
|
free(tmp_box);
|
|
bail_pixmap:
|
|
glamor_destroy_pixmap(tmp_pixmap);
|
|
bail:
|
|
return FALSE;
|
|
|
|
bail_ctx:
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* Returns TRUE if the copy has to be implemented with
|
|
* glamor_copy_fbo_fbo_temp() instead of glamor_copy_fbo_fbo().
|
|
*
|
|
* If the src and dst are in the same pixmap, then glamor_copy_fbo_fbo()'s
|
|
* sampling would give undefined results (since the same texture would be
|
|
* bound as an FBO destination and as a texture source). However, if we
|
|
* have GL_NV_texture_barrier, we can take advantage of the exception it
|
|
* added:
|
|
*
|
|
* "- If a texel has been written, then in order to safely read the result
|
|
* a texel fetch must be in a subsequent Draw separated by the command
|
|
*
|
|
* void TextureBarrierNV(void);
|
|
*
|
|
* TextureBarrierNV() will guarantee that writes have completed and caches
|
|
* have been invalidated before subsequent Draws are executed."
|
|
*/
|
|
static Bool
|
|
glamor_copy_needs_temp(DrawablePtr src,
|
|
DrawablePtr dst,
|
|
BoxPtr box,
|
|
int nbox,
|
|
int dx,
|
|
int dy)
|
|
{
|
|
PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src);
|
|
PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst);
|
|
ScreenPtr screen = dst->pScreen;
|
|
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
|
|
int n;
|
|
int dst_off_x, dst_off_y;
|
|
int src_off_x, src_off_y;
|
|
BoxRec bounds;
|
|
|
|
if (src_pixmap != dst_pixmap)
|
|
return FALSE;
|
|
|
|
if (nbox == 0)
|
|
return FALSE;
|
|
|
|
if (!glamor_priv->has_nv_texture_barrier)
|
|
return TRUE;
|
|
|
|
if (!glamor_priv->has_mesa_tile_raster_order) {
|
|
glamor_get_drawable_deltas(src, src_pixmap, &src_off_x, &src_off_y);
|
|
glamor_get_drawable_deltas(dst, dst_pixmap, &dst_off_x, &dst_off_y);
|
|
|
|
bounds = box[0];
|
|
for (n = 1; n < nbox; n++) {
|
|
bounds.x1 = min(bounds.x1, box[n].x1);
|
|
bounds.y1 = min(bounds.y1, box[n].y1);
|
|
|
|
bounds.x2 = max(bounds.x2, box[n].x2);
|
|
bounds.y2 = max(bounds.y2, box[n].y2);
|
|
}
|
|
|
|
/* Check to see if the pixmap-relative boxes overlap in both X and Y,
|
|
* in which case we can't rely on NV_texture_barrier and must
|
|
* make a temporary copy
|
|
*
|
|
* dst.x1 < src.x2 &&
|
|
* src.x1 < dst.x2 &&
|
|
*
|
|
* dst.y1 < src.y2 &&
|
|
* src.y1 < dst.y2
|
|
*/
|
|
if (bounds.x1 + dst_off_x < bounds.x2 + dx + src_off_x &&
|
|
bounds.x1 + dx + src_off_x < bounds.x2 + dst_off_x &&
|
|
|
|
bounds.y1 + dst_off_y < bounds.y2 + dy + src_off_y &&
|
|
bounds.y1 + dy + src_off_y < bounds.y2 + dst_off_y) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
glTextureBarrierNV();
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static Bool
|
|
glamor_copy_gl(DrawablePtr src,
|
|
DrawablePtr dst,
|
|
GCPtr gc,
|
|
BoxPtr box,
|
|
int nbox,
|
|
int dx,
|
|
int dy,
|
|
Bool reverse,
|
|
Bool upsidedown,
|
|
Pixel bitplane,
|
|
void *closure)
|
|
{
|
|
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);
|
|
|
|
if (GLAMOR_PIXMAP_PRIV_HAS_FBO(dst_priv)) {
|
|
if (GLAMOR_PIXMAP_PRIV_HAS_FBO(src_priv)) {
|
|
if (glamor_copy_needs_temp(src, dst, box, nbox, dx, dy))
|
|
return glamor_copy_fbo_fbo_temp(src, dst, gc, box, nbox, dx, dy,
|
|
reverse, upsidedown, bitplane, closure);
|
|
else
|
|
return glamor_copy_fbo_fbo_draw(src, dst, gc, box, nbox, dx, dy,
|
|
reverse, upsidedown, bitplane, closure);
|
|
}
|
|
|
|
return glamor_copy_cpu_fbo(src, dst, gc, box, nbox, dx, dy,
|
|
reverse, upsidedown, bitplane, closure);
|
|
} else if (GLAMOR_PIXMAP_PRIV_HAS_FBO(src_priv) &&
|
|
dst_priv->type != GLAMOR_DRM_ONLY &&
|
|
bitplane == 0) {
|
|
return glamor_copy_fbo_cpu(src, dst, gc, box, nbox, dx, dy,
|
|
reverse, upsidedown, bitplane, closure);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
glamor_copy(DrawablePtr src,
|
|
DrawablePtr dst,
|
|
GCPtr gc,
|
|
BoxPtr box,
|
|
int nbox,
|
|
int dx,
|
|
int dy,
|
|
Bool reverse,
|
|
Bool upsidedown,
|
|
Pixel bitplane,
|
|
void *closure)
|
|
{
|
|
if (nbox == 0)
|
|
return;
|
|
|
|
if (glamor_copy_gl(src, dst, gc, box, nbox, dx, dy, reverse, upsidedown, bitplane, closure))
|
|
return;
|
|
glamor_copy_bail(src, dst, gc, box, nbox, dx, dy, reverse, upsidedown, bitplane, closure);
|
|
}
|
|
|
|
RegionPtr
|
|
glamor_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc,
|
|
int srcx, int srcy, int width, int height, int dstx, int dsty)
|
|
{
|
|
return miDoCopy(src, dst, gc,
|
|
srcx, srcy, width, height,
|
|
dstx, dsty, glamor_copy, 0, NULL);
|
|
}
|
|
|
|
RegionPtr
|
|
glamor_copy_plane(DrawablePtr src, DrawablePtr dst, GCPtr gc,
|
|
int srcx, int srcy, int width, int height, int dstx, int dsty,
|
|
unsigned long bitplane)
|
|
{
|
|
if ((bitplane & FbFullMask(src->depth)) == 0)
|
|
return miHandleExposures(src, dst, gc,
|
|
srcx, srcy, width, height, dstx, dsty);
|
|
return miDoCopy(src, dst, gc,
|
|
srcx, srcy, width, height,
|
|
dstx, dsty, glamor_copy, bitplane, NULL);
|
|
}
|
|
|
|
void
|
|
glamor_copy_window(WindowPtr window, DDXPointRec old_origin, RegionPtr src_region)
|
|
{
|
|
PixmapPtr pixmap = glamor_get_drawable_pixmap(&window->drawable);
|
|
DrawablePtr drawable = &pixmap->drawable;
|
|
RegionRec dst_region;
|
|
int dx, dy;
|
|
|
|
dx = old_origin.x - window->drawable.x;
|
|
dy = old_origin.y - window->drawable.y;
|
|
RegionTranslate(src_region, -dx, -dy);
|
|
|
|
RegionNull(&dst_region);
|
|
|
|
RegionIntersect(&dst_region, &window->borderClip, src_region);
|
|
|
|
#ifdef COMPOSITE
|
|
if (pixmap->screen_x || pixmap->screen_y)
|
|
RegionTranslate(&dst_region, -pixmap->screen_x, -pixmap->screen_y);
|
|
#endif
|
|
|
|
miCopyRegion(drawable, drawable,
|
|
0, &dst_region, dx, dy, glamor_copy, 0, 0);
|
|
|
|
RegionUninit(&dst_region);
|
|
}
|