135c4bbdfSmrg/*
235c4bbdfSmrg * Copyright © 2009 Intel Corporation
335c4bbdfSmrg *
435c4bbdfSmrg * Permission is hereby granted, free of charge, to any person obtaining a
535c4bbdfSmrg * copy of this software and associated documentation files (the "Software"),
635c4bbdfSmrg * to deal in the Software without restriction, including without limitation
735c4bbdfSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
835c4bbdfSmrg * and/or sell copies of the Software, and to permit persons to whom the
935c4bbdfSmrg * Software is furnished to do so, subject to the following conditions:
1035c4bbdfSmrg *
1135c4bbdfSmrg * The above copyright notice and this permission notice (including the next
1235c4bbdfSmrg * paragraph) shall be included in all copies or substantial portions of the
1335c4bbdfSmrg * Software.
1435c4bbdfSmrg *
1535c4bbdfSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1635c4bbdfSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1735c4bbdfSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1835c4bbdfSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1935c4bbdfSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2035c4bbdfSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2135c4bbdfSmrg * IN THE SOFTWARE.
2235c4bbdfSmrg *
2335c4bbdfSmrg * Authors:
2435c4bbdfSmrg *    Eric Anholt <eric@anholt.net>
2535c4bbdfSmrg *    Zhigang Gong <zhigang.gong@linux.intel.com>
2635c4bbdfSmrg *    Junyan He <junyan.he@linux.intel.com>
2735c4bbdfSmrg *
2835c4bbdfSmrg */
2935c4bbdfSmrg
3035c4bbdfSmrg/** @file glamor_render.c
3135c4bbdfSmrg *
3235c4bbdfSmrg * Render acceleration implementation
3335c4bbdfSmrg */
3435c4bbdfSmrg
3535c4bbdfSmrg#include "glamor_priv.h"
3635c4bbdfSmrg
3735c4bbdfSmrg#include "mipict.h"
3835c4bbdfSmrg#include "fbpict.h"
3935c4bbdfSmrg#if 0
4035c4bbdfSmrg//#define DEBUGF(str, ...)  do {} while(0)
4135c4bbdfSmrg#define DEBUGF(str, ...) ErrorF(str, ##__VA_ARGS__)
4235c4bbdfSmrg//#define DEBUGRegionPrint(x) do {} while (0)
4335c4bbdfSmrg#define DEBUGRegionPrint RegionPrint
4435c4bbdfSmrg#endif
4535c4bbdfSmrg
4635c4bbdfSmrgstatic struct blendinfo composite_op_info[] = {
4735c4bbdfSmrg    [PictOpClear] = {0, 0, GL_ZERO, GL_ZERO},
4835c4bbdfSmrg    [PictOpSrc] = {0, 0, GL_ONE, GL_ZERO},
4935c4bbdfSmrg    [PictOpDst] = {0, 0, GL_ZERO, GL_ONE},
5035c4bbdfSmrg    [PictOpOver] = {0, 1, GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
5135c4bbdfSmrg    [PictOpOverReverse] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ONE},
5235c4bbdfSmrg    [PictOpIn] = {1, 0, GL_DST_ALPHA, GL_ZERO},
5335c4bbdfSmrg    [PictOpInReverse] = {0, 1, GL_ZERO, GL_SRC_ALPHA},
5435c4bbdfSmrg    [PictOpOut] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ZERO},
5535c4bbdfSmrg    [PictOpOutReverse] = {0, 1, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA},
5635c4bbdfSmrg    [PictOpAtop] = {1, 1, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
5735c4bbdfSmrg    [PictOpAtopReverse] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA},
5835c4bbdfSmrg    [PictOpXor] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
5935c4bbdfSmrg    [PictOpAdd] = {0, 0, GL_ONE, GL_ONE},
6035c4bbdfSmrg};
6135c4bbdfSmrg
6235c4bbdfSmrg#define RepeatFix			10
6335c4bbdfSmrgstatic GLuint
6435c4bbdfSmrgglamor_create_composite_fs(struct shader_key *key)
6535c4bbdfSmrg{
6635c4bbdfSmrg    const char *repeat_define =
6735c4bbdfSmrg        "#define RepeatNone               	      0\n"
6835c4bbdfSmrg        "#define RepeatNormal                     1\n"
6935c4bbdfSmrg        "#define RepeatPad                        2\n"
7035c4bbdfSmrg        "#define RepeatReflect                    3\n"
7135c4bbdfSmrg        "#define RepeatFix		      	      10\n"
7235c4bbdfSmrg        "uniform int 			source_repeat_mode;\n"
7335c4bbdfSmrg        "uniform int 			mask_repeat_mode;\n";
7435c4bbdfSmrg    const char *relocate_texture =
7535c4bbdfSmrg        "vec2 rel_tex_coord(vec2 texture, vec4 wh, int repeat) \n"
7635c4bbdfSmrg        "{\n"
7735c4bbdfSmrg        "	vec2 rel_tex; \n"
7835c4bbdfSmrg        "	rel_tex = texture * wh.xy; \n"
7935c4bbdfSmrg        "	if (repeat == RepeatFix + RepeatNone)\n"
8035c4bbdfSmrg        "		return rel_tex; \n"
8135c4bbdfSmrg        "	else if (repeat == RepeatFix + RepeatNormal) \n"
8235c4bbdfSmrg        "		rel_tex = floor(rel_tex) + (fract(rel_tex) / wh.xy); \n"
8335c4bbdfSmrg        "	else if (repeat == RepeatFix + RepeatPad) { \n"
8435c4bbdfSmrg        "		if (rel_tex.x >= 1.0) \n"
8535c4bbdfSmrg        "			rel_tex.x = 1.0 - wh.z * wh.x / 2.; \n"
8635c4bbdfSmrg        "		else if (rel_tex.x < 0.0) \n"
8735c4bbdfSmrg        "			rel_tex.x = 0.0; \n"
8835c4bbdfSmrg        "		if (rel_tex.y >= 1.0) \n"
8935c4bbdfSmrg        "			rel_tex.y = 1.0 - wh.w * wh.y / 2.; \n"
9035c4bbdfSmrg        "		else if (rel_tex.y < 0.0) \n"
9135c4bbdfSmrg        "			rel_tex.y = 0.0; \n"
9235c4bbdfSmrg        "		rel_tex = rel_tex / wh.xy; \n"
9335c4bbdfSmrg        "	} else if (repeat == RepeatFix + RepeatReflect) {\n"
9435c4bbdfSmrg        "		if ((1.0 - mod(abs(floor(rel_tex.x)), 2.0)) < 0.001)\n"
9535c4bbdfSmrg        "			rel_tex.x = 2.0 - (1.0 - fract(rel_tex.x)) / wh.x;\n"
9635c4bbdfSmrg        "		else \n"
9735c4bbdfSmrg        "			rel_tex.x = fract(rel_tex.x) / wh.x;\n"
9835c4bbdfSmrg        "		if ((1.0 - mod(abs(floor(rel_tex.y)), 2.0)) < 0.001)\n"
9935c4bbdfSmrg        "			rel_tex.y = 2.0 - (1.0 - fract(rel_tex.y)) / wh.y;\n"
10035c4bbdfSmrg        "		else \n"
10135c4bbdfSmrg        "			rel_tex.y = fract(rel_tex.y) / wh.y;\n"
10235c4bbdfSmrg        "	} \n"
10335c4bbdfSmrg        "	return rel_tex; \n"
10435c4bbdfSmrg        "}\n";
10535c4bbdfSmrg    /* The texture and the pixmap size is not match eaxctly, so can't sample it directly.
10635c4bbdfSmrg     * rel_sampler will recalculate the texture coords.*/
10735c4bbdfSmrg    const char *rel_sampler =
10835c4bbdfSmrg        " vec4 rel_sampler_rgba(sampler2D tex_image, vec2 tex, vec4 wh, int repeat)\n"
10935c4bbdfSmrg        "{\n"
11035c4bbdfSmrg        "	if (repeat >= RepeatFix) {\n"
11135c4bbdfSmrg        "		tex = rel_tex_coord(tex, wh, repeat);\n"
11235c4bbdfSmrg        "		if (repeat == RepeatFix + RepeatNone) {\n"
11335c4bbdfSmrg        "			if (tex.x < 0.0 || tex.x >= 1.0 || \n"
11435c4bbdfSmrg        "			    tex.y < 0.0 || tex.y >= 1.0)\n"
11535c4bbdfSmrg        "				return vec4(0.0, 0.0, 0.0, 0.0);\n"
11635c4bbdfSmrg        "			tex = (fract(tex) / wh.xy);\n"
11735c4bbdfSmrg        "		}\n"
11835c4bbdfSmrg        "	}\n"
11935c4bbdfSmrg        "	return texture2D(tex_image, tex);\n"
12035c4bbdfSmrg        "}\n"
12135c4bbdfSmrg        " vec4 rel_sampler_rgbx(sampler2D tex_image, vec2 tex, vec4 wh, int repeat)\n"
12235c4bbdfSmrg        "{\n"
12335c4bbdfSmrg        "	if (repeat >= RepeatFix) {\n"
12435c4bbdfSmrg        "		tex = rel_tex_coord(tex, wh, repeat);\n"
12535c4bbdfSmrg        "		if (repeat == RepeatFix + RepeatNone) {\n"
12635c4bbdfSmrg        "			if (tex.x < 0.0 || tex.x >= 1.0 || \n"
12735c4bbdfSmrg        "			    tex.y < 0.0 || tex.y >= 1.0)\n"
12835c4bbdfSmrg        "				return vec4(0.0, 0.0, 0.0, 0.0);\n"
12935c4bbdfSmrg        "			tex = (fract(tex) / wh.xy);\n"
13035c4bbdfSmrg        "		}\n"
13135c4bbdfSmrg        "	}\n"
13235c4bbdfSmrg        "	return vec4(texture2D(tex_image, tex).rgb, 1.0);\n"
13335c4bbdfSmrg        "}\n";
13435c4bbdfSmrg
13535c4bbdfSmrg    const char *source_solid_fetch =
13635c4bbdfSmrg        "uniform vec4 source;\n"
13735c4bbdfSmrg        "vec4 get_source()\n"
13835c4bbdfSmrg        "{\n"
13935c4bbdfSmrg        "	return source;\n"
14035c4bbdfSmrg        "}\n";
14135c4bbdfSmrg    const char *source_alpha_pixmap_fetch =
14235c4bbdfSmrg        "varying vec2 source_texture;\n"
14335c4bbdfSmrg        "uniform sampler2D source_sampler;\n"
14435c4bbdfSmrg        "uniform vec4 source_wh;"
14535c4bbdfSmrg        "vec4 get_source()\n"
14635c4bbdfSmrg        "{\n"
14735c4bbdfSmrg        "	return rel_sampler_rgba(source_sampler, source_texture,\n"
14835c4bbdfSmrg        "			        source_wh, source_repeat_mode);\n"
14935c4bbdfSmrg        "}\n";
15035c4bbdfSmrg    const char *source_pixmap_fetch =
15135c4bbdfSmrg        "varying vec2 source_texture;\n"
15235c4bbdfSmrg        "uniform sampler2D source_sampler;\n"
15335c4bbdfSmrg        "uniform vec4 source_wh;\n"
15435c4bbdfSmrg        "vec4 get_source()\n"
15535c4bbdfSmrg        "{\n"
15635c4bbdfSmrg        "	return rel_sampler_rgbx(source_sampler, source_texture,\n"
15735c4bbdfSmrg        "				source_wh, source_repeat_mode);\n"
15835c4bbdfSmrg        "}\n";
15935c4bbdfSmrg    const char *mask_none =
16035c4bbdfSmrg        "vec4 get_mask()\n"
16135c4bbdfSmrg        "{\n"
16235c4bbdfSmrg        "	return vec4(0.0, 0.0, 0.0, 1.0);\n"
16335c4bbdfSmrg        "}\n";
16435c4bbdfSmrg    const char *mask_solid_fetch =
16535c4bbdfSmrg        "uniform vec4 mask;\n"
16635c4bbdfSmrg        "vec4 get_mask()\n"
16735c4bbdfSmrg        "{\n"
16835c4bbdfSmrg        "	return mask;\n"
16935c4bbdfSmrg        "}\n";
17035c4bbdfSmrg    const char *mask_alpha_pixmap_fetch =
17135c4bbdfSmrg        "varying vec2 mask_texture;\n"
17235c4bbdfSmrg        "uniform sampler2D mask_sampler;\n"
17335c4bbdfSmrg        "uniform vec4 mask_wh;\n"
17435c4bbdfSmrg        "vec4 get_mask()\n"
17535c4bbdfSmrg        "{\n"
17635c4bbdfSmrg        "	return rel_sampler_rgba(mask_sampler, mask_texture,\n"
17735c4bbdfSmrg        "			        mask_wh, mask_repeat_mode);\n"
17835c4bbdfSmrg        "}\n";
17935c4bbdfSmrg    const char *mask_pixmap_fetch =
18035c4bbdfSmrg        "varying vec2 mask_texture;\n"
18135c4bbdfSmrg        "uniform sampler2D mask_sampler;\n"
18235c4bbdfSmrg        "uniform vec4 mask_wh;\n"
18335c4bbdfSmrg        "vec4 get_mask()\n"
18435c4bbdfSmrg        "{\n"
18535c4bbdfSmrg        "	return rel_sampler_rgbx(mask_sampler, mask_texture,\n"
18635c4bbdfSmrg        "				mask_wh, mask_repeat_mode);\n"
18735c4bbdfSmrg        "}\n";
18835c4bbdfSmrg
18935c4bbdfSmrg    const char *dest_swizzle_default =
19035c4bbdfSmrg        "vec4 dest_swizzle(vec4 color)\n"
19135c4bbdfSmrg        "{"
19235c4bbdfSmrg        "	return color;"
19335c4bbdfSmrg        "}";
19435c4bbdfSmrg    const char *dest_swizzle_alpha_to_red =
19535c4bbdfSmrg        "vec4 dest_swizzle(vec4 color)\n"
19635c4bbdfSmrg        "{"
19735c4bbdfSmrg        "	float undef;\n"
19835c4bbdfSmrg        "	return vec4(color.a, undef, undef, undef);"
19935c4bbdfSmrg        "}";
20035c4bbdfSmrg
20135c4bbdfSmrg    const char *in_normal =
20235c4bbdfSmrg        "void main()\n"
20335c4bbdfSmrg        "{\n"
20435c4bbdfSmrg        "	gl_FragColor = dest_swizzle(get_source() * get_mask().a);\n"
20535c4bbdfSmrg        "}\n";
20635c4bbdfSmrg    const char *in_ca_source =
20735c4bbdfSmrg        "void main()\n"
20835c4bbdfSmrg        "{\n"
20935c4bbdfSmrg        "	gl_FragColor = dest_swizzle(get_source() * get_mask());\n"
21035c4bbdfSmrg        "}\n";
21135c4bbdfSmrg    const char *in_ca_alpha =
21235c4bbdfSmrg        "void main()\n"
21335c4bbdfSmrg        "{\n"
21435c4bbdfSmrg        "	gl_FragColor = dest_swizzle(get_source().a * get_mask());\n"
21535c4bbdfSmrg        "}\n";
21635c4bbdfSmrg    const char *in_ca_dual_blend =
21735c4bbdfSmrg        "out vec4 color0;\n"
21835c4bbdfSmrg        "out vec4 color1;\n"
21935c4bbdfSmrg        "void main()\n"
22035c4bbdfSmrg        "{\n"
22135c4bbdfSmrg        "	color0 = dest_swizzle(get_source() * get_mask());\n"
22235c4bbdfSmrg        "	color1 = dest_swizzle(get_source().a * get_mask());\n"
22335c4bbdfSmrg        "}\n";
22435c4bbdfSmrg    const char *header_ca_dual_blend =
22535c4bbdfSmrg        "#version 130\n";
22635c4bbdfSmrg
22735c4bbdfSmrg    char *source;
22835c4bbdfSmrg    const char *source_fetch;
22935c4bbdfSmrg    const char *mask_fetch = "";
23035c4bbdfSmrg    const char *in;
23135c4bbdfSmrg    const char *header;
23235c4bbdfSmrg    const char *header_norm = "";
23335c4bbdfSmrg    const char *dest_swizzle;
23435c4bbdfSmrg    GLuint prog;
23535c4bbdfSmrg
23635c4bbdfSmrg    switch (key->source) {
23735c4bbdfSmrg    case SHADER_SOURCE_SOLID:
23835c4bbdfSmrg        source_fetch = source_solid_fetch;
23935c4bbdfSmrg        break;
24035c4bbdfSmrg    case SHADER_SOURCE_TEXTURE_ALPHA:
24135c4bbdfSmrg        source_fetch = source_alpha_pixmap_fetch;
24235c4bbdfSmrg        break;
24335c4bbdfSmrg    case SHADER_SOURCE_TEXTURE:
24435c4bbdfSmrg        source_fetch = source_pixmap_fetch;
24535c4bbdfSmrg        break;
24635c4bbdfSmrg    default:
24735c4bbdfSmrg        FatalError("Bad composite shader source");
24835c4bbdfSmrg    }
24935c4bbdfSmrg
25035c4bbdfSmrg    switch (key->mask) {
25135c4bbdfSmrg    case SHADER_MASK_NONE:
25235c4bbdfSmrg        mask_fetch = mask_none;
25335c4bbdfSmrg        break;
25435c4bbdfSmrg    case SHADER_MASK_SOLID:
25535c4bbdfSmrg        mask_fetch = mask_solid_fetch;
25635c4bbdfSmrg        break;
25735c4bbdfSmrg    case SHADER_MASK_TEXTURE_ALPHA:
25835c4bbdfSmrg        mask_fetch = mask_alpha_pixmap_fetch;
25935c4bbdfSmrg        break;
26035c4bbdfSmrg    case SHADER_MASK_TEXTURE:
26135c4bbdfSmrg        mask_fetch = mask_pixmap_fetch;
26235c4bbdfSmrg        break;
26335c4bbdfSmrg    default:
26435c4bbdfSmrg        FatalError("Bad composite shader mask");
26535c4bbdfSmrg    }
26635c4bbdfSmrg
26735c4bbdfSmrg    /* If we're storing to an a8 texture but our texture format is
26835c4bbdfSmrg     * GL_RED because of a core context, then we need to make sure to
26935c4bbdfSmrg     * put the alpha into the red channel.
27035c4bbdfSmrg     */
27135c4bbdfSmrg    switch (key->dest_swizzle) {
27235c4bbdfSmrg    case SHADER_DEST_SWIZZLE_DEFAULT:
27335c4bbdfSmrg        dest_swizzle = dest_swizzle_default;
27435c4bbdfSmrg        break;
27535c4bbdfSmrg    case SHADER_DEST_SWIZZLE_ALPHA_TO_RED:
27635c4bbdfSmrg        dest_swizzle = dest_swizzle_alpha_to_red;
27735c4bbdfSmrg        break;
27835c4bbdfSmrg    default:
27935c4bbdfSmrg        FatalError("Bad composite shader dest swizzle");
28035c4bbdfSmrg    }
28135c4bbdfSmrg
28235c4bbdfSmrg    header = header_norm;
28335c4bbdfSmrg    switch (key->in) {
28435c4bbdfSmrg    case glamor_program_alpha_normal:
28535c4bbdfSmrg        in = in_normal;
28635c4bbdfSmrg        break;
28735c4bbdfSmrg    case glamor_program_alpha_ca_first:
28835c4bbdfSmrg        in = in_ca_source;
28935c4bbdfSmrg        break;
29035c4bbdfSmrg    case glamor_program_alpha_ca_second:
29135c4bbdfSmrg        in = in_ca_alpha;
29235c4bbdfSmrg        break;
29335c4bbdfSmrg    case glamor_program_alpha_dual_blend:
29435c4bbdfSmrg        in = in_ca_dual_blend;
29535c4bbdfSmrg        header = header_ca_dual_blend;
29635c4bbdfSmrg        break;
29735c4bbdfSmrg    default:
29835c4bbdfSmrg        FatalError("Bad composite IN type");
29935c4bbdfSmrg    }
30035c4bbdfSmrg
30135c4bbdfSmrg    XNFasprintf(&source,
30235c4bbdfSmrg                "%s"
30335c4bbdfSmrg                GLAMOR_DEFAULT_PRECISION
30435c4bbdfSmrg                "%s%s%s%s%s%s%s", header, repeat_define, relocate_texture,
30535c4bbdfSmrg                rel_sampler, source_fetch, mask_fetch, dest_swizzle, in);
30635c4bbdfSmrg
30735c4bbdfSmrg    prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, source);
30835c4bbdfSmrg    free(source);
30935c4bbdfSmrg
31035c4bbdfSmrg    return prog;
31135c4bbdfSmrg}
31235c4bbdfSmrg
31335c4bbdfSmrgstatic GLuint
31435c4bbdfSmrgglamor_create_composite_vs(struct shader_key *key)
31535c4bbdfSmrg{
31635c4bbdfSmrg    const char *main_opening =
31735c4bbdfSmrg        "attribute vec4 v_position;\n"
31835c4bbdfSmrg        "attribute vec4 v_texcoord0;\n"
31935c4bbdfSmrg        "attribute vec4 v_texcoord1;\n"
32035c4bbdfSmrg        "varying vec2 source_texture;\n"
32135c4bbdfSmrg        "varying vec2 mask_texture;\n"
32235c4bbdfSmrg        "void main()\n"
32335c4bbdfSmrg        "{\n"
32435c4bbdfSmrg        "	gl_Position = v_position;\n";
32535c4bbdfSmrg    const char *source_coords = "	source_texture = v_texcoord0.xy;\n";
32635c4bbdfSmrg    const char *mask_coords = "	mask_texture = v_texcoord1.xy;\n";
32735c4bbdfSmrg    const char *main_closing = "}\n";
32835c4bbdfSmrg    const char *source_coords_setup = "";
32935c4bbdfSmrg    const char *mask_coords_setup = "";
33035c4bbdfSmrg    char *source;
33135c4bbdfSmrg    GLuint prog;
33235c4bbdfSmrg
33335c4bbdfSmrg    if (key->source != SHADER_SOURCE_SOLID)
33435c4bbdfSmrg        source_coords_setup = source_coords;
33535c4bbdfSmrg
33635c4bbdfSmrg    if (key->mask != SHADER_MASK_NONE && key->mask != SHADER_MASK_SOLID)
33735c4bbdfSmrg        mask_coords_setup = mask_coords;
33835c4bbdfSmrg
33935c4bbdfSmrg    XNFasprintf(&source,
34035c4bbdfSmrg                "%s%s%s%s",
34135c4bbdfSmrg                main_opening,
34235c4bbdfSmrg                source_coords_setup, mask_coords_setup, main_closing);
34335c4bbdfSmrg
34435c4bbdfSmrg    prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, source);
34535c4bbdfSmrg    free(source);
34635c4bbdfSmrg
34735c4bbdfSmrg    return prog;
34835c4bbdfSmrg}
34935c4bbdfSmrg
35035c4bbdfSmrgstatic void
35135c4bbdfSmrgglamor_create_composite_shader(ScreenPtr screen, struct shader_key *key,
35235c4bbdfSmrg                               glamor_composite_shader *shader)
35335c4bbdfSmrg{
35435c4bbdfSmrg    GLuint vs, fs, prog;
35535c4bbdfSmrg    GLint source_sampler_uniform_location, mask_sampler_uniform_location;
35635c4bbdfSmrg    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
35735c4bbdfSmrg
35835c4bbdfSmrg    glamor_make_current(glamor_priv);
35935c4bbdfSmrg    vs = glamor_create_composite_vs(key);
36035c4bbdfSmrg    if (vs == 0)
36135c4bbdfSmrg        return;
36235c4bbdfSmrg    fs = glamor_create_composite_fs(key);
36335c4bbdfSmrg    if (fs == 0)
36435c4bbdfSmrg        return;
36535c4bbdfSmrg
36635c4bbdfSmrg    prog = glCreateProgram();
36735c4bbdfSmrg    glAttachShader(prog, vs);
36835c4bbdfSmrg    glAttachShader(prog, fs);
36935c4bbdfSmrg
37035c4bbdfSmrg    glBindAttribLocation(prog, GLAMOR_VERTEX_POS, "v_position");
37135c4bbdfSmrg    glBindAttribLocation(prog, GLAMOR_VERTEX_SOURCE, "v_texcoord0");
37235c4bbdfSmrg    glBindAttribLocation(prog, GLAMOR_VERTEX_MASK, "v_texcoord1");
37335c4bbdfSmrg
37435c4bbdfSmrg    if (key->in == glamor_program_alpha_dual_blend) {
37535c4bbdfSmrg        glBindFragDataLocationIndexed(prog, 0, 0, "color0");
37635c4bbdfSmrg        glBindFragDataLocationIndexed(prog, 0, 1, "color1");
37735c4bbdfSmrg    }
37835c4bbdfSmrg    glamor_link_glsl_prog(screen, prog, "composite");
37935c4bbdfSmrg
38035c4bbdfSmrg    shader->prog = prog;
38135c4bbdfSmrg
38235c4bbdfSmrg    glUseProgram(prog);
38335c4bbdfSmrg
38435c4bbdfSmrg    if (key->source == SHADER_SOURCE_SOLID) {
38535c4bbdfSmrg        shader->source_uniform_location = glGetUniformLocation(prog, "source");
38635c4bbdfSmrg    }
38735c4bbdfSmrg    else {
38835c4bbdfSmrg        source_sampler_uniform_location =
38935c4bbdfSmrg            glGetUniformLocation(prog, "source_sampler");
39035c4bbdfSmrg        glUniform1i(source_sampler_uniform_location, 0);
39135c4bbdfSmrg        shader->source_wh = glGetUniformLocation(prog, "source_wh");
39235c4bbdfSmrg        shader->source_repeat_mode =
39335c4bbdfSmrg            glGetUniformLocation(prog, "source_repeat_mode");
39435c4bbdfSmrg    }
39535c4bbdfSmrg
39635c4bbdfSmrg    if (key->mask != SHADER_MASK_NONE) {
39735c4bbdfSmrg        if (key->mask == SHADER_MASK_SOLID) {
39835c4bbdfSmrg            shader->mask_uniform_location = glGetUniformLocation(prog, "mask");
39935c4bbdfSmrg        }
40035c4bbdfSmrg        else {
40135c4bbdfSmrg            mask_sampler_uniform_location =
40235c4bbdfSmrg                glGetUniformLocation(prog, "mask_sampler");
40335c4bbdfSmrg            glUniform1i(mask_sampler_uniform_location, 1);
40435c4bbdfSmrg            shader->mask_wh = glGetUniformLocation(prog, "mask_wh");
40535c4bbdfSmrg            shader->mask_repeat_mode =
40635c4bbdfSmrg                glGetUniformLocation(prog, "mask_repeat_mode");
40735c4bbdfSmrg        }
40835c4bbdfSmrg    }
40935c4bbdfSmrg}
41035c4bbdfSmrg
41135c4bbdfSmrgstatic glamor_composite_shader *
41235c4bbdfSmrgglamor_lookup_composite_shader(ScreenPtr screen, struct
41335c4bbdfSmrg                               shader_key
41435c4bbdfSmrg                               *key)
41535c4bbdfSmrg{
41635c4bbdfSmrg    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
41735c4bbdfSmrg    glamor_composite_shader *shader;
41835c4bbdfSmrg
41935c4bbdfSmrg    shader = &glamor_priv->composite_shader[key->source][key->mask][key->in][key->dest_swizzle];
42035c4bbdfSmrg    if (shader->prog == 0)
42135c4bbdfSmrg        glamor_create_composite_shader(screen, key, shader);
42235c4bbdfSmrg
42335c4bbdfSmrg    return shader;
42435c4bbdfSmrg}
42535c4bbdfSmrg
42635c4bbdfSmrgstatic GLenum
42735c4bbdfSmrgglamor_translate_blend_alpha_to_red(GLenum blend)
42835c4bbdfSmrg{
42935c4bbdfSmrg    switch (blend) {
43035c4bbdfSmrg    case GL_SRC_ALPHA:
43135c4bbdfSmrg        return GL_SRC_COLOR;
43235c4bbdfSmrg    case GL_DST_ALPHA:
43335c4bbdfSmrg        return GL_DST_COLOR;
43435c4bbdfSmrg    case GL_ONE_MINUS_SRC_ALPHA:
43535c4bbdfSmrg        return GL_ONE_MINUS_SRC_COLOR;
43635c4bbdfSmrg    case GL_ONE_MINUS_DST_ALPHA:
43735c4bbdfSmrg        return GL_ONE_MINUS_DST_COLOR;
43835c4bbdfSmrg    default:
43935c4bbdfSmrg        return blend;
44035c4bbdfSmrg    }
44135c4bbdfSmrg}
44235c4bbdfSmrg
44335c4bbdfSmrgstatic Bool
44435c4bbdfSmrgglamor_set_composite_op(ScreenPtr screen,
44535c4bbdfSmrg                        CARD8 op, struct blendinfo *op_info_result,
44635c4bbdfSmrg                        PicturePtr dest, PicturePtr mask,
44735c4bbdfSmrg                        enum ca_state ca_state,
44835c4bbdfSmrg                        struct shader_key *key)
44935c4bbdfSmrg{
45035c4bbdfSmrg    GLenum source_blend, dest_blend;
45135c4bbdfSmrg    struct blendinfo *op_info;
45235c4bbdfSmrg
45335c4bbdfSmrg    if (op >= ARRAY_SIZE(composite_op_info)) {
45435c4bbdfSmrg        glamor_fallback("unsupported render op %d \n", op);
45535c4bbdfSmrg        return GL_FALSE;
45635c4bbdfSmrg    }
45735c4bbdfSmrg
45835c4bbdfSmrg    op_info = &composite_op_info[op];
45935c4bbdfSmrg
46035c4bbdfSmrg    source_blend = op_info->source_blend;
46135c4bbdfSmrg    dest_blend = op_info->dest_blend;
46235c4bbdfSmrg
46335c4bbdfSmrg    /* If there's no dst alpha channel, adjust the blend op so that we'll treat
46435c4bbdfSmrg     * it as always 1.
46535c4bbdfSmrg     */
46635c4bbdfSmrg    if (PICT_FORMAT_A(dest->format) == 0 && op_info->dest_alpha) {
46735c4bbdfSmrg        if (source_blend == GL_DST_ALPHA)
46835c4bbdfSmrg            source_blend = GL_ONE;
46935c4bbdfSmrg        else if (source_blend == GL_ONE_MINUS_DST_ALPHA)
47035c4bbdfSmrg            source_blend = GL_ZERO;
47135c4bbdfSmrg    }
47235c4bbdfSmrg
47335c4bbdfSmrg    /* Set up the source alpha value for blending in component alpha mode. */
47435c4bbdfSmrg    if (ca_state == CA_DUAL_BLEND) {
47535c4bbdfSmrg        switch (dest_blend) {
47635c4bbdfSmrg        case GL_SRC_ALPHA:
47735c4bbdfSmrg            dest_blend = GL_SRC1_COLOR;
47835c4bbdfSmrg            break;
47935c4bbdfSmrg        case GL_ONE_MINUS_SRC_ALPHA:
48035c4bbdfSmrg            dest_blend = GL_ONE_MINUS_SRC1_COLOR;
48135c4bbdfSmrg            break;
48235c4bbdfSmrg        }
48335c4bbdfSmrg    } else if (mask && mask->componentAlpha
48435c4bbdfSmrg               && PICT_FORMAT_RGB(mask->format) != 0 && op_info->source_alpha) {
48535c4bbdfSmrg        switch (dest_blend) {
48635c4bbdfSmrg        case GL_SRC_ALPHA:
48735c4bbdfSmrg            dest_blend = GL_SRC_COLOR;
48835c4bbdfSmrg            break;
48935c4bbdfSmrg        case GL_ONE_MINUS_SRC_ALPHA:
49035c4bbdfSmrg            dest_blend = GL_ONE_MINUS_SRC_COLOR;
49135c4bbdfSmrg            break;
49235c4bbdfSmrg        }
49335c4bbdfSmrg    }
49435c4bbdfSmrg
49535c4bbdfSmrg    /* If we're outputting our alpha to the red channel, then any
49635c4bbdfSmrg     * reads of alpha for blending need to come from the red channel.
49735c4bbdfSmrg     */
49835c4bbdfSmrg    if (key->dest_swizzle == SHADER_DEST_SWIZZLE_ALPHA_TO_RED) {
49935c4bbdfSmrg        source_blend = glamor_translate_blend_alpha_to_red(source_blend);
50035c4bbdfSmrg        dest_blend = glamor_translate_blend_alpha_to_red(dest_blend);
50135c4bbdfSmrg    }
50235c4bbdfSmrg
50335c4bbdfSmrg    op_info_result->source_blend = source_blend;
50435c4bbdfSmrg    op_info_result->dest_blend = dest_blend;
50535c4bbdfSmrg    op_info_result->source_alpha = op_info->source_alpha;
50635c4bbdfSmrg    op_info_result->dest_alpha = op_info->dest_alpha;
50735c4bbdfSmrg
50835c4bbdfSmrg    return TRUE;
50935c4bbdfSmrg}
51035c4bbdfSmrg
51135c4bbdfSmrgstatic void
51235c4bbdfSmrgglamor_set_composite_texture(glamor_screen_private *glamor_priv, int unit,
51335c4bbdfSmrg                             PicturePtr picture,
51435c4bbdfSmrg                             PixmapPtr pixmap,
51535c4bbdfSmrg                             GLuint wh_location, GLuint repeat_location,
51635c4bbdfSmrg                             glamor_pixmap_private *dest_priv)
51735c4bbdfSmrg{
51835c4bbdfSmrg    glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
51935c4bbdfSmrg    glamor_pixmap_fbo *fbo = pixmap_priv->fbo;
52035c4bbdfSmrg    float wh[4];
52135c4bbdfSmrg    int repeat_type;
52235c4bbdfSmrg
52335c4bbdfSmrg    glamor_make_current(glamor_priv);
52435c4bbdfSmrg
52535c4bbdfSmrg    /* The red channel swizzling doesn't depend on whether we're using
52635c4bbdfSmrg     * 'fbo' as source or mask as we must have the same answer in case
52735c4bbdfSmrg     * the same fbo is being used for both. That means the mask
52835c4bbdfSmrg     * channel will sometimes get red bits in the R channel, and
52935c4bbdfSmrg     * sometimes get zero bits in the R channel, which is harmless.
53035c4bbdfSmrg     */
53135c4bbdfSmrg    glamor_bind_texture(glamor_priv, GL_TEXTURE0 + unit, fbo,
532ed6184dfSmrg                        dest_priv->fbo->is_red);
53335c4bbdfSmrg    repeat_type = picture->repeatType;
53435c4bbdfSmrg    switch (picture->repeatType) {
53535c4bbdfSmrg    case RepeatNone:
5361b5d61b8Smrg        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
5371b5d61b8Smrg        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
53835c4bbdfSmrg        break;
53935c4bbdfSmrg    case RepeatNormal:
54035c4bbdfSmrg        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
54135c4bbdfSmrg        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
54235c4bbdfSmrg        break;
54335c4bbdfSmrg    case RepeatPad:
54435c4bbdfSmrg        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
54535c4bbdfSmrg        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
54635c4bbdfSmrg        break;
54735c4bbdfSmrg    case RepeatReflect:
54835c4bbdfSmrg        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
54935c4bbdfSmrg        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
55035c4bbdfSmrg        break;
55135c4bbdfSmrg    }
55235c4bbdfSmrg
55335c4bbdfSmrg    switch (picture->filter) {
55435c4bbdfSmrg    default:
55535c4bbdfSmrg    case PictFilterFast:
55635c4bbdfSmrg    case PictFilterNearest:
55735c4bbdfSmrg        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
55835c4bbdfSmrg        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
55935c4bbdfSmrg        break;
56035c4bbdfSmrg    case PictFilterGood:
56135c4bbdfSmrg    case PictFilterBest:
56235c4bbdfSmrg    case PictFilterBilinear:
56335c4bbdfSmrg        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
56435c4bbdfSmrg        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
56535c4bbdfSmrg        break;
56635c4bbdfSmrg    }
56735c4bbdfSmrg
5681b5d61b8Smrg    /* Handle RepeatNone in the shader when the source is missing the
5691b5d61b8Smrg     * alpha channel, as GL will return an alpha for 1 if the texture
5701b5d61b8Smrg     * is RGB (no alpha), which we use for 16bpp textures.
5711b5d61b8Smrg     */
57235c4bbdfSmrg    if (glamor_pixmap_priv_is_large(pixmap_priv) ||
5731b5d61b8Smrg        (!PICT_FORMAT_A(picture->format) &&
57435c4bbdfSmrg         repeat_type == RepeatNone && picture->transform)) {
57535c4bbdfSmrg        glamor_pixmap_fbo_fix_wh_ratio(wh, pixmap, pixmap_priv);
57635c4bbdfSmrg        glUniform4fv(wh_location, 1, wh);
57735c4bbdfSmrg
57835c4bbdfSmrg        repeat_type += RepeatFix;
57935c4bbdfSmrg    }
58035c4bbdfSmrg
58135c4bbdfSmrg    glUniform1i(repeat_location, repeat_type);
58235c4bbdfSmrg}
58335c4bbdfSmrg
58435c4bbdfSmrgstatic void
58535c4bbdfSmrgglamor_set_composite_solid(float *color, GLint uniform_location)
58635c4bbdfSmrg{
58735c4bbdfSmrg    glUniform4fv(uniform_location, 1, color);
58835c4bbdfSmrg}
58935c4bbdfSmrg
59035c4bbdfSmrgstatic char
59135c4bbdfSmrgglamor_get_picture_location(PicturePtr picture)
59235c4bbdfSmrg{
59335c4bbdfSmrg    if (picture == NULL)
59435c4bbdfSmrg        return ' ';
59535c4bbdfSmrg
59635c4bbdfSmrg    if (picture->pDrawable == NULL) {
59735c4bbdfSmrg        switch (picture->pSourcePict->type) {
59835c4bbdfSmrg        case SourcePictTypeSolidFill:
59935c4bbdfSmrg            return 'c';
60035c4bbdfSmrg        case SourcePictTypeLinear:
60135c4bbdfSmrg            return 'l';
60235c4bbdfSmrg        case SourcePictTypeRadial:
60335c4bbdfSmrg            return 'r';
60435c4bbdfSmrg        default:
60535c4bbdfSmrg            return '?';
60635c4bbdfSmrg        }
60735c4bbdfSmrg    }
60835c4bbdfSmrg    return glamor_get_drawable_location(picture->pDrawable);
60935c4bbdfSmrg}
61035c4bbdfSmrg
61135c4bbdfSmrgstatic void *
61235c4bbdfSmrgglamor_setup_composite_vbo(ScreenPtr screen, int n_verts)
61335c4bbdfSmrg{
61435c4bbdfSmrg    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
61535c4bbdfSmrg    int vert_size;
61635c4bbdfSmrg    char *vbo_offset;
61735c4bbdfSmrg    float *vb;
61835c4bbdfSmrg
61935c4bbdfSmrg    glamor_priv->render_nr_quads = 0;
62035c4bbdfSmrg    glamor_priv->vb_stride = 2 * sizeof(float);
62135c4bbdfSmrg    if (glamor_priv->has_source_coords)
62235c4bbdfSmrg        glamor_priv->vb_stride += 2 * sizeof(float);
62335c4bbdfSmrg    if (glamor_priv->has_mask_coords)
62435c4bbdfSmrg        glamor_priv->vb_stride += 2 * sizeof(float);
62535c4bbdfSmrg
62635c4bbdfSmrg    vert_size = n_verts * glamor_priv->vb_stride;
62735c4bbdfSmrg
62835c4bbdfSmrg    glamor_make_current(glamor_priv);
62935c4bbdfSmrg    vb = glamor_get_vbo_space(screen, vert_size, &vbo_offset);
63035c4bbdfSmrg
63135c4bbdfSmrg    glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT, GL_FALSE,
63235c4bbdfSmrg                          glamor_priv->vb_stride, vbo_offset);
63335c4bbdfSmrg    glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
63435c4bbdfSmrg
63535c4bbdfSmrg    if (glamor_priv->has_source_coords) {
63635c4bbdfSmrg        glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2,
63735c4bbdfSmrg                              GL_FLOAT, GL_FALSE,
63835c4bbdfSmrg                              glamor_priv->vb_stride,
63935c4bbdfSmrg                              vbo_offset + 2 * sizeof(float));
64035c4bbdfSmrg        glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
64135c4bbdfSmrg    }
64235c4bbdfSmrg
64335c4bbdfSmrg    if (glamor_priv->has_mask_coords) {
64435c4bbdfSmrg        glVertexAttribPointer(GLAMOR_VERTEX_MASK, 2, GL_FLOAT, GL_FALSE,
64535c4bbdfSmrg                              glamor_priv->vb_stride,
64635c4bbdfSmrg                              vbo_offset + (glamor_priv->has_source_coords ?
64735c4bbdfSmrg                                            4 : 2) * sizeof(float));
64835c4bbdfSmrg        glEnableVertexAttribArray(GLAMOR_VERTEX_MASK);
64935c4bbdfSmrg    }
65035c4bbdfSmrg
65135c4bbdfSmrg    return vb;
65235c4bbdfSmrg}
65335c4bbdfSmrg
65435c4bbdfSmrgstatic void
65535c4bbdfSmrgglamor_flush_composite_rects(ScreenPtr screen)
65635c4bbdfSmrg{
65735c4bbdfSmrg    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
65835c4bbdfSmrg
65935c4bbdfSmrg    glamor_make_current(glamor_priv);
66035c4bbdfSmrg
66135c4bbdfSmrg    if (!glamor_priv->render_nr_quads)
66235c4bbdfSmrg        return;
66335c4bbdfSmrg
66435c4bbdfSmrg    glamor_glDrawArrays_GL_QUADS(glamor_priv, glamor_priv->render_nr_quads);
66535c4bbdfSmrg}
66635c4bbdfSmrg
66735c4bbdfSmrgstatic const int pict_format_combine_tab[][3] = {
66835c4bbdfSmrg    {PICT_TYPE_ARGB, PICT_TYPE_A, PICT_TYPE_ARGB},
66935c4bbdfSmrg    {PICT_TYPE_ABGR, PICT_TYPE_A, PICT_TYPE_ABGR},
67035c4bbdfSmrg};
67135c4bbdfSmrg
67235c4bbdfSmrgstatic Bool
67335c4bbdfSmrgcombine_pict_format(PictFormatShort * des, const PictFormatShort src,
67435c4bbdfSmrg                    const PictFormatShort mask, glamor_program_alpha in_ca)
67535c4bbdfSmrg{
67635c4bbdfSmrg    PictFormatShort new_vis;
67735c4bbdfSmrg    int src_type, mask_type, src_bpp;
67835c4bbdfSmrg    int i;
67935c4bbdfSmrg
68035c4bbdfSmrg    if (src == mask) {
68135c4bbdfSmrg        *des = src;
68235c4bbdfSmrg        return TRUE;
68335c4bbdfSmrg    }
68435c4bbdfSmrg    src_bpp = PICT_FORMAT_BPP(src);
68535c4bbdfSmrg
68635c4bbdfSmrg    assert(src_bpp == PICT_FORMAT_BPP(mask));
68735c4bbdfSmrg
68835c4bbdfSmrg    new_vis = PICT_FORMAT_VIS(src) | PICT_FORMAT_VIS(mask);
68935c4bbdfSmrg
69035c4bbdfSmrg    switch (in_ca) {
69135c4bbdfSmrg    case glamor_program_alpha_normal:
69235c4bbdfSmrg        src_type = PICT_FORMAT_TYPE(src);
69335c4bbdfSmrg        mask_type = PICT_TYPE_A;
69435c4bbdfSmrg        break;
69535c4bbdfSmrg    case glamor_program_alpha_ca_first:
69635c4bbdfSmrg        src_type = PICT_FORMAT_TYPE(src);
69735c4bbdfSmrg        mask_type = PICT_FORMAT_TYPE(mask);
69835c4bbdfSmrg        break;
69935c4bbdfSmrg    case glamor_program_alpha_ca_second:
70035c4bbdfSmrg        src_type = PICT_TYPE_A;
70135c4bbdfSmrg        mask_type = PICT_FORMAT_TYPE(mask);
70235c4bbdfSmrg        break;
70335c4bbdfSmrg    case glamor_program_alpha_dual_blend:
70435c4bbdfSmrg        src_type = PICT_FORMAT_TYPE(src);
70535c4bbdfSmrg        mask_type = PICT_FORMAT_TYPE(mask);
70635c4bbdfSmrg        break;
70735c4bbdfSmrg    default:
70835c4bbdfSmrg        return FALSE;
70935c4bbdfSmrg    }
71035c4bbdfSmrg
71135c4bbdfSmrg    if (src_type == mask_type) {
71235c4bbdfSmrg        *des = PICT_VISFORMAT(src_bpp, src_type, new_vis);
71335c4bbdfSmrg        return TRUE;
71435c4bbdfSmrg    }
71535c4bbdfSmrg
71635c4bbdfSmrg    for (i = 0; i < ARRAY_SIZE(pict_format_combine_tab); i++) {
71735c4bbdfSmrg        if ((src_type == pict_format_combine_tab[i][0]
71835c4bbdfSmrg             && mask_type == pict_format_combine_tab[i][1])
71935c4bbdfSmrg            || (src_type == pict_format_combine_tab[i][1]
72035c4bbdfSmrg                && mask_type == pict_format_combine_tab[i][0])) {
72135c4bbdfSmrg            *des = PICT_VISFORMAT(src_bpp, pict_format_combine_tab[i]
72235c4bbdfSmrg                                  [2], new_vis);
72335c4bbdfSmrg            return TRUE;
72435c4bbdfSmrg        }
72535c4bbdfSmrg    }
72635c4bbdfSmrg    return FALSE;
72735c4bbdfSmrg}
72835c4bbdfSmrg
72935c4bbdfSmrgstatic void
73035c4bbdfSmrgglamor_set_normalize_tcoords_generic(PixmapPtr pixmap,
73135c4bbdfSmrg                                     glamor_pixmap_private *priv,
73235c4bbdfSmrg                                     int repeat_type,
73335c4bbdfSmrg                                     float *matrix,
73435c4bbdfSmrg                                     float xscale, float yscale,
73535c4bbdfSmrg                                     int x1, int y1, int x2, int y2,
73635c4bbdfSmrg                                     float *texcoords,
73735c4bbdfSmrg                                     int stride)
73835c4bbdfSmrg{
73935c4bbdfSmrg    if (!matrix && repeat_type == RepeatNone)
74035c4bbdfSmrg        glamor_set_normalize_tcoords_ext(priv, xscale, yscale,
74135c4bbdfSmrg                                         x1, y1,
74235c4bbdfSmrg                                         x2, y2, texcoords, stride);
74335c4bbdfSmrg    else if (matrix && repeat_type == RepeatNone)
74435c4bbdfSmrg        glamor_set_transformed_normalize_tcoords_ext(priv, matrix, xscale,
74535c4bbdfSmrg                                                     yscale, x1, y1,
74635c4bbdfSmrg                                                     x2, y2,
74735c4bbdfSmrg                                                     texcoords, stride);
74835c4bbdfSmrg    else if (!matrix && repeat_type != RepeatNone)
74935c4bbdfSmrg        glamor_set_repeat_normalize_tcoords_ext(pixmap, priv, repeat_type,
75035c4bbdfSmrg                                                xscale, yscale,
75135c4bbdfSmrg                                                x1, y1,
75235c4bbdfSmrg                                                x2, y2,
75335c4bbdfSmrg                                                texcoords, stride);
75435c4bbdfSmrg    else if (matrix && repeat_type != RepeatNone)
75535c4bbdfSmrg        glamor_set_repeat_transformed_normalize_tcoords_ext(pixmap, priv, repeat_type,
75635c4bbdfSmrg                                                            matrix, xscale,
75735c4bbdfSmrg                                                            yscale, x1, y1, x2,
75835c4bbdfSmrg                                                            y2,
75935c4bbdfSmrg                                                            texcoords, stride);
76035c4bbdfSmrg}
76135c4bbdfSmrg
76235c4bbdfSmrg/**
76335c4bbdfSmrg * Returns whether the general composite path supports this picture
76435c4bbdfSmrg * format for a pixmap that is permanently stored in an FBO (as
7651b5d61b8Smrg * opposed to the dynamic upload path).
76635c4bbdfSmrg *
76735c4bbdfSmrg * We could support many more formats by using GL_ARB_texture_view to
76835c4bbdfSmrg * parse the same bits as different formats.  For now, we only support
769e23ec014Smrg * tweaking whether we sample the alpha bits, or just force them to 1.
77035c4bbdfSmrg */
77135c4bbdfSmrgstatic Bool
772e23ec014Smrgglamor_render_format_is_supported(PicturePtr picture)
77335c4bbdfSmrg{
774e23ec014Smrg    PictFormatShort storage_format;
775ed6184dfSmrg    glamor_screen_private *glamor_priv;
776ed6184dfSmrg    struct glamor_format *f;
777e23ec014Smrg
778e23ec014Smrg    /* Source-only pictures should always work */
779e23ec014Smrg    if (!picture->pDrawable)
780e23ec014Smrg        return TRUE;
781e23ec014Smrg
782ed6184dfSmrg    glamor_priv = glamor_get_screen_private(picture->pDrawable->pScreen);
783ed6184dfSmrg    f = &glamor_priv->formats[picture->pDrawable->depth];
784ed6184dfSmrg
785ed6184dfSmrg    if (!f->rendering_supported)
786ed6184dfSmrg        return FALSE;
787ed6184dfSmrg
788ed6184dfSmrg    storage_format = f->render_format;
789e23ec014Smrg
790e23ec014Smrg    switch (picture->format) {
791ed6184dfSmrg    case PICT_a2r10g10b10:
792e23ec014Smrg        return storage_format == PICT_x2r10g10b10;
79335c4bbdfSmrg    case PICT_a8r8g8b8:
79435c4bbdfSmrg    case PICT_x8r8g8b8:
795e23ec014Smrg        return storage_format == PICT_a8r8g8b8 || storage_format == PICT_x8r8g8b8;
796ed6184dfSmrg    case PICT_a1r5g5b5:
797ed6184dfSmrg        return storage_format == PICT_x1r5g5b5;
79835c4bbdfSmrg    default:
799ed6184dfSmrg        return picture->format == storage_format;
80035c4bbdfSmrg    }
80135c4bbdfSmrg}
80235c4bbdfSmrg
80335c4bbdfSmrgstatic Bool
80435c4bbdfSmrgglamor_composite_choose_shader(CARD8 op,
80535c4bbdfSmrg                               PicturePtr source,
80635c4bbdfSmrg                               PicturePtr mask,
80735c4bbdfSmrg                               PicturePtr dest,
80835c4bbdfSmrg                               PixmapPtr source_pixmap,
80935c4bbdfSmrg                               PixmapPtr mask_pixmap,
81035c4bbdfSmrg                               PixmapPtr dest_pixmap,
81135c4bbdfSmrg                               glamor_pixmap_private *source_pixmap_priv,
81235c4bbdfSmrg                               glamor_pixmap_private *mask_pixmap_priv,
81335c4bbdfSmrg                               glamor_pixmap_private *dest_pixmap_priv,
81435c4bbdfSmrg                               struct shader_key *s_key,
81535c4bbdfSmrg                               glamor_composite_shader ** shader,
81635c4bbdfSmrg                               struct blendinfo *op_info,
81735c4bbdfSmrg                               PictFormatShort *psaved_source_format,
81835c4bbdfSmrg                               enum ca_state ca_state)
81935c4bbdfSmrg{
82035c4bbdfSmrg    ScreenPtr screen = dest->pDrawable->pScreen;
82135c4bbdfSmrg    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
8221b5d61b8Smrg    Bool source_needs_upload = FALSE;
8231b5d61b8Smrg    Bool mask_needs_upload = FALSE;
82435c4bbdfSmrg    PictFormatShort saved_source_format = 0;
82535c4bbdfSmrg    struct shader_key key;
82635c4bbdfSmrg    GLfloat source_solid_color[4];
82735c4bbdfSmrg    GLfloat mask_solid_color[4];
82835c4bbdfSmrg    Bool ret = FALSE;
82935c4bbdfSmrg
83035c4bbdfSmrg    if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dest_pixmap_priv)) {
83135c4bbdfSmrg        glamor_fallback("dest has no fbo.\n");
83235c4bbdfSmrg        goto fail;
83335c4bbdfSmrg    }
83435c4bbdfSmrg
835e23ec014Smrg    if (!glamor_render_format_is_supported(dest)) {
83635c4bbdfSmrg        glamor_fallback("Unsupported dest picture format.\n");
83735c4bbdfSmrg        goto fail;
83835c4bbdfSmrg    }
83935c4bbdfSmrg
84035c4bbdfSmrg    memset(&key, 0, sizeof(key));
84135c4bbdfSmrg    if (!source) {
84235c4bbdfSmrg        key.source = SHADER_SOURCE_SOLID;
84335c4bbdfSmrg        source_solid_color[0] = 0.0;
84435c4bbdfSmrg        source_solid_color[1] = 0.0;
84535c4bbdfSmrg        source_solid_color[2] = 0.0;
84635c4bbdfSmrg        source_solid_color[3] = 0.0;
84735c4bbdfSmrg    }
84835c4bbdfSmrg    else if (!source->pDrawable) {
8491b5d61b8Smrg        SourcePictPtr sp = source->pSourcePict;
8501b5d61b8Smrg        if (sp->type == SourcePictTypeSolidFill) {
85135c4bbdfSmrg            key.source = SHADER_SOURCE_SOLID;
8521b5d61b8Smrg            glamor_get_rgba_from_color(&sp->solidFill.fullcolor,
8531b5d61b8Smrg                                       source_solid_color);
85435c4bbdfSmrg        }
85535c4bbdfSmrg        else
85635c4bbdfSmrg            goto fail;
85735c4bbdfSmrg    }
85835c4bbdfSmrg    else {
85935c4bbdfSmrg        if (PICT_FORMAT_A(source->format))
86035c4bbdfSmrg            key.source = SHADER_SOURCE_TEXTURE_ALPHA;
86135c4bbdfSmrg        else
86235c4bbdfSmrg            key.source = SHADER_SOURCE_TEXTURE;
86335c4bbdfSmrg    }
86435c4bbdfSmrg
86535c4bbdfSmrg    if (mask) {
86635c4bbdfSmrg        if (!mask->pDrawable) {
8671b5d61b8Smrg            SourcePictPtr sp = mask->pSourcePict;
8681b5d61b8Smrg            if (sp->type == SourcePictTypeSolidFill) {
86935c4bbdfSmrg                key.mask = SHADER_MASK_SOLID;
8701b5d61b8Smrg                glamor_get_rgba_from_color(&sp->solidFill.fullcolor,
8711b5d61b8Smrg                                           mask_solid_color);
87235c4bbdfSmrg            }
87335c4bbdfSmrg            else
87435c4bbdfSmrg                goto fail;
87535c4bbdfSmrg        }
87635c4bbdfSmrg        else {
8771b5d61b8Smrg            if (PICT_FORMAT_A(mask->format))
8781b5d61b8Smrg                key.mask = SHADER_MASK_TEXTURE_ALPHA;
8791b5d61b8Smrg            else
8801b5d61b8Smrg                key.mask = SHADER_MASK_TEXTURE;
88135c4bbdfSmrg        }
88235c4bbdfSmrg
88335c4bbdfSmrg        if (!mask->componentAlpha) {
88435c4bbdfSmrg            key.in = glamor_program_alpha_normal;
88535c4bbdfSmrg        }
88635c4bbdfSmrg        else {
88735c4bbdfSmrg            if (op == PictOpClear)
88835c4bbdfSmrg                key.mask = SHADER_MASK_NONE;
88935c4bbdfSmrg            else if (glamor_priv->has_dual_blend)
89035c4bbdfSmrg                key.in = glamor_program_alpha_dual_blend;
89135c4bbdfSmrg            else if (op == PictOpSrc || op == PictOpAdd
89235c4bbdfSmrg                     || op == PictOpIn || op == PictOpOut
89335c4bbdfSmrg                     || op == PictOpOverReverse)
89435c4bbdfSmrg                key.in = glamor_program_alpha_ca_second;
89535c4bbdfSmrg            else if (op == PictOpOutReverse || op == PictOpInReverse) {
89635c4bbdfSmrg                key.in = glamor_program_alpha_ca_first;
89735c4bbdfSmrg            }
89835c4bbdfSmrg            else {
89935c4bbdfSmrg                glamor_fallback("Unsupported component alpha op: %d\n", op);
90035c4bbdfSmrg                goto fail;
90135c4bbdfSmrg            }
90235c4bbdfSmrg        }
90335c4bbdfSmrg    }
90435c4bbdfSmrg    else {
90535c4bbdfSmrg        key.mask = SHADER_MASK_NONE;
90635c4bbdfSmrg    }
90735c4bbdfSmrg
90835c4bbdfSmrg    if (dest_pixmap->drawable.bitsPerPixel <= 8 &&
909ed6184dfSmrg        glamor_priv->formats[8].format == GL_RED) {
91035c4bbdfSmrg        key.dest_swizzle = SHADER_DEST_SWIZZLE_ALPHA_TO_RED;
91135c4bbdfSmrg    } else {
91235c4bbdfSmrg        key.dest_swizzle = SHADER_DEST_SWIZZLE_DEFAULT;
91335c4bbdfSmrg    }
91435c4bbdfSmrg
91535c4bbdfSmrg    if (source && source->alphaMap) {
91635c4bbdfSmrg        glamor_fallback("source alphaMap\n");
91735c4bbdfSmrg        goto fail;
91835c4bbdfSmrg    }
91935c4bbdfSmrg    if (mask && mask->alphaMap) {
92035c4bbdfSmrg        glamor_fallback("mask alphaMap\n");
92135c4bbdfSmrg        goto fail;
92235c4bbdfSmrg    }
92335c4bbdfSmrg
92435c4bbdfSmrg    if (key.source == SHADER_SOURCE_TEXTURE ||
92535c4bbdfSmrg        key.source == SHADER_SOURCE_TEXTURE_ALPHA) {
92635c4bbdfSmrg        if (source_pixmap == dest_pixmap) {
92735c4bbdfSmrg            /* XXX source and the dest share the same texture.
92835c4bbdfSmrg             * Does it need special handle? */
92935c4bbdfSmrg            glamor_fallback("source == dest\n");
93035c4bbdfSmrg        }
93135c4bbdfSmrg        if (source_pixmap_priv->gl_fbo == GLAMOR_FBO_UNATTACHED) {
9321b5d61b8Smrg            source_needs_upload = TRUE;
93335c4bbdfSmrg        }
93435c4bbdfSmrg    }
93535c4bbdfSmrg
93635c4bbdfSmrg    if (key.mask == SHADER_MASK_TEXTURE ||
93735c4bbdfSmrg        key.mask == SHADER_MASK_TEXTURE_ALPHA) {
93835c4bbdfSmrg        if (mask_pixmap == dest_pixmap) {
93935c4bbdfSmrg            glamor_fallback("mask == dest\n");
94035c4bbdfSmrg            goto fail;
94135c4bbdfSmrg        }
94235c4bbdfSmrg        if (mask_pixmap_priv->gl_fbo == GLAMOR_FBO_UNATTACHED) {
9431b5d61b8Smrg            mask_needs_upload = TRUE;
94435c4bbdfSmrg        }
94535c4bbdfSmrg    }
94635c4bbdfSmrg
9471b5d61b8Smrg    if (source_needs_upload && mask_needs_upload
94835c4bbdfSmrg        && source_pixmap == mask_pixmap) {
94935c4bbdfSmrg
95035c4bbdfSmrg        if (source->format != mask->format) {
95135c4bbdfSmrg            saved_source_format = source->format;
95235c4bbdfSmrg
95335c4bbdfSmrg            if (!combine_pict_format(&source->format, source->format,
95435c4bbdfSmrg                                     mask->format, key.in)) {
95535c4bbdfSmrg                glamor_fallback("combine source %x mask %x failed.\n",
95635c4bbdfSmrg                                source->format, mask->format);
95735c4bbdfSmrg                goto fail;
95835c4bbdfSmrg            }
95935c4bbdfSmrg
96035c4bbdfSmrg            /* XXX
96135c4bbdfSmrg             * By default, glamor_upload_picture_to_texture will wire alpha to 1
96235c4bbdfSmrg             * if one picture doesn't have alpha. So we don't do that again in
96335c4bbdfSmrg             * rendering function. But here is a special case, as source and
96435c4bbdfSmrg             * mask share the same texture but may have different formats. For
96535c4bbdfSmrg             * example, source doesn't have alpha, but mask has alpha. Then the
96635c4bbdfSmrg             * texture will have the alpha value for the mask. And will not wire
96735c4bbdfSmrg             * to 1 for the source. In this case, we have to use different shader
96835c4bbdfSmrg             * to wire the source's alpha to 1.
96935c4bbdfSmrg             *
97035c4bbdfSmrg             * But this may cause a potential problem if the source's repeat mode
97135c4bbdfSmrg             * is REPEAT_NONE, and if the source is smaller than the dest, then
97235c4bbdfSmrg             * for the region not covered by the source may be painted incorrectly.
97335c4bbdfSmrg             * because we wire the alpha to 1.
97435c4bbdfSmrg             *
97535c4bbdfSmrg             **/
97635c4bbdfSmrg            if (!PICT_FORMAT_A(saved_source_format)
97735c4bbdfSmrg                && PICT_FORMAT_A(mask->format))
97835c4bbdfSmrg                key.source = SHADER_SOURCE_TEXTURE;
97935c4bbdfSmrg
98035c4bbdfSmrg            if (!PICT_FORMAT_A(mask->format)
98135c4bbdfSmrg                && PICT_FORMAT_A(saved_source_format))
98235c4bbdfSmrg                key.mask = SHADER_MASK_TEXTURE;
98335c4bbdfSmrg        }
98435c4bbdfSmrg
9851b5d61b8Smrg        if (!glamor_upload_picture_to_texture(source)) {
98635c4bbdfSmrg            glamor_fallback("Failed to upload source texture.\n");
98735c4bbdfSmrg            goto fail;
98835c4bbdfSmrg        }
9891b5d61b8Smrg        mask_needs_upload = FALSE;
99035c4bbdfSmrg    }
99135c4bbdfSmrg    else {
9921b5d61b8Smrg        if (source_needs_upload) {
9931b5d61b8Smrg            if (!glamor_upload_picture_to_texture(source)) {
99435c4bbdfSmrg                glamor_fallback("Failed to upload source texture.\n");
99535c4bbdfSmrg                goto fail;
99635c4bbdfSmrg            }
99735c4bbdfSmrg        } else {
998e23ec014Smrg            if (source && !glamor_render_format_is_supported(source)) {
99935c4bbdfSmrg                glamor_fallback("Unsupported source picture format.\n");
100035c4bbdfSmrg                goto fail;
100135c4bbdfSmrg            }
100235c4bbdfSmrg        }
100335c4bbdfSmrg
10041b5d61b8Smrg        if (mask_needs_upload) {
10051b5d61b8Smrg            if (!glamor_upload_picture_to_texture(mask)) {
100635c4bbdfSmrg                glamor_fallback("Failed to upload mask texture.\n");
100735c4bbdfSmrg                goto fail;
100835c4bbdfSmrg            }
100935c4bbdfSmrg        } else if (mask) {
1010e23ec014Smrg            if (!glamor_render_format_is_supported(mask)) {
101135c4bbdfSmrg                glamor_fallback("Unsupported mask picture format.\n");
101235c4bbdfSmrg                goto fail;
101335c4bbdfSmrg            }
101435c4bbdfSmrg        }
101535c4bbdfSmrg    }
101635c4bbdfSmrg
101735c4bbdfSmrg    /* If the source and mask are two differently-formatted views of
101835c4bbdfSmrg     * the same pixmap bits, and the pixmap was already uploaded (so
101935c4bbdfSmrg     * the dynamic code above doesn't apply), then fall back to
102035c4bbdfSmrg     * software.  We should use texture views to fix this properly.
102135c4bbdfSmrg     */
102235c4bbdfSmrg    if (source_pixmap && source_pixmap == mask_pixmap &&
102335c4bbdfSmrg        source->format != mask->format) {
102435c4bbdfSmrg        goto fail;
102535c4bbdfSmrg    }
102635c4bbdfSmrg
102735c4bbdfSmrg    if (!glamor_set_composite_op(screen, op, op_info, dest, mask, ca_state,
102835c4bbdfSmrg                                 &key)) {
102935c4bbdfSmrg        goto fail;
103035c4bbdfSmrg    }
103135c4bbdfSmrg
103235c4bbdfSmrg    *shader = glamor_lookup_composite_shader(screen, &key);
103335c4bbdfSmrg    if ((*shader)->prog == 0) {
103435c4bbdfSmrg        glamor_fallback("no shader program for this render acccel mode\n");
103535c4bbdfSmrg        goto fail;
103635c4bbdfSmrg    }
103735c4bbdfSmrg
103835c4bbdfSmrg    if (key.source == SHADER_SOURCE_SOLID)
103935c4bbdfSmrg        memcpy(&(*shader)->source_solid_color[0],
104035c4bbdfSmrg               source_solid_color, 4 * sizeof(float));
104135c4bbdfSmrg    else {
104235c4bbdfSmrg        (*shader)->source_pixmap = source_pixmap;
104335c4bbdfSmrg        (*shader)->source = source;
104435c4bbdfSmrg    }
104535c4bbdfSmrg
104635c4bbdfSmrg    if (key.mask == SHADER_MASK_SOLID)
104735c4bbdfSmrg        memcpy(&(*shader)->mask_solid_color[0],
104835c4bbdfSmrg               mask_solid_color, 4 * sizeof(float));
104935c4bbdfSmrg    else {
105035c4bbdfSmrg        (*shader)->mask_pixmap = mask_pixmap;
105135c4bbdfSmrg        (*shader)->mask = mask;
105235c4bbdfSmrg    }
105335c4bbdfSmrg
105435c4bbdfSmrg    ret = TRUE;
105535c4bbdfSmrg    memcpy(s_key, &key, sizeof(key));
105635c4bbdfSmrg    *psaved_source_format = saved_source_format;
105735c4bbdfSmrg    goto done;
105835c4bbdfSmrg
105935c4bbdfSmrg fail:
106035c4bbdfSmrg    if (saved_source_format)
106135c4bbdfSmrg        source->format = saved_source_format;
106235c4bbdfSmrg done:
106335c4bbdfSmrg    return ret;
106435c4bbdfSmrg}
106535c4bbdfSmrg
106635c4bbdfSmrgstatic void
106735c4bbdfSmrgglamor_composite_set_shader_blend(glamor_screen_private *glamor_priv,
106835c4bbdfSmrg                                  glamor_pixmap_private *dest_priv,
106935c4bbdfSmrg                                  struct shader_key *key,
107035c4bbdfSmrg                                  glamor_composite_shader *shader,
107135c4bbdfSmrg                                  struct blendinfo *op_info)
107235c4bbdfSmrg{
107335c4bbdfSmrg    glamor_make_current(glamor_priv);
107435c4bbdfSmrg    glUseProgram(shader->prog);
107535c4bbdfSmrg
107635c4bbdfSmrg    if (key->source == SHADER_SOURCE_SOLID) {
107735c4bbdfSmrg        glamor_set_composite_solid(shader->source_solid_color,
107835c4bbdfSmrg                                   shader->source_uniform_location);
107935c4bbdfSmrg    }
108035c4bbdfSmrg    else {
108135c4bbdfSmrg        glamor_set_composite_texture(glamor_priv, 0,
108235c4bbdfSmrg                                     shader->source,
108335c4bbdfSmrg                                     shader->source_pixmap, shader->source_wh,
108435c4bbdfSmrg                                     shader->source_repeat_mode,
108535c4bbdfSmrg                                     dest_priv);
108635c4bbdfSmrg    }
108735c4bbdfSmrg
108835c4bbdfSmrg    if (key->mask != SHADER_MASK_NONE) {
108935c4bbdfSmrg        if (key->mask == SHADER_MASK_SOLID) {
109035c4bbdfSmrg            glamor_set_composite_solid(shader->mask_solid_color,
109135c4bbdfSmrg                                       shader->mask_uniform_location);
109235c4bbdfSmrg        }
109335c4bbdfSmrg        else {
109435c4bbdfSmrg            glamor_set_composite_texture(glamor_priv, 1,
109535c4bbdfSmrg                                         shader->mask,
109635c4bbdfSmrg                                         shader->mask_pixmap, shader->mask_wh,
109735c4bbdfSmrg                                         shader->mask_repeat_mode,
109835c4bbdfSmrg                                         dest_priv);
109935c4bbdfSmrg        }
110035c4bbdfSmrg    }
110135c4bbdfSmrg
1102ed6184dfSmrg    if (!glamor_priv->is_gles)
110335c4bbdfSmrg        glDisable(GL_COLOR_LOGIC_OP);
110435c4bbdfSmrg
110535c4bbdfSmrg    if (op_info->source_blend == GL_ONE && op_info->dest_blend == GL_ZERO) {
110635c4bbdfSmrg        glDisable(GL_BLEND);
110735c4bbdfSmrg    }
110835c4bbdfSmrg    else {
110935c4bbdfSmrg        glEnable(GL_BLEND);
111035c4bbdfSmrg        glBlendFunc(op_info->source_blend, op_info->dest_blend);
111135c4bbdfSmrg    }
111235c4bbdfSmrg}
111335c4bbdfSmrg
111435c4bbdfSmrgstatic Bool
111535c4bbdfSmrgglamor_composite_with_shader(CARD8 op,
111635c4bbdfSmrg                             PicturePtr source,
111735c4bbdfSmrg                             PicturePtr mask,
111835c4bbdfSmrg                             PicturePtr dest,
111935c4bbdfSmrg                             PixmapPtr source_pixmap,
112035c4bbdfSmrg                             PixmapPtr mask_pixmap,
112135c4bbdfSmrg                             PixmapPtr dest_pixmap,
112235c4bbdfSmrg                             glamor_pixmap_private *source_pixmap_priv,
112335c4bbdfSmrg                             glamor_pixmap_private *mask_pixmap_priv,
112435c4bbdfSmrg                             glamor_pixmap_private *dest_pixmap_priv,
112535c4bbdfSmrg                             int nrect, glamor_composite_rect_t *rects,
112635c4bbdfSmrg                             enum ca_state ca_state)
112735c4bbdfSmrg{
112835c4bbdfSmrg    ScreenPtr screen = dest->pDrawable->pScreen;
112935c4bbdfSmrg    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
113035c4bbdfSmrg    GLfloat dst_xscale, dst_yscale;
113135c4bbdfSmrg    GLfloat mask_xscale = 1, mask_yscale = 1, src_xscale = 1, src_yscale = 1;
113235c4bbdfSmrg    struct shader_key key, key_ca;
113335c4bbdfSmrg    int dest_x_off, dest_y_off;
113435c4bbdfSmrg    int source_x_off, source_y_off;
113535c4bbdfSmrg    int mask_x_off, mask_y_off;
113635c4bbdfSmrg    PictFormatShort saved_source_format = 0;
113735c4bbdfSmrg    float src_matrix[9], mask_matrix[9];
113835c4bbdfSmrg    float *psrc_matrix = NULL, *pmask_matrix = NULL;
113935c4bbdfSmrg    int nrect_max;
114035c4bbdfSmrg    Bool ret = FALSE;
114135c4bbdfSmrg    glamor_composite_shader *shader = NULL, *shader_ca = NULL;
114235c4bbdfSmrg    struct blendinfo op_info, op_info_ca;
114335c4bbdfSmrg
114435c4bbdfSmrg    if (!glamor_composite_choose_shader(op, source, mask, dest,
114535c4bbdfSmrg                                        source_pixmap, mask_pixmap, dest_pixmap,
114635c4bbdfSmrg                                        source_pixmap_priv, mask_pixmap_priv,
114735c4bbdfSmrg                                        dest_pixmap_priv,
114835c4bbdfSmrg                                        &key, &shader, &op_info,
114935c4bbdfSmrg                                        &saved_source_format, ca_state)) {
115035c4bbdfSmrg        glamor_fallback("glamor_composite_choose_shader failed\n");
11511b5d61b8Smrg        goto fail;
115235c4bbdfSmrg    }
115335c4bbdfSmrg    if (ca_state == CA_TWO_PASS) {
115435c4bbdfSmrg        if (!glamor_composite_choose_shader(PictOpAdd, source, mask, dest,
115535c4bbdfSmrg                                            source_pixmap, mask_pixmap, dest_pixmap,
115635c4bbdfSmrg                                            source_pixmap_priv,
115735c4bbdfSmrg                                            mask_pixmap_priv, dest_pixmap_priv,
115835c4bbdfSmrg                                            &key_ca, &shader_ca, &op_info_ca,
115935c4bbdfSmrg                                            &saved_source_format, ca_state)) {
116035c4bbdfSmrg            glamor_fallback("glamor_composite_choose_shader failed\n");
11611b5d61b8Smrg            goto fail;
116235c4bbdfSmrg        }
116335c4bbdfSmrg    }
116435c4bbdfSmrg
116535c4bbdfSmrg    glamor_make_current(glamor_priv);
116635c4bbdfSmrg
116735c4bbdfSmrg    glamor_set_destination_pixmap_priv_nc(glamor_priv, dest_pixmap, dest_pixmap_priv);
116835c4bbdfSmrg    glamor_composite_set_shader_blend(glamor_priv, dest_pixmap_priv, &key, shader, &op_info);
116935c4bbdfSmrg    glamor_set_alu(screen, GXcopy);
117035c4bbdfSmrg
117135c4bbdfSmrg    glamor_priv->has_source_coords = key.source != SHADER_SOURCE_SOLID;
117235c4bbdfSmrg    glamor_priv->has_mask_coords = (key.mask != SHADER_MASK_NONE &&
117335c4bbdfSmrg                                    key.mask != SHADER_MASK_SOLID);
117435c4bbdfSmrg
117535c4bbdfSmrg    dest_pixmap = glamor_get_drawable_pixmap(dest->pDrawable);
117635c4bbdfSmrg    dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap);
117735c4bbdfSmrg    glamor_get_drawable_deltas(dest->pDrawable, dest_pixmap,
117835c4bbdfSmrg                               &dest_x_off, &dest_y_off);
117935c4bbdfSmrg    pixmap_priv_get_dest_scale(dest_pixmap, dest_pixmap_priv, &dst_xscale, &dst_yscale);
118035c4bbdfSmrg
118135c4bbdfSmrg    if (glamor_priv->has_source_coords) {
118235c4bbdfSmrg        glamor_get_drawable_deltas(source->pDrawable,
118335c4bbdfSmrg                                   source_pixmap, &source_x_off, &source_y_off);
118435c4bbdfSmrg        pixmap_priv_get_scale(source_pixmap_priv, &src_xscale, &src_yscale);
118535c4bbdfSmrg        if (source->transform) {
118635c4bbdfSmrg            psrc_matrix = src_matrix;
118735c4bbdfSmrg            glamor_picture_get_matrixf(source, psrc_matrix);
118835c4bbdfSmrg        }
118935c4bbdfSmrg    }
119035c4bbdfSmrg
119135c4bbdfSmrg    if (glamor_priv->has_mask_coords) {
119235c4bbdfSmrg        glamor_get_drawable_deltas(mask->pDrawable, mask_pixmap,
119335c4bbdfSmrg                                   &mask_x_off, &mask_y_off);
119435c4bbdfSmrg        pixmap_priv_get_scale(mask_pixmap_priv, &mask_xscale, &mask_yscale);
119535c4bbdfSmrg        if (mask->transform) {
119635c4bbdfSmrg            pmask_matrix = mask_matrix;
119735c4bbdfSmrg            glamor_picture_get_matrixf(mask, pmask_matrix);
119835c4bbdfSmrg        }
119935c4bbdfSmrg    }
120035c4bbdfSmrg
120135c4bbdfSmrg    nrect_max = MIN(nrect, GLAMOR_COMPOSITE_VBO_VERT_CNT / 4);
120235c4bbdfSmrg
12031b5d61b8Smrg    if (nrect < 100) {
12041b5d61b8Smrg        BoxRec bounds = glamor_start_rendering_bounds();
12051b5d61b8Smrg
12061b5d61b8Smrg        for (int i = 0; i < nrect; i++) {
12071b5d61b8Smrg            BoxRec box = {
12081b5d61b8Smrg                .x1 = rects[i].x_dst,
12091b5d61b8Smrg                .y1 = rects[i].y_dst,
12101b5d61b8Smrg                .x2 = rects[i].x_dst + rects[i].width,
12111b5d61b8Smrg                .y2 = rects[i].y_dst + rects[i].height,
12121b5d61b8Smrg            };
12131b5d61b8Smrg            glamor_bounds_union_box(&bounds, &box);
12141b5d61b8Smrg        }
12151b5d61b8Smrg
12161b5d61b8Smrg        if (bounds.x1 >= bounds.x2 || bounds.y1 >= bounds.y2)
12171b5d61b8Smrg            goto disable_va;
12181b5d61b8Smrg
12191b5d61b8Smrg        glEnable(GL_SCISSOR_TEST);
12201b5d61b8Smrg        glScissor(bounds.x1 + dest_x_off,
12211b5d61b8Smrg                  bounds.y1 + dest_y_off,
12221b5d61b8Smrg                  bounds.x2 - bounds.x1,
12231b5d61b8Smrg                  bounds.y2 - bounds.y1);
12241b5d61b8Smrg    }
12251b5d61b8Smrg
122635c4bbdfSmrg    while (nrect) {
122735c4bbdfSmrg        int mrect, rect_processed;
122835c4bbdfSmrg        int vb_stride;
122935c4bbdfSmrg        float *vertices;
123035c4bbdfSmrg
123135c4bbdfSmrg        mrect = nrect > nrect_max ? nrect_max : nrect;
123235c4bbdfSmrg        vertices = glamor_setup_composite_vbo(screen, mrect * 4);
123335c4bbdfSmrg        rect_processed = mrect;
123435c4bbdfSmrg        vb_stride = glamor_priv->vb_stride / sizeof(float);
123535c4bbdfSmrg        while (mrect--) {
123635c4bbdfSmrg            INT16 x_source;
123735c4bbdfSmrg            INT16 y_source;
123835c4bbdfSmrg            INT16 x_mask;
123935c4bbdfSmrg            INT16 y_mask;
124035c4bbdfSmrg            INT16 x_dest;
124135c4bbdfSmrg            INT16 y_dest;
124235c4bbdfSmrg            CARD16 width;
124335c4bbdfSmrg            CARD16 height;
124435c4bbdfSmrg
124535c4bbdfSmrg            x_dest = rects->x_dst + dest_x_off;
124635c4bbdfSmrg            y_dest = rects->y_dst + dest_y_off;
124735c4bbdfSmrg            x_source = rects->x_src + source_x_off;
124835c4bbdfSmrg            y_source = rects->y_src + source_y_off;
124935c4bbdfSmrg            x_mask = rects->x_mask + mask_x_off;
125035c4bbdfSmrg            y_mask = rects->y_mask + mask_y_off;
125135c4bbdfSmrg            width = rects->width;
125235c4bbdfSmrg            height = rects->height;
125335c4bbdfSmrg
125435c4bbdfSmrg            DEBUGF
125535c4bbdfSmrg                ("dest(%d,%d) source(%d %d) mask (%d %d), width %d height %d \n",
125635c4bbdfSmrg                 x_dest, y_dest, x_source, y_source, x_mask, y_mask, width,
125735c4bbdfSmrg                 height);
125835c4bbdfSmrg
125935c4bbdfSmrg            glamor_set_normalize_vcoords_ext(dest_pixmap_priv, dst_xscale,
126035c4bbdfSmrg                                             dst_yscale, x_dest, y_dest,
126135c4bbdfSmrg                                             x_dest + width, y_dest + height,
126235c4bbdfSmrg                                             vertices,
126335c4bbdfSmrg                                             vb_stride);
126435c4bbdfSmrg            vertices += 2;
126535c4bbdfSmrg            if (key.source != SHADER_SOURCE_SOLID) {
126635c4bbdfSmrg                glamor_set_normalize_tcoords_generic(source_pixmap,
126735c4bbdfSmrg                                                     source_pixmap_priv,
126835c4bbdfSmrg                                                     source->repeatType,
126935c4bbdfSmrg                                                     psrc_matrix, src_xscale,
127035c4bbdfSmrg                                                     src_yscale, x_source,
127135c4bbdfSmrg                                                     y_source, x_source + width,
127235c4bbdfSmrg                                                     y_source + height,
127335c4bbdfSmrg                                                     vertices, vb_stride);
127435c4bbdfSmrg                vertices += 2;
127535c4bbdfSmrg            }
127635c4bbdfSmrg
127735c4bbdfSmrg            if (key.mask != SHADER_MASK_NONE && key.mask != SHADER_MASK_SOLID) {
127835c4bbdfSmrg                glamor_set_normalize_tcoords_generic(mask_pixmap,
127935c4bbdfSmrg                                                     mask_pixmap_priv,
128035c4bbdfSmrg                                                     mask->repeatType,
128135c4bbdfSmrg                                                     pmask_matrix, mask_xscale,
128235c4bbdfSmrg                                                     mask_yscale, x_mask,
128335c4bbdfSmrg                                                     y_mask, x_mask + width,
128435c4bbdfSmrg                                                     y_mask + height,
128535c4bbdfSmrg                                                     vertices, vb_stride);
128635c4bbdfSmrg                vertices += 2;
128735c4bbdfSmrg            }
128835c4bbdfSmrg            glamor_priv->render_nr_quads++;
128935c4bbdfSmrg            rects++;
129035c4bbdfSmrg
129135c4bbdfSmrg            /* We've incremented by one of our 4 verts, now do the other 3. */
129235c4bbdfSmrg            vertices += 3 * vb_stride;
129335c4bbdfSmrg        }
129435c4bbdfSmrg        glamor_put_vbo_space(screen);
129535c4bbdfSmrg        glamor_flush_composite_rects(screen);
129635c4bbdfSmrg        nrect -= rect_processed;
129735c4bbdfSmrg        if (ca_state == CA_TWO_PASS) {
129835c4bbdfSmrg            glamor_composite_set_shader_blend(glamor_priv, dest_pixmap_priv,
129935c4bbdfSmrg                                              &key_ca, shader_ca, &op_info_ca);
130035c4bbdfSmrg            glamor_flush_composite_rects(screen);
130135c4bbdfSmrg            if (nrect)
130235c4bbdfSmrg                glamor_composite_set_shader_blend(glamor_priv, dest_pixmap_priv,
130335c4bbdfSmrg                                                  &key, shader, &op_info);
130435c4bbdfSmrg        }
130535c4bbdfSmrg    }
130635c4bbdfSmrg
13071b5d61b8Smrg    glDisable(GL_SCISSOR_TEST);
13081b5d61b8Smrgdisable_va:
130935c4bbdfSmrg    glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
131035c4bbdfSmrg    glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
131135c4bbdfSmrg    glDisableVertexAttribArray(GLAMOR_VERTEX_MASK);
131235c4bbdfSmrg    glDisable(GL_BLEND);
131335c4bbdfSmrg    DEBUGF("finish rendering.\n");
131435c4bbdfSmrg    if (saved_source_format)
131535c4bbdfSmrg        source->format = saved_source_format;
131635c4bbdfSmrg
131735c4bbdfSmrg    ret = TRUE;
13181b5d61b8Smrg
13191b5d61b8Smrgfail:
13201b5d61b8Smrg    if (mask_pixmap && glamor_pixmap_is_memory(mask_pixmap))
13211b5d61b8Smrg        glamor_pixmap_destroy_fbo(mask_pixmap);
13221b5d61b8Smrg    if (source_pixmap && glamor_pixmap_is_memory(source_pixmap))
13231b5d61b8Smrg        glamor_pixmap_destroy_fbo(source_pixmap);
13241b5d61b8Smrg
132535c4bbdfSmrg    return ret;
132635c4bbdfSmrg}
132735c4bbdfSmrg
132835c4bbdfSmrgstatic PicturePtr
132935c4bbdfSmrgglamor_convert_gradient_picture(ScreenPtr screen,
133035c4bbdfSmrg                                PicturePtr source,
133135c4bbdfSmrg                                int x_source,
133235c4bbdfSmrg                                int y_source, int width, int height)
133335c4bbdfSmrg{
133435c4bbdfSmrg    PixmapPtr pixmap;
133535c4bbdfSmrg    PicturePtr dst = NULL;
133635c4bbdfSmrg    int error;
133735c4bbdfSmrg    PictFormatPtr pFormat;
133835c4bbdfSmrg    PictFormatShort format;
133935c4bbdfSmrg
134035c4bbdfSmrg    if (source->pDrawable) {
134135c4bbdfSmrg        pFormat = source->pFormat;
134235c4bbdfSmrg        format = pFormat->format;
134335c4bbdfSmrg    } else {
134435c4bbdfSmrg        format = PICT_a8r8g8b8;
134535c4bbdfSmrg        pFormat = PictureMatchFormat(screen, 32, format);
134635c4bbdfSmrg    }
134735c4bbdfSmrg
134835c4bbdfSmrg    if (!source->pDrawable) {
134935c4bbdfSmrg        if (source->pSourcePict->type == SourcePictTypeLinear) {
135035c4bbdfSmrg            dst = glamor_generate_linear_gradient_picture(screen,
135135c4bbdfSmrg                                                          source, x_source,
135235c4bbdfSmrg                                                          y_source, width,
135335c4bbdfSmrg                                                          height, format);
135435c4bbdfSmrg        }
135535c4bbdfSmrg        else if (source->pSourcePict->type == SourcePictTypeRadial) {
135635c4bbdfSmrg            dst = glamor_generate_radial_gradient_picture(screen,
135735c4bbdfSmrg                                                          source, x_source,
135835c4bbdfSmrg                                                          y_source, width,
135935c4bbdfSmrg                                                          height, format);
136035c4bbdfSmrg        }
136135c4bbdfSmrg
136235c4bbdfSmrg        if (dst) {
136335c4bbdfSmrg            return dst;
136435c4bbdfSmrg        }
136535c4bbdfSmrg    }
13661b5d61b8Smrg
136735c4bbdfSmrg    pixmap = glamor_create_pixmap(screen,
136835c4bbdfSmrg                                  width,
136935c4bbdfSmrg                                  height,
137035c4bbdfSmrg                                  PIXMAN_FORMAT_DEPTH(format),
137135c4bbdfSmrg                                  GLAMOR_CREATE_PIXMAP_CPU);
137235c4bbdfSmrg
137335c4bbdfSmrg    if (!pixmap)
137435c4bbdfSmrg        return NULL;
137535c4bbdfSmrg
137635c4bbdfSmrg    dst = CreatePicture(0,
137735c4bbdfSmrg                        &pixmap->drawable, pFormat, 0, 0, serverClient, &error);
137835c4bbdfSmrg    glamor_destroy_pixmap(pixmap);
137935c4bbdfSmrg    if (!dst)
138035c4bbdfSmrg        return NULL;
138135c4bbdfSmrg
138235c4bbdfSmrg    ValidatePicture(dst);
138335c4bbdfSmrg
138435c4bbdfSmrg    fbComposite(PictOpSrc, source, NULL, dst, x_source, y_source,
138535c4bbdfSmrg                0, 0, 0, 0, width, height);
138635c4bbdfSmrg    return dst;
138735c4bbdfSmrg}
138835c4bbdfSmrg
138935c4bbdfSmrgBool
139035c4bbdfSmrgglamor_composite_clipped_region(CARD8 op,
139135c4bbdfSmrg                                PicturePtr source,
139235c4bbdfSmrg                                PicturePtr mask,
139335c4bbdfSmrg                                PicturePtr dest,
139435c4bbdfSmrg                                PixmapPtr source_pixmap,
139535c4bbdfSmrg                                PixmapPtr mask_pixmap,
139635c4bbdfSmrg                                PixmapPtr dest_pixmap,
139735c4bbdfSmrg                                RegionPtr region,
139835c4bbdfSmrg                                int x_source,
139935c4bbdfSmrg                                int y_source,
140035c4bbdfSmrg                                int x_mask, int y_mask, int x_dest, int y_dest)
140135c4bbdfSmrg{
140235c4bbdfSmrg    glamor_pixmap_private *source_pixmap_priv = glamor_get_pixmap_private(source_pixmap);
140335c4bbdfSmrg    glamor_pixmap_private *mask_pixmap_priv = glamor_get_pixmap_private(mask_pixmap);
140435c4bbdfSmrg    glamor_pixmap_private *dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap);
140535c4bbdfSmrg    glamor_screen_private *glamor_priv = glamor_get_screen_private(dest_pixmap->drawable.pScreen);
140635c4bbdfSmrg    ScreenPtr screen = dest->pDrawable->pScreen;
140735c4bbdfSmrg    PicturePtr temp_src = source, temp_mask = mask;
140835c4bbdfSmrg    PixmapPtr temp_src_pixmap = source_pixmap;
140935c4bbdfSmrg    PixmapPtr temp_mask_pixmap = mask_pixmap;
141035c4bbdfSmrg    glamor_pixmap_private *temp_src_priv = source_pixmap_priv;
141135c4bbdfSmrg    glamor_pixmap_private *temp_mask_priv = mask_pixmap_priv;
141235c4bbdfSmrg    int x_temp_src, y_temp_src, x_temp_mask, y_temp_mask;
141335c4bbdfSmrg    BoxPtr extent;
141435c4bbdfSmrg    glamor_composite_rect_t rect[10];
141535c4bbdfSmrg    glamor_composite_rect_t *prect = rect;
141635c4bbdfSmrg    int prect_size = ARRAY_SIZE(rect);
141735c4bbdfSmrg    int ok = FALSE;
141835c4bbdfSmrg    int i;
141935c4bbdfSmrg    int width;
142035c4bbdfSmrg    int height;
142135c4bbdfSmrg    BoxPtr box;
142235c4bbdfSmrg    int nbox;
142335c4bbdfSmrg    enum ca_state ca_state = CA_NONE;
142435c4bbdfSmrg
142535c4bbdfSmrg    extent = RegionExtents(region);
142635c4bbdfSmrg    box = RegionRects(region);
142735c4bbdfSmrg    nbox = RegionNumRects(region);
142835c4bbdfSmrg    width = extent->x2 - extent->x1;
142935c4bbdfSmrg    height = extent->y2 - extent->y1;
143035c4bbdfSmrg
143135c4bbdfSmrg    x_temp_src = x_source;
143235c4bbdfSmrg    y_temp_src = y_source;
143335c4bbdfSmrg    x_temp_mask = x_mask;
143435c4bbdfSmrg    y_temp_mask = y_mask;
143535c4bbdfSmrg
143635c4bbdfSmrg    DEBUGF("clipped (%d %d) (%d %d) (%d %d) width %d height %d \n",
143735c4bbdfSmrg           x_source, y_source, x_mask, y_mask, x_dest, y_dest, width, height);
143835c4bbdfSmrg
143935c4bbdfSmrg    /* Is the composite operation equivalent to a copy? */
14401b5d61b8Smrg    if (source &&
14411b5d61b8Smrg        !mask && !source->alphaMap && !dest->alphaMap
144235c4bbdfSmrg        && source->pDrawable && !source->transform
14431b5d61b8Smrg        /* CopyArea is only defined with matching depths. */
14441b5d61b8Smrg        && dest->pDrawable->depth == source->pDrawable->depth
144535c4bbdfSmrg        && ((op == PictOpSrc
144635c4bbdfSmrg             && (source->format == dest->format
144735c4bbdfSmrg                 || (PICT_FORMAT_COLOR(dest->format)
144835c4bbdfSmrg                     && PICT_FORMAT_COLOR(source->format)
144935c4bbdfSmrg                     && dest->format == PICT_FORMAT(PICT_FORMAT_BPP(source->format),
145035c4bbdfSmrg                                                    PICT_FORMAT_TYPE(source->format),
145135c4bbdfSmrg                                                    0,
145235c4bbdfSmrg                                                    PICT_FORMAT_R(source->format),
145335c4bbdfSmrg                                                    PICT_FORMAT_G(source->format),
145435c4bbdfSmrg                                                    PICT_FORMAT_B(source->format)))))
145535c4bbdfSmrg            || (op == PictOpOver
145635c4bbdfSmrg                && source->format == dest->format
145735c4bbdfSmrg                && !PICT_FORMAT_A(source->format)))
145835c4bbdfSmrg        && x_source >= 0 && y_source >= 0
145935c4bbdfSmrg        && (x_source + width) <= source->pDrawable->width
146035c4bbdfSmrg        && (y_source + height) <= source->pDrawable->height) {
146135c4bbdfSmrg        x_source += source->pDrawable->x;
146235c4bbdfSmrg        y_source += source->pDrawable->y;
146335c4bbdfSmrg        x_dest += dest->pDrawable->x;
146435c4bbdfSmrg        y_dest += dest->pDrawable->y;
146535c4bbdfSmrg        glamor_copy(source->pDrawable, dest->pDrawable, NULL,
146635c4bbdfSmrg                    box, nbox, x_source - x_dest,
146735c4bbdfSmrg                    y_source - y_dest, FALSE, FALSE, 0, NULL);
146835c4bbdfSmrg        ok = TRUE;
146935c4bbdfSmrg        goto out;
147035c4bbdfSmrg    }
147135c4bbdfSmrg
147235c4bbdfSmrg    /* XXX is it possible source mask have non-zero drawable.x/y? */
147335c4bbdfSmrg    if (source
147435c4bbdfSmrg        && ((!source->pDrawable
147535c4bbdfSmrg             && (source->pSourcePict->type != SourcePictTypeSolidFill))
147635c4bbdfSmrg            || (source->pDrawable
147735c4bbdfSmrg                && !GLAMOR_PIXMAP_PRIV_HAS_FBO(source_pixmap_priv)
147835c4bbdfSmrg                && (source_pixmap->drawable.width != width
147935c4bbdfSmrg                    || source_pixmap->drawable.height != height)))) {
148035c4bbdfSmrg        temp_src =
148135c4bbdfSmrg            glamor_convert_gradient_picture(screen, source,
148235c4bbdfSmrg                                            extent->x1 + x_source - x_dest - dest->pDrawable->x,
148335c4bbdfSmrg                                            extent->y1 + y_source - y_dest - dest->pDrawable->y,
148435c4bbdfSmrg                                            width, height);
148535c4bbdfSmrg        if (!temp_src) {
148635c4bbdfSmrg            temp_src = source;
148735c4bbdfSmrg            goto out;
148835c4bbdfSmrg        }
148935c4bbdfSmrg        temp_src_pixmap = (PixmapPtr) (temp_src->pDrawable);
149035c4bbdfSmrg        temp_src_priv = glamor_get_pixmap_private(temp_src_pixmap);
149135c4bbdfSmrg        x_temp_src = -extent->x1 + x_dest + dest->pDrawable->x;
149235c4bbdfSmrg        y_temp_src = -extent->y1 + y_dest + dest->pDrawable->y;
149335c4bbdfSmrg    }
149435c4bbdfSmrg
149535c4bbdfSmrg    if (mask
149635c4bbdfSmrg        &&
149735c4bbdfSmrg        ((!mask->pDrawable
149835c4bbdfSmrg          && (mask->pSourcePict->type != SourcePictTypeSolidFill))
149935c4bbdfSmrg         || (mask->pDrawable && !GLAMOR_PIXMAP_PRIV_HAS_FBO(mask_pixmap_priv)
150035c4bbdfSmrg             && (mask_pixmap->drawable.width != width
150135c4bbdfSmrg                 || mask_pixmap->drawable.height != height)))) {
150235c4bbdfSmrg        /* XXX if mask->pDrawable is the same as source->pDrawable, we have an opportunity
15031b5d61b8Smrg         * to do reduce one conversion. */
150435c4bbdfSmrg        temp_mask =
150535c4bbdfSmrg            glamor_convert_gradient_picture(screen, mask,
150635c4bbdfSmrg                                            extent->x1 + x_mask - x_dest - dest->pDrawable->x,
150735c4bbdfSmrg                                            extent->y1 + y_mask - y_dest - dest->pDrawable->y,
150835c4bbdfSmrg                                            width, height);
150935c4bbdfSmrg        if (!temp_mask) {
151035c4bbdfSmrg            temp_mask = mask;
151135c4bbdfSmrg            goto out;
151235c4bbdfSmrg        }
151335c4bbdfSmrg        temp_mask_pixmap = (PixmapPtr) (temp_mask->pDrawable);
151435c4bbdfSmrg        temp_mask_priv = glamor_get_pixmap_private(temp_mask_pixmap);
151535c4bbdfSmrg        x_temp_mask = -extent->x1 + x_dest + dest->pDrawable->x;
151635c4bbdfSmrg        y_temp_mask = -extent->y1 + y_dest + dest->pDrawable->y;
151735c4bbdfSmrg    }
151835c4bbdfSmrg
151935c4bbdfSmrg    if (mask && mask->componentAlpha) {
152035c4bbdfSmrg        if (glamor_priv->has_dual_blend) {
152135c4bbdfSmrg            ca_state = CA_DUAL_BLEND;
152235c4bbdfSmrg        } else {
152335c4bbdfSmrg            if (op == PictOpOver) {
15241b5d61b8Smrg                if (glamor_pixmap_is_memory(mask_pixmap)) {
15251b5d61b8Smrg                    glamor_fallback("two pass not supported on memory pximaps\n");
15261b5d61b8Smrg                    goto out;
15271b5d61b8Smrg                }
152835c4bbdfSmrg                ca_state = CA_TWO_PASS;
152935c4bbdfSmrg                op = PictOpOutReverse;
153035c4bbdfSmrg            }
153135c4bbdfSmrg        }
153235c4bbdfSmrg    }
153335c4bbdfSmrg
153435c4bbdfSmrg    if (temp_src_pixmap == dest_pixmap) {
153535c4bbdfSmrg        glamor_fallback("source and dest pixmaps are the same\n");
153635c4bbdfSmrg        goto out;
153735c4bbdfSmrg    }
153835c4bbdfSmrg    if (temp_mask_pixmap == dest_pixmap) {
153935c4bbdfSmrg        glamor_fallback("mask and dest pixmaps are the same\n");
154035c4bbdfSmrg        goto out;
154135c4bbdfSmrg    }
154235c4bbdfSmrg
154335c4bbdfSmrg    x_dest += dest->pDrawable->x;
154435c4bbdfSmrg    y_dest += dest->pDrawable->y;
154535c4bbdfSmrg    if (temp_src && temp_src->pDrawable) {
154635c4bbdfSmrg        x_temp_src += temp_src->pDrawable->x;
154735c4bbdfSmrg        y_temp_src += temp_src->pDrawable->y;
154835c4bbdfSmrg    }
154935c4bbdfSmrg    if (temp_mask && temp_mask->pDrawable) {
155035c4bbdfSmrg        x_temp_mask += temp_mask->pDrawable->x;
155135c4bbdfSmrg        y_temp_mask += temp_mask->pDrawable->y;
155235c4bbdfSmrg    }
155335c4bbdfSmrg
155435c4bbdfSmrg    if (nbox > ARRAY_SIZE(rect)) {
155535c4bbdfSmrg        prect = calloc(nbox, sizeof(*prect));
155635c4bbdfSmrg        if (prect)
155735c4bbdfSmrg            prect_size = nbox;
155835c4bbdfSmrg        else {
155935c4bbdfSmrg            prect = rect;
156035c4bbdfSmrg            prect_size = ARRAY_SIZE(rect);
156135c4bbdfSmrg        }
156235c4bbdfSmrg    }
156335c4bbdfSmrg    while (nbox) {
156435c4bbdfSmrg        int box_cnt;
156535c4bbdfSmrg
156635c4bbdfSmrg        box_cnt = nbox > prect_size ? prect_size : nbox;
156735c4bbdfSmrg        for (i = 0; i < box_cnt; i++) {
156835c4bbdfSmrg            prect[i].x_src = box[i].x1 + x_temp_src - x_dest;
156935c4bbdfSmrg            prect[i].y_src = box[i].y1 + y_temp_src - y_dest;
157035c4bbdfSmrg            prect[i].x_mask = box[i].x1 + x_temp_mask - x_dest;
157135c4bbdfSmrg            prect[i].y_mask = box[i].y1 + y_temp_mask - y_dest;
157235c4bbdfSmrg            prect[i].x_dst = box[i].x1;
157335c4bbdfSmrg            prect[i].y_dst = box[i].y1;
157435c4bbdfSmrg            prect[i].width = box[i].x2 - box[i].x1;
157535c4bbdfSmrg            prect[i].height = box[i].y2 - box[i].y1;
157635c4bbdfSmrg            DEBUGF("dest %d %d \n", prect[i].x_dst, prect[i].y_dst);
157735c4bbdfSmrg        }
157835c4bbdfSmrg        ok = glamor_composite_with_shader(op, temp_src, temp_mask, dest,
157935c4bbdfSmrg                                          temp_src_pixmap, temp_mask_pixmap, dest_pixmap,
158035c4bbdfSmrg                                          temp_src_priv, temp_mask_priv,
158135c4bbdfSmrg                                          dest_pixmap_priv,
158235c4bbdfSmrg                                          box_cnt, prect, ca_state);
158335c4bbdfSmrg        if (!ok)
158435c4bbdfSmrg            break;
158535c4bbdfSmrg        nbox -= box_cnt;
158635c4bbdfSmrg        box += box_cnt;
158735c4bbdfSmrg    }
158835c4bbdfSmrg
158935c4bbdfSmrg    if (prect != rect)
159035c4bbdfSmrg        free(prect);
159135c4bbdfSmrg out:
159235c4bbdfSmrg    if (temp_src != source)
159335c4bbdfSmrg        FreePicture(temp_src, 0);
159435c4bbdfSmrg    if (temp_mask != mask)
159535c4bbdfSmrg        FreePicture(temp_mask, 0);
159635c4bbdfSmrg
159735c4bbdfSmrg    return ok;
159835c4bbdfSmrg}
159935c4bbdfSmrg
160035c4bbdfSmrgvoid
160135c4bbdfSmrgglamor_composite(CARD8 op,
160235c4bbdfSmrg                 PicturePtr source,
160335c4bbdfSmrg                 PicturePtr mask,
160435c4bbdfSmrg                 PicturePtr dest,
160535c4bbdfSmrg                 INT16 x_source,
160635c4bbdfSmrg                 INT16 y_source,
160735c4bbdfSmrg                 INT16 x_mask,
160835c4bbdfSmrg                 INT16 y_mask,
160935c4bbdfSmrg                 INT16 x_dest, INT16 y_dest, CARD16 width, CARD16 height)
161035c4bbdfSmrg{
161135c4bbdfSmrg    ScreenPtr screen = dest->pDrawable->pScreen;
161235c4bbdfSmrg    PixmapPtr dest_pixmap = glamor_get_drawable_pixmap(dest->pDrawable);
161335c4bbdfSmrg    PixmapPtr source_pixmap = NULL, mask_pixmap = NULL;
161435c4bbdfSmrg    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
161535c4bbdfSmrg    RegionRec region;
161635c4bbdfSmrg    BoxPtr extent;
161735c4bbdfSmrg    int nbox, ok = FALSE;
161835c4bbdfSmrg    int force_clip = 0;
161935c4bbdfSmrg
162035c4bbdfSmrg    if (source->pDrawable) {
162135c4bbdfSmrg        source_pixmap = glamor_get_drawable_pixmap(source->pDrawable);
162235c4bbdfSmrg        if (glamor_pixmap_drm_only(source_pixmap))
162335c4bbdfSmrg            goto fail;
162435c4bbdfSmrg    }
162535c4bbdfSmrg
162635c4bbdfSmrg    if (mask && mask->pDrawable) {
162735c4bbdfSmrg        mask_pixmap = glamor_get_drawable_pixmap(mask->pDrawable);
162835c4bbdfSmrg        if (glamor_pixmap_drm_only(mask_pixmap))
162935c4bbdfSmrg            goto fail;
163035c4bbdfSmrg    }
163135c4bbdfSmrg
163235c4bbdfSmrg    DEBUGF
163335c4bbdfSmrg        ("source pixmap %p (%d %d) mask(%d %d) dest(%d %d) width %d height %d \n",
163435c4bbdfSmrg         source_pixmap, x_source, y_source, x_mask, y_mask, x_dest, y_dest,
163535c4bbdfSmrg         width, height);
163635c4bbdfSmrg
163735c4bbdfSmrg    if (!glamor_pixmap_has_fbo(dest_pixmap))
163835c4bbdfSmrg        goto fail;
163935c4bbdfSmrg
164035c4bbdfSmrg    if (op >= ARRAY_SIZE(composite_op_info)) {
164135c4bbdfSmrg        glamor_fallback("Unsupported composite op %x\n", op);
164235c4bbdfSmrg        goto fail;
164335c4bbdfSmrg    }
164435c4bbdfSmrg
164535c4bbdfSmrg    if (mask && mask->componentAlpha && !glamor_priv->has_dual_blend) {
164635c4bbdfSmrg        if (op == PictOpAtop
164735c4bbdfSmrg            || op == PictOpAtopReverse
164835c4bbdfSmrg            || op == PictOpXor || op >= PictOpSaturate) {
164935c4bbdfSmrg            glamor_fallback("glamor_composite(): component alpha op %x\n", op);
165035c4bbdfSmrg            goto fail;
165135c4bbdfSmrg        }
165235c4bbdfSmrg    }
165335c4bbdfSmrg
165435c4bbdfSmrg    if ((source && source->filter >= PictFilterConvolution)
165535c4bbdfSmrg        || (mask && mask->filter >= PictFilterConvolution)) {
165635c4bbdfSmrg        glamor_fallback("glamor_composite(): unsupported filter\n");
165735c4bbdfSmrg        goto fail;
165835c4bbdfSmrg    }
165935c4bbdfSmrg
166035c4bbdfSmrg    if (!miComputeCompositeRegion(&region,
166135c4bbdfSmrg                                  source, mask, dest,
166235c4bbdfSmrg                                  x_source +
166335c4bbdfSmrg                                  (source_pixmap ? source->pDrawable->x : 0),
166435c4bbdfSmrg                                  y_source +
166535c4bbdfSmrg                                  (source_pixmap ? source->pDrawable->y : 0),
166635c4bbdfSmrg                                  x_mask +
166735c4bbdfSmrg                                  (mask_pixmap ? mask->pDrawable->x : 0),
166835c4bbdfSmrg                                  y_mask +
166935c4bbdfSmrg                                  (mask_pixmap ? mask->pDrawable->y : 0),
167035c4bbdfSmrg                                  x_dest + dest->pDrawable->x,
167135c4bbdfSmrg                                  y_dest + dest->pDrawable->y, width, height)) {
167235c4bbdfSmrg        return;
167335c4bbdfSmrg    }
167435c4bbdfSmrg
167535c4bbdfSmrg    nbox = REGION_NUM_RECTS(&region);
167635c4bbdfSmrg    DEBUGF("first clipped when compositing.\n");
167735c4bbdfSmrg    DEBUGRegionPrint(&region);
167835c4bbdfSmrg    extent = RegionExtents(&region);
167935c4bbdfSmrg    if (nbox == 0)
168035c4bbdfSmrg        return;
168135c4bbdfSmrg
168235c4bbdfSmrg    /* If destination is not a large pixmap, but the region is larger
168335c4bbdfSmrg     * than texture size limitation, and source or mask is memory pixmap,
168435c4bbdfSmrg     * then there may be need to load a large memory pixmap to a
168535c4bbdfSmrg     * texture, and this is not permitted. Then we force to clip the
168635c4bbdfSmrg     * destination and make sure latter will not upload a large memory
168735c4bbdfSmrg     * pixmap. */
168835c4bbdfSmrg    if (!glamor_check_fbo_size(glamor_priv,
168935c4bbdfSmrg                               extent->x2 - extent->x1, extent->y2 - extent->y1)
169035c4bbdfSmrg        && glamor_pixmap_is_large(dest_pixmap)
169135c4bbdfSmrg        && ((source_pixmap
169235c4bbdfSmrg             && (glamor_pixmap_is_memory(source_pixmap) ||
169335c4bbdfSmrg                 source->repeatType == RepeatPad))
169435c4bbdfSmrg            || (mask_pixmap &&
169535c4bbdfSmrg                (glamor_pixmap_is_memory(mask_pixmap) ||
169635c4bbdfSmrg                 mask->repeatType == RepeatPad))
169735c4bbdfSmrg            || (!source_pixmap &&
169835c4bbdfSmrg                (source->pSourcePict->type != SourcePictTypeSolidFill))
169935c4bbdfSmrg            || (!mask_pixmap && mask &&
170035c4bbdfSmrg                mask->pSourcePict->type != SourcePictTypeSolidFill)))
170135c4bbdfSmrg        force_clip = 1;
170235c4bbdfSmrg
170335c4bbdfSmrg    if (force_clip || glamor_pixmap_is_large(dest_pixmap)
170435c4bbdfSmrg        || (source_pixmap
170535c4bbdfSmrg            && glamor_pixmap_is_large(source_pixmap))
170635c4bbdfSmrg        || (mask_pixmap && glamor_pixmap_is_large(mask_pixmap)))
170735c4bbdfSmrg        ok = glamor_composite_largepixmap_region(op,
170835c4bbdfSmrg                                                 source, mask, dest,
170935c4bbdfSmrg                                                 source_pixmap,
171035c4bbdfSmrg                                                 mask_pixmap,
171135c4bbdfSmrg                                                 dest_pixmap,
171235c4bbdfSmrg                                                 &region, force_clip,
171335c4bbdfSmrg                                                 x_source, y_source,
171435c4bbdfSmrg                                                 x_mask, y_mask,
171535c4bbdfSmrg                                                 x_dest, y_dest, width, height);
171635c4bbdfSmrg    else
171735c4bbdfSmrg        ok = glamor_composite_clipped_region(op, source,
171835c4bbdfSmrg                                             mask, dest,
171935c4bbdfSmrg                                             source_pixmap,
172035c4bbdfSmrg                                             mask_pixmap,
172135c4bbdfSmrg                                             dest_pixmap,
172235c4bbdfSmrg                                             &region,
172335c4bbdfSmrg                                             x_source, y_source,
172435c4bbdfSmrg                                             x_mask, y_mask, x_dest, y_dest);
172535c4bbdfSmrg
172635c4bbdfSmrg    REGION_UNINIT(dest->pDrawable->pScreen, &region);
172735c4bbdfSmrg
172835c4bbdfSmrg    if (ok)
172935c4bbdfSmrg        return;
173035c4bbdfSmrg
173135c4bbdfSmrg fail:
173235c4bbdfSmrg
173335c4bbdfSmrg    glamor_fallback
173435c4bbdfSmrg        ("from picts %p:%p %dx%d / %p:%p %d x %d (%c,%c)  to pict %p:%p %dx%d (%c)\n",
173535c4bbdfSmrg         source, source->pDrawable,
173635c4bbdfSmrg         source->pDrawable ? source->pDrawable->width : 0,
173735c4bbdfSmrg         source->pDrawable ? source->pDrawable->height : 0, mask,
17381b5d61b8Smrg         (!mask) ? NULL : mask->pDrawable,
17391b5d61b8Smrg         (!mask || !mask->pDrawable) ? 0 : mask->pDrawable->width,
17401b5d61b8Smrg         (!mask || !mask->pDrawable) ? 0 : mask->pDrawable->height,
17411b5d61b8Smrg         glamor_get_picture_location(source),
17421b5d61b8Smrg         glamor_get_picture_location(mask),
17431b5d61b8Smrg         dest, dest->pDrawable,
174435c4bbdfSmrg         dest->pDrawable->width, dest->pDrawable->height,
174535c4bbdfSmrg         glamor_get_picture_location(dest));
174635c4bbdfSmrg
174735c4bbdfSmrg    if (glamor_prepare_access_picture_box(dest, GLAMOR_ACCESS_RW,
174835c4bbdfSmrg                                          x_dest, y_dest, width, height) &&
174935c4bbdfSmrg        glamor_prepare_access_picture_box(source, GLAMOR_ACCESS_RO,
175035c4bbdfSmrg                                          x_source, y_source, width, height) &&
175135c4bbdfSmrg        glamor_prepare_access_picture_box(mask, GLAMOR_ACCESS_RO,
175235c4bbdfSmrg                                          x_mask, y_mask, width, height))
175335c4bbdfSmrg    {
175435c4bbdfSmrg        fbComposite(op,
175535c4bbdfSmrg                    source, mask, dest,
175635c4bbdfSmrg                    x_source, y_source,
175735c4bbdfSmrg                    x_mask, y_mask, x_dest, y_dest, width, height);
175835c4bbdfSmrg    }
175935c4bbdfSmrg    glamor_finish_access_picture(mask);
176035c4bbdfSmrg    glamor_finish_access_picture(source);
176135c4bbdfSmrg    glamor_finish_access_picture(dest);
176235c4bbdfSmrg}
1763