Path: blob/21.2-virgl/src/gallium/auxiliary/tgsi/tgsi_aa_point.c
4565 views
/*1* Copyright 2014 VMware, Inc.2* All Rights Reserved.3*4* Permission is hereby granted, free of charge, to any person obtaining a5* copy of this software and associated documentation files (the6* "Software"), to deal in the Software without restriction, including7* without limitation the rights to use, copy, modify, merge, publish,8* distribute, sub license, and/or sell copies of the Software, and to9* permit persons to whom the Software is furnished to do so, subject to10* the following conditions:11*12* The above copyright notice and this permission notice (including the13* next paragraph) shall be included in all copies or substantial portions14* of the Software.15*16* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS17* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF18* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.19* IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR20* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,21* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE22* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.23*/242526/**27* This utility transforms the fragment shader to support anti-aliasing points.28*/2930#include "util/u_debug.h"31#include "util/u_math.h"32#include "tgsi_info.h"33#include "tgsi_aa_point.h"34#include "tgsi_transform.h"3536#define INVALID_INDEX 99993738struct aa_transform_context39{40struct tgsi_transform_context base;4142unsigned tmp; // temp register43unsigned color_out; // frag color out register44unsigned color_tmp; // frag color temp register45unsigned num_tmp; // number of temp registers46unsigned num_imm; // number of immediates47unsigned num_input; // number of inputs48unsigned aa_point_coord_index;49};5051static inline struct aa_transform_context *52aa_transform_context(struct tgsi_transform_context *ctx)53{54return (struct aa_transform_context *) ctx;55}5657/**58* TGSI declaration transform callback.59*/60static void61aa_decl(struct tgsi_transform_context *ctx,62struct tgsi_full_declaration *decl)63{64struct aa_transform_context *ts = aa_transform_context(ctx);6566if (decl->Declaration.File == TGSI_FILE_OUTPUT &&67decl->Semantic.Name == TGSI_SEMANTIC_COLOR &&68decl->Semantic.Index == 0) {69ts->color_out = decl->Range.First;70}71else if (decl->Declaration.File == TGSI_FILE_INPUT) {72ts->num_input++;73}74else if (decl->Declaration.File == TGSI_FILE_TEMPORARY) {75ts->num_tmp = MAX2(ts->num_tmp, (unsigned)(decl->Range.Last + 1));76}7778ctx->emit_declaration(ctx, decl);79}8081/**82* TGSI immediate declaration transform callback.83*/84static void85aa_immediate(struct tgsi_transform_context *ctx,86struct tgsi_full_immediate *imm)87{88struct aa_transform_context *ts = aa_transform_context(ctx);8990ctx->emit_immediate(ctx, imm);91ts->num_imm++;92}9394/**95* TGSI transform prolog callback.96*/97static void98aa_prolog(struct tgsi_transform_context *ctx)99{100struct aa_transform_context *ts = aa_transform_context(ctx);101unsigned tmp0;102unsigned texIn;103unsigned imm;104105/* Declare two temporary registers, one for temporary and106* one for color.107*/108ts->tmp = ts->num_tmp++;109ts->color_tmp = ts->num_tmp++;110111tgsi_transform_temps_decl(ctx, ts->tmp, ts->color_tmp);112113/* Declare new generic input/texcoord */114texIn = ts->num_input++;115tgsi_transform_input_decl(ctx, texIn, TGSI_SEMANTIC_GENERIC,116ts->aa_point_coord_index, TGSI_INTERPOLATE_LINEAR);117118/* Declare extra immediates */119imm = ts->num_imm++;120tgsi_transform_immediate_decl(ctx, 0.5, 0.5, 0.45, 1.0);121122/*123* Emit code to compute fragment coverage.124* The point always has radius 0.5. The threshold value will be a125* value less than, but close to 0.5, such as 0.45.126* We compute a coverage factor from the distance and threshold.127* If the coverage is negative, the fragment is outside the circle and128* it's discarded.129* If the coverage is >= 1, the fragment is fully inside the threshold130* distance. We limit/clamp the coverage to 1.131* Otherwise, the fragment is between the threshold value and 0.5 and we132* compute a coverage value in [0,1].133*134* Input reg (texIn) usage:135* texIn.x = x point coord in [0,1]136* texIn.y = y point coord in [0,1]137* texIn.z = "k" the smoothing threshold distance138* texIn.w = unused139*140* Temp reg (t0) usage:141* t0.x = distance of fragment from center point142* t0.y = boolean, is t0.x > 0.5, also misc temp usage143* t0.z = temporary for computing 1/(0.5-k) value144* t0.w = final coverage value145*/146147tmp0 = ts->tmp;148149/* SUB t0.xy, texIn, (0.5, 0,5) */150tgsi_transform_op2_inst(ctx, TGSI_OPCODE_ADD,151TGSI_FILE_TEMPORARY, tmp0, TGSI_WRITEMASK_XY,152TGSI_FILE_INPUT, texIn,153TGSI_FILE_IMMEDIATE, imm, true);154155/* DP2 t0.x, t0.xy, t0.xy; # t0.x = x^2 + y^2 */156tgsi_transform_op2_inst(ctx, TGSI_OPCODE_DP2,157TGSI_FILE_TEMPORARY, tmp0, TGSI_WRITEMASK_X,158TGSI_FILE_TEMPORARY, tmp0,159TGSI_FILE_TEMPORARY, tmp0, false);160161/* SQRT t0.x, t0.x */162tgsi_transform_op1_inst(ctx, TGSI_OPCODE_SQRT,163TGSI_FILE_TEMPORARY, tmp0, TGSI_WRITEMASK_X,164TGSI_FILE_TEMPORARY, tmp0);165166/* compute coverage factor = (0.5-d)/(0.5-k) */167168/* SUB t0.w, 0.5, texIn.z; # t0.w = 0.5-k */169tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_ADD,170TGSI_FILE_TEMPORARY, tmp0, TGSI_WRITEMASK_W,171TGSI_FILE_IMMEDIATE, imm, TGSI_SWIZZLE_X,172TGSI_FILE_INPUT, texIn, TGSI_SWIZZLE_Z, true);173174/* SUB t0.y, 0.5, t0.x; # t0.y = 0.5-d */175tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_ADD,176TGSI_FILE_TEMPORARY, tmp0, TGSI_WRITEMASK_Y,177TGSI_FILE_IMMEDIATE, imm, TGSI_SWIZZLE_X,178TGSI_FILE_TEMPORARY, tmp0, TGSI_SWIZZLE_X, true);179180/* DIV t0.w, t0.y, t0.w; # coverage = (0.5-d)/(0.5-k) */181tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_DIV,182TGSI_FILE_TEMPORARY, tmp0, TGSI_WRITEMASK_W,183TGSI_FILE_TEMPORARY, tmp0, TGSI_SWIZZLE_Y,184TGSI_FILE_TEMPORARY, tmp0, TGSI_SWIZZLE_W, false);185186/* If the coverage value is negative, it means the fragment is outside187* the point's circular boundary. Kill it.188*/189/* KILL_IF tmp0.w; # if tmp0.w < 0 KILL */190tgsi_transform_kill_inst(ctx, TGSI_FILE_TEMPORARY, tmp0,191TGSI_SWIZZLE_W, FALSE);192193/* If the distance is less than the threshold, the coverage/alpha value194* will be greater than one. Clamp to one here.195*/196/* MIN tmp0.w, tmp0.w, 1.0 */197tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_MIN,198TGSI_FILE_TEMPORARY, tmp0, TGSI_WRITEMASK_W,199TGSI_FILE_TEMPORARY, tmp0, TGSI_SWIZZLE_W,200TGSI_FILE_IMMEDIATE, imm, TGSI_SWIZZLE_W, false);201}202203/**204* TGSI instruction transform callback.205*/206static void207aa_inst(struct tgsi_transform_context *ctx,208struct tgsi_full_instruction *inst)209{210struct aa_transform_context *ts = aa_transform_context(ctx);211unsigned i;212213/* Look for writes to color output reg and replace it with214* color temp reg.215*/216for (i = 0; i < inst->Instruction.NumDstRegs; i++) {217struct tgsi_full_dst_register *dst = &inst->Dst[i];218if (dst->Register.File == TGSI_FILE_OUTPUT &&219dst->Register.Index == (int)ts->color_out) {220dst->Register.File = TGSI_FILE_TEMPORARY;221dst->Register.Index = ts->color_tmp;222}223}224225ctx->emit_instruction(ctx, inst);226}227228/**229* TGSI transform epilog callback.230*/231static void232aa_epilog(struct tgsi_transform_context *ctx)233{234struct aa_transform_context *ts = aa_transform_context(ctx);235236/* add alpha modulation code at tail of program */237assert(ts->color_out != INVALID_INDEX);238assert(ts->color_tmp != INVALID_INDEX);239240/* MOV output.color.xyz colorTmp */241tgsi_transform_op1_inst(ctx, TGSI_OPCODE_MOV,242TGSI_FILE_OUTPUT, ts->color_out,243TGSI_WRITEMASK_XYZ,244TGSI_FILE_TEMPORARY, ts->color_tmp);245246/* MUL output.color.w colorTmp.w tmp0.w */247tgsi_transform_op2_inst(ctx, TGSI_OPCODE_MUL,248TGSI_FILE_OUTPUT, ts->color_out,249TGSI_WRITEMASK_W,250TGSI_FILE_TEMPORARY, ts->color_tmp,251TGSI_FILE_TEMPORARY, ts->tmp, false);252}253254/**255* TGSI utility to transform a fragment shader to support antialiasing point.256*257* This utility accepts two inputs:258*\param tokens_in -- the original token string of the shader259*\param aa_point_coord_index -- the semantic index of the generic register260* that contains the point sprite texture coord261*262* For each fragment in the point, we compute the distance of the fragment263* from the point center using the point sprite texture coordinates.264* If the distance is greater than 0.5, we'll discard the fragment.265* Otherwise, we'll compute a coverage value which approximates how much266* of the fragment is inside the bounding circle of the point. If the distance267* is less than 'k', the coverage is 1. Else, the coverage is between 0 and 1.268* The final fragment color's alpha channel is then modulated by the coverage269* value.270*/271struct tgsi_token *272tgsi_add_aa_point(const struct tgsi_token *tokens_in,273const int aa_point_coord_index)274{275struct aa_transform_context transform;276const uint num_new_tokens = 200; /* should be enough */277const uint new_len = tgsi_num_tokens(tokens_in) + num_new_tokens;278struct tgsi_token *new_tokens;279280/* allocate new tokens buffer */281new_tokens = tgsi_alloc_tokens(new_len);282if (!new_tokens)283return NULL;284285/* setup transformation context */286memset(&transform, 0, sizeof(transform));287transform.base.transform_declaration = aa_decl;288transform.base.transform_instruction = aa_inst;289transform.base.transform_immediate = aa_immediate;290transform.base.prolog = aa_prolog;291transform.base.epilog = aa_epilog;292293transform.tmp = INVALID_INDEX;294transform.color_out = INVALID_INDEX;295transform.color_tmp = INVALID_INDEX;296297assert(aa_point_coord_index != -1);298transform.aa_point_coord_index = (unsigned)aa_point_coord_index;299300transform.num_tmp = 0;301transform.num_imm = 0;302transform.num_input = 0;303304/* transform the shader */305tgsi_transform_shader(tokens_in, new_tokens, new_len, &transform.base);306307return new_tokens;308}309310311