// 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 "Vulkan/VkDebug.hpp" #include <string.h> namespace sw { extern bool perspectiveCorrection; bool halfIntegerCoordinates = false; // Pixel centers are not at integer coordinates 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 = VK_COMPARE_OP_ALWAYS; stencilReference = 0; stencilMask = 0xFFFFFFFF; stencilFailOperation = VK_STENCIL_OP_KEEP; stencilPassOperation = VK_STENCIL_OP_KEEP; stencilZFailOperation = VK_STENCIL_OP_KEEP; stencilWriteMask = 0xFFFFFFFF; twoSidedStencil = false; stencilCompareModeCCW = VK_COMPARE_OP_ALWAYS; stencilReferenceCCW = 0; stencilMaskCCW = 0xFFFFFFFF; stencilFailOperationCCW = VK_STENCIL_OP_KEEP; stencilPassOperationCCW = VK_STENCIL_OP_KEEP; stencilZFailOperationCCW = VK_STENCIL_OP_KEEP; stencilWriteMaskCCW = 0xFFFFFFFF; alphaCompareMode = VK_COMPARE_OP_ALWAYS; alphaTestEnable = false; rasterizerDiscard = false; depthCompareMode = VK_COMPARE_OP_LESS; depthBufferEnable = true; depthWriteEnable = true; alphaBlendEnable = false; sourceBlendFactorState = VK_BLEND_FACTOR_ONE; destBlendFactorState = VK_BLEND_FACTOR_ZERO; blendOperationState = VK_BLEND_OP_ADD; separateAlphaBlendEnable = false; sourceBlendFactorStateAlpha = VK_BLEND_FACTOR_ONE; destBlendFactorStateAlpha = VK_BLEND_FACTOR_ZERO; blendOperationStateAlpha = VK_BLEND_OP_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 = VK_LOGIC_OP_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(VkBlendFactor sourceBlendFactor) { bool modified = (Context::sourceBlendFactorState != sourceBlendFactor); Context::sourceBlendFactorState = sourceBlendFactor; return modified; } bool Context::setDestBlendFactor(VkBlendFactor destBlendFactor) { bool modified = (Context::destBlendFactorState != destBlendFactor); Context::destBlendFactorState = destBlendFactor; return modified; } bool Context::setBlendOperation(VkBlendOp 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(VkBlendFactor sourceBlendFactorAlpha) { bool modified = (Context::sourceBlendFactorStateAlpha != sourceBlendFactorAlpha); Context::sourceBlendFactorStateAlpha = sourceBlendFactorAlpha; return modified; } bool Context::setDestBlendFactorAlpha(VkBlendFactor destBlendFactorAlpha) { bool modified = (Context::destBlendFactorStateAlpha != destBlendFactorAlpha); Context::destBlendFactorStateAlpha = destBlendFactorAlpha; return modified; } bool Context::setBlendOperationAlpha(VkBlendOp 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(VkLogicOp 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 == VK_COMPARE_OP_ALWAYS) return false; if(alphaReference == 0.0f && alphaCompareMode == VK_COMPARE_OP_GREATER_OR_EQUAL) 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() == VK_BLEND_OP_SRC_EXT && sourceBlendFactor() == VK_BLEND_FACTOR_ONE); bool alphaBlend = separateAlphaBlendEnable ? !(blendOperationAlpha() == VK_BLEND_OP_SRC_EXT && sourceBlendFactorAlpha() == VK_BLEND_FACTOR_ONE) : colorBlend; return colorBlend || alphaBlend; } VkLogicOp Context::colorLogicOp() { return colorLogicOpEnabled ? logicalOperation : VK_LOGIC_OP_COPY; } VkBlendFactor Context::sourceBlendFactor() { if(!alphaBlendEnable) return VK_BLEND_FACTOR_ONE; switch(blendOperationState) { case VK_BLEND_OP_ADD: case VK_BLEND_OP_SUBTRACT: case VK_BLEND_OP_REVERSE_SUBTRACT: return sourceBlendFactorState; case VK_BLEND_OP_MIN: return VK_BLEND_FACTOR_ONE; case VK_BLEND_OP_MAX: return VK_BLEND_FACTOR_ONE; default: ASSERT(false); } return sourceBlendFactorState; } VkBlendFactor Context::destBlendFactor() { if(!alphaBlendEnable) return VK_BLEND_FACTOR_ONE; switch(blendOperationState) { case VK_BLEND_OP_ADD: case VK_BLEND_OP_SUBTRACT: case VK_BLEND_OP_REVERSE_SUBTRACT: return destBlendFactorState; case VK_BLEND_OP_MIN: return VK_BLEND_FACTOR_ONE; case VK_BLEND_OP_MAX: return VK_BLEND_FACTOR_ONE; default: ASSERT(false); } return destBlendFactorState; } VkBlendOp Context::blendOperation() { if(!alphaBlendEnable) return VK_BLEND_OP_SRC_EXT; switch(blendOperationState) { case VK_BLEND_OP_ADD: if(sourceBlendFactor() == VK_BLEND_FACTOR_ZERO) { if(destBlendFactor() == VK_BLEND_FACTOR_ZERO) { return VK_BLEND_OP_ZERO_EXT; } else { return VK_BLEND_OP_DST_EXT; } } else if(sourceBlendFactor() == VK_BLEND_FACTOR_ONE) { if(destBlendFactor() == VK_BLEND_FACTOR_ZERO) { return VK_BLEND_OP_SRC_EXT; } else { return VK_BLEND_OP_ADD; } } else { if(destBlendFactor() == VK_BLEND_FACTOR_ZERO) { return VK_BLEND_OP_SRC_EXT; } else { return VK_BLEND_OP_ADD; } } case VK_BLEND_OP_SUBTRACT: if(sourceBlendFactor() == VK_BLEND_FACTOR_ZERO) { return VK_BLEND_OP_ZERO_EXT; // Negative, clamped to zero } else if(sourceBlendFactor() == VK_BLEND_FACTOR_ONE) { if(destBlendFactor() == VK_BLEND_FACTOR_ZERO) { return VK_BLEND_OP_SRC_EXT; } else { return VK_BLEND_OP_SUBTRACT; } } else { if(destBlendFactor() == VK_BLEND_FACTOR_ZERO) { return VK_BLEND_OP_SRC_EXT; } else { return VK_BLEND_OP_SUBTRACT; } } case VK_BLEND_OP_REVERSE_SUBTRACT: if(sourceBlendFactor() == VK_BLEND_FACTOR_ZERO) { if(destBlendFactor() == VK_BLEND_FACTOR_ZERO) { return VK_BLEND_OP_ZERO_EXT; } else { return VK_BLEND_OP_DST_EXT; } } else if(sourceBlendFactor() == VK_BLEND_FACTOR_ONE) { if(destBlendFactor() == VK_BLEND_FACTOR_ZERO) { return VK_BLEND_OP_ZERO_EXT; // Negative, clamped to zero } else { return VK_BLEND_OP_REVERSE_SUBTRACT; } } else { if(destBlendFactor() == VK_BLEND_OP_ZERO_EXT) { return VK_BLEND_OP_ZERO_EXT; // Negative, clamped to zero } else { return VK_BLEND_OP_REVERSE_SUBTRACT; } } case VK_BLEND_OP_MIN: return VK_BLEND_OP_MIN; case VK_BLEND_OP_MAX: return VK_BLEND_OP_MAX; default: ASSERT(false); } return blendOperationState; } VkBlendFactor Context::sourceBlendFactorAlpha() { if(!separateAlphaBlendEnable) { return sourceBlendFactor(); } else { switch(blendOperationStateAlpha) { case VK_BLEND_OP_ADD: case VK_BLEND_OP_SUBTRACT: case VK_BLEND_OP_REVERSE_SUBTRACT: return sourceBlendFactorStateAlpha; case VK_BLEND_OP_MIN: return VK_BLEND_FACTOR_ONE; case VK_BLEND_OP_MAX: return VK_BLEND_FACTOR_ONE; default: ASSERT(false); } return sourceBlendFactorStateAlpha; } } VkBlendFactor Context::destBlendFactorAlpha() { if(!separateAlphaBlendEnable) { return destBlendFactor(); } else { switch(blendOperationStateAlpha) { case VK_BLEND_OP_ADD: case VK_BLEND_OP_SUBTRACT: case VK_BLEND_OP_REVERSE_SUBTRACT: return destBlendFactorStateAlpha; case VK_BLEND_OP_MIN: return VK_BLEND_FACTOR_ONE; case VK_BLEND_OP_MAX: return VK_BLEND_FACTOR_ONE; default: ASSERT(false); } return destBlendFactorStateAlpha; } } VkBlendOp Context::blendOperationAlpha() { if(!separateAlphaBlendEnable) { return blendOperation(); } else { switch(blendOperationStateAlpha) { case VK_BLEND_OP_ADD: if(sourceBlendFactorAlpha() == VK_BLEND_FACTOR_ZERO) { if(destBlendFactorAlpha() == VK_BLEND_FACTOR_ZERO) { return VK_BLEND_OP_ZERO_EXT; } else { return VK_BLEND_OP_DST_EXT; } } else if(sourceBlendFactorAlpha() == VK_BLEND_FACTOR_ONE) { if(destBlendFactorAlpha() == VK_BLEND_FACTOR_ZERO) { return VK_BLEND_OP_SRC_EXT; } else { return VK_BLEND_OP_ADD; } } else { if(destBlendFactorAlpha() == VK_BLEND_FACTOR_ZERO) { return VK_BLEND_OP_SRC_EXT; } else { return VK_BLEND_OP_ADD; } } case VK_BLEND_OP_SUBTRACT: if(sourceBlendFactorAlpha() == VK_BLEND_FACTOR_ZERO) { return VK_BLEND_OP_ZERO_EXT; // Negative, clamped to zero } else if(sourceBlendFactorAlpha() == VK_BLEND_FACTOR_ONE) { if(destBlendFactorAlpha() == VK_BLEND_FACTOR_ZERO) { return VK_BLEND_OP_SRC_EXT; } else { return VK_BLEND_OP_SUBTRACT; } } else { if(destBlendFactorAlpha() == VK_BLEND_FACTOR_ZERO) { return VK_BLEND_OP_SRC_EXT; } else { return VK_BLEND_OP_SUBTRACT; } } case VK_BLEND_OP_REVERSE_SUBTRACT: if(sourceBlendFactorAlpha() == VK_BLEND_FACTOR_ZERO) { if(destBlendFactorAlpha() == VK_BLEND_FACTOR_ZERO) { return VK_BLEND_OP_ZERO_EXT; } else { return VK_BLEND_OP_DST_EXT; } } else if(sourceBlendFactorAlpha() == VK_BLEND_FACTOR_ONE) { if(destBlendFactorAlpha() == VK_BLEND_FACTOR_ZERO) { return VK_BLEND_OP_ZERO_EXT; // Negative, clamped to zero } else { return VK_BLEND_OP_REVERSE_SUBTRACT; } } else { if(destBlendFactorAlpha() == VK_BLEND_OP_ZERO_EXT) { return VK_BLEND_OP_ZERO_EXT; // Negative, clamped to zero } else { return VK_BLEND_OP_ZERO_EXT; } } case VK_BLEND_OP_MIN: return VK_BLEND_OP_MIN; case VK_BLEND_OP_MAX: return VK_BLEND_OP_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; } VkFormat Context::renderTargetInternalFormat(int index) { if(renderTarget[index]) { return renderTarget[index]->getInternalFormat(); } else { return VK_FORMAT_UNDEFINED; } } int Context::colorWriteActive() { return colorWriteActive(0) | colorWriteActive(1) | colorWriteActive(2) | colorWriteActive(3); } int Context::colorWriteActive(int index) { if(!renderTarget[index] || renderTarget[index]->getInternalFormat() == VK_FORMAT_UNDEFINED) { return 0; } if(blendOperation() == VK_BLEND_OP_DST_EXT && destBlendFactor() == VK_BLEND_FACTOR_ONE && (!separateAlphaBlendEnable || (blendOperationAlpha() == VK_BLEND_OP_DST_EXT && destBlendFactorAlpha() == VK_BLEND_FACTOR_ONE))) { return 0; } return colorWriteMask[index]; } bool Context::colorUsed() { return colorWriteActive() || alphaTestActive() || (pixelShader && pixelShader->containsKill()); } }