xserver-multidpi/glamor/glamor_transform.c

282 lines
8.6 KiB
C
Raw Normal View History

/*
* 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_transform.h"
/*
* Set up rendering to target the specified drawable, computing an
* appropriate transform for the vertex shader to convert
* drawable-relative coordinates into pixmap-relative coordinates. If
* requested, the offset from pixmap origin coordinates back to window
* system coordinates will be returned in *p_off_x, *p_off_y so that
* clipping computations can be adjusted as appropriate
*/
void
glamor_set_destination_drawable(DrawablePtr drawable,
int box_x,
int box_y,
Bool do_drawable_translate,
Bool center_offset,
GLint matrix_uniform_location,
int *p_off_x,
int *p_off_y)
{
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_x, box_y);
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
*
* I'll think about yInverted later, when I have some way to test
*/
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_pixmap_fbo_at(pixmap_priv, box_x, box_y),
0, 0, w, h);
}
/*
* Set up for solid rendering to the specified pixmap using alu, fg and planemask
* from the specified GC. Load the target color into the specified uniform
*/
void
glamor_set_color(PixmapPtr pixmap,
CARD32 pixel,
GLint uniform)
{
float color[4];
glamor_get_rgba_from_pixel(pixel,
&color[0], &color[1], &color[2], &color[3],
format_for_pixmap(pixmap));
glUniform4fv(uniform, 1, color);
}
Bool
glamor_set_solid(PixmapPtr pixmap,
GCPtr gc,
Bool use_alu,
GLint uniform)
{
CARD32 pixel;
int alu = use_alu ? gc->alu : GXcopy;
if (!glamor_set_planemask(pixmap, gc->planemask))
return FALSE;
pixel = gc->fgPixel;
if (!glamor_set_alu(pixmap->drawable.pScreen, alu)) {
switch (gc->alu) {
case GXclear:
pixel = 0;
break;
case GXcopyInverted:
pixel = ~pixel;
break;
case GXset:
pixel = ~0 & gc->planemask;
break;
default:
return FALSE;
}
}
glamor_set_color(pixmap, gc->fgPixel, uniform);
return TRUE;
}
Bool
glamor_set_texture(PixmapPtr pixmap,
PixmapPtr texture,
int off_x,
int off_y,
GLint offset_uniform,
GLint size_uniform)
{
glamor_pixmap_private *texture_priv;
texture_priv = glamor_get_pixmap_private(texture);
if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(texture_priv))
return FALSE;
if (texture_priv->type == GLAMOR_TEXTURE_LARGE)
return FALSE;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture_priv->base.fbo->tex);
glUniform2f(offset_uniform, off_x, off_y);
glUniform2f(size_uniform, texture->drawable.width, texture->drawable.height);
return TRUE;
}
Bool
glamor_set_tiled(PixmapPtr pixmap,
GCPtr gc,
GLint offset_uniform,
GLint size_uniform)
{
if (!glamor_set_alu(pixmap->drawable.pScreen, gc->alu))
return FALSE;
if (!glamor_set_planemask(pixmap, gc->planemask))
return FALSE;
return glamor_set_texture(pixmap,
gc->tile.pixmap,
-gc->patOrg.x,
-gc->patOrg.y,
offset_uniform,
size_uniform);
}
static PixmapPtr
glamor_get_stipple_pixmap(GCPtr gc)
{
glamor_gc_private *gc_priv = glamor_get_gc_private(gc);
ScreenPtr screen = gc->pScreen;
PixmapPtr bitmap;
PixmapPtr pixmap;
GCPtr scratch_gc;
ChangeGCVal changes[2];
if (gc_priv->stipple)
return gc_priv->stipple;
bitmap = gc->stipple;
if (!bitmap)
goto bail;
pixmap = glamor_create_pixmap(screen,
bitmap->drawable.width,
bitmap->drawable.height,
8, GLAMOR_CREATE_NO_LARGE);
if (!pixmap)
goto bail;
scratch_gc = GetScratchGC(8, screen);
if (!scratch_gc)
goto bail_pixmap;
changes[0].val = 0xff;
changes[1].val = 0x00;
if (ChangeGC(NullClient, scratch_gc,
GCForeground|GCBackground, changes) != Success)
goto bail_gc;
ValidateGC(&pixmap->drawable, scratch_gc);
(*scratch_gc->ops->CopyPlane)(&bitmap->drawable,
&pixmap->drawable,
scratch_gc,
0, 0,
bitmap->drawable.width,
bitmap->drawable.height,
0, 0, 0x1);
FreeScratchGC(scratch_gc);
gc_priv->stipple = pixmap;
glamor_track_stipple(gc);
return pixmap;
bail_gc:
FreeScratchGC(scratch_gc);
bail_pixmap:
glamor_destroy_pixmap(pixmap);
bail:
return NULL;
}
Bool
glamor_set_stippled(PixmapPtr pixmap,
GCPtr gc,
GLint fg_uniform,
GLint offset_uniform,
GLint size_uniform)
{
PixmapPtr stipple;
stipple = glamor_get_stipple_pixmap(gc);
if (!stipple)
return FALSE;
if (!glamor_set_solid(pixmap, gc, TRUE, fg_uniform))
return FALSE;
return glamor_set_texture(pixmap,
stipple,
-gc->patOrg.x,
-gc->patOrg.y,
offset_uniform,
size_uniform);
}