aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/glamor/glamor_render.c
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/glamor/glamor_render.c')
-rw-r--r--xorg-server/glamor/glamor_render.c2135
1 files changed, 2135 insertions, 0 deletions
diff --git a/xorg-server/glamor/glamor_render.c b/xorg-server/glamor/glamor_render.c
new file mode 100644
index 000000000..76a571f8b
--- /dev/null
+++ b/xorg-server/glamor/glamor_render.c
@@ -0,0 +1,2135 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ * Zhigang Gong <zhigang.gong@linux.intel.com>
+ * Junyan He <junyan.he@linux.intel.com>
+ *
+ */
+
+/** @file glamor_render.c
+ *
+ * Render acceleration implementation
+ */
+
+#include "glamor_priv.h"
+
+#ifdef RENDER
+#include "mipict.h"
+#include "fbpict.h"
+#if 0
+//#define DEBUGF(str, ...) do {} while(0)
+#define DEBUGF(str, ...) ErrorF(str, ##__VA_ARGS__)
+//#define DEBUGRegionPrint(x) do {} while (0)
+#define DEBUGRegionPrint RegionPrint
+#endif
+
+static struct blendinfo composite_op_info[] = {
+ [PictOpClear] = {0, 0, GL_ZERO, GL_ZERO},
+ [PictOpSrc] = {0, 0, GL_ONE, GL_ZERO},
+ [PictOpDst] = {0, 0, GL_ZERO, GL_ONE},
+ [PictOpOver] = {0, 1, GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
+ [PictOpOverReverse] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ONE},
+ [PictOpIn] = {1, 0, GL_DST_ALPHA, GL_ZERO},
+ [PictOpInReverse] = {0, 1, GL_ZERO, GL_SRC_ALPHA},
+ [PictOpOut] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ZERO},
+ [PictOpOutReverse] = {0, 1, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA},
+ [PictOpAtop] = {1, 1, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
+ [PictOpAtopReverse] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA},
+ [PictOpXor] =
+ {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
+ [PictOpAdd] = {0, 0, GL_ONE, GL_ONE},
+};
+#define RepeatFix 10
+static GLuint
+glamor_create_composite_fs(glamor_gl_dispatch * dispatch,
+ struct shader_key *key)
+{
+ const char *repeat_define =
+ "#define RepeatNone 0\n"
+ "#define RepeatNormal 1\n"
+ "#define RepeatPad 2\n"
+ "#define RepeatReflect 3\n"
+ "#define RepeatFix 10\n"
+ "uniform int source_repeat_mode;\n"
+ "uniform int mask_repeat_mode;\n";
+ const char *relocate_texture =
+ GLAMOR_DEFAULT_PRECISION
+ "vec2 rel_tex_coord(vec2 texture, vec4 wh, int repeat) \n"
+ "{\n"
+ " vec2 rel_tex; \n"
+ " rel_tex = texture * wh.xy; \n"
+ " if (repeat == RepeatNone)\n"
+ " return rel_tex; \n"
+ " else if (repeat == RepeatNormal) \n"
+ " rel_tex = floor(rel_tex) + (fract(rel_tex) / wh.xy); \n"
+ " else if(repeat == RepeatPad) { \n"
+ " if (rel_tex.x >= 1.0) rel_tex.x = 1.0 - wh.z * wh.x / 2.; \n"
+ " else if(rel_tex.x < 0.0) rel_tex.x = 0.0; \n"
+ " if (rel_tex.y >= 1.0) rel_tex.y = 1.0 - wh.w * wh.y / 2.; \n"
+ " else if(rel_tex.y < 0.0) rel_tex.y = 0.0; \n"
+ " rel_tex = rel_tex / wh.xy; \n"
+ " } \n"
+ " else if(repeat == RepeatReflect) {\n"
+ " if ((1.0 - mod(abs(floor(rel_tex.x)), 2.0)) < 0.001)\n"
+ " rel_tex.x = 2.0 - (1.0 - fract(rel_tex.x))/wh.x;\n"
+ " else \n"
+ " rel_tex.x = fract(rel_tex.x)/wh.x;\n"
+ " if ((1.0 - mod(abs(floor(rel_tex.y)), 2.0)) < 0.001)\n"
+ " rel_tex.y = 2.0 - (1.0 - fract(rel_tex.y))/wh.y;\n"
+ " else \n"
+ " rel_tex.y = fract(rel_tex.y)/wh.y;\n"
+ " } \n"
+ " return rel_tex; \n"
+ "}\n";
+ /* The texture and the pixmap size is not match eaxctly, so can't sample it directly.
+ * rel_sampler will recalculate the texture coords.*/
+ const char *rel_sampler =
+ " vec4 rel_sampler(sampler2D tex_image, vec2 tex, vec4 wh, int repeat, int set_alpha)\n"
+ "{\n"
+ " tex = rel_tex_coord(tex, wh, repeat - RepeatFix);\n"
+ " if (repeat == RepeatFix) {\n"
+ " if (!(tex.x >= 0.0 && tex.x < 1.0 \n"
+ " && tex.y >= 0.0 && tex.y < 1.0))\n"
+ " return vec4(0.0, 0.0, 0.0, set_alpha);\n"
+ " tex = (fract(tex) / wh.xy);\n"
+ " }\n"
+ " if (set_alpha != 1)\n"
+ " return texture2D(tex_image, tex);\n"
+ " else\n"
+ " return vec4(texture2D(tex_image, tex).rgb, 1.0);\n"
+ "}\n";
+
+ const char *source_solid_fetch =
+ GLAMOR_DEFAULT_PRECISION
+ "uniform vec4 source;\n"
+ "vec4 get_source()\n" "{\n" " return source;\n" "}\n";
+ const char *source_alpha_pixmap_fetch =
+ GLAMOR_DEFAULT_PRECISION
+ "varying vec2 source_texture;\n"
+ "uniform sampler2D source_sampler;\n"
+ "uniform vec4 source_wh;"
+ "vec4 get_source()\n"
+ "{\n"
+ " if (source_repeat_mode < RepeatFix)\n"
+ " return texture2D(source_sampler, source_texture);\n"
+ " else \n"
+ " return rel_sampler(source_sampler, source_texture,\n"
+ " source_wh, source_repeat_mode, 0);\n"
+ "}\n";
+ const char *source_pixmap_fetch =
+ GLAMOR_DEFAULT_PRECISION "varying vec2 source_texture;\n"
+ "uniform sampler2D source_sampler;\n"
+ "uniform vec4 source_wh;\n"
+ "vec4 get_source()\n"
+ "{\n"
+ " if (source_repeat_mode < RepeatFix) \n"
+ " return vec4(texture2D(source_sampler, source_texture).rgb, 1);\n"
+ " else \n"
+ " return rel_sampler(source_sampler, source_texture,\n"
+ " source_wh, source_repeat_mode, 1);\n"
+ "}\n";
+ const char *mask_solid_fetch =
+ GLAMOR_DEFAULT_PRECISION "uniform vec4 mask;\n"
+ "vec4 get_mask()\n" "{\n" " return mask;\n" "}\n";
+ const char *mask_alpha_pixmap_fetch =
+ GLAMOR_DEFAULT_PRECISION "varying vec2 mask_texture;\n"
+ "uniform sampler2D mask_sampler;\n"
+ "uniform vec4 mask_wh;\n"
+ "vec4 get_mask()\n"
+ "{\n"
+ " if (mask_repeat_mode < RepeatFix) \n"
+ " return texture2D(mask_sampler, mask_texture);\n"
+ " else \n"
+ " return rel_sampler(mask_sampler, mask_texture,\n"
+ " mask_wh, mask_repeat_mode, 0);\n"
+ "}\n";
+ const char *mask_pixmap_fetch =
+ GLAMOR_DEFAULT_PRECISION "varying vec2 mask_texture;\n"
+ "uniform sampler2D mask_sampler;\n"
+ "uniform vec4 mask_wh;\n"
+ "vec4 get_mask()\n"
+ "{\n"
+ " if (mask_repeat_mode < RepeatFix) \n"
+ " return vec4(texture2D(mask_sampler, mask_texture).rgb, 1);\n"
+ " else \n"
+ " return rel_sampler(mask_sampler, mask_texture,\n"
+ " mask_wh, mask_repeat_mode, 1);\n"
+ "}\n";
+ const char *in_source_only =
+ GLAMOR_DEFAULT_PRECISION "void main()\n" "{\n"
+ " gl_FragColor = get_source();\n" "}\n";
+ const char *in_normal =
+ GLAMOR_DEFAULT_PRECISION "void main()\n" "{\n"
+ " gl_FragColor = get_source() * get_mask().a;\n" "}\n";
+ const char *in_ca_source =
+ GLAMOR_DEFAULT_PRECISION "void main()\n" "{\n"
+ " gl_FragColor = get_source() * get_mask();\n" "}\n";
+ const char *in_ca_alpha =
+ GLAMOR_DEFAULT_PRECISION "void main()\n" "{\n"
+ " gl_FragColor = get_source().a * get_mask();\n" "}\n";
+ char *source;
+ const char *source_fetch;
+ const char *mask_fetch = "";
+ const char *in;
+ GLuint prog;
+
+ switch (key->source) {
+ case SHADER_SOURCE_SOLID:
+ source_fetch = source_solid_fetch;
+ break;
+ case SHADER_SOURCE_TEXTURE_ALPHA:
+ source_fetch = source_alpha_pixmap_fetch;
+ break;
+ case SHADER_SOURCE_TEXTURE:
+ source_fetch = source_pixmap_fetch;
+ break;
+ default:
+ FatalError("Bad composite shader source");
+ }
+
+ switch (key->mask) {
+ case SHADER_MASK_NONE:
+ break;
+ case SHADER_MASK_SOLID:
+ mask_fetch = mask_solid_fetch;
+ break;
+ case SHADER_MASK_TEXTURE_ALPHA:
+ mask_fetch = mask_alpha_pixmap_fetch;
+ break;
+ case SHADER_MASK_TEXTURE:
+ mask_fetch = mask_pixmap_fetch;
+ break;
+ default:
+ FatalError("Bad composite shader mask");
+ }
+
+ switch (key->in) {
+ case SHADER_IN_SOURCE_ONLY:
+ in = in_source_only;
+ break;
+ case SHADER_IN_NORMAL:
+ in = in_normal;
+ break;
+ case SHADER_IN_CA_SOURCE:
+ in = in_ca_source;
+ break;
+ case SHADER_IN_CA_ALPHA:
+ in = in_ca_alpha;
+ break;
+ default:
+ FatalError("Bad composite IN type");
+ }
+
+ XNFasprintf(&source, "%s%s%s%s%s%s", repeat_define, relocate_texture, rel_sampler,source_fetch, mask_fetch, in);
+
+
+ prog = glamor_compile_glsl_prog(dispatch, GL_FRAGMENT_SHADER,
+ source);
+ free(source);
+
+ return prog;
+}
+
+static GLuint
+glamor_create_composite_vs(glamor_gl_dispatch * dispatch,
+ struct shader_key *key)
+{
+ const char *main_opening =
+ "attribute vec4 v_position;\n"
+ "attribute vec4 v_texcoord0;\n"
+ "attribute vec4 v_texcoord1;\n"
+ "varying vec2 source_texture;\n"
+ "varying vec2 mask_texture;\n"
+ "void main()\n" "{\n" " gl_Position = v_position;\n";
+ const char *source_coords =
+ " source_texture = v_texcoord0.xy;\n";
+ const char *mask_coords = " mask_texture = v_texcoord1.xy;\n";
+ const char *main_closing = "}\n";
+ const char *source_coords_setup = "";
+ const char *mask_coords_setup = "";
+ char *source;
+ GLuint prog;
+
+ if (key->source != SHADER_SOURCE_SOLID)
+ source_coords_setup = source_coords;
+
+ if (key->mask != SHADER_MASK_NONE
+ && key->mask != SHADER_MASK_SOLID)
+ mask_coords_setup = mask_coords;
+
+ XNFasprintf(&source,
+ "%s%s%s%s",
+ main_opening,
+ source_coords_setup, mask_coords_setup, main_closing);
+
+ prog =
+ glamor_compile_glsl_prog(dispatch, GL_VERTEX_SHADER, source);
+ free(source);
+
+ return prog;
+}
+
+static void
+glamor_create_composite_shader(ScreenPtr screen, struct shader_key *key,
+ glamor_composite_shader * shader)
+{
+ GLuint vs, fs, prog;
+ GLint source_sampler_uniform_location,
+ mask_sampler_uniform_location;
+ glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
+ glamor_gl_dispatch *dispatch;
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+ vs = glamor_create_composite_vs(dispatch, key);
+ if (vs == 0)
+ goto out;
+ fs = glamor_create_composite_fs(dispatch, key);
+ if (fs == 0)
+ goto out;
+
+ prog = dispatch->glCreateProgram();
+ dispatch->glAttachShader(prog, vs);
+ dispatch->glAttachShader(prog, fs);
+
+ dispatch->glBindAttribLocation(prog, GLAMOR_VERTEX_POS,
+ "v_position");
+ dispatch->glBindAttribLocation(prog, GLAMOR_VERTEX_SOURCE,
+ "v_texcoord0");
+ dispatch->glBindAttribLocation(prog, GLAMOR_VERTEX_MASK,
+ "v_texcoord1");
+
+ glamor_link_glsl_prog(dispatch, prog);
+
+ shader->prog = prog;
+
+ dispatch->glUseProgram(prog);
+
+ if (key->source == SHADER_SOURCE_SOLID) {
+ shader->source_uniform_location =
+ dispatch->glGetUniformLocation(prog, "source");
+ } else {
+ source_sampler_uniform_location =
+ dispatch->glGetUniformLocation(prog, "source_sampler");
+ dispatch->glUniform1i(source_sampler_uniform_location, 0);
+ shader->source_wh = dispatch->glGetUniformLocation(prog, "source_wh");
+ shader->source_repeat_mode = dispatch->glGetUniformLocation(prog, "source_repeat_mode");
+ }
+
+ if (key->mask != SHADER_MASK_NONE) {
+ if (key->mask == SHADER_MASK_SOLID) {
+ shader->mask_uniform_location =
+ dispatch->glGetUniformLocation(prog, "mask");
+ } else {
+ mask_sampler_uniform_location =
+ dispatch->glGetUniformLocation(prog,
+ "mask_sampler");
+ dispatch->glUniform1i
+ (mask_sampler_uniform_location, 1);
+ shader->mask_wh = dispatch->glGetUniformLocation(prog, "mask_wh");
+ shader->mask_repeat_mode = dispatch->glGetUniformLocation(prog, "mask_repeat_mode");
+ }
+ }
+
+out:
+ glamor_put_dispatch(glamor_priv);
+}
+
+static glamor_composite_shader *
+glamor_lookup_composite_shader(ScreenPtr screen, struct
+ shader_key
+ *key)
+{
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ glamor_composite_shader *shader;
+
+ shader =
+ &glamor_priv->composite_shader[key->source][key->
+ mask][key->in];
+ if (shader->prog == 0)
+ glamor_create_composite_shader(screen, key, shader);
+
+ return shader;
+}
+
+static void
+glamor_init_eb(unsigned short *eb, int vert_cnt)
+{
+ int i, j;
+ for(i = 0, j = 0; j < vert_cnt; i += 6, j += 4)
+ {
+ eb[i] = j;
+ eb[i + 1] = j + 1;
+ eb[i + 2] = j + 2;
+ eb[i + 3] = j;
+ eb[i + 4] = j + 2;
+ eb[i + 5] = j + 3;
+ }
+}
+
+void
+glamor_init_composite_shaders(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv;
+ glamor_gl_dispatch *dispatch;
+ unsigned short *eb;
+ float *vb = NULL;
+ int eb_size;
+
+ glamor_priv = glamor_get_screen_private(screen);
+ dispatch = glamor_get_dispatch(glamor_priv);
+ dispatch->glGenBuffers(1, &glamor_priv->vbo);
+ dispatch->glGenBuffers(1, &glamor_priv->ebo);
+ dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glamor_priv->ebo);
+
+ eb_size = GLAMOR_COMPOSITE_VBO_VERT_CNT * sizeof(short) * 2;
+
+ if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
+ dispatch->glBufferData(GL_ELEMENT_ARRAY_BUFFER,
+ eb_size,
+ NULL, GL_STATIC_DRAW);
+ eb = dispatch->glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
+ }
+ else {
+ vb = malloc(GLAMOR_COMPOSITE_VBO_VERT_CNT * sizeof(float) * 2);
+ if (vb == NULL)
+ FatalError("Failed to allocate vb memory.\n");
+ eb = malloc(eb_size);
+ }
+
+ if (eb == NULL)
+ FatalError("fatal error, fail to get element buffer. GL context may be not created correctly.\n");
+ glamor_init_eb(eb, GLAMOR_COMPOSITE_VBO_VERT_CNT);
+
+ if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
+ dispatch->glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+ dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ } else {
+ dispatch->glBufferData(GL_ELEMENT_ARRAY_BUFFER,
+ eb_size,
+ eb, GL_STATIC_DRAW);
+ dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ dispatch->glBindBuffer(GL_ARRAY_BUFFER, glamor_priv->vbo);
+ dispatch->glBufferData(GL_ARRAY_BUFFER,
+ GLAMOR_COMPOSITE_VBO_VERT_CNT * sizeof(float) * 2,
+ NULL, GL_DYNAMIC_DRAW);
+ dispatch->glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ free(eb);
+ glamor_priv->vb = (char*)vb;
+ }
+
+ glamor_put_dispatch(glamor_priv);
+}
+
+void
+glamor_fini_composite_shaders(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv;
+ glamor_gl_dispatch *dispatch;
+ glamor_composite_shader *shader;
+ int i,j,k;
+
+ glamor_priv = glamor_get_screen_private(screen);
+ dispatch = glamor_get_dispatch(glamor_priv);
+ dispatch->glDeleteBuffers(1, &glamor_priv->vbo);
+ dispatch->glDeleteBuffers(1, &glamor_priv->ebo);
+
+ for(i = 0; i < SHADER_SOURCE_COUNT; i++)
+ for(j = 0; j < SHADER_MASK_COUNT; j++)
+ for(k = 0; k < SHADER_IN_COUNT; k++)
+ {
+ shader = &glamor_priv->composite_shader[i][j][k];
+ if (shader->prog)
+ dispatch->glDeleteProgram(shader->prog);
+ }
+ if (glamor_priv->gl_flavor != GLAMOR_GL_DESKTOP
+ && glamor_priv->vb)
+ free(glamor_priv->vb);
+
+ glamor_put_dispatch(glamor_priv);
+}
+
+static Bool
+glamor_set_composite_op(ScreenPtr screen,
+ CARD8 op, struct blendinfo *op_info_result,
+ PicturePtr dest, PicturePtr mask)
+{
+ GLenum source_blend, dest_blend;
+ struct blendinfo *op_info;
+
+ if (op >= ARRAY_SIZE(composite_op_info)) {
+ glamor_fallback("unsupported render op %d \n", op);
+ return GL_FALSE;
+ }
+ op_info = &composite_op_info[op];
+
+ source_blend = op_info->source_blend;
+ dest_blend = op_info->dest_blend;
+
+ /* If there's no dst alpha channel, adjust the blend op so that we'll treat
+ * it as always 1.
+ */
+ if (PICT_FORMAT_A(dest->format) == 0 && op_info->dest_alpha) {
+ if (source_blend == GL_DST_ALPHA)
+ source_blend = GL_ONE;
+ else if (source_blend == GL_ONE_MINUS_DST_ALPHA)
+ source_blend = GL_ZERO;
+ }
+
+ /* Set up the source alpha value for blending in component alpha mode. */
+ if (mask && mask->componentAlpha
+ && PICT_FORMAT_RGB(mask->format) != 0 && op_info->source_alpha)
+ {
+ if (dest_blend == GL_SRC_ALPHA)
+ dest_blend = GL_SRC_COLOR;
+ else if (dest_blend == GL_ONE_MINUS_SRC_ALPHA)
+ dest_blend = GL_ONE_MINUS_SRC_COLOR;
+ }
+
+ op_info_result->source_blend = source_blend;
+ op_info_result->dest_blend = dest_blend;
+ op_info_result->source_alpha = op_info->source_alpha;
+ op_info_result->dest_alpha = op_info->dest_alpha;
+
+ return TRUE;
+}
+
+static void
+glamor_set_composite_texture(glamor_screen_private *glamor_priv, int unit,
+ PicturePtr picture,
+ glamor_pixmap_private * pixmap_priv,
+ GLuint wh_location, GLuint repeat_location)
+{
+ glamor_gl_dispatch *dispatch;
+ float wh[4];
+ int repeat_type;
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+ dispatch->glActiveTexture(GL_TEXTURE0 + unit);
+ dispatch->glBindTexture(GL_TEXTURE_2D, pixmap_priv->base.fbo->tex);
+ repeat_type = picture->repeatType;
+ switch (picture->repeatType) {
+ case RepeatNone:
+#ifndef GLAMOR_GLES2
+ /* XXX GLES2 doesn't support GL_CLAMP_TO_BORDER. */
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
+ GL_CLAMP_TO_BORDER);
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
+ GL_CLAMP_TO_BORDER);
+#else
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
+ GL_CLAMP_TO_EDGE);
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
+ GL_CLAMP_TO_EDGE);
+#endif
+ break;
+ case RepeatNormal:
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
+ GL_REPEAT);
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
+ GL_REPEAT);
+ break;
+ case RepeatPad:
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
+ GL_CLAMP_TO_EDGE);
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
+ GL_CLAMP_TO_EDGE);
+ break;
+ case RepeatReflect:
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
+ GL_MIRRORED_REPEAT);
+ dispatch->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
+ GL_MIRRORED_REPEAT);
+ break;
+ }
+
+ switch (picture->filter) {
+ default:
+ case PictFilterFast:
+ case PictFilterNearest:
+ dispatch->glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ dispatch->glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST);
+ break;
+ case PictFilterGood:
+ case PictFilterBest:
+ case PictFilterBilinear:
+ dispatch->glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MIN_FILTER,
+ GL_LINEAR);
+ dispatch->glTexParameteri(GL_TEXTURE_2D,
+ GL_TEXTURE_MAG_FILTER,
+ GL_LINEAR);
+ break;
+ }
+#ifndef GLAMOR_GLES2
+ dispatch->glEnable(GL_TEXTURE_2D);
+#endif
+
+ /*
+ * GLES2 doesn't support RepeatNone. We need to fix it anyway.
+ *
+ **/
+ if (repeat_type != RepeatNone)
+ repeat_type += RepeatFix;
+ else if (glamor_priv->gl_flavor == GLAMOR_GL_ES2
+ || pixmap_priv->type == GLAMOR_TEXTURE_LARGE) {
+ if (picture->transform
+ || (GLAMOR_PIXMAP_FBO_NOT_EAXCT_SIZE(pixmap_priv)))
+ repeat_type += RepeatFix;
+ }
+ if (repeat_type >= RepeatFix) {
+ glamor_pixmap_fbo_fix_wh_ratio(wh, pixmap_priv);
+ if ((wh[0] != 1.0 || wh[1] != 1.0 )
+ || (glamor_priv->gl_flavor == GLAMOR_GL_ES2
+ && repeat_type == RepeatFix))
+ dispatch->glUniform4fv(wh_location, 1, wh);
+ else
+ repeat_type -= RepeatFix;
+ }
+ dispatch->glUniform1i(repeat_location, repeat_type);
+ glamor_put_dispatch(glamor_priv);
+}
+
+static void
+glamor_set_composite_solid(glamor_gl_dispatch * dispatch, float *color,
+ GLint uniform_location)
+{
+ dispatch->glUniform4fv(uniform_location, 1, color);
+}
+
+static int
+compatible_formats(CARD8 op, PicturePtr dst, PicturePtr src)
+{
+ if (op == PictOpSrc) {
+ if (src->format == dst->format)
+ return 1;
+
+ if (src->format == PICT_a8r8g8b8
+ && dst->format == PICT_x8r8g8b8)
+ return 1;
+
+ if (src->format == PICT_a8b8g8r8
+ && dst->format == PICT_x8b8g8r8)
+ return 1;
+ } else if (op == PictOpOver) {
+ if (src->alphaMap || dst->alphaMap)
+ return 0;
+
+ if (src->format != dst->format)
+ return 0;
+
+ if (src->format == PICT_x8r8g8b8
+ || src->format == PICT_x8b8g8r8)
+ return 1;
+ }
+
+ return 0;
+}
+
+static char
+glamor_get_picture_location(PicturePtr picture)
+{
+ if (picture == NULL)
+ return ' ';
+
+ if (picture->pDrawable == NULL) {
+ switch (picture->pSourcePict->type) {
+ case SourcePictTypeSolidFill:
+ return 'c';
+ case SourcePictTypeLinear:
+ return 'l';
+ case SourcePictTypeRadial:
+ return 'r';
+ default:
+ return '?';
+ }
+ }
+ return glamor_get_drawable_location(picture->pDrawable);
+}
+
+static Bool
+glamor_composite_with_copy(CARD8 op,
+ PicturePtr source,
+ PicturePtr dest,
+ INT16 x_source,
+ INT16 y_source,
+ INT16 x_dest,
+ INT16 y_dest,
+ RegionPtr region)
+{
+ int ret = FALSE;
+ if (!source->pDrawable)
+ return FALSE;
+
+ if (!compatible_formats(op, dest, source))
+ return FALSE;
+
+ if (source->repeat || source->transform) {
+ return FALSE;
+ }
+
+ x_dest += dest->pDrawable->x;
+ y_dest += dest->pDrawable->y;
+ x_source += source->pDrawable->x;
+ y_source += source->pDrawable->y;
+ if (PICT_FORMAT_A(source->format) == 0) {
+ /* Fallback if we sample outside the source so that we
+ * swizzle the correct clear color for out-of-bounds texels.
+ */
+ if (region->extents.x1 + x_source - x_dest < 0)
+ goto cleanup_region;
+ if (region->extents.x2 + x_source - x_dest > source->pDrawable->width)
+ goto cleanup_region;
+
+ if (region->extents.y1 + y_source - y_dest < 0)
+ goto cleanup_region;
+ if (region->extents.y2 + y_source - y_dest > source->pDrawable->height)
+ goto cleanup_region;
+ }
+ ret = glamor_copy_n_to_n_nf(source->pDrawable,
+ dest->pDrawable, NULL,
+ RegionRects(region), RegionNumRects(region),
+ x_source - x_dest, y_source - y_dest,
+ FALSE, FALSE, 0, NULL);
+cleanup_region:
+ return ret;
+}
+
+void
+glamor_setup_composite_vbo(ScreenPtr screen, int n_verts)
+{
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ glamor_gl_dispatch *dispatch;
+ int vert_size;
+
+ glamor_priv->render_nr_verts = 0;
+ glamor_priv->vb_stride = 2 * sizeof(float);
+ if (glamor_priv->has_source_coords)
+ glamor_priv->vb_stride += 2 * sizeof(float);
+ if (glamor_priv->has_mask_coords)
+ glamor_priv->vb_stride += 2 * sizeof(float);
+
+ vert_size = n_verts * glamor_priv->vb_stride;
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+ dispatch->glBindBuffer(GL_ARRAY_BUFFER, glamor_priv->vbo);
+ if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
+ if (glamor_priv->vbo_size < (glamor_priv->vbo_offset + vert_size)) {
+ glamor_priv->vbo_size = GLAMOR_COMPOSITE_VBO_VERT_CNT *
+ glamor_priv->vb_stride;
+ glamor_priv->vbo_offset = 0;
+ dispatch->glBufferData(GL_ARRAY_BUFFER,
+ glamor_priv->vbo_size,
+ NULL, GL_STREAM_DRAW);
+ }
+
+ glamor_priv->vb = dispatch->glMapBufferRange(GL_ARRAY_BUFFER,
+ glamor_priv->vbo_offset,
+ vert_size,
+ GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
+ assert(glamor_priv->vb != NULL);
+ glamor_priv->vb -= glamor_priv->vbo_offset;
+ } else
+ glamor_priv->vbo_offset = 0;
+
+ dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glamor_priv->ebo);
+
+ dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT,
+ GL_FALSE, glamor_priv->vb_stride,
+ (void *) ((long)
+ glamor_priv->vbo_offset));
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
+
+ if (glamor_priv->has_source_coords) {
+ dispatch->glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2,
+ GL_FLOAT, GL_FALSE,
+ glamor_priv->vb_stride,
+ (void *) ((long)
+ glamor_priv->vbo_offset
+ +
+ 2 *
+ sizeof(float)));
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+ }
+
+ if (glamor_priv->has_mask_coords) {
+ dispatch->glVertexAttribPointer(GLAMOR_VERTEX_MASK, 2,
+ GL_FLOAT, GL_FALSE,
+ glamor_priv->vb_stride,
+ (void *) ((long)
+ glamor_priv->vbo_offset
+ +
+ (glamor_priv->has_source_coords
+ ? 4 : 2) *
+ sizeof(float)));
+ dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_MASK);
+ }
+ glamor_put_dispatch(glamor_priv);
+}
+
+void
+glamor_emit_composite_vert(ScreenPtr screen,
+ const float *src_coords,
+ const float *mask_coords,
+ const float *dst_coords, int i)
+{
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ float *vb = (float *) (glamor_priv->vb + glamor_priv->vbo_offset);
+ int j = 0;
+
+ vb[j++] = dst_coords[i * 2 + 0];
+ vb[j++] = dst_coords[i * 2 + 1];
+ if (glamor_priv->has_source_coords) {
+ vb[j++] = src_coords[i * 2 + 0];
+ vb[j++] = src_coords[i * 2 + 1];
+ }
+ if (glamor_priv->has_mask_coords) {
+ vb[j++] = mask_coords[i * 2 + 0];
+ vb[j++] = mask_coords[i * 2 + 1];
+ }
+
+ glamor_priv->render_nr_verts++;
+ glamor_priv->vbo_offset += glamor_priv->vb_stride;
+}
+
+
+
+static void
+glamor_flush_composite_rects(ScreenPtr screen)
+{
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ glamor_gl_dispatch *dispatch;
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+ if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
+ dispatch->glUnmapBuffer(GL_ARRAY_BUFFER);
+ else {
+
+ dispatch->glBindBuffer(GL_ARRAY_BUFFER, glamor_priv->vbo);
+ dispatch->glBufferData(GL_ARRAY_BUFFER,
+ glamor_priv->vbo_offset,
+ glamor_priv->vb, GL_DYNAMIC_DRAW);
+ }
+
+ if (!glamor_priv->render_nr_verts)
+ return;
+
+#ifndef GLAMOR_GLES2
+ dispatch->glDrawRangeElements(GL_TRIANGLES, 0, glamor_priv->render_nr_verts,
+ (glamor_priv->render_nr_verts * 3) / 2,
+ GL_UNSIGNED_SHORT, NULL);
+#else
+ dispatch->glDrawElements(GL_TRIANGLES, (glamor_priv->render_nr_verts * 3) / 2,
+ GL_UNSIGNED_SHORT, NULL);
+#endif
+ glamor_put_dispatch(glamor_priv);
+}
+
+int pict_format_combine_tab[][3] = {
+ {PICT_TYPE_ARGB, PICT_TYPE_A, PICT_TYPE_ARGB},
+ {PICT_TYPE_ABGR, PICT_TYPE_A, PICT_TYPE_ABGR},
+};
+
+static Bool
+combine_pict_format(PictFormatShort * des, const PictFormatShort src,
+ const PictFormatShort mask, enum shader_in in_ca)
+{
+ PictFormatShort new_vis;
+ int src_type, mask_type, src_bpp, mask_bpp;
+ int i;
+ if (src == mask) {
+ *des = src;
+ return TRUE;
+ }
+ src_bpp = PICT_FORMAT_BPP(src);
+ mask_bpp = PICT_FORMAT_BPP(mask);
+
+ assert(src_bpp == mask_bpp);
+
+ new_vis = PICT_FORMAT_VIS(src) | PICT_FORMAT_VIS(mask);
+
+ switch (in_ca) {
+ case SHADER_IN_SOURCE_ONLY:
+ return TRUE;
+ case SHADER_IN_NORMAL:
+ src_type = PICT_FORMAT_TYPE(src);
+ mask_type = PICT_TYPE_A;
+ break;
+ case SHADER_IN_CA_SOURCE:
+ src_type = PICT_FORMAT_TYPE(src);
+ mask_type = PICT_FORMAT_TYPE(mask);
+ break;
+ case SHADER_IN_CA_ALPHA:
+ src_type = PICT_TYPE_A;
+ mask_type = PICT_FORMAT_TYPE(mask);
+ break;
+ default:
+ return FALSE;
+ }
+
+ if (src_type == mask_type) {
+ *des = PICT_VISFORMAT(src_bpp, src_type, new_vis);
+ return TRUE;
+ }
+
+ for (i = 0;
+ i <
+ sizeof(pict_format_combine_tab) /
+ sizeof(pict_format_combine_tab[0]); i++) {
+ if ((src_type == pict_format_combine_tab[i][0]
+ && mask_type == pict_format_combine_tab[i][1])
+ || (src_type == pict_format_combine_tab[i][1]
+ && mask_type == pict_format_combine_tab[i][0])) {
+ *des = PICT_VISFORMAT(src_bpp,
+ pict_format_combine_tab[i]
+ [2], new_vis);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static void
+glamor_set_normalize_tcoords_generic(glamor_pixmap_private *priv,
+ int repeat_type,
+ float *matrix,
+ float xscale, float yscale,
+ int x1, int y1, int x2, int y2,
+ int yInverted, float *texcoords,
+ int stride)
+{
+ if (!matrix && repeat_type == RepeatNone)
+ glamor_set_normalize_tcoords_ext(priv, xscale, yscale,
+ x1, y1,
+ x2, y2,
+ yInverted,
+ texcoords, stride);
+ else if (matrix && repeat_type == RepeatNone)
+ glamor_set_transformed_normalize_tcoords_ext(priv, matrix, xscale,
+ yscale, x1, y1,
+ x2, y2,
+ yInverted,
+ texcoords, stride);
+ else if (!matrix && repeat_type != RepeatNone)
+ glamor_set_repeat_normalize_tcoords_ext(priv, repeat_type,
+ xscale, yscale,
+ x1, y1,
+ x2, y2,
+ yInverted,
+ texcoords, stride);
+ else if (matrix && repeat_type != RepeatNone)
+ glamor_set_repeat_transformed_normalize_tcoords_ext(priv, repeat_type,
+ matrix, xscale, yscale,
+ x1, y1,
+ x2, y2,
+ yInverted,
+ texcoords, stride);
+}
+
+Bool glamor_composite_choose_shader(CARD8 op,
+ PicturePtr source,
+ PicturePtr mask,
+ PicturePtr dest,
+ glamor_pixmap_private *source_pixmap_priv,
+ glamor_pixmap_private *mask_pixmap_priv,
+ glamor_pixmap_private *dest_pixmap_priv,
+ struct shader_key *s_key,
+ glamor_composite_shader **shader,
+ struct blendinfo *op_info,
+ PictFormatShort *psaved_source_format)
+{
+ ScreenPtr screen = dest->pDrawable->pScreen;
+ PixmapPtr dest_pixmap = dest_pixmap_priv->base.pixmap;
+ PixmapPtr source_pixmap = NULL;
+ PixmapPtr mask_pixmap = NULL;
+ enum glamor_pixmap_status source_status = GLAMOR_NONE;
+ enum glamor_pixmap_status mask_status = GLAMOR_NONE;
+ PictFormatShort saved_source_format = 0;
+ struct shader_key key;
+ GLfloat source_solid_color[4];
+ GLfloat mask_solid_color[4];
+ Bool ret = FALSE;
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dest_pixmap_priv)) {
+ glamor_fallback("dest has no fbo.\n");
+ goto fail;
+ }
+
+ memset(&key, 0, sizeof(key));
+ if (!source) {
+ key.source = SHADER_SOURCE_SOLID;
+ source_solid_color[0] = 0.0;
+ source_solid_color[1] = 0.0;
+ source_solid_color[2] = 0.0;
+ source_solid_color[3] = 0.0;
+ } else if (!source->pDrawable) {
+ if (source->pSourcePict->type == SourcePictTypeSolidFill) {
+ key.source = SHADER_SOURCE_SOLID;
+ glamor_get_rgba_from_pixel(source->
+ pSourcePict->solidFill.
+ color,
+ &source_solid_color[0],
+ &source_solid_color[1],
+ &source_solid_color[2],
+ &source_solid_color[3],
+ PICT_a8r8g8b8);
+ } else
+ goto fail;
+ } else {
+ key.source = SHADER_SOURCE_TEXTURE_ALPHA;
+ }
+
+ if (mask) {
+ if (!mask->pDrawable) {
+ if (mask->pSourcePict->type ==
+ SourcePictTypeSolidFill) {
+ key.mask = SHADER_MASK_SOLID;
+ glamor_get_rgba_from_pixel
+ (mask->pSourcePict->solidFill.color,
+ &mask_solid_color[0],
+ &mask_solid_color[1],
+ &mask_solid_color[2],
+ &mask_solid_color[3], PICT_a8r8g8b8);
+ } else
+ goto fail;
+ } else {
+ key.mask = SHADER_MASK_TEXTURE_ALPHA;
+ }
+
+ if (!mask->componentAlpha) {
+ key.in = SHADER_IN_NORMAL;
+ } else {
+ if (op == PictOpClear)
+ key.mask = SHADER_MASK_NONE;
+ else if (op == PictOpSrc || op == PictOpAdd
+ || op == PictOpIn || op == PictOpOut
+ || op == PictOpOverReverse)
+ key.in = SHADER_IN_CA_SOURCE;
+ else if (op == PictOpOutReverse || op == PictOpInReverse) {
+ key.in = SHADER_IN_CA_ALPHA;
+ } else {
+ glamor_fallback("Unsupported component alpha op: %d\n", op);
+ goto fail;
+ }
+ }
+ } else {
+ key.mask = SHADER_MASK_NONE;
+ key.in = SHADER_IN_SOURCE_ONLY;
+ }
+
+ if (source && source->alphaMap) {
+ glamor_fallback("source alphaMap\n");
+ goto fail;
+ }
+ if (mask && mask->alphaMap) {
+ glamor_fallback("mask alphaMap\n");
+ goto fail;
+ }
+
+ if (key.source == SHADER_SOURCE_TEXTURE ||
+ key.source == SHADER_SOURCE_TEXTURE_ALPHA) {
+ source_pixmap = source_pixmap_priv->base.pixmap;
+ if (source_pixmap == dest_pixmap) {
+ /* XXX source and the dest share the same texture.
+ * Does it need special handle? */
+ glamor_fallback("source == dest\n");
+ }
+ if (source_pixmap_priv->base.gl_fbo == 0) {
+ /* XXX in Xephyr, we may have gl_fbo equal to 1 but gl_tex
+ * equal to zero when the pixmap is screen pixmap. Then we may
+ * refer the tex zero directly latter in the composition.
+ * It seems that it works fine, but it may have potential problem*/
+#ifdef GLAMOR_PIXMAP_DYNAMIC_UPLOAD
+ source_status = GLAMOR_UPLOAD_PENDING;
+#else
+ glamor_fallback("no texture in source\n");
+ goto fail;
+#endif
+ }
+ }
+
+ if (key.mask == SHADER_MASK_TEXTURE ||
+ key.mask == SHADER_MASK_TEXTURE_ALPHA) {
+ mask_pixmap = mask_pixmap_priv->base.pixmap;
+ if (mask_pixmap == dest_pixmap) {
+ glamor_fallback("mask == dest\n");
+ goto fail;
+ }
+ if (mask_pixmap_priv->base.gl_fbo == 0) {
+#ifdef GLAMOR_PIXMAP_DYNAMIC_UPLOAD
+ mask_status = GLAMOR_UPLOAD_PENDING;
+#else
+ glamor_fallback("no texture in mask\n");
+ goto fail;
+#endif
+ }
+ }
+
+#ifdef GLAMOR_PIXMAP_DYNAMIC_UPLOAD
+ if (source_status == GLAMOR_UPLOAD_PENDING
+ && mask_status == GLAMOR_UPLOAD_PENDING
+ && source_pixmap == mask_pixmap) {
+
+ if (source->format != mask->format) {
+ saved_source_format = source->format;
+
+ if (!combine_pict_format(&source->format, source->format,
+ mask->format, key.in)) {
+ glamor_fallback("combine source %x mask %x failed.\n",
+ source->format, mask->format);
+ goto fail;
+ }
+
+ if (source->format != saved_source_format) {
+ glamor_picture_format_fixup(source,
+ source_pixmap_priv);
+ }
+ /* XXX
+ * By default, glamor_upload_picture_to_texture will wire alpha to 1
+ * if one picture doesn't have alpha. So we don't do that again in
+ * rendering function. But here is a special case, as source and
+ * mask share the same texture but may have different formats. For
+ * example, source doesn't have alpha, but mask has alpha. Then the
+ * texture will have the alpha value for the mask. And will not wire
+ * to 1 for the source. In this case, we have to use different shader
+ * to wire the source's alpha to 1.
+ *
+ * But this may cause a potential problem if the source's repeat mode
+ * is REPEAT_NONE, and if the source is smaller than the dest, then
+ * for the region not covered by the source may be painted incorrectly.
+ * because we wire the alpha to 1.
+ *
+ **/
+ if (!PICT_FORMAT_A(saved_source_format)
+ && PICT_FORMAT_A(mask->format))
+ key.source = SHADER_SOURCE_TEXTURE;
+
+ if (!PICT_FORMAT_A(mask->format)
+ && PICT_FORMAT_A(saved_source_format))
+ key.mask = SHADER_MASK_TEXTURE;
+
+ mask_status = GLAMOR_NONE;
+ }
+
+ source_status = glamor_upload_picture_to_texture(source);
+ if (source_status != GLAMOR_UPLOAD_DONE) {
+ glamor_fallback("Failed to upload source texture.\n");
+ goto fail;
+ }
+ } else {
+ if (source_status == GLAMOR_UPLOAD_PENDING) {
+ source_status = glamor_upload_picture_to_texture(source);
+ if (source_status != GLAMOR_UPLOAD_DONE) {
+ glamor_fallback("Failed to upload source texture.\n");
+ goto fail;
+ }
+ }
+
+ if (mask_status == GLAMOR_UPLOAD_PENDING) {
+ mask_status = glamor_upload_picture_to_texture(mask);
+ if (mask_status != GLAMOR_UPLOAD_DONE) {
+ glamor_fallback("Failed to upload mask texture.\n");
+ goto fail;
+ }
+ }
+ }
+#endif
+
+ /*Before enter the rendering stage, we need to fixup
+ * transformed source and mask, if the transform is not int translate. */
+ if (key.source != SHADER_SOURCE_SOLID
+ && source->transform
+ && !pixman_transform_is_int_translate(source->transform)
+ && source_pixmap_priv->type != GLAMOR_TEXTURE_LARGE) {
+ if (!glamor_fixup_pixmap_priv(screen, source_pixmap_priv))
+ goto fail;
+ }
+ if (key.mask != SHADER_MASK_NONE && key.mask != SHADER_MASK_SOLID
+ && mask->transform
+ && !pixman_transform_is_int_translate(mask->transform)
+ && mask_pixmap_priv->type != GLAMOR_TEXTURE_LARGE) {
+ if (!glamor_fixup_pixmap_priv(screen, mask_pixmap_priv))
+ goto fail;
+ }
+
+
+ if (!glamor_set_composite_op(screen, op, op_info, dest, mask))
+ goto fail;
+
+ *shader = glamor_lookup_composite_shader(screen, &key);
+ if ((*shader)->prog == 0) {
+ glamor_fallback("no shader program for this"
+ "render acccel mode\n");
+ goto fail;
+ }
+
+ if (key.source == SHADER_SOURCE_SOLID)
+ memcpy(&(*shader)->source_solid_color[0],
+ source_solid_color, 4*sizeof(float));
+ else {
+ (*shader)->source_priv = source_pixmap_priv;
+ (*shader)->source = source;
+ }
+
+ if (key.mask == SHADER_MASK_SOLID)
+ memcpy(&(*shader)->mask_solid_color[0],
+ mask_solid_color, 4*sizeof(float));
+ else {
+ (*shader)->mask_priv = mask_pixmap_priv;
+ (*shader)->mask = mask;
+ }
+
+ ret = TRUE;
+ memcpy(s_key, &key, sizeof(key));
+ *psaved_source_format = saved_source_format;
+ goto done;
+
+fail:
+ if (saved_source_format)
+ source->format = saved_source_format;
+done:
+ return ret;
+}
+
+void
+glamor_composite_set_shader_blend(glamor_pixmap_private *dest_priv,
+ struct shader_key *key,
+ glamor_composite_shader *shader,
+ struct blendinfo *op_info)
+{
+ glamor_gl_dispatch *dispatch;
+ glamor_screen_private *glamor_priv;
+
+ glamor_priv = dest_priv->base.glamor_priv;
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+ dispatch->glUseProgram(shader->prog);
+
+ if (key->source == SHADER_SOURCE_SOLID) {
+ glamor_set_composite_solid(dispatch,
+ shader->source_solid_color,
+ shader->source_uniform_location);
+ } else {
+ glamor_set_composite_texture(glamor_priv, 0,
+ shader->source,
+ shader->source_priv, shader->source_wh,
+ shader->source_repeat_mode);
+ }
+
+ if (key->mask != SHADER_MASK_NONE) {
+ if (key->mask == SHADER_MASK_SOLID) {
+ glamor_set_composite_solid(dispatch,
+ shader->mask_solid_color,
+ shader->mask_uniform_location);
+ } else {
+ glamor_set_composite_texture(glamor_priv, 1,
+ shader->mask,
+ shader->mask_priv, shader->mask_wh,
+ shader->mask_repeat_mode);
+ }
+ }
+
+ if (op_info->source_blend == GL_ONE
+ && op_info->dest_blend == GL_ZERO) {
+ dispatch->glDisable(GL_BLEND);
+ } else {
+ dispatch->glEnable(GL_BLEND);
+ dispatch->glBlendFunc(op_info->source_blend,
+ op_info->dest_blend);
+ }
+
+ glamor_put_dispatch(glamor_priv);
+}
+
+static Bool
+glamor_composite_with_shader(CARD8 op,
+ PicturePtr source,
+ PicturePtr mask,
+ PicturePtr dest,
+ glamor_pixmap_private *source_pixmap_priv,
+ glamor_pixmap_private *mask_pixmap_priv,
+ glamor_pixmap_private *dest_pixmap_priv,
+ int nrect, glamor_composite_rect_t * rects,
+ Bool two_pass_ca)
+{
+ ScreenPtr screen = dest->pDrawable->pScreen;
+ glamor_screen_private *glamor_priv = dest_pixmap_priv->base.glamor_priv;
+ PixmapPtr dest_pixmap = dest_pixmap_priv->base.pixmap;
+ PixmapPtr source_pixmap = NULL;
+ PixmapPtr mask_pixmap = NULL;
+ glamor_gl_dispatch *dispatch = NULL;
+ GLfloat dst_xscale, dst_yscale;
+ GLfloat mask_xscale = 1, mask_yscale = 1,
+ src_xscale = 1, src_yscale = 1;
+ struct shader_key key, key_ca;
+ float *vertices;
+ int dest_x_off, dest_y_off;
+ int source_x_off, source_y_off;
+ int mask_x_off, mask_y_off;
+ PictFormatShort saved_source_format = 0;
+ float src_matrix[9], mask_matrix[9];
+ float *psrc_matrix = NULL, *pmask_matrix = NULL;
+ int vert_stride = 4;
+ int nrect_max;
+ Bool ret = FALSE;
+ glamor_composite_shader *shader = NULL, *shader_ca = NULL;
+ struct blendinfo op_info, op_info_ca;
+
+ if(!glamor_composite_choose_shader(op, source, mask, dest,
+ source_pixmap_priv, mask_pixmap_priv,
+ dest_pixmap_priv,
+ &key, &shader, &op_info,
+ &saved_source_format)) {
+ glamor_fallback("glamor_composite_choose_shader failed\n");
+ return ret;
+ }
+ if (two_pass_ca) {
+ if(!glamor_composite_choose_shader(PictOpAdd, source, mask, dest,
+ source_pixmap_priv, mask_pixmap_priv,
+ dest_pixmap_priv,
+ &key_ca, &shader_ca, &op_info_ca,
+ &saved_source_format)) {
+ glamor_fallback("glamor_composite_choose_shader failed\n");
+ return ret;
+ }
+ }
+
+ glamor_set_destination_pixmap_priv_nc(dest_pixmap_priv);
+ glamor_composite_set_shader_blend(dest_pixmap_priv, &key, shader, &op_info);
+
+ dispatch = glamor_get_dispatch(glamor_priv);
+
+ glamor_priv->has_source_coords = key.source != SHADER_SOURCE_SOLID;
+ glamor_priv->has_mask_coords = (key.mask != SHADER_MASK_NONE &&
+ key.mask != SHADER_MASK_SOLID);
+
+ dest_pixmap = glamor_get_drawable_pixmap(dest->pDrawable);
+ dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap);
+ glamor_get_drawable_deltas(dest->pDrawable, dest_pixmap,
+ &dest_x_off, &dest_y_off);
+ pixmap_priv_get_dest_scale(dest_pixmap_priv, &dst_xscale, &dst_yscale);
+
+ if (glamor_priv->has_source_coords) {
+ source_pixmap = source_pixmap_priv->base.pixmap;
+ glamor_get_drawable_deltas(source->pDrawable,
+ source_pixmap, &source_x_off,
+ &source_y_off);
+ pixmap_priv_get_scale(source_pixmap_priv, &src_xscale,
+ &src_yscale);
+ if (source->transform) {
+ psrc_matrix = src_matrix;
+ glamor_picture_get_matrixf(source, psrc_matrix);
+ }
+ vert_stride += 4;
+ }
+
+ if (glamor_priv->has_mask_coords) {
+ mask_pixmap = mask_pixmap_priv->base.pixmap;
+ glamor_get_drawable_deltas(mask->pDrawable, mask_pixmap,
+ &mask_x_off, &mask_y_off);
+ pixmap_priv_get_scale(mask_pixmap_priv, &mask_xscale,
+ &mask_yscale);
+ if (mask->transform) {
+ pmask_matrix = mask_matrix;
+ glamor_picture_get_matrixf(mask, pmask_matrix);
+ }
+ vert_stride += 4;
+ }
+
+ nrect_max = (vert_stride * nrect) > GLAMOR_COMPOSITE_VBO_VERT_CNT ?
+ (GLAMOR_COMPOSITE_VBO_VERT_CNT / vert_stride) : nrect;
+
+ while(nrect) {
+ int mrect, rect_processed;
+ int vb_stride;
+
+ mrect = nrect > nrect_max ? nrect_max : nrect ;
+ glamor_setup_composite_vbo(screen, mrect * vert_stride);
+ rect_processed = mrect;
+ vb_stride = glamor_priv->vb_stride/sizeof(float);
+ while (mrect--) {
+ INT16 x_source;
+ INT16 y_source;
+ INT16 x_mask;
+ INT16 y_mask;
+ INT16 x_dest;
+ INT16 y_dest;
+ CARD16 width;
+ CARD16 height;
+
+ x_dest = rects->x_dst + dest_x_off;
+ y_dest = rects->y_dst + dest_y_off;
+ x_source = rects->x_src + source_x_off;
+ y_source = rects->y_src + source_y_off;
+ x_mask = rects->x_mask + mask_x_off;
+ y_mask = rects->y_mask + mask_y_off;
+ width = rects->width;
+ height = rects->height;
+
+ DEBUGF("dest(%d,%d) source(%d %d) mask (%d %d), width %d height %d \n",
+ x_dest, y_dest, x_source, y_source,x_mask,y_mask,width,height);
+ vertices = (float*)(glamor_priv->vb + glamor_priv->vbo_offset);
+ assert(glamor_priv->vbo_offset < glamor_priv->vbo_size - glamor_priv->vb_stride);
+ glamor_set_normalize_vcoords_ext(dest_pixmap_priv, dst_xscale,
+ dst_yscale,
+ x_dest, y_dest,
+ x_dest + width, y_dest + height,
+ glamor_priv->yInverted,
+ vertices, vb_stride);
+ vertices += 2;
+ if (key.source != SHADER_SOURCE_SOLID) {
+ glamor_set_normalize_tcoords_generic(
+ source_pixmap_priv, source->repeatType, psrc_matrix,
+ src_xscale, src_yscale, x_source, y_source,
+ x_source + width, y_source + height,
+ glamor_priv->yInverted, vertices, vb_stride);
+ vertices += 2;
+ }
+
+ if (key.mask != SHADER_MASK_NONE
+ && key.mask != SHADER_MASK_SOLID) {
+ glamor_set_normalize_tcoords_generic(
+ mask_pixmap_priv, mask->repeatType, pmask_matrix,
+ mask_xscale, mask_yscale, x_mask, y_mask,
+ x_mask + width, y_mask + height,
+ glamor_priv->yInverted, vertices, vb_stride);
+ }
+ glamor_priv->render_nr_verts += 4;
+ glamor_priv->vbo_offset += glamor_priv->vb_stride * 4;
+ rects++;
+ }
+ glamor_flush_composite_rects(screen);
+ nrect -= rect_processed;
+ if (two_pass_ca) {
+ glamor_composite_set_shader_blend(dest_pixmap_priv,
+ &key_ca, shader_ca,
+ &op_info_ca);
+ glamor_flush_composite_rects(screen);
+ if (nrect)
+ glamor_composite_set_shader_blend(dest_pixmap_priv,
+ &key, shader,
+ &op_info);
+ }
+ }
+
+ dispatch->glBindBuffer(GL_ARRAY_BUFFER, 0);
+ dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
+ dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_MASK);
+ dispatch->glDisable(GL_BLEND);
+#ifndef GLAMOR_GLES2
+ dispatch->glActiveTexture(GL_TEXTURE0);
+ dispatch->glDisable(GL_TEXTURE_2D);
+ dispatch->glActiveTexture(GL_TEXTURE1);
+ dispatch->glDisable(GL_TEXTURE_2D);
+#endif
+ DEBUGF("finish rendering.\n");
+ dispatch->glUseProgram(0);
+ glamor_priv->state = RENDER_STATE;
+ glamor_priv->render_idle_cnt = 0;
+ if (saved_source_format)
+ source->format = saved_source_format;
+ glamor_put_dispatch(glamor_priv);
+
+ ret = TRUE;
+ return ret;
+}
+
+PicturePtr
+glamor_convert_gradient_picture(ScreenPtr screen,
+ PicturePtr source,
+ int x_source,
+ int y_source, int width, int height)
+{
+ PixmapPtr pixmap;
+ PicturePtr dst = NULL;
+ int error;
+ PictFormatShort format;
+ if (!source->pDrawable)
+ format = PICT_a8r8g8b8;
+ else
+ format = source->format;
+#ifdef GLAMOR_GRADIENT_SHADER
+ if (!source->pDrawable) {
+ if (source->pSourcePict->type == SourcePictTypeLinear) {
+ dst = glamor_generate_linear_gradient_picture(screen,
+ source, x_source, y_source, width, height, format);
+ } else if (source->pSourcePict->type == SourcePictTypeRadial) {
+ dst = glamor_generate_radial_gradient_picture(screen,
+ source, x_source, y_source, width, height, format);
+ }
+
+ if (dst) {
+#if 0 /* Debug to compare it to pixman, Enable it if needed. */
+ glamor_compare_pictures(screen, source,
+ dst, x_source, y_source, width, height,
+ 0, 3);
+#endif
+ return dst;
+ }
+ }
+#endif
+ pixmap = glamor_create_pixmap(screen,
+ width,
+ height,
+ PIXMAN_FORMAT_DEPTH(format),
+ GLAMOR_CREATE_PIXMAP_CPU);
+
+ if (!pixmap)
+ return NULL;
+
+ dst = CreatePicture(0,
+ &pixmap->drawable,
+ PictureMatchFormat(screen,
+ PIXMAN_FORMAT_DEPTH(format),
+ format),
+ 0, 0, serverClient, &error);
+ glamor_destroy_pixmap(pixmap);
+ if (!dst)
+ return NULL;
+
+ ValidatePicture(dst);
+
+ fbComposite(PictOpSrc, source, NULL, dst, x_source, y_source,
+ 0, 0, 0, 0, width, height);
+ return dst;
+}
+
+Bool
+glamor_composite_clipped_region(CARD8 op,
+ PicturePtr source,
+ PicturePtr mask,
+ PicturePtr dest,
+ glamor_pixmap_private *source_pixmap_priv,
+ glamor_pixmap_private *mask_pixmap_priv,
+ glamor_pixmap_private *dest_pixmap_priv,
+ RegionPtr region,
+ int x_source,
+ int y_source,
+ int x_mask,
+ int y_mask,
+ int x_dest,
+ int y_dest)
+{
+ ScreenPtr screen = dest->pDrawable->pScreen;
+ PixmapPtr source_pixmap = NULL, mask_pixmap = NULL;
+ PicturePtr temp_src = source, temp_mask = mask;
+ glamor_pixmap_private *temp_src_priv = source_pixmap_priv;
+ glamor_pixmap_private *temp_mask_priv = mask_pixmap_priv;
+ int x_temp_src, y_temp_src, x_temp_mask, y_temp_mask;
+ BoxPtr extent;
+ glamor_composite_rect_t rect[10];
+ glamor_composite_rect_t *prect = rect;
+ int prect_size = ARRAY_SIZE(rect);
+ int ok = FALSE;
+ int i;
+ int width;
+ int height;
+ BoxPtr box;
+ int nbox;
+ Bool two_pass_ca = FALSE;
+
+ extent = RegionExtents(region);
+ box = RegionRects(region);
+ nbox = RegionNumRects(region);
+ width = extent->x2 - extent->x1;
+ height = extent->y2 - extent->y1;
+
+ x_temp_src = x_source;
+ y_temp_src = y_source;
+ x_temp_mask = x_mask;
+ y_temp_mask = y_mask;
+
+ DEBUGF("clipped (%d %d) (%d %d) (%d %d) width %d height %d \n",
+ x_source, y_source, x_mask, y_mask, x_dest, y_dest, width, height);
+
+ if (source_pixmap_priv)
+ source_pixmap = source_pixmap_priv->base.pixmap;
+
+ if (mask_pixmap_priv)
+ mask_pixmap = mask_pixmap_priv->base.pixmap;
+
+ /* XXX is it possible source mask have non-zero drawable.x/y? */
+ if (source
+ && ((!source->pDrawable
+ && (source->pSourcePict->type != SourcePictTypeSolidFill))
+ || (source->pDrawable
+ && !GLAMOR_PIXMAP_PRIV_HAS_FBO(source_pixmap_priv)
+ && (source_pixmap->drawable.width != width
+ || source_pixmap->drawable.height != height)))) {
+ temp_src =
+ glamor_convert_gradient_picture(screen, source,
+ extent->x1 + x_source - x_dest,
+ extent->y1 + y_source - y_dest,
+ width, height);
+ if (!temp_src) {
+ temp_src = source;
+ goto out;
+ }
+ temp_src_priv = glamor_get_pixmap_private((PixmapPtr)(temp_src->pDrawable));
+ x_temp_src = - extent->x1 + x_dest;
+ y_temp_src = - extent->y1 + y_dest;
+ }
+
+ if (mask
+ &&
+ ((!mask->pDrawable
+ && (mask->pSourcePict->type != SourcePictTypeSolidFill))
+ || (mask->pDrawable
+ && !GLAMOR_PIXMAP_PRIV_HAS_FBO(mask_pixmap_priv)
+ && (mask_pixmap->drawable.width != width
+ || mask_pixmap->drawable.height != height)))) {
+ /* XXX if mask->pDrawable is the same as source->pDrawable, we have an opportunity
+ * to do reduce one convertion. */
+ temp_mask =
+ glamor_convert_gradient_picture(screen, mask,
+ extent->x1 + x_mask - x_dest,
+ extent->y1 + y_mask - y_dest,
+ width, height);
+ if (!temp_mask) {
+ temp_mask = mask;
+ goto out;
+ }
+ temp_mask_priv = glamor_get_pixmap_private((PixmapPtr)(temp_mask->pDrawable));
+ x_temp_mask = - extent->x1 + x_dest;
+ y_temp_mask = - extent->y1 + y_dest;
+ }
+ /* Do two-pass PictOpOver componentAlpha, until we enable
+ * dual source color blending.
+ */
+
+ if (mask && mask->componentAlpha) {
+ if (op == PictOpOver) {
+ two_pass_ca = TRUE;
+ op = PictOpOutReverse;
+ }
+ }
+
+ if (!mask && temp_src) {
+ if (glamor_composite_with_copy(op, temp_src, dest,
+ x_temp_src, y_temp_src,
+ x_dest, y_dest, region)) {
+ ok = TRUE;
+ goto out;
+ }
+ }
+
+ /*XXXXX, self copy?*/
+
+ x_dest += dest->pDrawable->x;
+ y_dest += dest->pDrawable->y;
+ if (temp_src && temp_src->pDrawable) {
+ x_temp_src += temp_src->pDrawable->x;
+ y_temp_src += temp_src->pDrawable->y;
+ }
+ if (temp_mask && temp_mask->pDrawable) {
+ x_temp_mask += temp_mask->pDrawable->x;
+ y_temp_mask += temp_mask->pDrawable->y;
+ }
+
+ if (nbox > ARRAY_SIZE(rect)) {
+ prect = calloc(nbox, sizeof(*prect));
+ if (prect)
+ prect_size = nbox;
+ else {
+ prect = rect;
+ prect_size = ARRAY_SIZE(rect);
+ }
+ }
+ while(nbox) {
+ int box_cnt;
+ box_cnt = nbox > prect_size ? prect_size : nbox;
+ for (i = 0; i < box_cnt; i++) {
+ prect[i].x_src = box[i].x1 + x_temp_src - x_dest;
+ prect[i].y_src = box[i].y1 + y_temp_src - y_dest;
+ prect[i].x_mask = box[i].x1 + x_temp_mask - x_dest;
+ prect[i].y_mask = box[i].y1 + y_temp_mask - y_dest;
+ prect[i].x_dst = box[i].x1;
+ prect[i].y_dst = box[i].y1;
+ prect[i].width = box[i].x2 - box[i].x1;
+ prect[i].height = box[i].y2 - box[i].y1;
+ DEBUGF("dest %d %d \n", prect[i].x_dst, prect[i].y_dst);
+ }
+ ok = glamor_composite_with_shader(op, temp_src, temp_mask, dest,
+ temp_src_priv, temp_mask_priv,
+ dest_pixmap_priv,
+ box_cnt, prect, two_pass_ca);
+ if (!ok)
+ break;
+ nbox -= box_cnt;
+ box += box_cnt;
+ }
+
+ if (prect != rect)
+ free(prect);
+out:
+ if (temp_src != source)
+ FreePicture(temp_src, 0);
+ if (temp_mask != mask)
+ FreePicture(temp_mask, 0);
+
+ return ok;
+}
+
+static Bool
+_glamor_composite(CARD8 op,
+ PicturePtr source,
+ PicturePtr mask,
+ PicturePtr dest,
+ INT16 x_source,
+ INT16 y_source,
+ INT16 x_mask,
+ INT16 y_mask,
+ INT16 x_dest, INT16 y_dest,
+ CARD16 width, CARD16 height, Bool fallback)
+{
+ ScreenPtr screen = dest->pDrawable->pScreen;
+ glamor_pixmap_private *dest_pixmap_priv;
+ glamor_pixmap_private *source_pixmap_priv =
+ NULL, *mask_pixmap_priv = NULL;
+ PixmapPtr dest_pixmap =
+ glamor_get_drawable_pixmap(dest->pDrawable);
+ PixmapPtr source_pixmap = NULL, mask_pixmap = NULL;
+ glamor_screen_private *glamor_priv =
+ glamor_get_screen_private(screen);
+ Bool ret = TRUE;
+ RegionRec region;
+ BoxPtr extent;
+ int nbox, ok = FALSE;
+ PixmapPtr sub_dest_pixmap = NULL;
+ PixmapPtr sub_source_pixmap = NULL;
+ PixmapPtr sub_mask_pixmap = NULL;
+ int dest_x_off, dest_y_off, saved_dest_x, saved_dest_y;
+ int source_x_off, source_y_off, saved_source_x, saved_source_y;
+ int mask_x_off, mask_y_off, saved_mask_x, saved_mask_y;
+ DrawablePtr saved_dest_drawable;
+ DrawablePtr saved_source_drawable;
+ DrawablePtr saved_mask_drawable;
+ int force_clip = 0;
+ dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap);
+
+ if (source->pDrawable) {
+ source_pixmap = glamor_get_drawable_pixmap(source->pDrawable);
+ source_pixmap_priv = glamor_get_pixmap_private(source_pixmap);
+ if (source_pixmap_priv && source_pixmap_priv->type == GLAMOR_DRM_ONLY)
+ goto fail;
+ }
+
+ if (mask && mask->pDrawable) {
+ mask_pixmap = glamor_get_drawable_pixmap(mask->pDrawable);
+ mask_pixmap_priv = glamor_get_pixmap_private(mask_pixmap);
+ if (mask_pixmap_priv && mask_pixmap_priv->type == GLAMOR_DRM_ONLY)
+ goto fail;
+ }
+
+ DEBUGF("source pixmap %p (%d %d) mask(%d %d) dest(%d %d) width %d height %d \n",
+ source_pixmap, x_source, y_source, x_mask, y_mask, x_dest, y_dest, width, height);
+
+ if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dest_pixmap_priv)) {
+ goto fail;
+ }
+
+ if (op >= ARRAY_SIZE(composite_op_info))
+ goto fail;
+
+ if (mask && mask->componentAlpha) {
+ if (op == PictOpAtop
+ || op == PictOpAtopReverse
+ || op == PictOpXor
+ || op >= PictOpSaturate) {
+ glamor_fallback
+ ("glamor_composite(): component alpha op %x\n", op);
+ goto fail;
+ }
+ }
+
+ if ((source && source->filter >= PictFilterConvolution)
+ || (mask && mask->filter >= PictFilterConvolution)) {
+ glamor_fallback("glamor_composite(): unsupported filter\n");
+ goto fail;
+ }
+
+ if (!miComputeCompositeRegion(&region,
+ source, mask, dest,
+ x_source + (source_pixmap ? source->pDrawable->x : 0),
+ y_source + (source_pixmap ? source->pDrawable->y : 0),
+ x_mask + (mask_pixmap ? mask->pDrawable->x : 0),
+ y_mask + (mask_pixmap ? mask->pDrawable->y : 0),
+ x_dest + dest->pDrawable->x,
+ y_dest + dest->pDrawable->y,
+ width,
+ height)) {
+ ret = TRUE;
+ goto done;
+ }
+
+ nbox = REGION_NUM_RECTS(&region);
+ DEBUGF("first clipped when compositing.\n");
+ DEBUGRegionPrint(&region);
+ extent = RegionExtents(&region);
+ if (nbox == 0) {
+ ret = TRUE;
+ goto done;
+ }
+ /* If destination is not a large pixmap, but the region is larger
+ * than texture size limitation, and source or mask is memory pixmap,
+ * then there may be need to load a large memory pixmap to a
+ * texture, and this is not permitted. Then we force to clip the
+ * destination and make sure latter will not upload a large memory
+ * pixmap. */
+ if (!glamor_check_fbo_size(glamor_priv,
+ extent->x2 - extent->x1, extent->y2 - extent->y1)
+ && (dest_pixmap_priv->type != GLAMOR_TEXTURE_LARGE)
+ && ((source_pixmap_priv
+ && (source_pixmap_priv->type == GLAMOR_MEMORY || source->repeatType == RepeatPad))
+ || (mask_pixmap_priv
+ && (mask_pixmap_priv->type == GLAMOR_MEMORY || mask->repeatType == RepeatPad))
+ || (!source_pixmap_priv
+ && (source->pSourcePict->type != SourcePictTypeSolidFill))
+ || (!mask_pixmap_priv && mask
+ && mask->pSourcePict->type != SourcePictTypeSolidFill)))
+ force_clip = 1;
+
+ if (force_clip || dest_pixmap_priv->type == GLAMOR_TEXTURE_LARGE
+ || (source_pixmap_priv
+ && source_pixmap_priv->type == GLAMOR_TEXTURE_LARGE)
+ || (mask_pixmap_priv
+ && mask_pixmap_priv->type == GLAMOR_TEXTURE_LARGE))
+ ok = glamor_composite_largepixmap_region(op,
+ source, mask, dest,
+ source_pixmap_priv,
+ mask_pixmap_priv,
+ dest_pixmap_priv,
+ &region, force_clip,
+ x_source, y_source,
+ x_mask, y_mask,
+ x_dest, y_dest,
+ width, height);
+ else
+ ok = glamor_composite_clipped_region(op, source,
+ mask, dest,
+ source_pixmap_priv,
+ mask_pixmap_priv,
+ dest_pixmap_priv,
+ &region,
+ x_source, y_source,
+ x_mask, y_mask,
+ x_dest, y_dest);
+
+ REGION_UNINIT(dest->pDrawable->pScreen, &region);
+
+ if (ok)
+ goto done;
+fail:
+
+ if (!fallback
+ && glamor_ddx_fallback_check_pixmap(&dest_pixmap->drawable)
+ && (!source_pixmap
+ || glamor_ddx_fallback_check_pixmap(&source_pixmap->drawable))
+ && (!mask_pixmap
+ || glamor_ddx_fallback_check_pixmap(&mask_pixmap->drawable))) {
+ ret = FALSE;
+ goto done;
+ }
+
+ glamor_fallback
+ ("from picts %p:%p %dx%d / %p:%p %d x %d (%c,%c) to pict %p:%p %dx%d (%c)\n",
+ source, source->pDrawable,
+ source->pDrawable ? source->pDrawable->width : 0,
+ source->pDrawable ? source->pDrawable->height : 0, mask,
+ (!mask) ? NULL : mask->pDrawable, (!mask
+ || !mask->pDrawable) ? 0 :
+ mask->pDrawable->width, (!mask
+ || !mask->
+ pDrawable) ? 0 : mask->pDrawable->
+ height, glamor_get_picture_location(source),
+ glamor_get_picture_location(mask), dest, dest->pDrawable,
+ dest->pDrawable->width, dest->pDrawable->height,
+ glamor_get_picture_location(dest));
+
+#define GET_SUB_PICTURE(p, access) do { \
+ glamor_get_drawable_deltas(p->pDrawable, p ##_pixmap, \
+ & p ##_x_off, & p ##_y_off); \
+ sub_ ##p ##_pixmap = glamor_get_sub_pixmap(p ##_pixmap, \
+ x_ ##p + p ##_x_off + p->pDrawable->x, \
+ y_ ##p + p ##_y_off + p->pDrawable->y, \
+ width, height, access); \
+ if (sub_ ##p ##_pixmap != NULL) { \
+ saved_ ##p ##_drawable = p->pDrawable; \
+ saved_ ##p ##_x = x_ ##p; \
+ saved_ ##p ##_y = y_ ##p; \
+ if (p->pCompositeClip) \
+ pixman_region_translate (p->pCompositeClip, \
+ -p->pDrawable->x - x_ ##p, \
+ -p->pDrawable->y - y_ ##p); \
+ p->pDrawable = &sub_ ##p ##_pixmap->drawable; \
+ x_ ##p = 0; \
+ y_ ##p = 0; \
+ } } while(0)
+ GET_SUB_PICTURE(dest, GLAMOR_ACCESS_RW);
+ if (source->pDrawable && !source->transform)
+ GET_SUB_PICTURE(source, GLAMOR_ACCESS_RO);
+ if (mask && mask->pDrawable && !mask->transform)
+ GET_SUB_PICTURE(mask, GLAMOR_ACCESS_RO);
+
+ if (glamor_prepare_access_picture(dest, GLAMOR_ACCESS_RW)) {
+ if (source_pixmap == dest_pixmap || glamor_prepare_access_picture
+ (source, GLAMOR_ACCESS_RO)) {
+ if (!mask
+ || glamor_prepare_access_picture(mask,
+ GLAMOR_ACCESS_RO))
+ {
+ fbComposite(op,
+ source, mask, dest,
+ x_source, y_source,
+ x_mask, y_mask, x_dest,
+ y_dest, width, height);
+ if (mask)
+ glamor_finish_access_picture(mask, GLAMOR_ACCESS_RO);
+ }
+ if (source_pixmap != dest_pixmap)
+ glamor_finish_access_picture(source, GLAMOR_ACCESS_RO);
+ }
+ glamor_finish_access_picture(dest, GLAMOR_ACCESS_RW);
+ }
+
+#define PUT_SUB_PICTURE(p, access) do { \
+ if (sub_ ##p ##_pixmap != NULL) { \
+ x_ ##p = saved_ ##p ##_x; \
+ y_ ##p = saved_ ##p ##_y; \
+ p->pDrawable = saved_ ##p ##_drawable; \
+ if (p->pCompositeClip) \
+ pixman_region_translate (p->pCompositeClip, \
+ p->pDrawable->x + x_ ##p, \
+ p->pDrawable->y + y_ ##p); \
+ glamor_put_sub_pixmap(sub_ ##p ##_pixmap, p ##_pixmap, \
+ x_ ##p + p ##_x_off + p->pDrawable->x, \
+ y_ ##p + p ##_y_off + p->pDrawable->y, \
+ width, height, access); \
+ }} while(0)
+ if (mask && mask->pDrawable)
+ PUT_SUB_PICTURE(mask, GLAMOR_ACCESS_RO);
+ if (source->pDrawable)
+ PUT_SUB_PICTURE(source, GLAMOR_ACCESS_RO);
+ PUT_SUB_PICTURE(dest, GLAMOR_ACCESS_RW);
+ done:
+ return ret;
+}
+
+void
+glamor_composite(CARD8 op,
+ PicturePtr source,
+ PicturePtr mask,
+ PicturePtr dest,
+ INT16 x_source,
+ INT16 y_source,
+ INT16 x_mask,
+ INT16 y_mask,
+ INT16 x_dest, INT16 y_dest,
+ CARD16 width, CARD16 height)
+{
+ _glamor_composite(op, source, mask, dest, x_source, y_source,
+ x_mask, y_mask, x_dest, y_dest, width, height,
+ TRUE);
+}
+
+Bool
+glamor_composite_nf(CARD8 op,
+ PicturePtr source,
+ PicturePtr mask,
+ PicturePtr dest,
+ INT16 x_source,
+ INT16 y_source,
+ INT16 x_mask,
+ INT16 y_mask,
+ INT16 x_dest, INT16 y_dest,
+ CARD16 width, CARD16 height)
+{
+ return _glamor_composite(op, source, mask, dest, x_source, y_source,
+ x_mask, y_mask, x_dest, y_dest, width, height,
+ FALSE);
+}
+
+static void
+glamor_get_src_rect_extent(int nrect,
+ glamor_composite_rect_t *rects,
+ BoxPtr extent)
+{
+ extent->x1 = MAXSHORT;
+ extent->y1 = MAXSHORT;
+ extent->x2 = MINSHORT;
+ extent->y2 = MINSHORT;
+
+ while(nrect--) {
+ if (extent->x1 > rects->x_src)
+ extent->x1 = rects->x_src;
+ if (extent->y1 > rects->y_src)
+ extent->y1 = rects->y_src;
+ if (extent->x2 < rects->x_src + rects->width)
+ extent->x2 = rects->x_src + rects->width;
+ if (extent->y2 < rects->y_src + rects->height)
+ extent->y2 = rects->y_src + rects->height;
+ rects++;
+ }
+}
+
+static void
+glamor_composite_src_rect_translate(int nrect,
+ glamor_composite_rect_t *rects,
+ int x, int y)
+{
+ while(nrect--) {
+ rects->x_src += x;
+ rects->y_src += y;
+ rects++;
+ }
+}
+
+void
+glamor_composite_glyph_rects(CARD8 op,
+ PicturePtr src, PicturePtr mask, PicturePtr dst,
+ int nrect, glamor_composite_rect_t * rects)
+{
+ int n;
+ PicturePtr temp_src = NULL;
+ glamor_composite_rect_t *r;
+
+ ValidatePicture(src);
+ ValidatePicture(dst);
+ if (!(glamor_is_large_picture(src)
+ || (mask && glamor_is_large_picture(mask))
+ || glamor_is_large_picture(dst))) {
+ glamor_pixmap_private *src_pixmap_priv = NULL;
+ glamor_pixmap_private *mask_pixmap_priv = NULL;
+ glamor_pixmap_private *dst_pixmap_priv;
+ glamor_pixmap_private *temp_src_priv = NULL;
+ BoxRec src_extent;
+
+ dst_pixmap_priv = glamor_get_pixmap_private
+ (glamor_get_drawable_pixmap(dst->pDrawable));
+
+ if (mask && mask->pDrawable)
+ mask_pixmap_priv = glamor_get_pixmap_private
+ (glamor_get_drawable_pixmap(mask->pDrawable));
+ if (src->pDrawable)
+ src_pixmap_priv = glamor_get_pixmap_private
+ (glamor_get_drawable_pixmap(src->pDrawable));
+
+ if (!src->pDrawable
+ && (src->pSourcePict->type != SourcePictTypeSolidFill)) {
+ glamor_get_src_rect_extent(nrect, rects, &src_extent);
+ temp_src = glamor_convert_gradient_picture(dst->pDrawable->pScreen,
+ src,
+ src_extent.x1, src_extent.y1,
+ src_extent.x2 - src_extent.x1,
+ src_extent.y2 - src_extent.y1);
+ if (!temp_src)
+ goto fallback;
+
+ temp_src_priv = glamor_get_pixmap_private
+ ((PixmapPtr)(temp_src->pDrawable));
+ glamor_composite_src_rect_translate(nrect, rects,
+ -src_extent.x1, -src_extent.y1);
+ } else {
+ temp_src = src;
+ temp_src_priv = src_pixmap_priv;
+ }
+
+ if (mask && mask->componentAlpha) {
+ if (op == PictOpOver) {
+ if (glamor_composite_with_shader(PictOpOutReverse,
+ temp_src, mask, dst, temp_src_priv,
+ mask_pixmap_priv, dst_pixmap_priv, nrect, rects,
+ TRUE))
+ goto done;
+ }
+ } else {
+ if (glamor_composite_with_shader(op, temp_src, mask, dst, temp_src_priv,
+ mask_pixmap_priv, dst_pixmap_priv, nrect, rects, FALSE))
+ goto done;
+ }
+ }
+fallback:
+ n = nrect;
+ r = rects;
+
+ while (n--) {
+ CompositePicture(op,
+ temp_src ? temp_src : src,
+ mask,
+ dst,
+ r->x_src, r->y_src,
+ r->x_mask, r->y_mask,
+ r->x_dst, r->y_dst, r->width, r->height);
+ r++;
+ }
+
+done:
+ if (temp_src && temp_src != src)
+ FreePicture(temp_src, 0);
+}
+
+static Bool
+_glamor_composite_rects (CARD8 op,
+ PicturePtr pDst,
+ xRenderColor *color,
+ int nRect,
+ xRectangle *rects,
+ Bool fallback)
+{
+ miCompositeRects(op, pDst, color, nRect, rects);
+ return TRUE;
+}
+
+void
+glamor_composite_rects (CARD8 op,
+ PicturePtr pDst,
+ xRenderColor *color,
+ int nRect,
+ xRectangle *rects)
+{
+ _glamor_composite_rects(op, pDst, color, nRect, rects, TRUE);
+}
+
+Bool
+glamor_composite_rects_nf (CARD8 op,
+ PicturePtr pDst,
+ xRenderColor *color,
+ int nRect,
+ xRectangle *rects)
+{
+ return _glamor_composite_rects(op, pDst, color, nRect, rects, FALSE);
+}
+
+#endif /* RENDER */