Add SwiftShader source to repo

Oct 6 code drop from Transgaming
Review URL: https://chromereviews.googleplex.com/3846015
diff --git a/src/Renderer/VertexProcessor.cpp b/src/Renderer/VertexProcessor.cpp
new file mode 100644
index 0000000..6f23be7
--- /dev/null
+++ b/src/Renderer/VertexProcessor.cpp
@@ -0,0 +1,978 @@
+// SwiftShader Software Renderer
+//
+// Copyright(c) 2005-2011 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 "VertexProcessor.hpp"
+
+#include "Viewport.hpp"
+#include "Math.hpp"
+#include "VertexPipeline.hpp"
+#include "VertexProgram.hpp"
+#include "VertexShader.hpp"
+#include "PixelShader.hpp"
+#include "Constants.hpp"
+#include "Debug.hpp"
+
+#include <malloc.h>
+
+namespace sw
+{
+	void VertexCache::clear()
+	{
+		for(int i = 0; i < 16; i++)
+		{
+			tag[i] = 0x80000000;
+		}
+	}
+
+	unsigned int VertexProcessor::States::computeHash()
+	{
+		unsigned int *state = (unsigned int*)this;
+		unsigned int hash = 0;
+
+		for(int i = 0; i < sizeof(States) / 4; i++)
+		{
+			hash ^= state[i];
+		}
+
+		return hash;
+	}
+
+	VertexProcessor::State::State()
+	{
+		memset(this, 0, sizeof(State));
+	}
+
+	bool VertexProcessor::State::operator==(const State &state) const
+	{
+		if(hash != state.hash)
+		{
+			return false;
+		}
+
+		return memcmp(static_cast<const States*>(this), static_cast<const States*>(&state), sizeof(States)) == 0;
+	}
+
+	VertexProcessor::VertexProcessor(Context *context) : context(context)
+	{
+		for(int i = 0; i < 12; i++)
+		{
+			M[i] = 1;
+		}
+
+		V = 1;
+		B = 1;
+		P = 0;
+		PB = 0;
+		PBV = 0;
+		
+		for(int i = 0; i < 12; i++)
+		{
+			PBVM[i] = 0;
+		}
+
+		setLightingEnable(true);
+		setSpecularEnable(false);
+
+		for(int i = 0; i < 8; i++)
+		{
+			setLightEnable(i, false);
+			setLightPosition(i, 0);
+		}
+
+		updateMatrix = true;
+		updateViewMatrix = true;
+		updateBaseMatrix = true;
+		updateProjectionMatrix = true;
+		updateLighting = true;
+
+		for(int i = 0; i < 12; i++)
+		{
+			updateModelMatrix[i] = true;
+		}
+
+		routineCache = 0;
+		setRoutineCacheSize(1024);
+	}
+
+	VertexProcessor::~VertexProcessor()
+	{
+		delete routineCache;
+		routineCache = 0;
+	}
+
+	void VertexProcessor::setInputStream(int index, const Stream &stream)
+	{
+		context->input[index] = stream;
+	}
+
+	void VertexProcessor::setInputPositionStream(const Stream &stream)
+	{
+		context->input[Position] = stream;
+	}
+
+	void VertexProcessor::setInputBlendWeightStream(const Stream &stream)
+	{
+		context->input[BlendWeight] = stream;
+	}
+
+	void VertexProcessor::setInputBlendIndicesStream(const Stream &stream)
+	{
+		context->input[BlendIndices] = stream;
+	}
+
+	void VertexProcessor::setInputNormalStream(const Stream &stream)
+	{
+		context->input[Normal] = stream;
+	}
+
+	void VertexProcessor::setInputPSizeStream(const Stream &stream)
+	{
+		context->input[PSize] = stream;
+	}
+
+	void VertexProcessor::setInputTexCoordStream(const Stream &stream, int index)
+	{
+		context->input[TexCoord0 + index] = stream;
+	}
+
+	void VertexProcessor::setInputPositiontStream(const Stream &stream)
+	{
+		context->input[PositionT] = stream;
+	}
+
+	void VertexProcessor::setInputColorStream(const Stream &stream, int index)
+	{
+		context->input[Color0 + index] = stream;
+	}
+
+	void VertexProcessor::resetInputStreams(bool preTransformed)
+	{
+		for(int i = 0; i < 16; i++)
+		{
+			context->input[i].defaults();
+		}
+
+		context->preTransformed = preTransformed;
+	}
+
+	void VertexProcessor::setFloatConstant(unsigned int index, const float value[4])
+	{
+		if(index < 256)
+		{
+			c[index][0] = value[0];
+			c[index][1] = value[1];
+			c[index][2] = value[2];
+			c[index][3] = value[3];
+		}
+		else ASSERT(false);
+	}
+
+	void VertexProcessor::setIntegerConstant(unsigned int index, const int integer[4])
+	{
+		if(index < 16)
+		{
+			i[index][0] = integer[0];
+			i[index][1] = integer[1];
+			i[index][2] = integer[2];
+			i[index][3] = integer[3];
+		}
+		else ASSERT(false);
+	}
+
+	void VertexProcessor::setBooleanConstant(unsigned int index, int boolean)
+	{
+		if(index < 16)
+		{
+			b[index] = boolean != 0;
+		}
+		else ASSERT(false);
+	}
+
+	void VertexProcessor::setModelMatrix(const Matrix &M, int i)
+	{
+		if(i < 12)
+		{
+			this->M[i] = M;
+
+			updateMatrix = true;
+			updateModelMatrix[i] = true;
+			updateLighting = true;
+		}
+		else ASSERT(false);
+	}
+
+	void VertexProcessor::setViewMatrix(const Matrix &V)
+	{
+		this->V = V;
+
+		updateMatrix = true;
+		updateViewMatrix = true;
+	}
+
+	void VertexProcessor::setBaseMatrix(const Matrix &B)
+	{
+		this->B = B;
+
+		updateMatrix = true;
+		updateBaseMatrix = true;
+	}
+
+	void VertexProcessor::setProjectionMatrix(const Matrix &P)
+	{
+		this->P = P;
+		context->wBasedFog = (P[3][0] != 0.0f) || (P[3][1] != 0.0f) || (P[3][2] != 0.0f) || (P[3][3] != 1.0f);
+
+		updateMatrix = true;
+		updateProjectionMatrix = true;
+	}
+
+	void VertexProcessor::setLightingEnable(bool lightingEnable)
+	{
+		context->setLightingEnable(lightingEnable);
+
+		updateLighting = true;
+	}
+
+	void VertexProcessor::setLightEnable(unsigned int light, bool lightEnable)
+	{
+		if(light < 8)
+		{
+			context->setLightEnable(light, lightEnable);
+		}
+		else ASSERT(false);
+
+		updateLighting = true;
+	}
+
+	void VertexProcessor::setSpecularEnable(bool specularEnable)
+	{
+		context->setSpecularEnable(specularEnable);
+
+		updateLighting = true;
+	}
+
+	void VertexProcessor::setLightPosition(unsigned int light, const Point &lightPosition)
+	{
+		if(light < 8)
+		{
+			context->setLightPosition(light, lightPosition);
+		}
+		else ASSERT(false);
+
+		updateLighting = true;
+	}
+
+	void VertexProcessor::setLightDiffuse(unsigned int light, const Color<float> &lightDiffuse)
+	{
+		if(light < 8)
+		{
+			ff.lightDiffuse[light][0] = lightDiffuse.r;
+			ff.lightDiffuse[light][1] = lightDiffuse.g;
+			ff.lightDiffuse[light][2] = lightDiffuse.b;
+			ff.lightDiffuse[light][3] = lightDiffuse.a;
+		}
+		else ASSERT(false);
+	}
+
+	void VertexProcessor::setLightSpecular(unsigned int light, const Color<float> &lightSpecular)
+	{
+		if(light < 8)
+		{
+			ff.lightSpecular[light][0] = lightSpecular.r;
+			ff.lightSpecular[light][1] = lightSpecular.g;
+			ff.lightSpecular[light][2] = lightSpecular.b;
+			ff.lightSpecular[light][3] = lightSpecular.a;
+		}
+		else ASSERT(false);
+	}
+
+	void VertexProcessor::setLightAmbient(unsigned int light, const Color<float> &lightAmbient)
+	{
+		if(light < 8)
+		{
+			ff.lightAmbient[light][0] = lightAmbient.r;
+			ff.lightAmbient[light][1] = lightAmbient.g;
+			ff.lightAmbient[light][2] = lightAmbient.b;
+			ff.lightAmbient[light][3] = lightAmbient.a;
+		}
+		else ASSERT(false);
+	}
+
+	void VertexProcessor::setLightAttenuation(unsigned int light, float constant, float linear, float quadratic)
+	{
+		if(light < 8)
+		{
+			ff.attenuationConstant[light] = replicate(constant);			
+			ff.attenuationLinear[light] = replicate(linear);
+			ff.attenuationQuadratic[light] = replicate(quadratic);
+		}
+		else ASSERT(false);
+	}
+
+	void VertexProcessor::setLightRange(unsigned int light, float lightRange)
+	{
+		if(light < 8)
+		{
+			ff.lightRange[light] = lightRange;
+		}
+		else ASSERT(false);
+	}
+
+	void VertexProcessor::setFogEnable(bool fogEnable)
+	{
+		context->fogEnable = fogEnable;
+	}
+
+	void VertexProcessor::setVertexFogMode(Context::FogMode fogMode)
+	{
+		context->vertexFogMode = fogMode;
+	}
+
+	void VertexProcessor::setColorVertexEnable(bool colorVertexEnable)
+	{
+		context->setColorVertexEnable(colorVertexEnable);
+	}
+
+	void VertexProcessor::setDiffuseMaterialSource(Context::MaterialSource diffuseMaterialSource)
+	{
+		context->setDiffuseMaterialSource(diffuseMaterialSource);
+	}
+
+	void VertexProcessor::setSpecularMaterialSource(Context::MaterialSource specularMaterialSource)
+	{
+		context->setSpecularMaterialSource(specularMaterialSource);
+	}
+
+	void VertexProcessor::setAmbientMaterialSource(Context::MaterialSource ambientMaterialSource)
+	{
+		context->setAmbientMaterialSource(ambientMaterialSource);
+	}
+
+	void VertexProcessor::setEmissiveMaterialSource(Context::MaterialSource emissiveMaterialSource)
+	{
+		context->setEmissiveMaterialSource(emissiveMaterialSource);
+	}
+
+	void VertexProcessor::setGlobalAmbient(const Color<float> &globalAmbient)
+	{
+		ff.globalAmbient[0] = globalAmbient.r;
+		ff.globalAmbient[1] = globalAmbient.g;
+		ff.globalAmbient[2] = globalAmbient.b;
+		ff.globalAmbient[3] = globalAmbient.a;
+	}
+
+	void VertexProcessor::setMaterialEmission(const Color<float> &emission)
+	{
+		ff.materialEmission[0] = emission.r;
+		ff.materialEmission[1] = emission.g;
+		ff.materialEmission[2] = emission.b;
+		ff.materialEmission[3] = emission.a;
+	}
+
+	void VertexProcessor::setMaterialAmbient(const Color<float> &materialAmbient)
+	{
+		ff.materialAmbient[0] = materialAmbient.r;
+		ff.materialAmbient[1] = materialAmbient.g;
+		ff.materialAmbient[2] = materialAmbient.b;
+		ff.materialAmbient[3] = materialAmbient.a;
+	}
+
+	void VertexProcessor::setMaterialDiffuse(const Color<float> &diffuseColor)
+	{
+		ff.materialDiffuse[0] = diffuseColor.r;
+		ff.materialDiffuse[1] = diffuseColor.g;
+		ff.materialDiffuse[2] = diffuseColor.b;
+		ff.materialDiffuse[3] = diffuseColor.a;
+	}
+
+	void VertexProcessor::setMaterialSpecular(const Color<float> &specularColor)
+	{
+		ff.materialSpecular[0] = specularColor.r;
+		ff.materialSpecular[1] = specularColor.g;
+		ff.materialSpecular[2] = specularColor.b;
+		ff.materialSpecular[3] = specularColor.a;
+	}
+
+	void VertexProcessor::setMaterialShininess(float specularPower)
+	{
+		ff.materialShininess = specularPower;
+	}
+
+	void VertexProcessor::setLightViewPosition(unsigned int light, const Point &P)
+	{
+		if(light < 8)
+		{
+			ff.lightPosition[light][0] = P.x;
+			ff.lightPosition[light][1] = P.y;
+			ff.lightPosition[light][2] = P.z;
+			ff.lightPosition[light][3] = 1;
+		}
+		else ASSERT(false);
+	}
+
+	void VertexProcessor::setRangeFogEnable(bool enable)
+	{
+		context->rangeFogEnable = enable;
+	}
+
+	void VertexProcessor::setIndexedVertexBlendEnable(bool indexedVertexBlendEnable)
+	{
+		context->indexedVertexBlendEnable = indexedVertexBlendEnable;
+	}
+
+	void VertexProcessor::setVertexBlendMatrixCount(unsigned int vertexBlendMatrixCount)
+	{
+		if(vertexBlendMatrixCount <= 4)
+		{
+			context->vertexBlendMatrixCount = vertexBlendMatrixCount;
+		}
+		else ASSERT(false);
+	}
+
+	void VertexProcessor::setTextureWrap(unsigned int stage, int mask)
+	{
+		if(stage < 16)
+		{
+			context->textureWrap[stage] = mask;
+		}
+		else ASSERT(false);
+
+		context->textureWrapActive = false;
+
+		for(int i = 0; i < 16; i++)
+		{
+			context->textureWrapActive |= (context->textureWrap[i] != 0x00);
+		}
+	}
+
+	void VertexProcessor::setTexGen(unsigned int stage, Context::TexGen texGen)
+	{
+		if(stage < 8)
+		{
+			context->texGen[stage] = texGen;
+		}
+		else ASSERT(false);
+	}
+
+	void VertexProcessor::setLocalViewer(bool localViewer)
+	{
+		context->localViewer = localViewer;
+	}
+
+	void VertexProcessor::setNormalizeNormals(bool normalizeNormals)
+	{
+		context->normalizeNormals = normalizeNormals;
+	}
+
+	void VertexProcessor::setTextureMatrix(int stage, const Matrix &T)
+	{
+		for(int i = 0; i < 4; i++)
+		{
+			for(int j = 0; j < 4; j++)
+			{
+				ff.textureTransform[stage][i][j] = T[i][j];
+			}
+		}
+	}
+
+	void VertexProcessor::setTextureTransform(int stage, int count, bool project)
+	{
+		context->textureTransformCount[stage] = count;
+		context->textureTransformProject[stage] = project;
+	}
+
+	void VertexProcessor::setTextureFilter(unsigned int sampler, FilterType textureFilter)
+	{
+		if(sampler < 4)
+		{
+			context->sampler[16 + sampler].setTextureFilter(textureFilter);
+		}
+		else ASSERT(false);
+	}
+
+	void VertexProcessor::setMipmapFilter(unsigned int sampler, MipmapType mipmapFilter)
+	{
+		if(sampler < 4)
+		{
+			context->sampler[16 + sampler].setMipmapFilter(mipmapFilter);
+		}
+		else ASSERT(false);
+	}
+
+	void VertexProcessor::setGatherEnable(unsigned int sampler, bool enable)
+	{
+		if(sampler < 4)
+		{
+			context->sampler[16 + sampler].setGatherEnable(enable);
+		}
+		else ASSERT(false);
+	}
+
+	void VertexProcessor::setAddressingModeU(unsigned int sampler, AddressingMode addressMode)
+	{
+		if(sampler < 4)
+		{
+			context->sampler[16 + sampler].setAddressingModeU(addressMode);
+		}
+		else ASSERT(false);
+	}
+
+	void VertexProcessor::setAddressingModeV(unsigned int sampler, AddressingMode addressMode)
+	{
+		if(sampler < 4)
+		{
+			context->sampler[16 + sampler].setAddressingModeV(addressMode);
+		}
+		else ASSERT(false);
+	}
+
+	void VertexProcessor::setAddressingModeW(unsigned int sampler, AddressingMode addressMode)
+	{
+		if(sampler < 4)
+		{
+			context->sampler[16 + sampler].setAddressingModeW(addressMode);
+		}
+		else ASSERT(false);
+	}
+
+	void VertexProcessor::setReadSRGB(unsigned int sampler, bool sRGB)
+	{
+		if(sampler < 4)
+		{
+			context->sampler[16 + sampler].setReadSRGB(sRGB);
+		}
+		else ASSERT(false);
+	}
+
+	void VertexProcessor::setMipmapLOD(unsigned int sampler, float bias)
+	{
+		if(sampler < 4)
+		{
+			context->sampler[16 + sampler].setMipmapLOD(bias);
+		}
+		else ASSERT(false);
+	}
+
+	void VertexProcessor::setBorderColor(unsigned int sampler, const Color<float> &borderColor)
+	{
+		if(sampler < 4)
+		{
+			context->sampler[16 + sampler].setBorderColor(borderColor);
+		}
+		else ASSERT(false);
+	}
+
+	void VertexProcessor::setMaxAnisotropy(unsigned int sampler, unsigned int maxAnisotropy)
+	{
+		if(sampler < 4)
+		{
+			context->sampler[16 + sampler].setMaxAnisotropy(maxAnisotropy);
+		}
+		else ASSERT(false);
+	}
+
+	void VertexProcessor::setPointSize(float pointSize)
+	{
+		point.pointSize = replicate(pointSize);
+	}
+
+	void VertexProcessor::setPointSizeMin(float pointSizeMin)
+	{
+		point.pointSizeMin = pointSizeMin;
+	}
+
+	void VertexProcessor::setPointSizeMax(float pointSizeMax)
+	{
+		point.pointSizeMax = pointSizeMax;
+	}
+
+	void VertexProcessor::setPointScaleA(float pointScaleA)
+	{
+		point.pointScaleA = pointScaleA;
+	}
+
+	void VertexProcessor::setPointScaleB(float pointScaleB)
+	{
+		point.pointScaleB = pointScaleB;
+	}
+
+	void VertexProcessor::setPointScaleC(float pointScaleC)
+	{
+		point.pointScaleC = pointScaleC;
+	}
+
+	const Matrix &VertexProcessor::getModelTransform(int i)
+	{
+		updateTransform();
+		return PBVM[i];
+	}
+
+	const Matrix &VertexProcessor::getViewTransform()
+	{
+		updateTransform();
+		return PBV;
+	}
+
+	bool VertexProcessor::isFixedFunction()
+	{
+		return !context->vertexShader;
+	}
+
+	void VertexProcessor::setTransform(const Matrix &M, int i)
+	{
+		ff.transformT[i][0][0] = M[0][0];
+		ff.transformT[i][0][1] = M[1][0];
+		ff.transformT[i][0][2] = M[2][0];
+		ff.transformT[i][0][3] = M[3][0];
+
+		ff.transformT[i][1][0] = M[0][1];
+		ff.transformT[i][1][1] = M[1][1];
+		ff.transformT[i][1][2] = M[2][1];
+		ff.transformT[i][1][3] = M[3][1];
+
+		ff.transformT[i][2][0] = M[0][2];
+		ff.transformT[i][2][1] = M[1][2];
+		ff.transformT[i][2][2] = M[2][2];
+		ff.transformT[i][2][3] = M[3][2];
+
+		ff.transformT[i][3][0] = M[0][3];
+		ff.transformT[i][3][1] = M[1][3];
+		ff.transformT[i][3][2] = M[2][3];
+		ff.transformT[i][3][3] = M[3][3];
+	}
+
+	void VertexProcessor::setCameraTransform(const Matrix &M, int i)
+	{
+		ff.cameraTransformT[i][0][0] = M[0][0];
+		ff.cameraTransformT[i][0][1] = M[1][0];
+		ff.cameraTransformT[i][0][2] = M[2][0];
+		ff.cameraTransformT[i][0][3] = M[3][0];
+
+		ff.cameraTransformT[i][1][0] = M[0][1];
+		ff.cameraTransformT[i][1][1] = M[1][1];
+		ff.cameraTransformT[i][1][2] = M[2][1];
+		ff.cameraTransformT[i][1][3] = M[3][1];
+
+		ff.cameraTransformT[i][2][0] = M[0][2];
+		ff.cameraTransformT[i][2][1] = M[1][2];
+		ff.cameraTransformT[i][2][2] = M[2][2];
+		ff.cameraTransformT[i][2][3] = M[3][2];
+
+		ff.cameraTransformT[i][3][0] = M[0][3];
+		ff.cameraTransformT[i][3][1] = M[1][3];
+		ff.cameraTransformT[i][3][2] = M[2][3];
+		ff.cameraTransformT[i][3][3] = M[3][3];
+	}
+
+	void VertexProcessor::setNormalTransform(const Matrix &M, int i)
+	{
+		ff.normalTransformT[i][0][0] = M[0][0];
+		ff.normalTransformT[i][0][1] = M[1][0];
+		ff.normalTransformT[i][0][2] = M[2][0];
+		ff.normalTransformT[i][0][3] = M[3][0];
+
+		ff.normalTransformT[i][1][0] = M[0][1];
+		ff.normalTransformT[i][1][1] = M[1][1];
+		ff.normalTransformT[i][1][2] = M[2][1];
+		ff.normalTransformT[i][1][3] = M[3][1];
+
+		ff.normalTransformT[i][2][0] = M[0][2];
+		ff.normalTransformT[i][2][1] = M[1][2];
+		ff.normalTransformT[i][2][2] = M[2][2];
+		ff.normalTransformT[i][2][3] = M[3][2];
+
+		ff.normalTransformT[i][3][0] = M[0][3];
+		ff.normalTransformT[i][3][1] = M[1][3];
+		ff.normalTransformT[i][3][2] = M[2][3];
+		ff.normalTransformT[i][3][3] = M[3][3];
+	}
+
+	void VertexProcessor::updateTransform()
+	{
+		if(!updateMatrix) return;
+
+		int activeMatrices = context->indexedVertexBlendEnable ? 12 : max(context->vertexBlendMatrixCount, 1);
+
+		if(updateProjectionMatrix)
+		{
+			PB = P * B;
+			PBV = PB * V;
+			
+			for(int i = 0; i < activeMatrices; i++)
+			{
+				PBVM[i] = PBV * M[i];
+				updateModelMatrix[i] = false;
+			}
+
+			updateProjectionMatrix = false;
+			updateBaseMatrix = false;
+			updateViewMatrix = false;
+		}
+
+		if(updateBaseMatrix)
+		{
+			PB = P * B;
+			PBV = PB * V;
+			
+			for(int i = 0; i < activeMatrices; i++)
+			{
+				PBVM[i] = PBV * M[i];
+				updateModelMatrix[i] = false;
+			}
+
+			updateBaseMatrix = false;
+			updateViewMatrix = false;
+		}
+
+		if(updateViewMatrix)
+		{
+			PBV = PB * V;
+			
+			for(int i = 0; i < activeMatrices; i++)
+			{
+				PBVM[i] = PBV * M[i];
+				updateModelMatrix[i] = false;
+			}
+
+			updateViewMatrix = false;
+		}
+
+		for(int i = 0; i < activeMatrices; i++)
+		{
+			if(updateModelMatrix[i])
+			{
+				PBVM[i] = PBV * M[i];
+				updateModelMatrix[i] = false;
+			}
+		}
+
+		for(int i = 0; i < activeMatrices; i++)
+		{
+			setTransform(PBVM[i], i);
+			setCameraTransform(B * V * M[i], i);
+			setNormalTransform(~!(B * V * M[i]), i);
+		}
+
+		updateMatrix = false;
+	}
+
+	void VertexProcessor::setRoutineCacheSize(int cacheSize)
+	{
+		delete routineCache;
+		routineCache = new LRUCache<State, Routine>(clamp(cacheSize, 1, 65536));
+	}
+
+	const VertexProcessor::State VertexProcessor::update()
+	{
+		if(isFixedFunction())
+		{
+			updateTransform();
+
+			if(updateLighting)
+			{
+				for(int i = 0; i < 8; i++)
+				{
+					if(context->vertexLightActive(i))
+					{
+						// Light position in camera coordinates
+						setLightViewPosition(i, B * V * context->getLightPosition(i));
+					}
+				}
+
+				updateLighting = false;
+			}
+		}
+
+		State state;
+
+		if(context->vertexShader)
+		{
+			state.shaderHash = context->vertexShader->getHash();
+		}
+		else
+		{
+			state.shaderHash = 0;
+		}
+
+		state.fixedFunction = !context->vertexShader && context->pixelShaderVersion() < 0x0300;
+		state.shaderContainsTexldl = context->vertexShader ? context->vertexShader->containsTexldl() : false;
+		state.positionRegister = context->vertexShader ? context->vertexShader->positionRegister : Pos;
+		state.pointSizeRegister = context->vertexShader ? context->vertexShader->pointSizeRegister : Pts;
+		
+		state.vertexBlendMatrixCount = context->vertexBlendMatrixCountActive();
+		state.indexedVertexBlendEnable = context->indexedVertexBlendActive();
+		state.vertexNormalActive = context->vertexNormalActive();
+		state.normalizeNormals = context->normalizeNormalsActive();
+		state.vertexLightingActive = context->vertexLightingActive();
+		state.diffuseActive = context->diffuseActive();
+		state.specularActive = context->specularActive();
+		state.vertexSpecularActive = context->vertexSpecularActive();
+
+		state.vertexLightActive = context->vertexLightActive(0) << 0 |
+		                          context->vertexLightActive(1) << 1 |
+		                          context->vertexLightActive(2) << 2 |
+		                          context->vertexLightActive(3) << 3 |
+		                          context->vertexLightActive(4) << 4 |
+		                          context->vertexLightActive(5) << 5 |
+		                          context->vertexLightActive(6) << 6 |
+		                          context->vertexLightActive(7) << 7;
+
+		state.vertexDiffuseMaterialSourceActive = context->vertexDiffuseMaterialSourceActive();
+		state.vertexSpecularMaterialSourceActive = context->vertexSpecularMaterialSourceActive();
+		state.vertexAmbientMaterialSourceActive = context->vertexAmbientMaterialSourceActive();
+		state.vertexEmissiveMaterialSourceActive = context->vertexEmissiveMaterialSourceActive();
+		state.fogActive = context->fogActive();
+		state.vertexFogMode = context->vertexFogModeActive();
+		state.rangeFogActive = context->rangeFogActive();
+		state.localViewerActive = context->localViewerActive();
+		state.pointSizeActive = context->pointSizeActive();
+		state.pointScaleActive = context->pointScaleActive();
+
+		state.preTransformed = context->preTransformed;
+		state.postTransform = context->postTransform;
+		state.superSampling = context->renderTarget[0]->getSuperSampleCount() > 1;
+		state.multiSampling = context->renderTarget[0]->getMultiSampleCount() > 1;
+
+		for(int i = 0; i < 16; i++)
+		{
+			state.input[i].type = context->input[i].type;
+			state.input[i].count = context->input[i].count;
+			state.input[i].normalized = context->input[i].normalized;
+		}
+
+		if(!context->vertexShader)
+		{
+			for(int i = 0; i < 8; i++)
+			{
+			//	state.textureState[i].vertexTextureActive = context->vertexTextureActive(i, 0);
+				state.textureState[i].texGenActive = context->texGenActive(i);
+				state.textureState[i].textureTransformCountActive = context->textureTransformCountActive(i);
+				state.textureState[i].texCoordIndexActive = context->texCoordIndexActive(i);
+			}
+		}
+		else
+		{
+			for(unsigned int i = 0; i < 4; i++)
+			{
+				if(context->vertexShader->usesSampler(i))
+				{
+					state.samplerState[i] = context->sampler[16 + i].samplerState();
+				}
+			}
+		}
+
+		if(context->vertexShader)   // FIXME: Also when pre-transformed?
+		{
+			for(int i = 0; i < 12; i++)
+			{
+				state.output[i].xWrite = context->vertexShader->output[i][0].active();
+				state.output[i].yWrite = context->vertexShader->output[i][1].active();
+				state.output[i].zWrite = context->vertexShader->output[i][2].active();
+				state.output[i].wWrite = context->vertexShader->output[i][3].active();
+			}
+		}
+		else if(!context->preTransformed || context->pixelShaderVersion() < 0x0300)
+		{
+			state.output[Pos].write = 0xF;
+
+			if(context->diffuseActive() && (context->lightingEnable || context->input[Color0]))
+			{
+				state.output[D0].write = 0xF;
+			}
+			
+			if(context->specularActive())
+			{
+				state.output[D1].write = 0xF;
+			}
+
+			for(int stage = 0; stage < 8; stage++)
+			{
+				if(context->vertexTextureActive(stage, 0)) state.output[T0 + stage].write |= 0x01;
+				if(context->vertexTextureActive(stage, 1)) state.output[T0 + stage].write |= 0x02;
+				if(context->vertexTextureActive(stage, 2)) state.output[T0 + stage].write |= 0x04;
+				if(context->vertexTextureActive(stage, 3)) state.output[T0 + stage].write |= 0x08;
+			}
+
+			if(context->fogActive())
+			{
+				state.output[Fog].xWrite = true;
+			}
+
+			if(context->pointSizeActive())
+			{
+				state.output[Pts].yWrite = true;
+			}
+		}
+		else
+		{
+			state.output[Pos].write = 0xF;
+
+			for(int i = 0; i < 2; i++)
+			{
+				if(context->input[Color0 + i])
+				{
+					state.output[D0 + i].write = 0xF;
+				}
+			}
+
+			for(int i = 0; i < 8; i++)
+			{
+				if(context->input[TexCoord0 + i])
+				{
+					state.output[T0 + i].write = 0xF;
+				}
+			}
+
+			if(context->input[PSize])
+			{
+				state.output[Pts].yWrite = true;
+			}
+		}
+
+		if(context->vertexShaderVersion() < 0x0300)
+		{
+			state.output[D0].clamp = 0xF;
+			state.output[D1].clamp = 0xF;
+			state.output[Fog].xClamp = true;
+		}
+
+		state.hash = state.computeHash();
+
+		return state;
+	}
+
+	Routine *VertexProcessor::routine(const State &state)
+	{
+		Routine *routine = routineCache->query(state);
+
+		if(!routine)   // Create one
+		{
+			VertexRoutine *generator = 0;
+
+			if(state.fixedFunction)
+			{
+				generator = new VertexPipeline(state);
+			}
+			else
+			{
+				generator = new VertexProgram(state, context->vertexShader);
+			}
+
+			generator->generate();
+			routine = generator->getRoutine();
+			delete generator;
+
+			routineCache->add(state, routine);
+		}
+
+		return routine;
+	}
+}