/* * 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); } Bool glamor_set_stippled(PixmapPtr pixmap, GCPtr gc, GLint fg_uniform, GLint offset_uniform, GLint size_uniform) { if (!glamor_set_solid(pixmap, gc, TRUE, fg_uniform)) return FALSE; if (!glamor_set_texture(pixmap, gc->stipple, gc->patOrg.x, gc->patOrg.y, offset_uniform, size_uniform)) return FALSE; return TRUE; }