748 lines
24 KiB
C
748 lines
24 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;
|
||
|
|
||
|
glActiveTexture(GL_TEXTURE0);
|
||
|
glBindTexture(GL_TEXTURE_2D, src->tex);
|
||
|
|
||
|
glUniform2f(prog->fill_offset_uniform, args->dx, args->dy);
|
||
|
glUniform2f(prog->fill_size_uniform, src->width, 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;\n"),
|
||
|
.fs_exec = " gl_FragColor = texture2D(sampler, fill_pos);\n",
|
||
|
.locations = glamor_program_location_fill,
|
||
|
.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;
|
||
|
|
||
|
glActiveTexture(GL_TEXTURE0);
|
||
|
glBindTexture(GL_TEXTURE_2D, src->tex);
|
||
|
|
||
|
glUniform2f(prog->fill_offset_uniform, args->dx, args->dy);
|
||
|
glUniform2f(prog->fill_size_uniform, src->width, 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 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;\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_fill|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 GPU 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);
|
||
|
FbBits *src_bits;
|
||
|
FbStride src_stride;
|
||
|
int src_bpp;
|
||
|
int src_xoff, src_yoff;
|
||
|
int dst_xoff, dst_yoff;
|
||
|
|
||
|
if (gc && gc->alu != GXcopy)
|
||
|
goto bail;
|
||
|
|
||
|
if (gc && !glamor_pm_is_solid(dst, gc->planemask))
|
||
|
goto bail;
|
||
|
|
||
|
glamor_make_current(glamor_priv);
|
||
|
glamor_prepare_access(src, GLAMOR_ACCESS_RO);
|
||
|
|
||
|
glamor_get_drawable_deltas(dst, dst_pixmap, &dst_xoff, &dst_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(dst, gc->planemask))
|
||
|
goto bail;
|
||
|
|
||
|
glamor_make_current(glamor_priv);
|
||
|
glamor_prepare_access(dst, GLAMOR_ACCESS_RW);
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* 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_x, src_box_y, dst_box_x, dst_box_y;
|
||
|
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;
|
||
|
Bool set_scissor;
|
||
|
int n;
|
||
|
|
||
|
glamor_make_current(glamor_priv);
|
||
|
|
||
|
if (gc && !glamor_set_planemask(dst_pixmap, 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))
|
||
|
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);
|
||
|
|
||
|
set_scissor = src_priv->type == GLAMOR_TEXTURE_LARGE;
|
||
|
if (set_scissor)
|
||
|
glEnable(GL_SCISSOR_TEST);
|
||
|
|
||
|
glamor_pixmap_loop(src_priv, src_box_x, src_box_y) {
|
||
|
BoxPtr src_box = glamor_pixmap_box_at(src_priv, src_box_x, src_box_y);
|
||
|
|
||
|
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_x, src_box_y);
|
||
|
|
||
|
if (!glamor_use_program(dst_pixmap, gc, prog, &args))
|
||
|
goto bail_ctx;
|
||
|
|
||
|
glamor_pixmap_loop(dst_priv, dst_box_x, dst_box_y) {
|
||
|
glamor_set_destination_drawable(dst, dst_box_x, dst_box_y, FALSE, FALSE,
|
||
|
prog->matrix_uniform, &dst_off_x, &dst_off_y);
|
||
|
|
||
|
if (set_scissor)
|
||
|
glScissor(dst_off_x - args.dx,
|
||
|
dst_off_y - args.dy,
|
||
|
src_box->x2 - src_box->x1,
|
||
|
src_box->y2 - src_box->y1);
|
||
|
|
||
|
if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
|
||
|
glDrawArrays(GL_QUADS, 0, nbox * 4);
|
||
|
else {
|
||
|
int i;
|
||
|
for (i = 0; i < nbox; i++)
|
||
|
glDrawArrays(GL_TRIANGLE_FAN, i*4, 4);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (set_scissor)
|
||
|
glDisable(GL_SCISSOR_TEST);
|
||
|
glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
|
||
|
|
||
|
glDisable(GL_COLOR_LOGIC_OP);
|
||
|
return TRUE;
|
||
|
|
||
|
bail_ctx:
|
||
|
glDisable(GL_COLOR_LOGIC_OP);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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 dst_pixmap = glamor_get_drawable_pixmap(dst);
|
||
|
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(dst_pixmap, gc->planemask))
|
||
|
goto bail_ctx;
|
||
|
|
||
|
if (!glamor_set_alu(screen, gc ? gc->alu : GXcopy))
|
||
|
goto bail_ctx;
|
||
|
glDisable(GL_COLOR_LOGIC_OP);
|
||
|
|
||
|
/* 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:
|
||
|
glDisable(GL_COLOR_LOGIC_OP);
|
||
|
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;
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
if (bitplane == 0)
|
||
|
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 (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);
|
||
|
}
|
||
|
|
||
|
Bool
|
||
|
glamor_copy_n_to_n_nf(DrawablePtr src,
|
||
|
DrawablePtr dst,
|
||
|
GCPtr gc,
|
||
|
BoxPtr box,
|
||
|
int nbox,
|
||
|
int dx,
|
||
|
int dy,
|
||
|
Bool reverse,
|
||
|
Bool upsidedown, Pixel bitplane,
|
||
|
void *closure)
|
||
|
{
|
||
|
if (glamor_copy_gl(src, dst, gc, box, nbox, dx, dy, reverse, upsidedown, bitplane, closure))
|
||
|
return TRUE;
|
||
|
if (glamor_ddx_fallback_check_pixmap(src) && glamor_ddx_fallback_check_pixmap(dst))
|
||
|
return FALSE;
|
||
|
glamor_copy_bail(src, dst, gc, box, nbox, dx, dy, reverse, upsidedown, bitplane, closure);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
Bool
|
||
|
glamor_copy_plane_nf(DrawablePtr src, DrawablePtr dst, GCPtr gc,
|
||
|
int srcx, int srcy, int w, int h, int dstx, int dsty,
|
||
|
unsigned long bitplane, RegionPtr *region)
|
||
|
{
|
||
|
if (glamor_ddx_fallback_check_pixmap(src) &&
|
||
|
glamor_ddx_fallback_check_pixmap(dst) &&
|
||
|
glamor_ddx_fallback_check_gc(gc))
|
||
|
return FALSE;
|
||
|
|
||
|
*region = glamor_copy_plane(src, dst, gc,
|
||
|
srcx, srcy, w, h, dstx, dsty,
|
||
|
bitplane);
|
||
|
return TRUE;
|
||
|
}
|