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(®ion, 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(®ion); 167635c4bbdfSmrg DEBUGF("first clipped when compositing.\n"); 167735c4bbdfSmrg DEBUGRegionPrint(®ion); 167835c4bbdfSmrg extent = RegionExtents(®ion); 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 ®ion, 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 ®ion, 172335c4bbdfSmrg x_source, y_source, 172435c4bbdfSmrg x_mask, y_mask, x_dest, y_dest); 172535c4bbdfSmrg 172635c4bbdfSmrg REGION_UNINIT(dest->pDrawable->pScreen, ®ion); 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