Add SwiftShader source to repo
Oct 6 code drop from Transgaming
Review URL: https://chromereviews.googleplex.com/3846015
diff --git a/src/Renderer/PixelProcessor.cpp b/src/Renderer/PixelProcessor.cpp
new file mode 100644
index 0000000..b0b285a
--- /dev/null
+++ b/src/Renderer/PixelProcessor.cpp
@@ -0,0 +1,1054 @@
+// 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 "PixelProcessor.hpp"
+
+#include "QuadRasterizer.hpp"
+#include "PixelShader.hpp"
+#include "MetaMacro.hpp"
+#include "Surface.hpp"
+#include "Primitive.hpp"
+#include "Constants.hpp"
+#include "Debug.hpp"
+
+namespace sw
+{
+ extern bool complementaryDepthBuffer;
+ extern Context::TransparencyAntialiasing transparencyAntialiasing;
+ extern bool perspectiveCorrection;
+
+ unsigned int PixelProcessor::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;
+ }
+
+ PixelProcessor::State::State()
+ {
+ memset(this, 0, sizeof(State));
+ }
+
+ bool PixelProcessor::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;
+ }
+
+ PixelProcessor::PixelProcessor(Context *context) : context(context)
+ {
+ setGlobalMipmapBias(0.0f); // Round to highest LOD [0.5, 1.0]: -0.5
+ // Round to nearest LOD [0.7, 1.4]: 0.0
+ // Round to lowest LOD [1.0, 2.0]: 0.5
+
+ routineCache = 0;
+ setRoutineCacheSize(1024);
+ }
+
+ PixelProcessor::~PixelProcessor()
+ {
+ delete routineCache;
+ routineCache = 0;
+ }
+
+ void PixelProcessor::setFloatConstant(unsigned int index, const float value[4])
+ {
+ if(index < 224)
+ {
+ c[index][0] = value[0];
+ c[index][1] = value[1];
+ c[index][2] = value[2];
+ c[index][3] = value[3];
+ }
+ else ASSERT(false);
+
+ if(index < 8) // ps_1_x constants
+ {
+ // FIXME: Compact into generic function
+ short x = iround(4095 * clamp(value[0], -1.0f, 1.0f));
+ short y = iround(4095 * clamp(value[1], -1.0f, 1.0f));
+ short z = iround(4095 * clamp(value[2], -1.0f, 1.0f));
+ short w = iround(4095 * clamp(value[3], -1.0f, 1.0f));
+
+ cW[index][0][0] = x;
+ cW[index][0][1] = x;
+ cW[index][0][2] = x;
+ cW[index][0][3] = x;
+
+ cW[index][1][0] = y;
+ cW[index][1][1] = y;
+ cW[index][1][2] = y;
+ cW[index][1][3] = y;
+
+ cW[index][2][0] = z;
+ cW[index][2][1] = z;
+ cW[index][2][2] = z;
+ cW[index][2][3] = z;
+
+ cW[index][3][0] = w;
+ cW[index][3][1] = w;
+ cW[index][3][2] = w;
+ cW[index][3][3] = w;
+ }
+ }
+
+ void PixelProcessor::setIntegerConstant(unsigned int index, const int value[4])
+ {
+ if(index < 16)
+ {
+ i[index][0] = value[0];
+ i[index][1] = value[1];
+ i[index][2] = value[2];
+ i[index][3] = value[3];
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setBooleanConstant(unsigned int index, int boolean)
+ {
+ if(index < 16)
+ {
+ b[index] = boolean != 0;
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setRenderTarget(int index, Surface *renderTarget)
+ {
+ context->renderTarget[index] = renderTarget;
+ }
+
+ void PixelProcessor::setDepthStencil(Surface *depthStencil)
+ {
+ context->depthStencil = depthStencil;
+ }
+
+ void PixelProcessor::setTexCoordIndex(unsigned int stage, int texCoordIndex)
+ {
+ if(stage < 8)
+ {
+ context->textureStage[stage].setTexCoordIndex(texCoordIndex);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setStageOperation(unsigned int stage, TextureStage::StageOperation stageOperation)
+ {
+ if(stage < 8)
+ {
+ context->textureStage[stage].setStageOperation(stageOperation);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setFirstArgument(unsigned int stage, TextureStage::SourceArgument firstArgument)
+ {
+ if(stage < 8)
+ {
+ context->textureStage[stage].setFirstArgument(firstArgument);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setSecondArgument(unsigned int stage, TextureStage::SourceArgument secondArgument)
+ {
+ if(stage < 8)
+ {
+ context->textureStage[stage].setSecondArgument(secondArgument);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setThirdArgument(unsigned int stage, TextureStage::SourceArgument thirdArgument)
+ {
+ if(stage < 8)
+ {
+ context->textureStage[stage].setThirdArgument(thirdArgument);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setStageOperationAlpha(unsigned int stage, TextureStage::StageOperation stageOperationAlpha)
+ {
+ if(stage < 8)
+ {
+ context->textureStage[stage].setStageOperationAlpha(stageOperationAlpha);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setFirstArgumentAlpha(unsigned int stage, TextureStage::SourceArgument firstArgumentAlpha)
+ {
+ if(stage < 8)
+ {
+ context->textureStage[stage].setFirstArgumentAlpha(firstArgumentAlpha);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setSecondArgumentAlpha(unsigned int stage, TextureStage::SourceArgument secondArgumentAlpha)
+ {
+ if(stage < 8)
+ {
+ context->textureStage[stage].setSecondArgumentAlpha(secondArgumentAlpha);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setThirdArgumentAlpha(unsigned int stage, TextureStage::SourceArgument thirdArgumentAlpha)
+ {
+ if(stage < 8)
+ {
+ context->textureStage[stage].setThirdArgumentAlpha(thirdArgumentAlpha);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setFirstModifier(unsigned int stage, TextureStage::ArgumentModifier firstModifier)
+ {
+ if(stage < 8)
+ {
+ context->textureStage[stage].setFirstModifier(firstModifier);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setSecondModifier(unsigned int stage, TextureStage::ArgumentModifier secondModifier)
+ {
+ if(stage < 8)
+ {
+ context->textureStage[stage].setSecondModifier(secondModifier);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setThirdModifier(unsigned int stage, TextureStage::ArgumentModifier thirdModifier)
+ {
+ if(stage < 8)
+ {
+ context->textureStage[stage].setThirdModifier(thirdModifier);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setFirstModifierAlpha(unsigned int stage, TextureStage::ArgumentModifier firstModifierAlpha)
+ {
+ if(stage < 8)
+ {
+ context->textureStage[stage].setFirstModifierAlpha(firstModifierAlpha);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setSecondModifierAlpha(unsigned int stage, TextureStage::ArgumentModifier secondModifierAlpha)
+ {
+ if(stage < 8)
+ {
+ context->textureStage[stage].setSecondModifierAlpha(secondModifierAlpha);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setThirdModifierAlpha(unsigned int stage, TextureStage::ArgumentModifier thirdModifierAlpha)
+ {
+ if(stage < 8)
+ {
+ context->textureStage[stage].setThirdModifierAlpha(thirdModifierAlpha);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setDestinationArgument(unsigned int stage, TextureStage::DestinationArgument destinationArgument)
+ {
+ if(stage < 8)
+ {
+ context->textureStage[stage].setDestinationArgument(destinationArgument);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setConstantColor(unsigned int stage, const Color<float> &constantColor)
+ {
+ if(stage < 8)
+ {
+ context->textureStage[stage].setConstantColor(constantColor);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setBumpmapMatrix(unsigned int stage, int element, float value)
+ {
+ if(stage < 8)
+ {
+ context->textureStage[stage].setBumpmapMatrix(element, value);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setLuminanceScale(unsigned int stage, float value)
+ {
+ if(stage < 8)
+ {
+ context->textureStage[stage].setLuminanceScale(value);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setLuminanceOffset(unsigned int stage, float value)
+ {
+ if(stage < 8)
+ {
+ context->textureStage[stage].setLuminanceOffset(value);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setTextureFilter(unsigned int sampler, FilterType textureFilter)
+ {
+ if(sampler < 16)
+ {
+ context->sampler[sampler].setTextureFilter(textureFilter);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setMipmapFilter(unsigned int sampler, MipmapType mipmapFilter)
+ {
+ if(sampler < 16)
+ {
+ context->sampler[sampler].setMipmapFilter(mipmapFilter);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setGatherEnable(unsigned int sampler, bool enable)
+ {
+ if(sampler < 16)
+ {
+ context->sampler[sampler].setGatherEnable(enable);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setAddressingModeU(unsigned int sampler, AddressingMode addressMode)
+ {
+ if(sampler < 16)
+ {
+ context->sampler[sampler].setAddressingModeU(addressMode);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setAddressingModeV(unsigned int sampler, AddressingMode addressMode)
+ {
+ if(sampler < 16)
+ {
+ context->sampler[sampler].setAddressingModeV(addressMode);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setAddressingModeW(unsigned int sampler, AddressingMode addressMode)
+ {
+ if(sampler < 16)
+ {
+ context->sampler[sampler].setAddressingModeW(addressMode);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setReadSRGB(unsigned int sampler, bool sRGB)
+ {
+ if(sampler < 16)
+ {
+ context->sampler[sampler].setReadSRGB(sRGB);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setMipmapLOD(unsigned int sampler, float bias)
+ {
+ if(sampler < 16)
+ {
+ context->sampler[sampler].setMipmapLOD(bias);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setBorderColor(unsigned int sampler, const Color<float> &borderColor)
+ {
+ if(sampler < 16)
+ {
+ context->sampler[sampler].setBorderColor(borderColor);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setMaxAnisotropy(unsigned int sampler, unsigned int maxAnisotropy)
+ {
+ if(sampler < 16)
+ {
+ context->sampler[sampler].setMaxAnisotropy(maxAnisotropy);
+ }
+ else ASSERT(false);
+ }
+
+ void PixelProcessor::setWriteSRGB(bool sRGB)
+ {
+ context->setWriteSRGB(sRGB);
+ }
+
+ void PixelProcessor::setDepthBufferEnable(bool depthBufferEnable)
+ {
+ context->setDepthBufferEnable(depthBufferEnable);
+ }
+
+ void PixelProcessor::setDepthCompare(Context::DepthCompareMode depthCompareMode)
+ {
+ context->depthCompareMode = depthCompareMode;
+ }
+
+ void PixelProcessor::setAlphaCompare(Context::AlphaCompareMode alphaCompareMode)
+ {
+ context->alphaCompareMode = alphaCompareMode;
+ }
+
+ void PixelProcessor::setDepthWriteEnable(bool depthWriteEnable)
+ {
+ context->depthWriteEnable = depthWriteEnable;
+ }
+
+ void PixelProcessor::setAlphaTestEnable(bool alphaTestEnable)
+ {
+ context->alphaTestEnable = alphaTestEnable;
+ }
+
+ void PixelProcessor::setCullMode(Context::CullMode cullMode)
+ {
+ context->cullMode = cullMode;
+ }
+
+ void PixelProcessor::setColorWriteMask(int index, int rgbaMask)
+ {
+ context->setColorWriteMask(index, rgbaMask);
+ }
+
+ void PixelProcessor::setStencilEnable(bool stencilEnable)
+ {
+ context->stencilEnable = stencilEnable;
+ }
+
+ void PixelProcessor::setStencilCompare(Context::StencilCompareMode stencilCompareMode)
+ {
+ context->stencilCompareMode = stencilCompareMode;
+ }
+
+ void PixelProcessor::setStencilReference(int stencilReference)
+ {
+ context->stencilReference = stencilReference;
+ stencil.set(stencilReference, context->stencilMask, context->stencilWriteMask);
+ }
+
+ void PixelProcessor::setStencilReferenceCCW(int stencilReferenceCCW)
+ {
+ context->stencilReferenceCCW = stencilReferenceCCW;
+ stencilCCW.set(stencilReferenceCCW, context->stencilMaskCCW, context->stencilWriteMaskCCW);
+ }
+
+ void PixelProcessor::setStencilMask(int stencilMask)
+ {
+ context->stencilMask = stencilMask;
+ stencil.set(context->stencilReference, stencilMask, context->stencilWriteMask);
+ }
+
+ void PixelProcessor::setStencilMaskCCW(int stencilMaskCCW)
+ {
+ context->stencilMaskCCW = stencilMaskCCW;
+ stencilCCW.set(context->stencilReferenceCCW, stencilMaskCCW, context->stencilWriteMaskCCW);
+ }
+
+ void PixelProcessor::setStencilFailOperation(Context::StencilOperation stencilFailOperation)
+ {
+ context->stencilFailOperation = stencilFailOperation;
+ }
+
+ void PixelProcessor::setStencilPassOperation(Context::StencilOperation stencilPassOperation)
+ {
+ context->stencilPassOperation = stencilPassOperation;
+ }
+
+ void PixelProcessor::setStencilZFailOperation(Context::StencilOperation stencilZFailOperation)
+ {
+ context->stencilZFailOperation = stencilZFailOperation;
+ }
+
+ void PixelProcessor::setStencilWriteMask(int stencilWriteMask)
+ {
+ context->stencilWriteMask = stencilWriteMask;
+ stencil.set(context->stencilReference, context->stencilMask, stencilWriteMask);
+ }
+
+ void PixelProcessor::setStencilWriteMaskCCW(int stencilWriteMaskCCW)
+ {
+ context->stencilWriteMaskCCW = stencilWriteMaskCCW;
+ stencilCCW.set(context->stencilReferenceCCW, context->stencilMaskCCW, stencilWriteMaskCCW);
+ }
+
+ void PixelProcessor::setTwoSidedStencil(bool enable)
+ {
+ context->twoSidedStencil = enable;
+ }
+
+ void PixelProcessor::setStencilCompareCCW(Context::StencilCompareMode stencilCompareMode)
+ {
+ context->stencilCompareModeCCW = stencilCompareMode;
+ }
+
+ void PixelProcessor::setStencilFailOperationCCW(Context::StencilOperation stencilFailOperation)
+ {
+ context->stencilFailOperationCCW = stencilFailOperation;
+ }
+
+ void PixelProcessor::setStencilPassOperationCCW(Context::StencilOperation stencilPassOperation)
+ {
+ context->stencilPassOperationCCW = stencilPassOperation;
+ }
+
+ void PixelProcessor::setStencilZFailOperationCCW(Context::StencilOperation stencilZFailOperation)
+ {
+ context->stencilZFailOperationCCW = stencilZFailOperation;
+ }
+
+ void PixelProcessor::setTextureFactor(const Color<float> &textureFactor)
+ {
+ // FIXME: Compact into generic function // FIXME: Clamp
+ short textureFactorR = iround(4095 * textureFactor.r);
+ short textureFactorG = iround(4095 * textureFactor.g);
+ short textureFactorB = iround(4095 * textureFactor.b);
+ short textureFactorA = iround(4095 * textureFactor.a);
+
+ factor.textureFactor4[0][0] = textureFactorR;
+ factor.textureFactor4[0][1] = textureFactorR;
+ factor.textureFactor4[0][2] = textureFactorR;
+ factor.textureFactor4[0][3] = textureFactorR;
+
+ factor.textureFactor4[1][0] = textureFactorG;
+ factor.textureFactor4[1][1] = textureFactorG;
+ factor.textureFactor4[1][2] = textureFactorG;
+ factor.textureFactor4[1][3] = textureFactorG;
+
+ factor.textureFactor4[2][0] = textureFactorB;
+ factor.textureFactor4[2][1] = textureFactorB;
+ factor.textureFactor4[2][2] = textureFactorB;
+ factor.textureFactor4[2][3] = textureFactorB;
+
+ factor.textureFactor4[3][0] = textureFactorA;
+ factor.textureFactor4[3][1] = textureFactorA;
+ factor.textureFactor4[3][2] = textureFactorA;
+ factor.textureFactor4[3][3] = textureFactorA;
+ }
+
+ void PixelProcessor::setBlendConstant(const Color<float> &blendConstant)
+ {
+ // FIXME: Compact into generic function // FIXME: Clamp
+ short blendConstantR = iround(65535 * blendConstant.r);
+ short blendConstantG = iround(65535 * blendConstant.g);
+ short blendConstantB = iround(65535 * blendConstant.b);
+ short blendConstantA = iround(65535 * blendConstant.a);
+
+ factor.blendConstant4W[0][0] = blendConstantR;
+ factor.blendConstant4W[0][1] = blendConstantR;
+ factor.blendConstant4W[0][2] = blendConstantR;
+ factor.blendConstant4W[0][3] = blendConstantR;
+
+ factor.blendConstant4W[1][0] = blendConstantG;
+ factor.blendConstant4W[1][1] = blendConstantG;
+ factor.blendConstant4W[1][2] = blendConstantG;
+ factor.blendConstant4W[1][3] = blendConstantG;
+
+ factor.blendConstant4W[2][0] = blendConstantB;
+ factor.blendConstant4W[2][1] = blendConstantB;
+ factor.blendConstant4W[2][2] = blendConstantB;
+ factor.blendConstant4W[2][3] = blendConstantB;
+
+ factor.blendConstant4W[3][0] = blendConstantA;
+ factor.blendConstant4W[3][1] = blendConstantA;
+ factor.blendConstant4W[3][2] = blendConstantA;
+ factor.blendConstant4W[3][3] = blendConstantA;
+
+ // FIXME: Compact into generic function // FIXME: Clamp
+ short invBlendConstantR = iround(65535 * (1 - blendConstant.r));
+ short invBlendConstantG = iround(65535 * (1 - blendConstant.g));
+ short invBlendConstantB = iround(65535 * (1 - blendConstant.b));
+ short invBlendConstantA = iround(65535 * (1 - blendConstant.a));
+
+ factor.invBlendConstant4W[0][0] = invBlendConstantR;
+ factor.invBlendConstant4W[0][1] = invBlendConstantR;
+ factor.invBlendConstant4W[0][2] = invBlendConstantR;
+ factor.invBlendConstant4W[0][3] = invBlendConstantR;
+
+ factor.invBlendConstant4W[1][0] = invBlendConstantG;
+ factor.invBlendConstant4W[1][1] = invBlendConstantG;
+ factor.invBlendConstant4W[1][2] = invBlendConstantG;
+ factor.invBlendConstant4W[1][3] = invBlendConstantG;
+
+ factor.invBlendConstant4W[2][0] = invBlendConstantB;
+ factor.invBlendConstant4W[2][1] = invBlendConstantB;
+ factor.invBlendConstant4W[2][2] = invBlendConstantB;
+ factor.invBlendConstant4W[2][3] = invBlendConstantB;
+
+ factor.invBlendConstant4W[3][0] = invBlendConstantA;
+ factor.invBlendConstant4W[3][1] = invBlendConstantA;
+ factor.invBlendConstant4W[3][2] = invBlendConstantA;
+ factor.invBlendConstant4W[3][3] = invBlendConstantA;
+
+ factor.blendConstant4F[0][0] = blendConstant.r;
+ factor.blendConstant4F[0][1] = blendConstant.r;
+ factor.blendConstant4F[0][2] = blendConstant.r;
+ factor.blendConstant4F[0][3] = blendConstant.r;
+
+ factor.blendConstant4F[1][0] = blendConstant.g;
+ factor.blendConstant4F[1][1] = blendConstant.g;
+ factor.blendConstant4F[1][2] = blendConstant.g;
+ factor.blendConstant4F[1][3] = blendConstant.g;
+
+ factor.blendConstant4F[2][0] = blendConstant.b;
+ factor.blendConstant4F[2][1] = blendConstant.b;
+ factor.blendConstant4F[2][2] = blendConstant.b;
+ factor.blendConstant4F[2][3] = blendConstant.b;
+
+ factor.blendConstant4F[3][0] = blendConstant.a;
+ factor.blendConstant4F[3][1] = blendConstant.a;
+ factor.blendConstant4F[3][2] = blendConstant.a;
+ factor.blendConstant4F[3][3] = blendConstant.a;
+
+ factor.invBlendConstant4F[0][0] = 1 - blendConstant.r;
+ factor.invBlendConstant4F[0][1] = 1 - blendConstant.r;
+ factor.invBlendConstant4F[0][2] = 1 - blendConstant.r;
+ factor.invBlendConstant4F[0][3] = 1 - blendConstant.r;
+
+ factor.invBlendConstant4F[1][0] = 1 - blendConstant.g;
+ factor.invBlendConstant4F[1][1] = 1 - blendConstant.g;
+ factor.invBlendConstant4F[1][2] = 1 - blendConstant.g;
+ factor.invBlendConstant4F[1][3] = 1 - blendConstant.g;
+
+ factor.invBlendConstant4F[2][0] = 1 - blendConstant.b;
+ factor.invBlendConstant4F[2][1] = 1 - blendConstant.b;
+ factor.invBlendConstant4F[2][2] = 1 - blendConstant.b;
+ factor.invBlendConstant4F[2][3] = 1 - blendConstant.b;
+
+ factor.invBlendConstant4F[3][0] = 1 - blendConstant.a;
+ factor.invBlendConstant4F[3][1] = 1 - blendConstant.a;
+ factor.invBlendConstant4F[3][2] = 1 - blendConstant.a;
+ factor.invBlendConstant4F[3][3] = 1 - blendConstant.a;
+ }
+
+ void PixelProcessor::setFillMode(Context::FillMode fillMode)
+ {
+ context->fillMode = fillMode;
+ }
+
+ void PixelProcessor::setShadingMode(Context::ShadingMode shadingMode)
+ {
+ context->shadingMode = shadingMode;
+ }
+
+ void PixelProcessor::setAlphaBlendEnable(bool alphaBlendEnable)
+ {
+ context->setAlphaBlendEnable(alphaBlendEnable);
+ }
+
+ void PixelProcessor::setSourceBlendFactor(Context::BlendFactor sourceBlendFactor)
+ {
+ context->setSourceBlendFactor(sourceBlendFactor);
+ }
+
+ void PixelProcessor::setDestBlendFactor(Context::BlendFactor destBlendFactor)
+ {
+ context->setDestBlendFactor(destBlendFactor);
+ }
+
+ void PixelProcessor::setBlendOperation(Context::BlendOperation blendOperation)
+ {
+ context->setBlendOperation(blendOperation);
+ }
+
+ void PixelProcessor::setSeparateAlphaBlendEnable(bool separateAlphaBlendEnable)
+ {
+ context->setSeparateAlphaBlendEnable(separateAlphaBlendEnable);
+ }
+
+ void PixelProcessor::setSourceBlendFactorAlpha(Context::BlendFactor sourceBlendFactorAlpha)
+ {
+ context->setSourceBlendFactorAlpha(sourceBlendFactorAlpha);
+ }
+
+ void PixelProcessor::setDestBlendFactorAlpha(Context::BlendFactor destBlendFactorAlpha)
+ {
+ context->setDestBlendFactorAlpha(destBlendFactorAlpha);
+ }
+
+ void PixelProcessor::setBlendOperationAlpha(Context::BlendOperation blendOperationAlpha)
+ {
+ context->setBlendOperationAlpha(blendOperationAlpha);
+ }
+
+ void PixelProcessor::setAlphaReference(int alphaReference)
+ {
+ context->alphaReference = alphaReference;
+
+ factor.alphaReference4[0] = (word)iround((float)alphaReference * 0x1000 / 0xFF);
+ factor.alphaReference4[1] = (word)iround((float)alphaReference * 0x1000 / 0xFF);
+ factor.alphaReference4[2] = (word)iround((float)alphaReference * 0x1000 / 0xFF);
+ factor.alphaReference4[3] = (word)iround((float)alphaReference * 0x1000 / 0xFF);
+ }
+
+ void PixelProcessor::setGlobalMipmapBias(float bias)
+ {
+ context->setGlobalMipmapBias(bias);
+ }
+
+ void PixelProcessor::setFogStart(float start)
+ {
+ setFogRanges(start, context->fogEnd);
+ }
+
+ void PixelProcessor::setFogEnd(float end)
+ {
+ setFogRanges(context->fogStart, end);
+ }
+
+ void PixelProcessor::setFogColor(Color<float> fogColor)
+ {
+ // TODO: Compact into generic function
+ word fogR = (unsigned short)(65535 * fogColor.r);
+ word fogG = (unsigned short)(65535 * fogColor.g);
+ word fogB = (unsigned short)(65535 * fogColor.b);
+
+ fog.color4[0][0] = fogR;
+ fog.color4[0][1] = fogR;
+ fog.color4[0][2] = fogR;
+ fog.color4[0][3] = fogR;
+
+ fog.color4[1][0] = fogG;
+ fog.color4[1][1] = fogG;
+ fog.color4[1][2] = fogG;
+ fog.color4[1][3] = fogG;
+
+ fog.color4[2][0] = fogB;
+ fog.color4[2][1] = fogB;
+ fog.color4[2][2] = fogB;
+ fog.color4[2][3] = fogB;
+
+ fog.colorF[0] = replicate(fogColor.r);
+ fog.colorF[1] = replicate(fogColor.g);
+ fog.colorF[2] = replicate(fogColor.b);
+ }
+
+ void PixelProcessor::setFogDensity(float fogDensity)
+ {
+ fog.densityE = replicate(-fogDensity * 1.442695f); // 1/e^x = 2^(-x*1.44)
+ fog.densityE2 = replicate(fogDensity * 1.201122f); // 1/e^(x^2) = 2^(-(x*1.20)^2)
+ }
+
+ void PixelProcessor::setPixelFogMode(Context::FogMode fogMode)
+ {
+ context->pixelFogMode = fogMode;
+ }
+
+ void PixelProcessor::setPerspectiveCorrection(bool perspectiveEnable)
+ {
+ perspectiveCorrection = perspectiveEnable;
+ }
+
+ void PixelProcessor::setOcclusionEnabled(bool enable)
+ {
+ context->occlusionEnabled = enable;
+ }
+
+ void PixelProcessor::setRoutineCacheSize(int cacheSize)
+ {
+ delete routineCache;
+ routineCache = new LRUCache<State, Routine>(clamp(cacheSize, 1, 65536));
+ }
+
+ void PixelProcessor::setFogRanges(float start, float end)
+ {
+ context->fogStart = start;
+ context->fogEnd = end;
+
+ if(start == end)
+ {
+ end += 0.001f; // Hack: ensure there is a small range
+ }
+
+ float fogScale = -1.0f / (end - start);
+ float fogOffset = end * -fogScale;
+
+ fog.scale = replicate(fogScale);
+ fog.offset = replicate(fogOffset);
+ }
+
+ const PixelProcessor::State PixelProcessor::update() const
+ {
+ State state;
+
+ if(context->pixelShader)
+ {
+ state.shaderHash = context->pixelShader->getHash();
+ }
+ else
+ {
+ state.shaderHash = 0;
+ }
+
+ state.depthOverride = context->pixelShader && context->pixelShader->depthOverride();
+ state.shaderContainsTexkill = context->pixelShader ? context->pixelShader->containsTexkill() : false;
+
+ if(context->alphaTestActive())
+ {
+ state.alphaCompareMode = context->alphaCompareMode;
+
+ state.transparencyAntialiasing = context->renderTarget[0]->getMultiSampleCount() > 1 ? transparencyAntialiasing : Context::TRANSPARENCY_NONE;
+ }
+
+ state.depthWriteEnable = context->depthWriteActive();
+
+ if(context->stencilActive())
+ {
+ state.stencilActive = true;
+ state.stencilCompareMode = context->stencilCompareMode;
+ state.stencilFailOperation = context->stencilFailOperation;
+ state.stencilPassOperation = context->stencilPassOperation;
+ state.stencilZFailOperation = context->stencilZFailOperation;
+ state.noStencilMask = (context->stencilMask == 0xFF);
+ state.noStencilWriteMask = (context->stencilWriteMask == 0xFF);
+ state.stencilWriteMasked = (context->stencilWriteMask == 0x00);
+
+ state.twoSidedStencil = context->twoSidedStencil;
+ state.stencilCompareModeCCW = context->twoSidedStencil ? context->stencilCompareModeCCW : state.stencilCompareMode;
+ state.stencilFailOperationCCW = context->twoSidedStencil ? context->stencilFailOperationCCW : state.stencilFailOperation;
+ state.stencilPassOperationCCW = context->twoSidedStencil ? context->stencilPassOperationCCW : state.stencilPassOperation;
+ state.stencilZFailOperationCCW = context->twoSidedStencil ? context->stencilZFailOperationCCW : state.stencilZFailOperation;
+ state.noStencilMaskCCW = context->twoSidedStencil ? (context->stencilMaskCCW == 0xFF) : state.noStencilMask;
+ state.noStencilWriteMaskCCW = context->twoSidedStencil ? (context->stencilWriteMaskCCW == 0xFF) : state.noStencilWriteMask;
+ state.stencilWriteMaskedCCW = context->twoSidedStencil ? (context->stencilWriteMaskCCW == 0x00) : state.stencilWriteMasked;
+ }
+
+ if(context->depthBufferActive())
+ {
+ state.depthTestActive = true;
+ state.depthCompareMode = context->depthCompareMode;
+ state.quadLayoutDepthBuffer = context->depthStencil->getInternalFormat() != FORMAT_D32F_LOCKABLE &&
+ context->depthStencil->getInternalFormat() != FORMAT_D32F_TEXTURE &&
+ context->depthStencil->getInternalFormat() != FORMAT_D32F_SHADOW;
+ }
+
+ state.occlusionEnabled = context->occlusionEnabled;
+
+ state.fogActive = context->fogActive();
+ state.pixelFogMode = context->pixelFogActive();
+ state.wBasedFog = context->wBasedFog && context->pixelFogActive() != Context::FOG_NONE;
+ state.perspective = context->perspectiveActive();
+
+ if(context->alphaBlendActive())
+ {
+ state.alphaBlendActive = true;
+ state.sourceBlendFactor = context->sourceBlendFactor();
+ state.destBlendFactor = context->destBlendFactor();
+ state.blendOperation = context->blendOperation();
+ state.sourceBlendFactorAlpha = context->sourceBlendFactorAlpha();
+ state.destBlendFactorAlpha = context->destBlendFactorAlpha();
+ state.blendOperationAlpha = context->blendOperationAlpha();
+ }
+
+ state.colorWriteMask = (context->colorWriteActive(0) << 0) |
+ (context->colorWriteActive(1) << 4) |
+ (context->colorWriteActive(2) << 8) |
+ (context->colorWriteActive(3) << 12);
+
+ for(int i = 0; i < 4; i++)
+ {
+ state.targetFormat[i] = context->renderTargetInternalFormat(i);
+ }
+
+ state.writeSRGB = context->writeSRGB && Surface::isSRGBwritable(context->renderTarget[0]->getExternalFormat());
+ state.multiSample = context->renderTarget[0]->getMultiSampleCount();
+ state.multiSampleMask = context->multiSampleMask;
+
+ if(state.multiSample > 1 && context->pixelShader)
+ {
+ state.centroid = context->pixelShader->containsCentroid();
+ }
+
+ if(!context->pixelShader)
+ {
+ for(unsigned int i = 0; i < 8; i++)
+ {
+ state.textureStage[i] = context->textureStage[i].textureStageState();
+ }
+
+ state.specularAdd = context->specularActive() && context->specularEnable;
+ }
+
+ for(unsigned int i = 0; i < 16; i++)
+ {
+ if(context->pixelShader)
+ {
+ if(context->pixelShader->usesSampler(i))
+ {
+ state.sampler[i] = context->sampler[i].samplerState();
+ }
+ }
+ else
+ {
+ if(i < 8 && state.textureStage[i].stageOperation != TextureStage::STAGE_DISABLE)
+ {
+ state.sampler[i] = context->sampler[i].samplerState();
+ }
+ else break;
+ }
+ }
+
+ const bool point = context->isDrawPoint(true);
+ const bool sprite = context->pointSpriteActive();
+ const bool flatShading = (context->shadingMode == Context::SHADING_FLAT) || point;
+
+ if(context->pixelShaderVersion() < 0x0300)
+ {
+ for(int coordinate = 0; coordinate < 8; coordinate++)
+ {
+ for(int component = 0; component < 4; component++)
+ {
+ if(context->textureActive(coordinate, component))
+ {
+ state.texture[coordinate].component |= 1 << component;
+
+ if(point && !sprite)
+ {
+ state.texture[coordinate].flat |= 1 << component;
+ }
+ }
+ }
+
+ if(context->textureTransformProject[coordinate] && context->pixelShaderVersion() <= 0x0103)
+ {
+ if(context->textureTransformCount[coordinate] == 2)
+ {
+ state.texture[coordinate].project = 1;
+ }
+ else if(context->textureTransformCount[coordinate] == 3)
+ {
+ state.texture[coordinate].project = 2;
+ }
+ else if(context->textureTransformCount[coordinate] == 4 || context->textureTransformCount[coordinate] == 0)
+ {
+ state.texture[coordinate].project = 3;
+ }
+ }
+ }
+
+ for(int color = 0; color < 2; color++)
+ {
+ for(int component = 0; component < 4; component++)
+ {
+ if(context->colorActive(color, component))
+ {
+ state.color[color].component |= 1 << component;
+
+ if(point || flatShading)
+ {
+ state.color[color].flat |= 1 << component;
+ }
+ }
+ }
+ }
+
+ if(context->fogActive())
+ {
+ state.fog.component = true;
+
+ if(point)
+ {
+ state.fog.flat = true;
+ }
+ }
+ }
+ else
+ {
+ for(int interpolant = 0; interpolant < 10; interpolant++)
+ {
+ for(int component = 0; component < 4; component++)
+ {
+ if(context->pixelShader->semantic[interpolant][component].active())
+ {
+ bool flat = point;
+
+ switch(context->pixelShader->semantic[interpolant][component].usage)
+ {
+ case ShaderOperation::USAGE_TEXCOORD: flat = point && !sprite; break;
+ case ShaderOperation::USAGE_COLOR: flat = flatShading; break;
+ }
+
+ state.interpolant[interpolant].component |= 1 << component;
+
+ if(flat)
+ {
+ state.interpolant[interpolant].flat |= 1 << component;
+ }
+ }
+ }
+ }
+ }
+
+ if(state.centroid)
+ {
+ for(int interpolant = 0; interpolant < 10; interpolant++)
+ {
+ for(int component = 0; component < 4; component++)
+ {
+ state.interpolant[interpolant].centroid = context->pixelShader->semantic[interpolant][0].centroid;
+ }
+ }
+ }
+
+ state.hash = state.computeHash();
+
+ return state;
+ }
+
+ Routine *PixelProcessor::routine(const State &state)
+ {
+ Routine *routine = routineCache->query(state);
+
+ if(!routine)
+ {
+ Rasterizer *generator = new QuadRasterizer(state, context->pixelShader);
+ generator->generate();
+ routine = generator->getRoutine();
+ delete generator;
+
+ routineCache->add(state, routine);
+ }
+
+ return routine;
+ }
+}