From 30af30b78075159fce477ae99cc72540133714d0 Mon Sep 17 00:00:00 2001 From: marha Date: Sun, 26 Jan 2014 20:05:50 +0100 Subject: xserver randrproto libxtrans fontconfig libxcb xcb-proto mesa git update 26 Jan 2014 xserver commit c1ce807d9f18f215332d7eeb844e8c640f71c53c libxcb commit e7263931aff3e3450dc938ad465a7577f943549f libxcb/xcb-proto commit d898fd39ad6c82207eb78666b2daad982dd757b5 randrproto commit a4a6694c059d74247c16527eef4a0ec9f56bbef6 libxtrans commit e1e6121a1638d43d9929589b4723da2b38cb6b44 fontconfig commit e2b406053c2937799da8636c56b72a77998bcab0 mesa commit 07149f0252c52b4ac58b6df4e307fd786b49b490 --- xorg-server/glamor/glamor_render.c | 2135 ++++++++++++++++++++++++++++++++++++ 1 file changed, 2135 insertions(+) create mode 100644 xorg-server/glamor/glamor_render.c (limited to 'xorg-server/glamor/glamor_render.c') 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 + * Zhigang Gong + * Junyan He + * + */ + +/** @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(®ion, + 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(®ion); + DEBUGF("first clipped when compositing.\n"); + DEBUGRegionPrint(®ion); + extent = RegionExtents(®ion); + 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, + ®ion, 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, + ®ion, + x_source, y_source, + x_mask, y_mask, + x_dest, y_dest); + + REGION_UNINIT(dest->pDrawable->pScreen, ®ion); + + 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 */ -- cgit v1.2.3