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;
+ }
+}