mirror of
https://gitlab.freedesktop.org/xorg/xserver.git
synced 2025-12-20 04:40:02 +01:00
Some hardware (preferably mobile) working on GLES3 way faster than on desktop GL and supports more features. This commit will allow using GLES3 if glamor is running over GL ES, and version 3 is supported. Changes are the following: 1. Add compatibility layer for 120/GLES2 shaders with defines in and out 2. Switch attribute and varying to in and out in almost all shaders (aside gradient) 3. Add newGL-only frag_color variable, which defines as gl_FragColor on old pipelines 4. Switch all shaders to use frag_color. 5. Previous commit is reverted, because now we have more than one GL ES version, previous commit used to set version 100 for all ES shaders, which is not true for ES 3 Signed-off-by: Konstantin Pugin <ria.freelander@gmail.com>
793 lines
26 KiB
C
793 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 {
|
|
DrawablePtr src_drawable;
|
|
glamor_pixmap_fbo *src;
|
|
uint32_t bitplane;
|
|
int dx, dy;
|
|
};
|
|
|
|
static Bool
|
|
use_copyarea(DrawablePtr drawable, 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(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 = "in vec2 primitive;\n",
|
|
.vs_exec = (GLAMOR_POS(gl_Position, primitive.xy)
|
|
" fill_pos = (fill_offset + primitive.xy) * fill_size_inv;\n"),
|
|
.fs_exec = " frag_color = texture(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(DrawablePtr drawable, 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(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(drawable, gc->fgPixel, prog->fg_uniform);
|
|
glamor_set_color(drawable, gc->bgPixel, prog->bg_uniform);
|
|
|
|
/* XXX handle 2 10 10 10 and 1555 formats; presumably the pixmap private knows this? */
|
|
switch (glamor_drawable_effective_depth(args->src_drawable)) {
|
|
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 = "in 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(texture(sampler, fill_pos) * bitmul));\n"
|
|
" if ((bits & bitplane) != uvec4(0,0,0,0))\n"
|
|
" frag_color = fg;\n"
|
|
" else\n"
|
|
" frag_color = 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,
|
|
glamor_drawable_effective_depth(dst), 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, 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, 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, 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_drawable = src;
|
|
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, 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,
|
|
glamor_drawable_effective_depth(src), 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(glamor_drawable_effective_depth(src))) == 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);
|
|
|
|
#if defined(COMPOSITE) || defined(ROOTLESS)
|
|
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);
|
|
}
|