/**********************************************************
* Copyright 2008-2009 VMware, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
**********************************************************/
#include "pipe/p_shader_tokens.h"
#include "tgsi/tgsi_parse.h"
#include "util/u_memory.h"
#include "svga_tgsi_emit.h"
/**
* Translate TGSI semantic info into SVGA3d semantic info.
* This is called for VS outputs and PS inputs only.
*/
static boolean
translate_vs_ps_semantic(struct svga_shader_emitter *emit,
struct tgsi_declaration_semantic semantic,
unsigned *usage,
unsigned *idx)
{
switch (semantic.Name) {
case TGSI_SEMANTIC_POSITION:
*idx = semantic.Index;
*usage = SVGA3D_DECLUSAGE_POSITION;
break;
case TGSI_SEMANTIC_COLOR:
*idx = semantic.Index;
*usage = SVGA3D_DECLUSAGE_COLOR;
break;
case TGSI_SEMANTIC_BCOLOR:
*idx = semantic.Index + 2; /* sharing with COLOR */
*usage = SVGA3D_DECLUSAGE_COLOR;
break;
case TGSI_SEMANTIC_FOG:
*idx = 0;
assert(semantic.Index == 0);
*usage = SVGA3D_DECLUSAGE_TEXCOORD;
break;
case TGSI_SEMANTIC_PSIZE:
*idx = semantic.Index;
*usage = SVGA3D_DECLUSAGE_PSIZE;
break;
case TGSI_SEMANTIC_GENERIC:
*idx = svga_remap_generic_index(emit->key.generic_remap_table,
semantic.Index);
*usage = SVGA3D_DECLUSAGE_TEXCOORD;
break;
case TGSI_SEMANTIC_NORMAL:
*idx = semantic.Index;
*usage = SVGA3D_DECLUSAGE_NORMAL;
break;
case TGSI_SEMANTIC_CLIPDIST:
case TGSI_SEMANTIC_CLIPVERTEX:
/* XXX at this time we don't support clip distance or clip vertices */
debug_warn_once("unsupported clip distance/vertex attribute\n");
*usage = SVGA3D_DECLUSAGE_TEXCOORD;
*idx = 0;
return TRUE;
default:
assert(0);
*usage = SVGA3D_DECLUSAGE_TEXCOORD;
*idx = 0;
return FALSE;
}
return TRUE;
}
/**
* Emit a PS input (or VS depth/fog output) register declaration.
* For example, if usage = SVGA3D_DECLUSAGE_TEXCOORD, reg.num = 1, and
* index = 3, we'll emit "dcl_texcoord3 v1".
*/
static boolean
emit_decl(struct svga_shader_emitter *emit,
SVGA3dShaderDestToken reg,
unsigned usage,
unsigned index)
{
SVGA3DOpDclArgs dcl;
SVGA3dShaderInstToken opcode;
/* check values against bitfield sizes */
assert(index < 16);
assert(usage <= SVGA3D_DECLUSAGE_MAX);
opcode = inst_token( SVGA3DOP_DCL );
dcl.values[0] = 0;
dcl.values[1] = 0;
dcl.dst = reg;
dcl.usage = usage;
dcl.index = index;
dcl.values[0] |= 1<<31;
return (emit_instruction(emit, opcode) &&
svga_shader_emit_dwords( emit, dcl.values, ARRAY_SIZE(dcl.values)));
}
/**
* Emit declaration for PS front/back-face input register.
*/
static boolean
emit_vface_decl(struct svga_shader_emitter *emit)
{
if (!emit->emitted_vface) {
SVGA3dShaderDestToken reg =
dst_register(SVGA3DREG_MISCTYPE, SVGA3DMISCREG_FACE);
if (!emit_decl( emit, reg, 0, 0 ))
return FALSE;
emit->emitted_vface = TRUE;
}
return TRUE;
}
/**
* Emit PS input register to pass depth/fog coordinates.
* Note that this always goes into texcoord[0].
*/
static boolean
ps30_input_emit_depth_fog( struct svga_shader_emitter *emit,
struct src_register *out )
{
struct src_register reg;
if (emit->emitted_depth_fog) {
*out = emit->ps_depth_fog;
return TRUE;
}
if (emit->ps30_input_count >= SVGA3D_INPUTREG_MAX)
return FALSE;
reg = src_register( SVGA3DREG_INPUT,
emit->ps30_input_count++ );
*out = emit->ps_depth_fog = reg;
emit->emitted_depth_fog = TRUE;
return emit_decl( emit, dst( reg ), SVGA3D_DECLUSAGE_TEXCOORD, 0 );
}
/**
* Process a PS input declaration.
* We'll emit a declaration like "dcl_texcoord1 v2"
*/
static boolean
ps30_input(struct svga_shader_emitter *emit,
struct tgsi_declaration_semantic semantic,
unsigned idx)
{
unsigned usage, index;
SVGA3dShaderDestToken reg;
if (semantic.Name == TGSI_SEMANTIC_POSITION) {
emit->ps_true_pos = src_register( SVGA3DREG_MISCTYPE,
SVGA3DMISCREG_POSITION );
emit->ps_true_pos.base.swizzle = TRANSLATE_SWIZZLE( TGSI_SWIZZLE_X,
TGSI_SWIZZLE_Y,
TGSI_SWIZZLE_Y,
TGSI_SWIZZLE_Y );
reg = writemask( dst(emit->ps_true_pos),
TGSI_WRITEMASK_XY );
emit->ps_reads_pos = TRUE;
if (emit->info.reads_z) {
emit->ps_temp_pos = dst_register( SVGA3DREG_TEMP,
emit->nr_hw_temp );
emit->input_map[idx] = src_register( SVGA3DREG_TEMP,
emit->nr_hw_temp );
emit->nr_hw_temp++;
if (!ps30_input_emit_depth_fog( emit, &emit->ps_depth_pos ))
return FALSE;
emit->ps_depth_pos.base.swizzle = TRANSLATE_SWIZZLE( TGSI_SWIZZLE_Z,
TGSI_SWIZZLE_Z,
TGSI_SWIZZLE_Z,
TGSI_SWIZZLE_W );
}
else {
emit->input_map[idx] = emit->ps_true_pos;
}
return emit_decl( emit, reg, 0, 0 );
}
else if (emit->key.fs.light_twoside &&
(semantic.Name == TGSI_SEMANTIC_COLOR)) {
if (!translate_vs_ps_semantic( emit, semantic, &usage, &index ))
return FALSE;
emit->internal_color_idx[emit->internal_color_count] = idx;
emit->input_map[idx] = src_register( SVGA3DREG_INPUT, emit->ps30_input_count );
emit->ps30_input_count++;
emit->internal_color_count++;
reg = dst( emit->input_map[idx] );
if (!emit_decl( emit, reg, usage, index ))
return FALSE;
semantic.Name = TGSI_SEMANTIC_BCOLOR;
if (!translate_vs_ps_semantic( emit, semantic, &usage, &index ))
return FALSE;
if (emit->ps30_input_count >= SVGA3D_INPUTREG_MAX)
return FALSE;
reg = dst_register( SVGA3DREG_INPUT, emit->ps30_input_count++ );
if (!emit_decl( emit, reg, usage, index ))
return FALSE;
if (!emit_vface_decl( emit ))
return FALSE;
return TRUE;
}
else if (semantic.Name == TGSI_SEMANTIC_FACE) {
if (!emit_vface_decl( emit ))
return FALSE;
emit->emit_frontface = TRUE;
emit->internal_frontface_idx = idx;
return TRUE;
}
else if (semantic.Name == TGSI_SEMANTIC_FOG) {
assert(semantic.Index == 0);
if (!ps30_input_emit_depth_fog( emit, &emit->input_map[idx] ))
return FALSE;
emit->input_map[idx].base.swizzle = TRANSLATE_SWIZZLE( TGSI_SWIZZLE_X,
TGSI_SWIZZLE_X,
TGSI_SWIZZLE_X,
TGSI_SWIZZLE_X );
return TRUE;
}
else {
if (!translate_vs_ps_semantic( emit, semantic, &usage, &index ))
return FALSE;
if (emit->ps30_input_count >= SVGA3D_INPUTREG_MAX)
return FALSE;
emit->input_map[idx] = src_register( SVGA3DREG_INPUT, emit->ps30_input_count++ );
reg = dst( emit->input_map[idx] );
if (!emit_decl( emit, reg, usage, index ))
return FALSE;
if (semantic.Name == TGSI_SEMANTIC_GENERIC &&
emit->key.sprite_origin_lower_left &&
index >= 1 &&
emit->key.tex[index - 1].sprite_texgen) {
/* This is a sprite texture coord with lower-left origin.
* We need to invert the texture T coordinate since the SVGA3D
* device only supports an upper-left origin.
*/
unsigned unit = index - 1;
emit->inverted_texcoords |= (1 << unit);
/* save original texcoord reg */
emit->ps_true_texcoord[unit] = emit->input_map[idx];
/* this temp register will be the results of the MAD instruction */
emit->ps_inverted_texcoord[unit] =
src_register(SVGA3DREG_TEMP, emit->nr_hw_temp);
emit->nr_hw_temp++;
emit->ps_inverted_texcoord_input[unit] = idx;
/* replace input_map entry with the temp register */
emit->input_map[idx] = emit->ps_inverted_texcoord[unit];
}
return TRUE;
}
}
/**
* Process a PS output declaration.
* Note that we don't actually emit a SVGA3DOpDcl for PS outputs.
* \idx register index, such as OUT[2] (not semantic index)
*/
static boolean
ps30_output(struct svga_shader_emitter *emit,
struct tgsi_declaration_semantic semantic,
unsigned idx)
{
switch (semantic.Name) {
case TGSI_SEMANTIC_COLOR:
if (emit->unit == PIPE_SHADER_FRAGMENT) {
if (emit->key.fs.white_fragments) {
/* Used for XOR logicop mode */
emit->output_map[idx] = dst_register( SVGA3DREG_TEMP,
emit->nr_hw_temp++ );
emit->temp_color_output[idx] = emit->output_map[idx];
emit->true_color_output[idx] = dst_register(SVGA3DREG_COLOROUT,
semantic.Index);
}
else if (emit->key.fs.write_color0_to_n_cbufs) {
/* We'll write color output [0] to all render targets.
* Prepare all the output registers here, but only when the
* semantic.Index == 0 so we don't do this more than once.
*/
if (semantic.Index == 0) {
unsigned i;
for (i = 0; i < emit->key.fs.write_color0_to_n_cbufs; i++) {
emit->output_map[idx+i] = dst_register(SVGA3DREG_TEMP,
emit->nr_hw_temp++);
emit->temp_color_output[i] = emit->output_map[idx+i];
emit->true_color_output[i] = dst_register(SVGA3DREG_COLOROUT,
i);
}
}
}
else {
emit->output_map[idx] =
dst_register(SVGA3DREG_COLOROUT, semantic.Index);
}
}
else {
emit->output_map[idx] = dst_register( SVGA3DREG_COLOROUT,
semantic.Index );
}
break;
case TGSI_SEMANTIC_POSITION:
emit->output_map[idx] = dst_register( SVGA3DREG_TEMP,
emit->nr_hw_temp++ );
emit->temp_pos = emit->output_map[idx];
emit->true_pos = dst_register( SVGA3DREG_DEPTHOUT,
semantic.Index );
break;
default:
assert(0);
/* A wild stab in the dark. */
emit->output_map[idx] = dst_register( SVGA3DREG_COLOROUT, 0 );
break;
}
return TRUE;
}
/**
* Declare a VS input register.
* We still make up the input semantics the same as in 2.0
*/
static boolean
vs30_input(struct svga_shader_emitter *emit,
struct tgsi_declaration_semantic semantic,
unsigned idx)
{
SVGA3DOpDclArgs dcl;
SVGA3dShaderInstToken opcode;
unsigned usage, index;
opcode = inst_token( SVGA3DOP_DCL );
dcl.values[0] = 0;
dcl.values[1] = 0;
emit->input_map[idx] = src_register( SVGA3DREG_INPUT, idx );
dcl.dst = dst_register( SVGA3DREG_INPUT, idx );
assert(dcl.dst.reserved0);
svga_generate_vdecl_semantics( idx, &usage, &index );
dcl.usage = usage;
dcl.index = index;
dcl.values[0] |= 1<<31;
return (emit_instruction(emit, opcode) &&
svga_shader_emit_dwords( emit, dcl.values, ARRAY_SIZE(dcl.values)));
}
/**
* Declare VS output for holding depth/fog.
*/
static boolean
vs30_output_emit_depth_fog(struct svga_shader_emitter *emit,
SVGA3dShaderDestToken *out)
{
SVGA3dShaderDestToken reg;
if (emit->emitted_depth_fog) {
*out = emit->vs_depth_fog;
return TRUE;
}
reg = dst_register( SVGA3DREG_OUTPUT, emit->vs30_output_count++ );
*out = emit->vs_depth_fog = reg;
emit->emitted_depth_fog = TRUE;
return emit_decl( emit, reg, SVGA3D_DECLUSAGE_TEXCOORD, 0 );
}
/**
* Declare a VS output.
* VS3.0 outputs have proper declarations and semantic info for
* matching against PS inputs.
*/
static boolean
vs30_output(struct svga_shader_emitter *emit,
struct tgsi_declaration_semantic semantic,
unsigned idx)
{
SVGA3DOpDclArgs dcl;
SVGA3dShaderInstToken opcode;
unsigned usage, index;
opcode = inst_token( SVGA3DOP_DCL );
dcl.values[0] = 0;
dcl.values[1] = 0;
if (!translate_vs_ps_semantic( emit, semantic, &usage, &index ))
return FALSE;
if (emit->vs30_output_count >= SVGA3D_OUTPUTREG_MAX)
return FALSE;
dcl.dst = dst_register( SVGA3DREG_OUTPUT, emit->vs30_output_count++ );
dcl.usage = usage;
dcl.index = index;
dcl.values[0] |= 1<<31;
if (semantic.Name == TGSI_SEMANTIC_POSITION) {
assert(idx == 0);
emit->output_map[idx] = dst_register( SVGA3DREG_TEMP,
emit->nr_hw_temp++ );
emit->temp_pos = emit->output_map[idx];
emit->true_pos = dcl.dst;
/* Grab an extra output for the depth output */
if (!vs30_output_emit_depth_fog( emit, &emit->depth_pos ))
return FALSE;
}
else if (semantic.Name == TGSI_SEMANTIC_PSIZE) {
emit->output_map[idx] = dst_register( SVGA3DREG_TEMP,
emit->nr_hw_temp++ );
emit->temp_psiz = emit->output_map[idx];
/* This has the effect of not declaring psiz (below) and not
* emitting the final MOV to true_psiz in the postamble.
*/
if (!emit->key.vs.allow_psiz)
return TRUE;
emit->true_psiz = dcl.dst;
}
else if (semantic.Name == TGSI_SEMANTIC_FOG) {
/*
* Fog is shared with depth.
* So we need to decrement out_count since emit_depth_fog will increment it.
*/
emit->vs30_output_count--;
if (!vs30_output_emit_depth_fog( emit, &emit->output_map[idx] ))
return FALSE;
return TRUE;
}
else {
emit->output_map[idx] = dcl.dst;
}
return (emit_instruction(emit, opcode) &&
svga_shader_emit_dwords( emit, dcl.values, ARRAY_SIZE(dcl.values)));
}
/** Translate PIPE_TEXTURE_x to SVGA3DSAMP_x */
static ubyte
svga_tgsi_sampler_type(const struct svga_shader_emitter *emit, int idx)
{
switch (emit->sampler_target[idx]) {
case TGSI_TEXTURE_1D:
return SVGA3DSAMP_2D;
case TGSI_TEXTURE_2D:
case TGSI_TEXTURE_RECT:
return SVGA3DSAMP_2D;
case TGSI_TEXTURE_3D:
return SVGA3DSAMP_VOLUME;
case TGSI_TEXTURE_CUBE:
return SVGA3DSAMP_CUBE;
}
return SVGA3DSAMP_UNKNOWN;
}
static boolean
ps30_sampler( struct svga_shader_emitter *emit,
unsigned idx )
{
SVGA3DOpDclArgs dcl;
SVGA3dShaderInstToken opcode;
opcode = inst_token( SVGA3DOP_DCL );
dcl.values[0] = 0;
dcl.values[1] = 0;
dcl.dst = dst_register( SVGA3DREG_SAMPLER, idx );
dcl.type = svga_tgsi_sampler_type( emit, idx );
dcl.values[0] |= 1<<31;
return (emit_instruction(emit, opcode) &&
svga_shader_emit_dwords( emit, dcl.values, ARRAY_SIZE(dcl.values)));
}
boolean
svga_shader_emit_samplers_decl( struct svga_shader_emitter *emit )
{
unsigned i;
for (i = 0; i < emit->num_samplers; i++) {
if (!ps30_sampler(emit, i))
return FALSE;
}
return TRUE;
}
boolean
svga_translate_decl_sm30( struct svga_shader_emitter *emit,
const struct tgsi_full_declaration *decl )
{
unsigned first = decl->Range.First;
unsigned last = decl->Range.Last;
unsigned idx;
for( idx = first; idx <= last; idx++ ) {
boolean ok = TRUE;
switch (decl->Declaration.File) {
case TGSI_FILE_SAMPLER:
assert (emit->unit == PIPE_SHADER_FRAGMENT);
/* just keep track of the number of samplers here.
* Will emit the declaration in the helpers function.
*/
emit->num_samplers = MAX2(emit->num_samplers, decl->Range.Last + 1);
break;
case TGSI_FILE_INPUT:
if (emit->unit == PIPE_SHADER_VERTEX)
ok = vs30_input( emit, decl->Semantic, idx );
else
ok = ps30_input( emit, decl->Semantic, idx );
break;
case TGSI_FILE_OUTPUT:
if (emit->unit == PIPE_SHADER_VERTEX)
ok = vs30_output( emit, decl->Semantic, idx );
else
ok = ps30_output( emit, decl->Semantic, idx );
break;
case TGSI_FILE_SAMPLER_VIEW:
{
unsigned unit = decl->Range.First;
assert(decl->Range.First == decl->Range.Last);
emit->sampler_target[unit] = decl->SamplerView.Resource;
}
break;
default:
/* don't need to declare other vars */
ok = TRUE;
}
if (!ok)
return FALSE;
}
return TRUE;
}