Path: blob/21.2-virgl/src/gallium/frontends/xa/xa_composite.c
4561 views
/**********************************************************1* Copyright 2009-2011 VMware, Inc. All rights reserved.2*3* Permission is hereby granted, free of charge, to any person4* obtaining a copy of this software and associated documentation5* files (the "Software"), to deal in the Software without6* restriction, including without limitation the rights to use, copy,7* modify, merge, publish, distribute, sublicense, and/or sell copies8* of the Software, and to permit persons to whom the Software is9* furnished to do so, subject to the following conditions:10*11* The above copyright notice and this permission notice shall be12* included in all copies or substantial portions of the Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,15* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF16* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND17* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS18* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN19* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN20* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE21* SOFTWARE.22*23*********************************************************24* Authors:25* Zack Rusin <zackr-at-vmware-dot-com>26* Thomas Hellstrom <thellstrom-at-vmware-dot-com>27*/2829#include "xa_composite.h"30#include "xa_context.h"31#include "xa_priv.h"32#include "cso_cache/cso_context.h"33#include "util/u_sampler.h"34#include "util/u_inlines.h"353637/*XXX also in Xrender.h but the including it here breaks compilition */38#define XFixedToDouble(f) (((double) (f)) / 65536.)3940struct xa_composite_blend {41unsigned op : 8;4243unsigned alpha_dst : 4;44unsigned alpha_src : 4;4546unsigned rgb_src : 8; /**< PIPE_BLENDFACTOR_x */47unsigned rgb_dst : 8; /**< PIPE_BLENDFACTOR_x */48};4950#define XA_BLEND_OP_OVER 351static const struct xa_composite_blend xa_blends[] = {52{ xa_op_clear,530, 0, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO},54{ xa_op_src,550, 0, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ZERO},56{ xa_op_dst,570, 0, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ONE},58{ xa_op_over,590, 1, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_INV_SRC_ALPHA},60{ xa_op_over_reverse,611, 0, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ONE},62{ xa_op_in,631, 0, PIPE_BLENDFACTOR_DST_ALPHA, PIPE_BLENDFACTOR_ZERO},64{ xa_op_in_reverse,650, 1, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_SRC_ALPHA},66{ xa_op_out,671, 0, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_ZERO},68{ xa_op_out_reverse,690, 1, PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_INV_SRC_ALPHA},70{ xa_op_atop,711, 1, PIPE_BLENDFACTOR_DST_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA},72{ xa_op_atop_reverse,731, 1, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_SRC_ALPHA},74{ xa_op_xor,751, 1, PIPE_BLENDFACTOR_INV_DST_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA},76{ xa_op_add,770, 0, PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE},78};7980/*81* The alpha value stored in a L8 texture is read by the82* hardware as color, and R8 is read as red. The source alpha value83* at the end of the fragment shader is stored in all color channels,84* so the correct approach is to blend using DST_COLOR instead of85* DST_ALPHA and then output any color channel (L8) or the red channel (R8).86*/87static unsigned88xa_convert_blend_for_luminance(unsigned factor)89{90switch(factor) {91case PIPE_BLENDFACTOR_DST_ALPHA:92return PIPE_BLENDFACTOR_DST_COLOR;93case PIPE_BLENDFACTOR_INV_DST_ALPHA:94return PIPE_BLENDFACTOR_INV_DST_COLOR;95default:96break;97}98return factor;99}100101static boolean102blend_for_op(struct xa_composite_blend *blend,103enum xa_composite_op op,104struct xa_picture *src_pic,105struct xa_picture *mask_pic,106struct xa_picture *dst_pic)107{108const int num_blends =109sizeof(xa_blends)/sizeof(struct xa_composite_blend);110int i;111boolean supported = FALSE;112113/*114* our default in case something goes wrong115*/116*blend = xa_blends[XA_BLEND_OP_OVER];117118for (i = 0; i < num_blends; ++i) {119if (xa_blends[i].op == op) {120*blend = xa_blends[i];121supported = TRUE;122break;123}124}125126/*127* No component alpha yet.128*/129if (mask_pic && mask_pic->component_alpha && blend->alpha_src)130return FALSE;131132if (!dst_pic->srf)133return supported;134135if ((dst_pic->srf->tex->format == PIPE_FORMAT_L8_UNORM ||136dst_pic->srf->tex->format == PIPE_FORMAT_R8_UNORM)) {137blend->rgb_src = xa_convert_blend_for_luminance(blend->rgb_src);138blend->rgb_dst = xa_convert_blend_for_luminance(blend->rgb_dst);139}140141/*142* If there's no dst alpha channel, adjust the blend op so that we'll treat143* it as always 1.144*/145146if (xa_format_a(dst_pic->pict_format) == 0 && blend->alpha_dst) {147if (blend->rgb_src == PIPE_BLENDFACTOR_DST_ALPHA)148blend->rgb_src = PIPE_BLENDFACTOR_ONE;149else if (blend->rgb_src == PIPE_BLENDFACTOR_INV_DST_ALPHA)150blend->rgb_src = PIPE_BLENDFACTOR_ZERO;151}152153return supported;154}155156157static inline int158xa_repeat_to_gallium(int mode)159{160switch(mode) {161case xa_wrap_clamp_to_border:162return PIPE_TEX_WRAP_CLAMP_TO_BORDER;163case xa_wrap_repeat:164return PIPE_TEX_WRAP_REPEAT;165case xa_wrap_mirror_repeat:166return PIPE_TEX_WRAP_MIRROR_REPEAT;167case xa_wrap_clamp_to_edge:168return PIPE_TEX_WRAP_CLAMP_TO_EDGE;169default:170break;171}172return PIPE_TEX_WRAP_REPEAT;173}174175static inline boolean176xa_filter_to_gallium(int xrender_filter, int *out_filter)177{178179switch (xrender_filter) {180case xa_filter_nearest:181*out_filter = PIPE_TEX_FILTER_NEAREST;182break;183case xa_filter_linear:184*out_filter = PIPE_TEX_FILTER_LINEAR;185break;186default:187*out_filter = PIPE_TEX_FILTER_NEAREST;188return FALSE;189}190return TRUE;191}192193static int194xa_is_filter_accelerated(struct xa_picture *pic)195{196int filter;197if (pic && !xa_filter_to_gallium(pic->filter, &filter))198return 0;199return 1;200}201202/**203* xa_src_pict_is_accelerated - Check whether we support acceleration204* of the given src_pict type205*206* \param src_pic[in]: Pointer to a union xa_source_pict to check.207*208* \returns TRUE if accelerated, FALSE otherwise.209*/210static boolean211xa_src_pict_is_accelerated(const union xa_source_pict *src_pic)212{213if (!src_pic)214return TRUE;215216if (src_pic->type == xa_src_pict_solid_fill ||217src_pic->type == xa_src_pict_float_solid_fill)218return TRUE;219220return FALSE;221}222223XA_EXPORT int224xa_composite_check_accelerated(const struct xa_composite *comp)225{226struct xa_picture *src_pic = comp->src;227struct xa_picture *mask_pic = comp->mask;228struct xa_composite_blend blend;229230if (!xa_is_filter_accelerated(src_pic) ||231!xa_is_filter_accelerated(comp->mask)) {232return -XA_ERR_INVAL;233}234235if (!xa_src_pict_is_accelerated(src_pic->src_pict) ||236(mask_pic && !xa_src_pict_is_accelerated(mask_pic->src_pict)))237return -XA_ERR_INVAL;238239if (!blend_for_op(&blend, comp->op, comp->src, comp->mask, comp->dst))240return -XA_ERR_INVAL;241242/*243* No component alpha yet.244*/245if (mask_pic && mask_pic->component_alpha && blend.alpha_src)246return -XA_ERR_INVAL;247248return XA_ERR_NONE;249}250251static int252bind_composite_blend_state(struct xa_context *ctx,253const struct xa_composite *comp)254{255struct xa_composite_blend blend_opt;256struct pipe_blend_state blend;257258if (!blend_for_op(&blend_opt, comp->op, comp->src, comp->mask, comp->dst))259return -XA_ERR_INVAL;260261memset(&blend, 0, sizeof(struct pipe_blend_state));262blend.rt[0].blend_enable = 1;263blend.rt[0].colormask = PIPE_MASK_RGBA;264265blend.rt[0].rgb_src_factor = blend_opt.rgb_src;266blend.rt[0].alpha_src_factor = blend_opt.rgb_src;267blend.rt[0].rgb_dst_factor = blend_opt.rgb_dst;268blend.rt[0].alpha_dst_factor = blend_opt.rgb_dst;269270cso_set_blend(ctx->cso, &blend);271return XA_ERR_NONE;272}273274static unsigned int275picture_format_fixups(struct xa_picture *src_pic,276int mask)277{278boolean set_alpha = FALSE;279boolean swizzle = FALSE;280unsigned ret = 0;281struct xa_surface *src = src_pic->srf;282enum xa_formats src_hw_format, src_pic_format;283enum xa_surface_type src_hw_type, src_pic_type;284285if (!src)286return 0;287288src_hw_format = xa_surface_format(src);289src_pic_format = src_pic->pict_format;290291set_alpha = (xa_format_type_is_color(src_hw_format) &&292xa_format_a(src_pic_format) == 0);293294if (set_alpha)295ret |= mask ? FS_MASK_SET_ALPHA : FS_SRC_SET_ALPHA;296297if (src_hw_format == src_pic_format) {298if (src->tex->format == PIPE_FORMAT_L8_UNORM ||299src->tex->format == PIPE_FORMAT_R8_UNORM)300return ((mask) ? FS_MASK_LUMINANCE : FS_SRC_LUMINANCE);301302return ret;303}304305src_hw_type = xa_format_type(src_hw_format);306src_pic_type = xa_format_type(src_pic_format);307308swizzle = ((src_hw_type == xa_type_argb &&309src_pic_type == xa_type_abgr) ||310((src_hw_type == xa_type_abgr &&311src_pic_type == xa_type_argb)));312313if (!swizzle && (src_hw_type != src_pic_type))314return ret;315316if (swizzle)317ret |= mask ? FS_MASK_SWIZZLE_RGB : FS_SRC_SWIZZLE_RGB;318319return ret;320}321322static void323xa_src_in_mask(float src[4], const float mask[4])324{325src[0] *= mask[3];326src[1] *= mask[3];327src[2] *= mask[3];328src[3] *= mask[3];329}330331/**332* xa_handle_src_pict - Set up xa_context state and fragment shader333* input based on scr_pict type334*335* \param ctx[in, out]: Pointer to the xa context.336* \param src_pict[in]: Pointer to the union xa_source_pict to consider.337* \param is_mask[in]: Whether we're considering a mask picture.338*339* \returns TRUE if succesful, FALSE otherwise.340*341* This function computes some xa_context state used to determine whether342* to upload the solid color and also the solid color itself used as an input343* to the fragment shader.344*/345static boolean346xa_handle_src_pict(struct xa_context *ctx,347const union xa_source_pict *src_pict,348boolean is_mask)349{350float solid_color[4];351352switch(src_pict->type) {353case xa_src_pict_solid_fill:354xa_pixel_to_float4(src_pict->solid_fill.color, solid_color);355break;356case xa_src_pict_float_solid_fill:357memcpy(solid_color, src_pict->float_solid_fill.color,358sizeof(solid_color));359break;360default:361return FALSE;362}363364if (is_mask && ctx->has_solid_src)365xa_src_in_mask(ctx->solid_color, solid_color);366else367memcpy(ctx->solid_color, solid_color, sizeof(solid_color));368369if (is_mask)370ctx->has_solid_mask = TRUE;371else372ctx->has_solid_src = TRUE;373374return TRUE;375}376377static int378bind_shaders(struct xa_context *ctx, const struct xa_composite *comp)379{380unsigned vs_traits = 0, fs_traits = 0;381struct xa_shader shader;382struct xa_picture *src_pic = comp->src;383struct xa_picture *mask_pic = comp->mask;384struct xa_picture *dst_pic = comp->dst;385386ctx->has_solid_src = FALSE;387ctx->has_solid_mask = FALSE;388389if (dst_pic && xa_format_type(dst_pic->pict_format) !=390xa_format_type(xa_surface_format(dst_pic->srf)))391return -XA_ERR_INVAL;392393if (src_pic) {394if (src_pic->wrap == xa_wrap_clamp_to_border && src_pic->has_transform)395fs_traits |= FS_SRC_REPEAT_NONE;396397fs_traits |= FS_COMPOSITE;398vs_traits |= VS_COMPOSITE;399400if (src_pic->src_pict) {401if (!xa_handle_src_pict(ctx, src_pic->src_pict, false))402return -XA_ERR_INVAL;403fs_traits |= FS_SRC_SRC;404vs_traits |= VS_SRC_SRC;405} else406fs_traits |= picture_format_fixups(src_pic, 0);407}408409if (mask_pic) {410vs_traits |= VS_MASK;411fs_traits |= FS_MASK;412if (mask_pic->component_alpha)413fs_traits |= FS_CA;414if (mask_pic->src_pict) {415if (!xa_handle_src_pict(ctx, mask_pic->src_pict, true))416return -XA_ERR_INVAL;417418if (ctx->has_solid_src) {419vs_traits &= ~VS_MASK;420fs_traits &= ~FS_MASK;421} else {422vs_traits |= VS_MASK_SRC;423fs_traits |= FS_MASK_SRC;424}425} else {426if (mask_pic->wrap == xa_wrap_clamp_to_border &&427mask_pic->has_transform)428fs_traits |= FS_MASK_REPEAT_NONE;429430fs_traits |= picture_format_fixups(mask_pic, 1);431}432}433434if (ctx->srf->format == PIPE_FORMAT_L8_UNORM ||435ctx->srf->format == PIPE_FORMAT_R8_UNORM)436fs_traits |= FS_DST_LUMINANCE;437438shader = xa_shaders_get(ctx->shaders, vs_traits, fs_traits);439cso_set_vertex_shader_handle(ctx->cso, shader.vs);440cso_set_fragment_shader_handle(ctx->cso, shader.fs);441return XA_ERR_NONE;442}443444static void445bind_samplers(struct xa_context *ctx,446const struct xa_composite *comp)447{448struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];449struct pipe_sampler_state src_sampler, mask_sampler;450struct pipe_sampler_view view_templ;451struct pipe_sampler_view *src_view;452struct pipe_context *pipe = ctx->pipe;453struct xa_picture *src_pic = comp->src;454struct xa_picture *mask_pic = comp->mask;455int num_samplers = 0;456457xa_ctx_sampler_views_destroy(ctx);458memset(&src_sampler, 0, sizeof(struct pipe_sampler_state));459memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state));460461if (src_pic && !ctx->has_solid_src) {462unsigned src_wrap = xa_repeat_to_gallium(src_pic->wrap);463int filter;464465(void) xa_filter_to_gallium(src_pic->filter, &filter);466467src_sampler.wrap_s = src_wrap;468src_sampler.wrap_t = src_wrap;469src_sampler.min_img_filter = filter;470src_sampler.mag_img_filter = filter;471src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;472src_sampler.normalized_coords = 1;473samplers[0] = &src_sampler;474u_sampler_view_default_template(&view_templ,475src_pic->srf->tex,+ src_pic->srf->tex->format);476src_view = pipe->create_sampler_view(pipe, src_pic->srf->tex,477&view_templ);478ctx->bound_sampler_views[0] = src_view;479num_samplers++;480}481482if (mask_pic && !ctx->has_solid_mask) {483unsigned mask_wrap = xa_repeat_to_gallium(mask_pic->wrap);484int filter;485486(void) xa_filter_to_gallium(mask_pic->filter, &filter);487488mask_sampler.wrap_s = mask_wrap;489mask_sampler.wrap_t = mask_wrap;490mask_sampler.min_img_filter = filter;491mask_sampler.mag_img_filter = filter;492src_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;493mask_sampler.normalized_coords = 1;494samplers[num_samplers] = &mask_sampler;495u_sampler_view_default_template(&view_templ,496mask_pic->srf->tex,497mask_pic->srf->tex->format);498src_view = pipe->create_sampler_view(pipe, mask_pic->srf->tex,499&view_templ);500ctx->bound_sampler_views[num_samplers] = src_view;501num_samplers++;502}503504cso_set_samplers(ctx->cso, PIPE_SHADER_FRAGMENT, num_samplers,505(const struct pipe_sampler_state **)samplers);506pipe->set_sampler_views(pipe, PIPE_SHADER_FRAGMENT, 0, num_samplers, 0,507ctx->bound_sampler_views);508ctx->num_bound_samplers = num_samplers;509}510511XA_EXPORT int512xa_composite_prepare(struct xa_context *ctx,513const struct xa_composite *comp)514{515struct xa_surface *dst_srf = comp->dst->srf;516int ret;517518ret = xa_ctx_srf_create(ctx, dst_srf);519if (ret != XA_ERR_NONE)520return ret;521522ctx->dst = dst_srf;523renderer_bind_destination(ctx, ctx->srf);524525ret = bind_composite_blend_state(ctx, comp);526if (ret != XA_ERR_NONE)527return ret;528ret = bind_shaders(ctx, comp);529if (ret != XA_ERR_NONE)530return ret;531bind_samplers(ctx, comp);532533if (ctx->num_bound_samplers == 0 ) { /* solid fill */534renderer_begin_solid(ctx);535} else {536renderer_begin_textures(ctx);537ctx->comp = comp;538}539540xa_ctx_srf_destroy(ctx);541return XA_ERR_NONE;542}543544XA_EXPORT void545xa_composite_rect(struct xa_context *ctx,546int srcX, int srcY, int maskX, int maskY,547int dstX, int dstY, int width, int height)548{549if (ctx->num_bound_samplers == 0 ) { /* solid fill */550xa_scissor_update(ctx, dstX, dstY, dstX + width, dstY + height);551renderer_solid(ctx, dstX, dstY, dstX + width, dstY + height);552} else {553const struct xa_composite *comp = ctx->comp;554int pos[6] = {srcX, srcY, maskX, maskY, dstX, dstY};555const float *src_matrix = NULL;556const float *mask_matrix = NULL;557558xa_scissor_update(ctx, dstX, dstY, dstX + width, dstY + height);559560if (comp->src->has_transform)561src_matrix = comp->src->transform;562if (comp->mask && comp->mask->has_transform)563mask_matrix = comp->mask->transform;564565renderer_texture(ctx, pos, width, height,566src_matrix, mask_matrix);567}568}569570XA_EXPORT void571xa_composite_done(struct xa_context *ctx)572{573renderer_draw_flush(ctx);574575ctx->comp = NULL;576ctx->has_solid_src = FALSE;577ctx->has_solid_mask = FALSE;578xa_ctx_sampler_views_destroy(ctx);579}580581static const struct xa_composite_allocation a = {582.xa_composite_size = sizeof(struct xa_composite),583.xa_picture_size = sizeof(struct xa_picture),584.xa_source_pict_size = sizeof(union xa_source_pict),585};586587XA_EXPORT const struct xa_composite_allocation *588xa_composite_allocation(void)589{590return &a;591}592593594