blob: 246e2783c4f7bc935ff83e720dee1e444fb9fc85 [file] [log] [blame]
// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "VertexProcessor.hpp"
#include "Shader/VertexPipeline.hpp"
#include "Shader/VertexProgram.hpp"
#include "Shader/VertexShader.hpp"
#include "Shader/PixelShader.hpp"
#include "Shader/Constants.hpp"
#include "Common/Math.hpp"
#include "Common/Debug.hpp"
#include <cstring>
namespace sw
{
bool precacheVertex = false;
void VertexCache::clear()
{
for(int i = 0; i < 16; i++)
{
tag[i] = 0x80000000;
}
}
uint32_t VertexProcessor::States::computeHash()
{
uint32_t *state = reinterpret_cast<uint32_t*>(this);
uint32_t hash = 0;
for(unsigned int i = 0; i < sizeof(States) / sizeof(uint32_t); i++)
{
hash ^= state[i];
}
return hash;
}
bool VertexProcessor::State::operator==(const State &state) const
{
if(hash != state.hash)
{
return false;
}
static_assert(is_memcmparable<State>::value, "Cannot memcmp States");
return memcmp(static_cast<const States*>(this), static_cast<const States*>(&state), sizeof(States)) == 0;
}
VertexProcessor::TransformFeedbackInfo::TransformFeedbackInfo()
{
buffer = nullptr;
offset = 0;
reg = 0;
row = 0;
col = 0;
stride = 0;
}
VertexProcessor::UniformBufferInfo::UniformBufferInfo()
{
buffer = nullptr;
offset = 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 = nullptr;
setRoutineCacheSize(1024);
}
VertexProcessor::~VertexProcessor()
{
delete routineCache;
routineCache = nullptr;
}
void VertexProcessor::setInputStream(int index, const Stream &stream)
{
context->input[index] = stream;
}
void VertexProcessor::resetInputStreams(bool preTransformed)
{
for(int i = 0; i < MAX_VERTEX_INPUTS; i++)
{
context->input[i].defaults();
}
context->preTransformed = preTransformed;
}
void VertexProcessor::setFloatConstant(unsigned int index, const float value[4])
{
if(index < VERTEX_UNIFORM_VECTORS)
{
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::setUniformBuffer(int index, sw::Resource* buffer, int offset)
{
uniformBufferInfo[index].buffer = buffer;
uniformBufferInfo[index].offset = offset;
}
void VertexProcessor::lockUniformBuffers(byte** u, sw::Resource* uniformBuffers[])
{
for(int i = 0; i < MAX_UNIFORM_BUFFER_BINDINGS; ++i)
{
u[i] = uniformBufferInfo[i].buffer ? static_cast<byte*>(uniformBufferInfo[i].buffer->lock(PUBLIC, PRIVATE)) + uniformBufferInfo[i].offset : nullptr;
uniformBuffers[i] = uniformBufferInfo[i].buffer;
}
}
void VertexProcessor::setTransformFeedbackBuffer(int index, sw::Resource* buffer, int offset, unsigned int reg, unsigned int row, unsigned int col, unsigned int stride)
{
transformFeedbackInfo[index].buffer = buffer;
transformFeedbackInfo[index].offset = offset;
transformFeedbackInfo[index].reg = reg;
transformFeedbackInfo[index].row = row;
transformFeedbackInfo[index].col = col;
transformFeedbackInfo[index].stride = stride;
}
void VertexProcessor::lockTransformFeedbackBuffers(byte** t, unsigned int* v, unsigned int* r, unsigned int* c, unsigned int* s, sw::Resource* transformFeedbackBuffers[])
{
for(int i = 0; i < MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS; ++i)
{
t[i] = transformFeedbackInfo[i].buffer ? static_cast<byte*>(transformFeedbackInfo[i].buffer->lock(PUBLIC, PRIVATE)) + transformFeedbackInfo[i].offset : nullptr;
transformFeedbackBuffers[i] = transformFeedbackInfo[i].buffer;
v[i] = transformFeedbackInfo[i].reg;
r[i] = transformFeedbackInfo[i].row;
c[i] = transformFeedbackInfo[i].col;
s[i] = transformFeedbackInfo[i].stride;
}
}
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(FogMode fogMode)
{
context->vertexFogMode = fogMode;
}
void VertexProcessor::setInstanceID(int instanceID)
{
context->instanceID = instanceID;
}
void VertexProcessor::setColorVertexEnable(bool colorVertexEnable)
{
context->setColorVertexEnable(colorVertexEnable);
}
void VertexProcessor::setDiffuseMaterialSource(MaterialSource diffuseMaterialSource)
{
context->setDiffuseMaterialSource(diffuseMaterialSource);
}
void VertexProcessor::setSpecularMaterialSource(MaterialSource specularMaterialSource)
{
context->setSpecularMaterialSource(specularMaterialSource);
}
void VertexProcessor::setAmbientMaterialSource(MaterialSource ambientMaterialSource)
{
context->setAmbientMaterialSource(ambientMaterialSource);
}
void VertexProcessor::setEmissiveMaterialSource(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 < TEXTURE_IMAGE_UNITS)
{
context->textureWrap[stage] = mask;
}
else ASSERT(false);
context->textureWrapActive = false;
for(int i = 0; i < TEXTURE_IMAGE_UNITS; i++)
{
context->textureWrapActive |= (context->textureWrap[i] != 0x00);
}
}
void VertexProcessor::setTexGen(unsigned int stage, 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 < VERTEX_TEXTURE_IMAGE_UNITS)
{
context->sampler[TEXTURE_IMAGE_UNITS + sampler].setTextureFilter(textureFilter);
}
else ASSERT(false);
}
void VertexProcessor::setMipmapFilter(unsigned int sampler, MipmapType mipmapFilter)
{
if(sampler < VERTEX_TEXTURE_IMAGE_UNITS)
{
context->sampler[TEXTURE_IMAGE_UNITS + sampler].setMipmapFilter(mipmapFilter);
}
else ASSERT(false);
}
void VertexProcessor::setGatherEnable(unsigned int sampler, bool enable)
{
if(sampler < VERTEX_TEXTURE_IMAGE_UNITS)
{
context->sampler[TEXTURE_IMAGE_UNITS + sampler].setGatherEnable(enable);
}
else ASSERT(false);
}
void VertexProcessor::setAddressingModeU(unsigned int sampler, AddressingMode addressMode)
{
if(sampler < VERTEX_TEXTURE_IMAGE_UNITS)
{
context->sampler[TEXTURE_IMAGE_UNITS + sampler].setAddressingModeU(addressMode);
}
else ASSERT(false);
}
void VertexProcessor::setAddressingModeV(unsigned int sampler, AddressingMode addressMode)
{
if(sampler < VERTEX_TEXTURE_IMAGE_UNITS)
{
context->sampler[TEXTURE_IMAGE_UNITS + sampler].setAddressingModeV(addressMode);
}
else ASSERT(false);
}
void VertexProcessor::setAddressingModeW(unsigned int sampler, AddressingMode addressMode)
{
if(sampler < VERTEX_TEXTURE_IMAGE_UNITS)
{
context->sampler[TEXTURE_IMAGE_UNITS + sampler].setAddressingModeW(addressMode);
}
else ASSERT(false);
}
void VertexProcessor::setReadSRGB(unsigned int sampler, bool sRGB)
{
if(sampler < VERTEX_TEXTURE_IMAGE_UNITS)
{
context->sampler[TEXTURE_IMAGE_UNITS + sampler].setReadSRGB(sRGB);
}
else ASSERT(false);
}
void VertexProcessor::setMipmapLOD(unsigned int sampler, float bias)
{
if(sampler < VERTEX_TEXTURE_IMAGE_UNITS)
{
context->sampler[TEXTURE_IMAGE_UNITS + sampler].setMipmapLOD(bias);
}
else ASSERT(false);
}
void VertexProcessor::setBorderColor(unsigned int sampler, const Color<float> &borderColor)
{
if(sampler < VERTEX_TEXTURE_IMAGE_UNITS)
{
context->sampler[TEXTURE_IMAGE_UNITS + sampler].setBorderColor(borderColor);
}
else ASSERT(false);
}
void VertexProcessor::setMaxAnisotropy(unsigned int sampler, float maxAnisotropy)
{
if(sampler < VERTEX_TEXTURE_IMAGE_UNITS)
{
context->sampler[TEXTURE_IMAGE_UNITS + sampler].setMaxAnisotropy(maxAnisotropy);
}
else ASSERT(false);
}
void VertexProcessor::setHighPrecisionFiltering(unsigned int sampler, bool highPrecisionFiltering)
{
if(sampler < TEXTURE_IMAGE_UNITS)
{
context->sampler[sampler].setHighPrecisionFiltering(highPrecisionFiltering);
}
else ASSERT(false);
}
void VertexProcessor::setSwizzleR(unsigned int sampler, SwizzleType swizzleR)
{
if(sampler < VERTEX_TEXTURE_IMAGE_UNITS)
{
context->sampler[TEXTURE_IMAGE_UNITS + sampler].setSwizzleR(swizzleR);
}
else ASSERT(false);
}
void VertexProcessor::setSwizzleG(unsigned int sampler, SwizzleType swizzleG)
{
if(sampler < VERTEX_TEXTURE_IMAGE_UNITS)
{
context->sampler[TEXTURE_IMAGE_UNITS + sampler].setSwizzleG(swizzleG);
}
else ASSERT(false);
}
void VertexProcessor::setSwizzleB(unsigned int sampler, SwizzleType swizzleB)
{
if(sampler < VERTEX_TEXTURE_IMAGE_UNITS)
{
context->sampler[TEXTURE_IMAGE_UNITS + sampler].setSwizzleB(swizzleB);
}
else ASSERT(false);
}
void VertexProcessor::setSwizzleA(unsigned int sampler, SwizzleType swizzleA)
{
if(sampler < VERTEX_TEXTURE_IMAGE_UNITS)
{
context->sampler[TEXTURE_IMAGE_UNITS + sampler].setSwizzleA(swizzleA);
}
else ASSERT(false);
}
void VertexProcessor::setCompareFunc(unsigned int sampler, CompareFunc compFunc)
{
if(sampler < VERTEX_TEXTURE_IMAGE_UNITS)
{
context->sampler[TEXTURE_IMAGE_UNITS + sampler].setCompareFunc(compFunc);
}
else ASSERT(false);
}
void VertexProcessor::setBaseLevel(unsigned int sampler, int baseLevel)
{
if(sampler < VERTEX_TEXTURE_IMAGE_UNITS)
{
context->sampler[TEXTURE_IMAGE_UNITS + sampler].setBaseLevel(baseLevel);
}
else ASSERT(false);
}
void VertexProcessor::setMaxLevel(unsigned int sampler, int maxLevel)
{
if(sampler < VERTEX_TEXTURE_IMAGE_UNITS)
{
context->sampler[TEXTURE_IMAGE_UNITS + sampler].setMaxLevel(maxLevel);
}
else ASSERT(false);
}
void VertexProcessor::setMinLod(unsigned int sampler, float minLod)
{
if(sampler < VERTEX_TEXTURE_IMAGE_UNITS)
{
context->sampler[TEXTURE_IMAGE_UNITS + sampler].setMinLod(minLod);
}
else ASSERT(false);
}
void VertexProcessor::setMaxLod(unsigned int sampler, float maxLod)
{
if(sampler < VERTEX_TEXTURE_IMAGE_UNITS)
{
context->sampler[TEXTURE_IMAGE_UNITS + sampler].setMaxLod(maxLod);
}
else ASSERT(false);
}
void VertexProcessor::setSyncRequired(unsigned int sampler, bool isSincRequired)
{
if(sampler < TEXTURE_IMAGE_UNITS)
{
context->sampler[sampler].setSyncRequired(isSincRequired);
}
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;
}
void VertexProcessor::setTransformFeedbackQueryEnabled(bool enable)
{
context->transformFeedbackQueryEnabled = enable;
}
void VertexProcessor::enableTransformFeedback(uint64_t enable)
{
context->transformFeedbackEnabled = enable;
}
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 RoutineCache<State>(clamp(cacheSize, 1, 65536));
}
const VertexProcessor::State VertexProcessor::update(DrawType drawType)
{
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.shaderID = context->vertexShader->getSerialID();
}
else
{
state.shaderID = 0;
}
state.fixedFunction = !context->vertexShader && context->pixelShaderModel() < 0x0300;
state.textureSampling = context->vertexShader ? context->vertexShader->containsTextureSampling() : false;
state.positionRegister = context->vertexShader ? context->vertexShader->getPositionRegister() : Pos;
state.pointSizeRegister = context->vertexShader ? context->vertexShader->getPointSizeRegister() : 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.superSampling = context->getSuperSampleCount() > 1;
state.transformFeedbackQueryEnabled = context->transformFeedbackQueryEnabled;
state.transformFeedbackEnabled = context->transformFeedbackEnabled;
// Note: Quads aren't handled for verticesPerPrimitive, but verticesPerPrimitive is used for transform feedback,
// which is an OpenGL ES 3.0 feature, and OpenGL ES 3.0 doesn't support quads as a primitive type.
DrawType type = static_cast<DrawType>(static_cast<unsigned int>(drawType) & 0xF);
state.verticesPerPrimitive = 1 + (type >= DRAW_LINELIST) + (type >= DRAW_TRIANGLELIST);
for(int i = 0; i < MAX_VERTEX_INPUTS; 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;
state.input[i].attribType = context->vertexShader ? context->vertexShader->getAttribType(i) : VertexShader::ATTRIBTYPE_FLOAT;
}
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 < VERTEX_TEXTURE_IMAGE_UNITS; i++)
{
if(context->vertexShader->usesSampler(i))
{
state.sampler[i] = context->sampler[TEXTURE_IMAGE_UNITS + i].samplerState();
}
}
}
if(context->vertexShader) // FIXME: Also when pre-transformed?
{
for(int i = 0; i < MAX_VERTEX_OUTPUTS; i++)
{
state.output[i].xWrite = context->vertexShader->getOutput(i, 0).active();
state.output[i].yWrite = context->vertexShader->getOutput(i, 1).active();
state.output[i].zWrite = context->vertexShader->getOutput(i, 2).active();
state.output[i].wWrite = context->vertexShader->getOutput(i, 3).active();
}
}
else if(!context->preTransformed || context->pixelShaderModel() < 0x0300)
{
state.output[Pos].write = 0xF;
if(context->diffuseActive() && (context->lightingEnable || context->input[Color0]))
{
state.output[C0].write = 0xF;
}
if(context->specularActive())
{
state.output[C1].write = 0xF;
}
for(int stage = 0; stage < 8; stage++)
{
if(context->texCoordActive(stage, 0)) state.output[T0 + stage].write |= 0x01;
if(context->texCoordActive(stage, 1)) state.output[T0 + stage].write |= 0x02;
if(context->texCoordActive(stage, 2)) state.output[T0 + stage].write |= 0x04;
if(context->texCoordActive(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[C0 + i].write = 0xF;
}
}
for(int i = 0; i < 8; i++)
{
if(context->input[TexCoord0 + i])
{
state.output[T0 + i].write = 0xF;
}
}
if(context->input[PointSize])
{
state.output[Pts].yWrite = true;
}
}
if(context->vertexShaderModel() < 0x0300)
{
state.output[C0].clamp = 0xF;
state.output[C1].clamp = 0xF;
state.output[Fog].xClamp = true;
}
state.hash = state.computeHash();
return state;
}
std::shared_ptr<Routine> VertexProcessor::routine(const State &state)
{
auto routine = routineCache->query(state);
if(!routine) // Create one
{
VertexRoutine *generator = nullptr;
if(state.fixedFunction)
{
generator = new VertexPipeline(state);
}
else
{
generator = new VertexProgram(state, context->vertexShader);
}
generator->generate();
routine = (*generator)("VertexRoutine_%0.8X", state.shaderID);
delete generator;
routineCache->add(state, routine);
}
return routine;
}
}