blob: 3b888d723e25bfe797166eab4f00eadd3b29b1ad [file] [log] [blame]
// SwiftShader Software Renderer
//
// Copyright(c) 2005-2013 TransGaming Inc.
//
// All rights reserved. No part of this software may be copied, distributed, transmitted,
// transcribed, stored in a retrieval system, translated into any human or computer
// language by any means, or disclosed to third parties without the explicit written
// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
// or implied, including but not limited to any patent rights, are granted to you.
//
#include "VertexShader.hpp"
#include "Vertex.hpp"
#include "Debug.hpp"
#include <string.h>
namespace sw
{
VertexShader::VertexShader(const VertexShader *vs) : Shader()
{
version = 0x0300;
positionRegister = Pos;
pointSizeRegister = -1; // No vertex point size
instanceIdDeclared = false;
for(int i = 0; i < MAX_INPUT_ATTRIBUTES; i++)
{
input[i] = Semantic(-1, -1);
}
if(vs) // Make a copy
{
for(size_t i = 0; i < vs->getLength(); i++)
{
append(new sw::Shader::Instruction(*vs->getInstruction(i)));
}
memcpy(output, vs->output, sizeof(output));
memcpy(input, vs->input, sizeof(input));
positionRegister = vs->positionRegister;
pointSizeRegister = vs->pointSizeRegister;
usedSamplers = vs->usedSamplers;
optimize();
analyze();
}
}
VertexShader::VertexShader(const unsigned long *token) : Shader()
{
parse(token);
positionRegister = Pos;
pointSizeRegister = -1; // No vertex point size
instanceIdDeclared = false;
for(int i = 0; i < MAX_INPUT_ATTRIBUTES; i++)
{
input[i] = Semantic(-1, -1);
}
optimize();
analyze();
}
VertexShader::~VertexShader()
{
}
int VertexShader::validate(const unsigned long *const token)
{
if(!token)
{
return 0;
}
unsigned short version = (unsigned short)(token[0] & 0x0000FFFF);
unsigned char minorVersion = (unsigned char)(token[0] & 0x000000FF);
unsigned char majorVersion = (unsigned char)((token[0] & 0x0000FF00) >> 8);
ShaderType shaderType = (ShaderType)((token[0] & 0xFFFF0000) >> 16);
if(shaderType != SHADER_VERTEX || majorVersion > 3)
{
return 0;
}
int instructionCount = 1;
for(int i = 0; token[i] != 0x0000FFFF; i++)
{
if((token[i] & 0x0000FFFF) == 0x0000FFFE) // Comment token
{
int length = (token[i] & 0x7FFF0000) >> 16;
i += length;
}
else
{
Shader::Opcode opcode = (Shader::Opcode)(token[i] & 0x0000FFFF);
switch(opcode)
{
case Shader::OPCODE_TEXCOORD:
case Shader::OPCODE_TEXKILL:
case Shader::OPCODE_TEX:
case Shader::OPCODE_TEXBEM:
case Shader::OPCODE_TEXBEML:
case Shader::OPCODE_TEXREG2AR:
case Shader::OPCODE_TEXREG2GB:
case Shader::OPCODE_TEXM3X2PAD:
case Shader::OPCODE_TEXM3X2TEX:
case Shader::OPCODE_TEXM3X3PAD:
case Shader::OPCODE_TEXM3X3TEX:
case Shader::OPCODE_RESERVED0:
case Shader::OPCODE_TEXM3X3SPEC:
case Shader::OPCODE_TEXM3X3VSPEC:
case Shader::OPCODE_TEXREG2RGB:
case Shader::OPCODE_TEXDP3TEX:
case Shader::OPCODE_TEXM3X2DEPTH:
case Shader::OPCODE_TEXDP3:
case Shader::OPCODE_TEXM3X3:
case Shader::OPCODE_TEXDEPTH:
case Shader::OPCODE_CMP0:
case Shader::OPCODE_BEM:
case Shader::OPCODE_DP2ADD:
case Shader::OPCODE_DFDX:
case Shader::OPCODE_DFDY:
case Shader::OPCODE_TEXLDD:
return 0; // Unsupported operation
default:
instructionCount++;
break;
}
i += size(token[i], version);
}
}
return instructionCount;
}
bool VertexShader::containsTexldl() const
{
return texldl;
}
void VertexShader::analyze()
{
analyzeInput();
analyzeOutput();
analyzeDirtyConstants();
analyzeTexldl();
analyzeDynamicBranching();
analyzeSamplers();
analyzeCallSites();
analyzeDynamicIndexing();
}
void VertexShader::analyzeInput()
{
for(unsigned int i = 0; i < instruction.size(); i++)
{
if(instruction[i]->opcode == Shader::OPCODE_DCL &&
instruction[i]->dst.type == Shader::PARAMETER_INPUT)
{
int index = instruction[i]->dst.index;
input[index] = Semantic(instruction[i]->usage, instruction[i]->usageIndex);
}
}
}
void VertexShader::analyzeOutput()
{
if(version < 0x0300)
{
output[Pos][0] = Semantic(Shader::USAGE_POSITION, 0);
output[Pos][1] = Semantic(Shader::USAGE_POSITION, 0);
output[Pos][2] = Semantic(Shader::USAGE_POSITION, 0);
output[Pos][3] = Semantic(Shader::USAGE_POSITION, 0);
for(unsigned int i = 0; i < instruction.size(); i++)
{
const DestinationParameter &dst = instruction[i]->dst;
switch(dst.type)
{
case Shader::PARAMETER_RASTOUT:
switch(dst.index)
{
case 0:
// Position already assumed written
break;
case 1:
output[Fog][0] = Semantic(Shader::USAGE_FOG, 0);
break;
case 2:
output[Pts][1] = Semantic(Shader::USAGE_PSIZE, 0);
pointSizeRegister = Pts;
break;
default: ASSERT(false);
}
break;
case Shader::PARAMETER_ATTROUT:
if(dst.index == 0)
{
if(dst.x) output[D0][0] = Semantic(Shader::USAGE_COLOR, 0);
if(dst.y) output[D0][1] = Semantic(Shader::USAGE_COLOR, 0);
if(dst.z) output[D0][2] = Semantic(Shader::USAGE_COLOR, 0);
if(dst.w) output[D0][3] = Semantic(Shader::USAGE_COLOR, 0);
}
else if(dst.index == 1)
{
if(dst.x) output[D1][0] = Semantic(Shader::USAGE_COLOR, 1);
if(dst.y) output[D1][1] = Semantic(Shader::USAGE_COLOR, 1);
if(dst.z) output[D1][2] = Semantic(Shader::USAGE_COLOR, 1);
if(dst.w) output[D1][3] = Semantic(Shader::USAGE_COLOR, 1);
}
else ASSERT(false);
break;
case Shader::PARAMETER_TEXCRDOUT:
if(dst.x) output[T0 + dst.index][0] = Semantic(Shader::USAGE_TEXCOORD, dst.index);
if(dst.y) output[T0 + dst.index][1] = Semantic(Shader::USAGE_TEXCOORD, dst.index);
if(dst.z) output[T0 + dst.index][2] = Semantic(Shader::USAGE_TEXCOORD, dst.index);
if(dst.w) output[T0 + dst.index][3] = Semantic(Shader::USAGE_TEXCOORD, dst.index);
break;
default:
break;
}
}
}
else // Shader Model 3.0 input declaration
{
for(unsigned int i = 0; i < instruction.size(); i++)
{
if(instruction[i]->opcode == Shader::OPCODE_DCL &&
instruction[i]->dst.type == Shader::PARAMETER_OUTPUT)
{
unsigned char usage = instruction[i]->usage;
unsigned char usageIndex = instruction[i]->usageIndex;
const DestinationParameter &dst = instruction[i]->dst;
if(dst.x) output[dst.index][0] = Semantic(usage, usageIndex);
if(dst.y) output[dst.index][1] = Semantic(usage, usageIndex);
if(dst.z) output[dst.index][2] = Semantic(usage, usageIndex);
if(dst.w) output[dst.index][3] = Semantic(usage, usageIndex);
if(usage == Shader::USAGE_POSITION && usageIndex == 0)
{
positionRegister = dst.index;
}
if(usage == Shader::USAGE_PSIZE && usageIndex == 0)
{
pointSizeRegister = dst.index;
}
}
}
}
}
void VertexShader::analyzeTexldl()
{
texldl = false;
for(unsigned int i = 0; i < instruction.size(); i++)
{
if(instruction[i]->opcode == Shader::OPCODE_TEXLDL)
{
texldl = true;
break;
}
}
}
}