blob: d9bad6bab707a34d15301c2ddd9d6761cc29c109 [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 "Context.hpp"
#include "Primitive.hpp"
#include "Surface.hpp"
#include "Pipeline/PixelShader.hpp"
#include "Pipeline/VertexShader.hpp"
#include "System/Memory.hpp"
#include "System/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() const
{
switch(drawType)
{
case DRAW_POINTLIST:
case DRAW_INDEXEDPOINTLIST16:
case DRAW_INDEXEDPOINTLIST32:
return true;
case DRAW_LINELIST:
case DRAW_LINESTRIP:
case DRAW_INDEXEDLINELIST16:
case DRAW_INDEXEDLINESTRIP16:
case DRAW_INDEXEDLINELIST32:
case DRAW_INDEXEDLINESTRIP32:
return false;
case DRAW_TRIANGLELIST:
case DRAW_TRIANGLESTRIP:
case DRAW_TRIANGLEFAN:
case DRAW_INDEXEDTRIANGLELIST16:
case DRAW_INDEXEDTRIANGLESTRIP16:
case DRAW_INDEXEDTRIANGLEFAN16:
case DRAW_INDEXEDTRIANGLELIST32:
case DRAW_INDEXEDTRIANGLESTRIP32:
case DRAW_INDEXEDTRIANGLEFAN32:
return false;
default:
ASSERT(false);
}
return false;
}
bool Context::isDrawLine() const
{
switch(drawType)
{
case DRAW_POINTLIST:
case DRAW_INDEXEDPOINTLIST16:
case DRAW_INDEXEDPOINTLIST32:
return false;
case DRAW_LINELIST:
case DRAW_LINESTRIP:
case DRAW_INDEXEDLINELIST16:
case DRAW_INDEXEDLINESTRIP16:
case DRAW_INDEXEDLINELIST32:
case DRAW_INDEXEDLINESTRIP32:
return true;
case DRAW_TRIANGLELIST:
case DRAW_TRIANGLESTRIP:
case DRAW_TRIANGLEFAN:
case DRAW_INDEXEDTRIANGLELIST16:
case DRAW_INDEXEDTRIANGLESTRIP16:
case DRAW_INDEXEDTRIANGLEFAN16:
case DRAW_INDEXEDTRIANGLELIST32:
case DRAW_INDEXEDTRIANGLESTRIP32:
case DRAW_INDEXEDTRIANGLEFAN32:
return false;
default:
ASSERT(false);
}
return false;
}
bool Context::isDrawTriangle() const
{
switch(drawType)
{
case DRAW_POINTLIST:
case DRAW_INDEXEDPOINTLIST16:
case DRAW_INDEXEDPOINTLIST32:
return false;
case DRAW_LINELIST:
case DRAW_LINESTRIP:
case DRAW_INDEXEDLINELIST16:
case DRAW_INDEXEDLINESTRIP16:
case DRAW_INDEXEDLINELIST32:
case DRAW_INDEXEDLINESTRIP32:
return false;
case DRAW_TRIANGLELIST:
case DRAW_TRIANGLESTRIP:
case DRAW_TRIANGLEFAN:
case DRAW_INDEXEDTRIANGLELIST16:
case DRAW_INDEXEDTRIANGLESTRIP16:
case DRAW_INDEXEDTRIANGLEFAN16:
case DRAW_INDEXEDTRIANGLELIST32:
case DRAW_INDEXEDTRIANGLESTRIP32:
case DRAW_INDEXEDTRIANGLEFAN32:
return true;
default:
ASSERT(false);
}
return true;
}
void Context::init()
{
// Set vertex streams to null stream
for(int i = 0; i < MAX_VERTEX_INPUTS; i++)
{
input[i].defaults();
}
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;
alphaCompareMode = ALPHA_ALWAYS;
alphaTestEnable = false;
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;
}
pixelShader = nullptr;
vertexShader = nullptr;
instanceID = 0;
occlusionEnabled = false;
transformFeedbackQueryEnabled = false;
transformFeedbackEnabled = 0;
lineWidth = 1.0f;
writeSRGB = false;
sampleMask = 0xFFFFFFFF;
colorLogicOpEnabled = false;
logicalOperation = LOGICALOP_COPY;
}
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;
}
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::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::perspectiveActive()
{
if(!colorUsed())
{
return false;
}
if(!perspectiveCorrection)
{
return false;
}
if(isDrawPoint())
{
return false;
}
return true;
}
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;
}
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());
}
}