Duplicate source files for Vulkan.
The Vulkan implementation needs a directory for each architectural
layer, similar to the OpenGL ES stack. The entire rendering stack is
duplicated, leaving only Reactor common between them:
Renderer -> Device
Shader -> Pipeline
Common -> System
Main -> WSI
Bug b/117152542
Change-Id: I9c26b23654016d637f88ec2416f019ef65b9afbd
Reviewed-on: https://swiftshader-review.googlesource.com/c/21248
Reviewed-by: Alexis Hétu <sugoi@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Device/Context.cpp b/src/Device/Context.cpp
new file mode 100644
index 0000000..25c5775
--- /dev/null
+++ b/src/Device/Context.cpp
@@ -0,0 +1,1496 @@
+// 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 "Context.hpp"
+
+#include "Primitive.hpp"
+#include "Surface.hpp"
+#include "Shader/PixelShader.hpp"
+#include "Shader/VertexShader.hpp"
+#include "Common/Memory.hpp"
+#include "Common/Debug.hpp"
+
+#include <string.h>
+
+namespace sw
+{
+ extern bool perspectiveCorrection;
+
+ bool halfIntegerCoordinates = false; // Pixel centers are not at integer coordinates
+ bool symmetricNormalizedDepth = false; // [-1, 1] instead of [0, 1]
+ bool booleanFaceRegister = false;
+ bool fullPixelPositionRegister = false;
+ bool leadingVertexFirst = false; // Flat shading uses first vertex, else last
+ bool secondaryColor = false; // Specular lighting is applied after texturing
+ bool colorsDefaultToZero = false;
+
+ bool forceWindowed = false;
+ bool quadLayoutEnabled = false;
+ bool veryEarlyDepthTest = true;
+ bool complementaryDepthBuffer = false;
+ bool postBlendSRGB = false;
+ bool exactColorRounding = false;
+ TransparencyAntialiasing transparencyAntialiasing = TRANSPARENCY_NONE;
+ bool forceClearRegisters = false;
+
+ Context::Context()
+ {
+ init();
+ }
+
+ Context::~Context()
+ {
+ }
+
+ void *Context::operator new(size_t bytes)
+ {
+ return allocate((unsigned int)bytes);
+ }
+
+ void Context::operator delete(void *pointer, size_t bytes)
+ {
+ deallocate(pointer);
+ }
+
+ bool Context::isDrawPoint(bool fillModeAware) const
+ {
+ switch(drawType)
+ {
+ case DRAW_POINTLIST:
+ case DRAW_INDEXEDPOINTLIST8:
+ case DRAW_INDEXEDPOINTLIST16:
+ case DRAW_INDEXEDPOINTLIST32:
+ return true;
+ case DRAW_LINELIST:
+ case DRAW_LINESTRIP:
+ case DRAW_LINELOOP:
+ case DRAW_INDEXEDLINELIST8:
+ case DRAW_INDEXEDLINESTRIP8:
+ case DRAW_INDEXEDLINELOOP8:
+ case DRAW_INDEXEDLINELIST16:
+ case DRAW_INDEXEDLINESTRIP16:
+ case DRAW_INDEXEDLINELOOP16:
+ case DRAW_INDEXEDLINELIST32:
+ case DRAW_INDEXEDLINESTRIP32:
+ case DRAW_INDEXEDLINELOOP32:
+ return false;
+ case DRAW_TRIANGLELIST:
+ case DRAW_TRIANGLESTRIP:
+ case DRAW_TRIANGLEFAN:
+ case DRAW_INDEXEDTRIANGLELIST8:
+ case DRAW_INDEXEDTRIANGLESTRIP8:
+ case DRAW_INDEXEDTRIANGLEFAN8:
+ case DRAW_INDEXEDTRIANGLELIST16:
+ case DRAW_INDEXEDTRIANGLESTRIP16:
+ case DRAW_INDEXEDTRIANGLEFAN16:
+ case DRAW_INDEXEDTRIANGLELIST32:
+ case DRAW_INDEXEDTRIANGLESTRIP32:
+ case DRAW_INDEXEDTRIANGLEFAN32:
+ return fillModeAware ? fillMode == FILL_VERTEX : false;
+ case DRAW_QUADLIST:
+ return false;
+ default:
+ ASSERT(false);
+ }
+
+ return false;
+ }
+
+ bool Context::isDrawLine(bool fillModeAware) const
+ {
+ switch(drawType)
+ {
+ case DRAW_POINTLIST:
+ case DRAW_INDEXEDPOINTLIST8:
+ case DRAW_INDEXEDPOINTLIST16:
+ case DRAW_INDEXEDPOINTLIST32:
+ return false;
+ case DRAW_LINELIST:
+ case DRAW_LINESTRIP:
+ case DRAW_LINELOOP:
+ case DRAW_INDEXEDLINELIST8:
+ case DRAW_INDEXEDLINESTRIP8:
+ case DRAW_INDEXEDLINELOOP8:
+ case DRAW_INDEXEDLINELIST16:
+ case DRAW_INDEXEDLINESTRIP16:
+ case DRAW_INDEXEDLINELOOP16:
+ case DRAW_INDEXEDLINELIST32:
+ case DRAW_INDEXEDLINESTRIP32:
+ case DRAW_INDEXEDLINELOOP32:
+ return true;
+ case DRAW_TRIANGLELIST:
+ case DRAW_TRIANGLESTRIP:
+ case DRAW_TRIANGLEFAN:
+ case DRAW_INDEXEDTRIANGLELIST8:
+ case DRAW_INDEXEDTRIANGLESTRIP8:
+ case DRAW_INDEXEDTRIANGLEFAN8:
+ case DRAW_INDEXEDTRIANGLELIST16:
+ case DRAW_INDEXEDTRIANGLESTRIP16:
+ case DRAW_INDEXEDTRIANGLEFAN16:
+ case DRAW_INDEXEDTRIANGLELIST32:
+ case DRAW_INDEXEDTRIANGLESTRIP32:
+ case DRAW_INDEXEDTRIANGLEFAN32:
+ return fillModeAware ? fillMode == FILL_WIREFRAME : false;
+ case DRAW_QUADLIST:
+ return false;
+ default:
+ ASSERT(false);
+ }
+
+ return false;
+ }
+
+ bool Context::isDrawTriangle(bool fillModeAware) const
+ {
+ switch(drawType)
+ {
+ case DRAW_POINTLIST:
+ case DRAW_INDEXEDPOINTLIST8:
+ case DRAW_INDEXEDPOINTLIST16:
+ case DRAW_INDEXEDPOINTLIST32:
+ return false;
+ case DRAW_LINELIST:
+ case DRAW_LINESTRIP:
+ case DRAW_LINELOOP:
+ case DRAW_INDEXEDLINELIST8:
+ case DRAW_INDEXEDLINESTRIP8:
+ case DRAW_INDEXEDLINELOOP8:
+ case DRAW_INDEXEDLINELIST16:
+ case DRAW_INDEXEDLINESTRIP16:
+ case DRAW_INDEXEDLINELOOP16:
+ case DRAW_INDEXEDLINELIST32:
+ case DRAW_INDEXEDLINESTRIP32:
+ case DRAW_INDEXEDLINELOOP32:
+ return false;
+ case DRAW_TRIANGLELIST:
+ case DRAW_TRIANGLESTRIP:
+ case DRAW_TRIANGLEFAN:
+ case DRAW_INDEXEDTRIANGLELIST8:
+ case DRAW_INDEXEDTRIANGLESTRIP8:
+ case DRAW_INDEXEDTRIANGLEFAN8:
+ case DRAW_INDEXEDTRIANGLELIST16:
+ case DRAW_INDEXEDTRIANGLESTRIP16:
+ case DRAW_INDEXEDTRIANGLEFAN16:
+ case DRAW_INDEXEDTRIANGLELIST32:
+ case DRAW_INDEXEDTRIANGLESTRIP32:
+ case DRAW_INDEXEDTRIANGLEFAN32:
+ return fillModeAware ? fillMode == FILL_SOLID : true;
+ case DRAW_QUADLIST:
+ // Quads are broken up into triangles
+ return fillModeAware ? fillMode == FILL_SOLID : true;
+ default:
+ ASSERT(false);
+ }
+
+ return true;
+ }
+
+ void Context::init()
+ {
+ for(int i = 0; i < 8; i++)
+ {
+ textureStage[i].init(i, &sampler[i], (i >= 1) ? &textureStage[i - 1] : 0);
+ }
+
+ // Set vertex streams to null stream
+ for(int i = 0; i < MAX_VERTEX_INPUTS; i++)
+ {
+ input[i].defaults();
+ }
+
+ fogStart = 0.0f;
+ fogEnd = 1.0f;
+
+ for(int i = 0; i < TEXTURE_IMAGE_UNITS; i++) textureWrap[i] = 0;
+ for(int i = 0; i < 8; i++) texGen[i] = TEXGEN_PASSTHRU;
+ for(int i = 0; i < 8; i++) textureTransformCount[i] = 0;
+ for(int i = 0; i < 8; i++) textureTransformProject[i] = false;
+ textureWrapActive = false;
+ localViewer = true;
+ normalizeNormals = false;
+
+ for(int i = 0; i < RENDERTARGETS; ++i)
+ {
+ renderTarget[i] = nullptr;
+ }
+ depthBuffer = nullptr;
+ stencilBuffer = nullptr;
+
+ stencilEnable = false;
+ stencilCompareMode = STENCIL_ALWAYS;
+ stencilReference = 0;
+ stencilMask = 0xFFFFFFFF;
+ stencilFailOperation = OPERATION_KEEP;
+ stencilPassOperation = OPERATION_KEEP;
+ stencilZFailOperation = OPERATION_KEEP;
+ stencilWriteMask = 0xFFFFFFFF;
+
+ twoSidedStencil = false;
+ stencilCompareModeCCW = STENCIL_ALWAYS;
+ stencilReferenceCCW = 0;
+ stencilMaskCCW = 0xFFFFFFFF;
+ stencilFailOperationCCW = OPERATION_KEEP;
+ stencilPassOperationCCW = OPERATION_KEEP;
+ stencilZFailOperationCCW = OPERATION_KEEP;
+ stencilWriteMaskCCW = 0xFFFFFFFF;
+
+ setGlobalMipmapBias(0);
+
+ lightingEnable = true;
+ specularEnable = false;
+ for(int i = 0; i < 8; i++) lightEnable[i] = false;
+ for(int i = 0; i < 8; i++) worldLightPosition[i] = 0;
+
+ alphaCompareMode = ALPHA_ALWAYS;
+ alphaTestEnable = false;
+ fillMode = FILL_SOLID;
+ shadingMode = SHADING_GOURAUD;
+
+ rasterizerDiscard = false;
+
+ depthCompareMode = DEPTH_LESS;
+ depthBufferEnable = true;
+ depthWriteEnable = true;
+
+ alphaBlendEnable = false;
+ sourceBlendFactorState = BLEND_ONE;
+ destBlendFactorState = BLEND_ZERO;
+ blendOperationState = BLENDOP_ADD;
+
+ separateAlphaBlendEnable = false;
+ sourceBlendFactorStateAlpha = BLEND_ONE;
+ destBlendFactorStateAlpha = BLEND_ZERO;
+ blendOperationStateAlpha = BLENDOP_ADD;
+
+ cullMode = CULL_CLOCKWISE;
+ frontFacingCCW = true;
+ alphaReference = 0.0f;
+
+ depthBias = 0.0f;
+ slopeDepthBias = 0.0f;
+
+ for(int i = 0; i < RENDERTARGETS; i++)
+ {
+ colorWriteMask[i] = 0x0000000F;
+ }
+
+ ambientMaterialSource = MATERIAL_MATERIAL;
+ diffuseMaterialSource = MATERIAL_COLOR1;
+ specularMaterialSource = MATERIAL_COLOR2;
+ emissiveMaterialSource = MATERIAL_MATERIAL;
+ colorVertexEnable = true;
+
+ fogEnable = false;
+ pixelFogMode = FOG_NONE;
+ vertexFogMode = FOG_NONE;
+ wBasedFog = false;
+ rangeFogEnable = false;
+
+ indexedVertexBlendEnable = false;
+ vertexBlendMatrixCount = 0;
+
+ pixelShader = 0;
+ vertexShader = 0;
+
+ instanceID = 0;
+
+ occlusionEnabled = false;
+ transformFeedbackQueryEnabled = false;
+ transformFeedbackEnabled = 0;
+
+ pointSpriteEnable = false;
+ pointScaleEnable = false;
+ lineWidth = 1.0f;
+
+ writeSRGB = false;
+ sampleMask = 0xFFFFFFFF;
+
+ colorLogicOpEnabled = false;
+ logicalOperation = LOGICALOP_COPY;
+ }
+
+ const float &Context::exp2Bias()
+ {
+ return bias;
+ }
+
+ const Point &Context::getLightPosition(int light)
+ {
+ return worldLightPosition[light];
+ }
+
+ void Context::setGlobalMipmapBias(float bias)
+ {
+ this->bias = exp2(bias + 0.5f);
+ }
+
+ void Context::setLightingEnable(bool lightingEnable)
+ {
+ this->lightingEnable = lightingEnable;
+ }
+
+ void Context::setSpecularEnable(bool specularEnable)
+ {
+ Context::specularEnable = specularEnable;
+ }
+
+ void Context::setLightEnable(int light, bool lightEnable)
+ {
+ Context::lightEnable[light] = lightEnable;
+ }
+
+ void Context::setLightPosition(int light, Point worldLightPosition)
+ {
+ Context::worldLightPosition[light] = worldLightPosition;
+ }
+
+ void Context::setAmbientMaterialSource(MaterialSource ambientMaterialSource)
+ {
+ Context::ambientMaterialSource = ambientMaterialSource;
+ }
+
+ void Context::setDiffuseMaterialSource(MaterialSource diffuseMaterialSource)
+ {
+ Context::diffuseMaterialSource = diffuseMaterialSource;
+ }
+
+ void Context::setSpecularMaterialSource(MaterialSource specularMaterialSource)
+ {
+ Context::specularMaterialSource = specularMaterialSource;
+ }
+
+ void Context::setEmissiveMaterialSource(MaterialSource emissiveMaterialSource)
+ {
+ Context::emissiveMaterialSource = emissiveMaterialSource;
+ }
+
+ void Context::setPointSpriteEnable(bool pointSpriteEnable)
+ {
+ Context::pointSpriteEnable = pointSpriteEnable;
+ }
+
+ void Context::setPointScaleEnable(bool pointScaleEnable)
+ {
+ Context::pointScaleEnable = pointScaleEnable;
+ }
+
+ bool Context::setDepthBufferEnable(bool depthBufferEnable)
+ {
+ bool modified = (Context::depthBufferEnable != depthBufferEnable);
+ Context::depthBufferEnable = depthBufferEnable;
+ return modified;
+ }
+
+ bool Context::setAlphaBlendEnable(bool alphaBlendEnable)
+ {
+ bool modified = (Context::alphaBlendEnable != alphaBlendEnable);
+ Context::alphaBlendEnable = alphaBlendEnable;
+ return modified;
+ }
+
+ bool Context::setSourceBlendFactor(BlendFactor sourceBlendFactor)
+ {
+ bool modified = (Context::sourceBlendFactorState != sourceBlendFactor);
+ Context::sourceBlendFactorState = sourceBlendFactor;
+ return modified;
+ }
+
+ bool Context::setDestBlendFactor(BlendFactor destBlendFactor)
+ {
+ bool modified = (Context::destBlendFactorState != destBlendFactor);
+ Context::destBlendFactorState = destBlendFactor;
+ return modified;
+ }
+
+ bool Context::setBlendOperation(BlendOperation blendOperation)
+ {
+ bool modified = (Context::blendOperationState != blendOperation);
+ Context::blendOperationState = blendOperation;
+ return modified;
+ }
+
+ bool Context::setSeparateAlphaBlendEnable(bool separateAlphaBlendEnable)
+ {
+ bool modified = (Context::separateAlphaBlendEnable != separateAlphaBlendEnable);
+ Context::separateAlphaBlendEnable = separateAlphaBlendEnable;
+ return modified;
+ }
+
+ bool Context::setSourceBlendFactorAlpha(BlendFactor sourceBlendFactorAlpha)
+ {
+ bool modified = (Context::sourceBlendFactorStateAlpha != sourceBlendFactorAlpha);
+ Context::sourceBlendFactorStateAlpha = sourceBlendFactorAlpha;
+ return modified;
+ }
+
+ bool Context::setDestBlendFactorAlpha(BlendFactor destBlendFactorAlpha)
+ {
+ bool modified = (Context::destBlendFactorStateAlpha != destBlendFactorAlpha);
+ Context::destBlendFactorStateAlpha = destBlendFactorAlpha;
+ return modified;
+ }
+
+ bool Context::setBlendOperationAlpha(BlendOperation blendOperationAlpha)
+ {
+ bool modified = (Context::blendOperationStateAlpha != blendOperationAlpha);
+ Context::blendOperationStateAlpha = blendOperationAlpha;
+ return modified;
+ }
+
+ bool Context::setColorWriteMask(int index, int colorWriteMask)
+ {
+ bool modified = (Context::colorWriteMask[index] != colorWriteMask);
+ Context::colorWriteMask[index] = colorWriteMask;
+ return modified;
+ }
+
+ bool Context::setWriteSRGB(bool sRGB)
+ {
+ bool modified = (Context::writeSRGB != sRGB);
+ Context::writeSRGB = sRGB;
+ return modified;
+ }
+
+ bool Context::setColorLogicOpEnabled(bool enabled)
+ {
+ bool modified = (Context::colorLogicOpEnabled != enabled);
+ Context::colorLogicOpEnabled = enabled;
+ return modified;
+ }
+
+ bool Context::setLogicalOperation(LogicalOperation logicalOperation)
+ {
+ bool modified = (Context::logicalOperation != logicalOperation);
+ Context::logicalOperation = logicalOperation;
+ return modified;
+ }
+
+ void Context::setColorVertexEnable(bool colorVertexEnable)
+ {
+ Context::colorVertexEnable = colorVertexEnable;
+ }
+
+ bool Context::fogActive()
+ {
+ if(!colorUsed()) return false;
+
+ if(pixelShaderModel() >= 0x0300) return false;
+
+ return fogEnable;
+ }
+
+ bool Context::pointSizeActive()
+ {
+ if(vertexShader)
+ {
+ return false;
+ }
+
+ return isDrawPoint(true) && (input[PointSize] || (!preTransformed && pointScaleActive()));
+ }
+
+ FogMode Context::pixelFogActive()
+ {
+ if(fogActive())
+ {
+ return pixelFogMode;
+ }
+
+ return FOG_NONE;
+ }
+
+ bool Context::depthWriteActive()
+ {
+ if(!depthBufferActive()) return false;
+
+ return depthWriteEnable;
+ }
+
+ bool Context::alphaTestActive()
+ {
+ if(transparencyAntialiasing != TRANSPARENCY_NONE) return true;
+ if(!alphaTestEnable) return false;
+ if(alphaCompareMode == ALPHA_ALWAYS) return false;
+ if(alphaReference == 0.0f && alphaCompareMode == ALPHA_GREATEREQUAL) return false;
+
+ return true;
+ }
+
+ bool Context::depthBufferActive()
+ {
+ return depthBuffer && depthBufferEnable;
+ }
+
+ bool Context::stencilActive()
+ {
+ return stencilBuffer && stencilEnable;
+ }
+
+ bool Context::vertexLightingActive()
+ {
+ if(vertexShader)
+ {
+ return false;
+ }
+
+ return lightingEnable && !preTransformed;
+ }
+
+ bool Context::texCoordActive(int coordinate, int component)
+ {
+ bool hasTexture = pointSpriteActive();
+
+ if(vertexShader)
+ {
+ if(!preTransformed)
+ {
+ if(vertexShader->getOutput(T0 + coordinate, component).usage == Shader::USAGE_TEXCOORD)
+ {
+ hasTexture = true;
+ }
+ }
+ else
+ {
+ hasTexture = true; // FIXME: Check vertex buffer streams
+ }
+ }
+ else
+ {
+ switch(texGen[coordinate])
+ {
+ case TEXGEN_NONE:
+ hasTexture = true;
+ break;
+ case TEXGEN_PASSTHRU:
+ hasTexture = hasTexture || (component < input[TexCoord0 + textureStage[coordinate].texCoordIndex].count);
+ break;
+ case TEXGEN_NORMAL:
+ hasTexture = hasTexture || (component <= 2);
+ break;
+ case TEXGEN_POSITION:
+ hasTexture = hasTexture || (component <= 2);
+ break;
+ case TEXGEN_REFLECTION:
+ hasTexture = hasTexture || (component <= 2);
+ break;
+ case TEXGEN_SPHEREMAP:
+ hasTexture = hasTexture || (component <= 1);
+ break;
+ default:
+ ASSERT(false);
+ }
+ }
+
+ bool project = isProjectionComponent(coordinate, component);
+ bool usesTexture = false;
+
+ if(pixelShader)
+ {
+ usesTexture = pixelShader->usesTexture(coordinate, component) || project;
+ }
+ else
+ {
+ usesTexture = textureStage[coordinate].usesTexture() || project;
+ }
+
+ return hasTexture && usesTexture;
+ }
+
+ bool Context::texCoordActive(int coordinate)
+ {
+ return texCoordActive(coordinate, 0) ||
+ texCoordActive(coordinate, 1) ||
+ texCoordActive(coordinate, 2) ||
+ texCoordActive(coordinate, 3);
+ }
+
+ bool Context::isProjectionComponent(unsigned int coordinate, int component)
+ {
+ if(pixelShaderModel() <= 0x0103 && coordinate < 8 && textureTransformProject[coordinate])
+ {
+ if(textureTransformCount[coordinate] == 2)
+ {
+ if(component == 1) return true;
+ }
+ else if(textureTransformCount[coordinate] == 3)
+ {
+ if(component == 2) return true;
+ }
+ else if(textureTransformCount[coordinate] == 4 || textureTransformCount[coordinate] == 0)
+ {
+ if(component == 3) return true;
+ }
+ }
+
+ return false;
+ }
+
+ bool Context::vertexSpecularActive()
+ {
+ return vertexLightingActive() && specularEnable && vertexNormalActive();
+ }
+
+ bool Context::vertexNormalActive()
+ {
+ if(vertexShader)
+ {
+ return false;
+ }
+
+ return input[Normal];
+ }
+
+ bool Context::vertexLightActive(int i)
+ {
+ if(vertexShader)
+ {
+ return false;
+ }
+
+ return lightingEnable && lightEnable[i];
+ }
+
+ MaterialSource Context::vertexDiffuseMaterialSourceActive()
+ {
+ if(vertexShader)
+ {
+ return MATERIAL_MATERIAL;
+ }
+
+ if(diffuseMaterialSource == MATERIAL_MATERIAL || !colorVertexEnable ||
+ (diffuseMaterialSource == MATERIAL_COLOR1 && !input[Color0]) ||
+ (diffuseMaterialSource == MATERIAL_COLOR2 && !input[Color1]))
+ {
+ return MATERIAL_MATERIAL;
+ }
+
+ return diffuseMaterialSource;
+ }
+
+ MaterialSource Context::vertexSpecularMaterialSourceActive()
+ {
+ if(vertexShader)
+ {
+ return MATERIAL_MATERIAL;
+ }
+
+ if(!colorVertexEnable ||
+ (specularMaterialSource == MATERIAL_COLOR1 && !input[Color0]) ||
+ (specularMaterialSource == MATERIAL_COLOR2 && !input[Color1]))
+ {
+ return MATERIAL_MATERIAL;
+ }
+
+ return specularMaterialSource;
+ }
+
+ MaterialSource Context::vertexAmbientMaterialSourceActive()
+ {
+ if(vertexShader)
+ {
+ return MATERIAL_MATERIAL;
+ }
+
+ if(!colorVertexEnable ||
+ (ambientMaterialSource == MATERIAL_COLOR1 && !input[Color0]) ||
+ (ambientMaterialSource == MATERIAL_COLOR2 && !input[Color1]))
+ {
+ return MATERIAL_MATERIAL;
+ }
+
+ return ambientMaterialSource;
+ }
+
+ MaterialSource Context::vertexEmissiveMaterialSourceActive()
+ {
+ if(vertexShader)
+ {
+ return MATERIAL_MATERIAL;
+ }
+
+ if(!colorVertexEnable ||
+ (emissiveMaterialSource == MATERIAL_COLOR1 && !input[Color0]) ||
+ (emissiveMaterialSource == MATERIAL_COLOR2 && !input[Color1]))
+ {
+ return MATERIAL_MATERIAL;
+ }
+
+ return emissiveMaterialSource;
+ }
+
+ bool Context::pointSpriteActive()
+ {
+ return isDrawPoint(true) && pointSpriteEnable;
+ }
+
+ bool Context::pointScaleActive()
+ {
+ if(vertexShader)
+ {
+ return false;
+ }
+
+ return isDrawPoint(true) && pointScaleEnable;
+ }
+
+ bool Context::alphaBlendActive()
+ {
+ if(!alphaBlendEnable)
+ {
+ return false;
+ }
+
+ if(!colorUsed())
+ {
+ return false;
+ }
+
+ bool colorBlend = !(blendOperation() == BLENDOP_SOURCE && sourceBlendFactor() == BLEND_ONE);
+ bool alphaBlend = separateAlphaBlendEnable ? !(blendOperationAlpha() == BLENDOP_SOURCE && sourceBlendFactorAlpha() == BLEND_ONE) : colorBlend;
+
+ return colorBlend || alphaBlend;
+ }
+
+ LogicalOperation Context::colorLogicOp()
+ {
+ return colorLogicOpEnabled ? logicalOperation : LOGICALOP_COPY;
+ }
+
+ BlendFactor Context::sourceBlendFactor()
+ {
+ if(!alphaBlendEnable) return BLEND_ONE;
+
+ switch(blendOperationState)
+ {
+ case BLENDOP_ADD:
+ case BLENDOP_SUB:
+ case BLENDOP_INVSUB:
+ return sourceBlendFactorState;
+ case BLENDOP_MIN:
+ return BLEND_ONE;
+ case BLENDOP_MAX:
+ return BLEND_ONE;
+ default:
+ ASSERT(false);
+ }
+
+ return sourceBlendFactorState;
+ }
+
+ BlendFactor Context::destBlendFactor()
+ {
+ if(!alphaBlendEnable) return BLEND_ZERO;
+
+ switch(blendOperationState)
+ {
+ case BLENDOP_ADD:
+ case BLENDOP_SUB:
+ case BLENDOP_INVSUB:
+ return destBlendFactorState;
+ case BLENDOP_MIN:
+ return BLEND_ONE;
+ case BLENDOP_MAX:
+ return BLEND_ONE;
+ default:
+ ASSERT(false);
+ }
+
+ return destBlendFactorState;
+ }
+
+ BlendOperation Context::blendOperation()
+ {
+ if(!alphaBlendEnable) return BLENDOP_SOURCE;
+
+ switch(blendOperationState)
+ {
+ case BLENDOP_ADD:
+ if(sourceBlendFactor() == BLEND_ZERO)
+ {
+ if(destBlendFactor() == BLEND_ZERO)
+ {
+ return BLENDOP_NULL;
+ }
+ else
+ {
+ return BLENDOP_DEST;
+ }
+ }
+ else if(sourceBlendFactor() == BLEND_ONE)
+ {
+ if(destBlendFactor() == BLEND_ZERO)
+ {
+ return BLENDOP_SOURCE;
+ }
+ else
+ {
+ return BLENDOP_ADD;
+ }
+ }
+ else
+ {
+ if(destBlendFactor() == BLEND_ZERO)
+ {
+ return BLENDOP_SOURCE;
+ }
+ else
+ {
+ return BLENDOP_ADD;
+ }
+ }
+ case BLENDOP_SUB:
+ if(sourceBlendFactor() == BLEND_ZERO)
+ {
+ return BLENDOP_NULL; // Negative, clamped to zero
+ }
+ else if(sourceBlendFactor() == BLEND_ONE)
+ {
+ if(destBlendFactor() == BLEND_ZERO)
+ {
+ return BLENDOP_SOURCE;
+ }
+ else
+ {
+ return BLENDOP_SUB;
+ }
+ }
+ else
+ {
+ if(destBlendFactor() == BLEND_ZERO)
+ {
+ return BLENDOP_SOURCE;
+ }
+ else
+ {
+ return BLENDOP_SUB;
+ }
+ }
+ case BLENDOP_INVSUB:
+ if(sourceBlendFactor() == BLEND_ZERO)
+ {
+ if(destBlendFactor() == BLEND_ZERO)
+ {
+ return BLENDOP_NULL;
+ }
+ else
+ {
+ return BLENDOP_DEST;
+ }
+ }
+ else if(sourceBlendFactor() == BLEND_ONE)
+ {
+ if(destBlendFactor() == BLEND_ZERO)
+ {
+ return BLENDOP_NULL; // Negative, clamped to zero
+ }
+ else
+ {
+ return BLENDOP_INVSUB;
+ }
+ }
+ else
+ {
+ if(destBlendFactor() == BLEND_ZERO)
+ {
+ return BLENDOP_NULL; // Negative, clamped to zero
+ }
+ else
+ {
+ return BLENDOP_INVSUB;
+ }
+ }
+ case BLENDOP_MIN:
+ return BLENDOP_MIN;
+ case BLENDOP_MAX:
+ return BLENDOP_MAX;
+ default:
+ ASSERT(false);
+ }
+
+ return blendOperationState;
+ }
+
+ BlendFactor Context::sourceBlendFactorAlpha()
+ {
+ if(!separateAlphaBlendEnable)
+ {
+ return sourceBlendFactor();
+ }
+ else
+ {
+ switch(blendOperationStateAlpha)
+ {
+ case BLENDOP_ADD:
+ case BLENDOP_SUB:
+ case BLENDOP_INVSUB:
+ return sourceBlendFactorStateAlpha;
+ case BLENDOP_MIN:
+ return BLEND_ONE;
+ case BLENDOP_MAX:
+ return BLEND_ONE;
+ default:
+ ASSERT(false);
+ }
+
+ return sourceBlendFactorStateAlpha;
+ }
+ }
+
+ BlendFactor Context::destBlendFactorAlpha()
+ {
+ if(!separateAlphaBlendEnable)
+ {
+ return destBlendFactor();
+ }
+ else
+ {
+ switch(blendOperationStateAlpha)
+ {
+ case BLENDOP_ADD:
+ case BLENDOP_SUB:
+ case BLENDOP_INVSUB:
+ return destBlendFactorStateAlpha;
+ case BLENDOP_MIN:
+ return BLEND_ONE;
+ case BLENDOP_MAX:
+ return BLEND_ONE;
+ default:
+ ASSERT(false);
+ }
+
+ return destBlendFactorStateAlpha;
+ }
+ }
+
+ BlendOperation Context::blendOperationAlpha()
+ {
+ if(!separateAlphaBlendEnable)
+ {
+ return blendOperation();
+ }
+ else
+ {
+ switch(blendOperationStateAlpha)
+ {
+ case BLENDOP_ADD:
+ if(sourceBlendFactorAlpha() == BLEND_ZERO)
+ {
+ if(destBlendFactorAlpha() == BLEND_ZERO)
+ {
+ return BLENDOP_NULL;
+ }
+ else
+ {
+ return BLENDOP_DEST;
+ }
+ }
+ else if(sourceBlendFactorAlpha() == BLEND_ONE)
+ {
+ if(destBlendFactorAlpha() == BLEND_ZERO)
+ {
+ return BLENDOP_SOURCE;
+ }
+ else
+ {
+ return BLENDOP_ADD;
+ }
+ }
+ else
+ {
+ if(destBlendFactorAlpha() == BLEND_ZERO)
+ {
+ return BLENDOP_SOURCE;
+ }
+ else
+ {
+ return BLENDOP_ADD;
+ }
+ }
+ case BLENDOP_SUB:
+ if(sourceBlendFactorAlpha() == BLEND_ZERO)
+ {
+ return BLENDOP_NULL; // Negative, clamped to zero
+ }
+ else if(sourceBlendFactorAlpha() == BLEND_ONE)
+ {
+ if(destBlendFactorAlpha() == BLEND_ZERO)
+ {
+ return BLENDOP_SOURCE;
+ }
+ else
+ {
+ return BLENDOP_SUB;
+ }
+ }
+ else
+ {
+ if(destBlendFactorAlpha() == BLEND_ZERO)
+ {
+ return BLENDOP_SOURCE;
+ }
+ else
+ {
+ return BLENDOP_SUB;
+ }
+ }
+ case BLENDOP_INVSUB:
+ if(sourceBlendFactorAlpha() == BLEND_ZERO)
+ {
+ if(destBlendFactorAlpha() == BLEND_ZERO)
+ {
+ return BLENDOP_NULL;
+ }
+ else
+ {
+ return BLENDOP_DEST;
+ }
+ }
+ else if(sourceBlendFactorAlpha() == BLEND_ONE)
+ {
+ if(destBlendFactorAlpha() == BLEND_ZERO)
+ {
+ return BLENDOP_NULL; // Negative, clamped to zero
+ }
+ else
+ {
+ return BLENDOP_INVSUB;
+ }
+ }
+ else
+ {
+ if(destBlendFactorAlpha() == BLEND_ZERO)
+ {
+ return BLENDOP_NULL; // Negative, clamped to zero
+ }
+ else
+ {
+ return BLENDOP_INVSUB;
+ }
+ }
+ case BLENDOP_MIN:
+ return BLENDOP_MIN;
+ case BLENDOP_MAX:
+ return BLENDOP_MAX;
+ default:
+ ASSERT(false);
+ }
+
+ return blendOperationStateAlpha;
+ }
+ }
+
+ bool Context::indexedVertexBlendActive()
+ {
+ if(vertexShader)
+ {
+ return false;
+ }
+
+ return indexedVertexBlendEnable;
+ }
+
+ int Context::vertexBlendMatrixCountActive()
+ {
+ if(vertexShader)
+ {
+ return 0;
+ }
+
+ return vertexBlendMatrixCount;
+ }
+
+ bool Context::localViewerActive()
+ {
+ if(vertexShader)
+ {
+ return false;
+ }
+
+ return localViewer;
+ }
+
+ bool Context::normalizeNormalsActive()
+ {
+ if(vertexShader)
+ {
+ return false;
+ }
+
+ return normalizeNormals;
+ }
+
+ FogMode Context::vertexFogModeActive()
+ {
+ if(vertexShader || !fogActive())
+ {
+ return FOG_NONE;
+ }
+
+ return vertexFogMode;
+ }
+
+ bool Context::rangeFogActive()
+ {
+ if(vertexShader || !fogActive())
+ {
+ return false;
+ }
+
+ return rangeFogEnable;
+ }
+
+ TexGen Context::texGenActive(int stage)
+ {
+ if(vertexShader || !texCoordActive(stage))
+ {
+ return TEXGEN_PASSTHRU;
+ }
+
+ return texGen[stage];
+ }
+
+ int Context::textureTransformCountActive(int stage)
+ {
+ if(vertexShader || !texCoordActive(stage))
+ {
+ return 0;
+ }
+
+ return textureTransformCount[stage];
+ }
+
+ int Context::texCoordIndexActive(int stage)
+ {
+ if(vertexShader || !texCoordActive(stage))
+ {
+ return stage;
+ }
+
+ return textureStage[stage].texCoordIndex;
+ }
+
+ bool Context::perspectiveActive()
+ {
+ if(!colorUsed())
+ {
+ return false;
+ }
+
+ if(!perspectiveCorrection)
+ {
+ return false;
+ }
+
+ if(isDrawPoint(true))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ bool Context::diffuseUsed()
+ {
+ return diffuseUsed(0) || diffuseUsed(1) || diffuseUsed(2) || diffuseUsed(3);
+ }
+
+ bool Context::diffuseUsed(int component)
+ {
+ if(!colorUsed())
+ {
+ return false;
+ }
+
+ if(pixelShader)
+ {
+ return pixelShader->usesDiffuse(component);
+ }
+
+ // Directly using the diffuse input color
+ for(int i = 0; i < 8; i++)
+ {
+ if(textureStage[i].isStageDisabled())
+ {
+ break;
+ }
+
+ if(textureStage[i].usesDiffuse())
+ {
+ return true;
+ }
+ }
+
+ // Using the current color (initialized to diffuse) before it's overwritten
+ for(int i = 0; i < 8; i++)
+ {
+ if(textureStage[i].usesCurrent() || textureStage[i].isStageDisabled()) // Current color contains diffuse before being overwritten
+ {
+ return true;
+ }
+
+ if(textureStage[i].writesCurrent())
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ bool Context::diffuseActive()
+ {
+ return diffuseActive(0) || diffuseActive(1) || diffuseActive(2) || diffuseActive(3);
+ }
+
+ bool Context::diffuseActive(int component)
+ {
+ if(!colorUsed())
+ {
+ return false;
+ }
+
+ // Vertex processor provides diffuse component
+ bool vertexDiffuse;
+
+ if(vertexShader)
+ {
+ vertexDiffuse = vertexShader->getOutput(C0, component).active();
+ }
+ else if(!preTransformed)
+ {
+ vertexDiffuse = input[Color0] || lightingEnable;
+ }
+ else
+ {
+ vertexDiffuse = input[Color0];
+ }
+
+ // Pixel processor requires diffuse component
+ bool pixelDiffuse = diffuseUsed(component);
+
+ return vertexDiffuse && pixelDiffuse;
+ }
+
+ bool Context::specularUsed()
+ {
+ return Context::specularUsed(0) || Context::specularUsed(1) || Context::specularUsed(2) || Context::specularUsed(3);
+ }
+
+ bool Context::specularUsed(int component)
+ {
+ if(!colorUsed())
+ {
+ return false;
+ }
+
+ if(pixelShader)
+ {
+ return pixelShader->usesSpecular(component);
+ }
+
+ bool pixelSpecular = specularEnable;
+
+ for(int i = 0; i < 8; i++)
+ {
+ if(textureStage[i].isStageDisabled()) break;
+
+ pixelSpecular = pixelSpecular || textureStage[i].usesSpecular();
+ }
+
+ return pixelSpecular;
+ }
+
+ bool Context::specularActive()
+ {
+ return specularActive(0) || specularActive(1) || specularActive(2) || specularActive(3);
+ }
+
+ bool Context::specularActive(int component)
+ {
+ if(!colorUsed())
+ {
+ return false;
+ }
+
+ // Vertex processor provides specular component
+ bool vertexSpecular;
+
+ if(!vertexShader)
+ {
+ vertexSpecular = input[Color1] || (lightingEnable && specularEnable);
+ }
+ else
+ {
+ vertexSpecular = vertexShader->getOutput(C1, component).active();
+ }
+
+ // Pixel processor requires specular component
+ bool pixelSpecular = specularUsed(component);
+
+ return vertexSpecular && pixelSpecular;
+ }
+
+ bool Context::colorActive(int color, int component)
+ {
+ if(color == 0)
+ {
+ return diffuseActive(component);
+ }
+ else
+ {
+ return specularActive(component);
+ }
+ }
+
+ bool Context::textureActive()
+ {
+ for(int i = 0; i < 8; i++)
+ {
+ if(textureActive(i))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ bool Context::textureActive(int coordinate)
+ {
+ return textureActive(coordinate, 0) || textureActive(coordinate, 1) || textureActive(coordinate, 2) || textureActive(coordinate, 3);
+ }
+
+ bool Context::textureActive(int coordinate, int component)
+ {
+ if(!colorUsed())
+ {
+ return false;
+ }
+
+ if(!texCoordActive(coordinate, component))
+ {
+ return false;
+ }
+
+ if(textureTransformProject[coordinate] && pixelShaderModel() <= 0x0103)
+ {
+ if(textureTransformCount[coordinate] == 2)
+ {
+ if(component == 1) return true;
+ }
+ else if(textureTransformCount[coordinate] == 3)
+ {
+ if(component == 2) return true;
+ }
+ else if(textureTransformCount[coordinate] == 4 || textureTransformCount[coordinate] == 0)
+ {
+ if(component == 3) return true;
+ }
+ }
+
+ if(!pixelShader)
+ {
+ bool texture = textureStage[coordinate].usesTexture();
+ bool cube = sampler[coordinate].hasCubeTexture();
+ bool volume = sampler[coordinate].hasVolumeTexture();
+
+ if(texture)
+ {
+ for(int i = coordinate; i >= 0; i--)
+ {
+ if(textureStage[i].stageOperation == TextureStage::STAGE_DISABLE)
+ {
+ return false;
+ }
+ }
+ }
+
+ switch(component)
+ {
+ case 0:
+ return texture;
+ case 1:
+ return texture;
+ case 2:
+ return (texture && (cube || volume));
+ case 3:
+ return false;
+ }
+ }
+ else
+ {
+ return pixelShader->usesTexture(coordinate, component);
+ }
+
+ return false;
+ }
+
+ unsigned short Context::pixelShaderModel() const
+ {
+ return pixelShader ? pixelShader->getShaderModel() : 0x0000;
+ }
+
+ unsigned short Context::vertexShaderModel() const
+ {
+ return vertexShader ? vertexShader->getShaderModel() : 0x0000;
+ }
+
+ int Context::getMultiSampleCount() const
+ {
+ return renderTarget[0] ? renderTarget[0]->getMultiSampleCount() : 1;
+ }
+
+ int Context::getSuperSampleCount() const
+ {
+ return renderTarget[0] ? renderTarget[0]->getSuperSampleCount() : 1;
+ }
+
+ Format Context::renderTargetInternalFormat(int index)
+ {
+ if(renderTarget[index])
+ {
+ return renderTarget[index]->getInternalFormat();
+ }
+ else
+ {
+ return FORMAT_NULL;
+ }
+ }
+
+ int Context::colorWriteActive()
+ {
+ return colorWriteActive(0) | colorWriteActive(1) | colorWriteActive(2) | colorWriteActive(3);
+ }
+
+ int Context::colorWriteActive(int index)
+ {
+ if(!renderTarget[index] || renderTarget[index]->getInternalFormat() == FORMAT_NULL)
+ {
+ return 0;
+ }
+
+ if(blendOperation() == BLENDOP_DEST && destBlendFactor() == BLEND_ONE &&
+ (!separateAlphaBlendEnable || (blendOperationAlpha() == BLENDOP_DEST && destBlendFactorAlpha() == BLEND_ONE)))
+ {
+ return 0;
+ }
+
+ return colorWriteMask[index];
+ }
+
+ bool Context::colorUsed()
+ {
+ return colorWriteActive() || alphaTestActive() || (pixelShader && pixelShader->containsKill());
+ }
+}