|  | // 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 "System/Memory.hpp" | 
|  | #include "Vulkan/VkDebug.hpp" | 
|  | #include "Vulkan/VkImageView.hpp" | 
|  | #include "Pipeline/SpirvShader.hpp" | 
|  |  | 
|  | #include <string.h> | 
|  |  | 
|  | namespace sw | 
|  | { | 
|  | Context::Context() | 
|  | { | 
|  | init(); | 
|  | } | 
|  |  | 
|  | bool Context::isDrawPoint(bool polygonModeAware) const | 
|  | { | 
|  | switch(topology) | 
|  | { | 
|  | case VK_PRIMITIVE_TOPOLOGY_POINT_LIST: | 
|  | return true; | 
|  | case VK_PRIMITIVE_TOPOLOGY_LINE_LIST: | 
|  | case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP: | 
|  | return false; | 
|  | case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: | 
|  | case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: | 
|  | case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: | 
|  | return polygonModeAware ? (polygonMode == VK_POLYGON_MODE_POINT) : false; | 
|  | default: | 
|  | UNIMPLEMENTED("topology %d", int(topology)); | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool Context::isDrawLine(bool polygonModeAware) const | 
|  | { | 
|  | switch(topology) | 
|  | { | 
|  | case VK_PRIMITIVE_TOPOLOGY_POINT_LIST: | 
|  | return false; | 
|  | case VK_PRIMITIVE_TOPOLOGY_LINE_LIST: | 
|  | case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP: | 
|  | return true; | 
|  | case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: | 
|  | case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: | 
|  | case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: | 
|  | return polygonModeAware ? (polygonMode == VK_POLYGON_MODE_LINE) : false; | 
|  | default: | 
|  | UNIMPLEMENTED("topology %d", int(topology)); | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool Context::isDrawTriangle(bool polygonModeAware) const | 
|  | { | 
|  | switch(topology) | 
|  | { | 
|  | case VK_PRIMITIVE_TOPOLOGY_POINT_LIST: | 
|  | case VK_PRIMITIVE_TOPOLOGY_LINE_LIST: | 
|  | case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP: | 
|  | return false; | 
|  | case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: | 
|  | case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: | 
|  | case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: | 
|  | return polygonModeAware ? (polygonMode == VK_POLYGON_MODE_FILL) : true; | 
|  | default: | 
|  | UNIMPLEMENTED("topology %d", int(topology)); | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void Context::init() | 
|  | { | 
|  | for(int i = 0; i < RENDERTARGETS; ++i) | 
|  | { | 
|  | renderTarget[i] = nullptr; | 
|  | } | 
|  |  | 
|  | depthBuffer = nullptr; | 
|  | stencilBuffer = nullptr; | 
|  |  | 
|  | stencilEnable = false; | 
|  | frontStencil = {}; | 
|  | backStencil = {}; | 
|  |  | 
|  | robustBufferAccess = false; | 
|  |  | 
|  | rasterizerDiscard = false; | 
|  |  | 
|  | depthCompareMode = VK_COMPARE_OP_LESS; | 
|  | depthBoundsTestEnable = false; | 
|  | depthBufferEnable = false; | 
|  | depthWriteEnable = false; | 
|  |  | 
|  | cullMode = VK_CULL_MODE_FRONT_BIT; | 
|  | frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; | 
|  | provokingVertexMode = VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT; | 
|  | lineRasterizationMode = VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT; | 
|  |  | 
|  | depthBias = 0.0f; | 
|  | slopeDepthBias = 0.0f; | 
|  |  | 
|  | for(int i = 0; i < RENDERTARGETS; i++) | 
|  | { | 
|  | colorWriteMask[i] = 0x0000000F; | 
|  | } | 
|  |  | 
|  | pipelineLayout = nullptr; | 
|  |  | 
|  | pixelShader = nullptr; | 
|  | vertexShader = nullptr; | 
|  |  | 
|  | occlusionEnabled = false; | 
|  |  | 
|  | lineWidth = 1.0f; | 
|  |  | 
|  | sampleMask = 0xFFFFFFFF; | 
|  | alphaToCoverage = false; | 
|  | } | 
|  |  | 
|  | bool Context::depthWriteActive() const | 
|  | { | 
|  | if(!depthBufferActive()) return false; | 
|  |  | 
|  | return depthWriteEnable; | 
|  | } | 
|  |  | 
|  | bool Context::depthBufferActive() const | 
|  | { | 
|  | return depthBuffer && depthBufferEnable; | 
|  | } | 
|  |  | 
|  | bool Context::stencilActive() const | 
|  | { | 
|  | return stencilBuffer && stencilEnable; | 
|  | } | 
|  |  | 
|  | void Context::setBlendState(int index, BlendState state) | 
|  | { | 
|  | ASSERT((index >= 0) && (index < RENDERTARGETS)); | 
|  |  | 
|  | blendState[index] = state; | 
|  | } | 
|  |  | 
|  | BlendState Context::getBlendState(int index) const | 
|  | { | 
|  | ASSERT((index >= 0) && (index < RENDERTARGETS)); | 
|  |  | 
|  | BlendState activeBlendState; | 
|  | activeBlendState.alphaBlendEnable = alphaBlendActive(index); | 
|  | activeBlendState.sourceBlendFactor = sourceBlendFactor(index); | 
|  | activeBlendState.destBlendFactor = destBlendFactor(index); | 
|  | activeBlendState.blendOperation = blendOperation(index); | 
|  | activeBlendState.sourceBlendFactorAlpha = sourceBlendFactorAlpha(index); | 
|  | activeBlendState.destBlendFactorAlpha = destBlendFactorAlpha(index); | 
|  | activeBlendState.blendOperationAlpha = blendOperationAlpha(index); | 
|  | return activeBlendState; | 
|  | } | 
|  |  | 
|  | bool Context::alphaBlendActive(int index) const | 
|  | { | 
|  | ASSERT((index >= 0) && (index < RENDERTARGETS)); | 
|  |  | 
|  | if(!blendState[index].alphaBlendEnable) | 
|  | { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if(!colorUsed()) | 
|  | { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool colorBlend = !(blendOperation(index) == VK_BLEND_OP_SRC_EXT && sourceBlendFactor(index) == VK_BLEND_FACTOR_ONE); | 
|  | bool alphaBlend = !(blendOperationAlpha(index) == VK_BLEND_OP_SRC_EXT && sourceBlendFactorAlpha(index) == VK_BLEND_FACTOR_ONE); | 
|  |  | 
|  | return colorBlend || alphaBlend; | 
|  | } | 
|  |  | 
|  | VkBlendFactor Context::sourceBlendFactor(int index) const | 
|  | { | 
|  | ASSERT((index >= 0) && (index < RENDERTARGETS)); | 
|  |  | 
|  | if(!blendState[index].alphaBlendEnable) return VK_BLEND_FACTOR_ONE; | 
|  |  | 
|  | switch(blendState[index].blendOperation) | 
|  | { | 
|  | case VK_BLEND_OP_ADD: | 
|  | case VK_BLEND_OP_SUBTRACT: | 
|  | case VK_BLEND_OP_REVERSE_SUBTRACT: | 
|  | return blendState[index].sourceBlendFactor; | 
|  | case VK_BLEND_OP_MIN: | 
|  | return VK_BLEND_FACTOR_ONE; | 
|  | case VK_BLEND_OP_MAX: | 
|  | return VK_BLEND_FACTOR_ONE; | 
|  | default: | 
|  | ASSERT(false); | 
|  | } | 
|  |  | 
|  | return blendState[index].sourceBlendFactor; | 
|  | } | 
|  |  | 
|  | VkBlendFactor Context::destBlendFactor(int index) const | 
|  | { | 
|  | ASSERT((index >= 0) && (index < RENDERTARGETS)); | 
|  |  | 
|  | if(!blendState[index].alphaBlendEnable) return VK_BLEND_FACTOR_ONE; | 
|  |  | 
|  | switch(blendState[index].blendOperation) | 
|  | { | 
|  | case VK_BLEND_OP_ADD: | 
|  | case VK_BLEND_OP_SUBTRACT: | 
|  | case VK_BLEND_OP_REVERSE_SUBTRACT: | 
|  | return blendState[index].destBlendFactor; | 
|  | case VK_BLEND_OP_MIN: | 
|  | return VK_BLEND_FACTOR_ONE; | 
|  | case VK_BLEND_OP_MAX: | 
|  | return VK_BLEND_FACTOR_ONE; | 
|  | default: | 
|  | ASSERT(false); | 
|  | } | 
|  |  | 
|  | return blendState[index].destBlendFactor; | 
|  | } | 
|  |  | 
|  | bool Context::allTargetsColorClamp() const | 
|  | { | 
|  | // TODO: remove all of this and support VkPhysicalDeviceFeatures::independentBlend instead | 
|  | for (int i = 0; i < RENDERTARGETS; i++) | 
|  | { | 
|  | if (renderTarget[i] && renderTarget[i]->getFormat().isFloatFormat()) | 
|  | { | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | VkBlendOp Context::blendOperation(int index) const | 
|  | { | 
|  | ASSERT((index >= 0) && (index < RENDERTARGETS)); | 
|  |  | 
|  | if(!blendState[index].alphaBlendEnable) return VK_BLEND_OP_SRC_EXT; | 
|  |  | 
|  | switch(blendState[index].blendOperation) | 
|  | { | 
|  | case VK_BLEND_OP_ADD: | 
|  | if(sourceBlendFactor(index) == VK_BLEND_FACTOR_ZERO) | 
|  | { | 
|  | if(destBlendFactor(index) == VK_BLEND_FACTOR_ZERO) | 
|  | { | 
|  | return VK_BLEND_OP_ZERO_EXT; | 
|  | } | 
|  | else | 
|  | { | 
|  | return VK_BLEND_OP_DST_EXT; | 
|  | } | 
|  | } | 
|  | else if(sourceBlendFactor(index) == VK_BLEND_FACTOR_ONE) | 
|  | { | 
|  | if(destBlendFactor(index) == VK_BLEND_FACTOR_ZERO) | 
|  | { | 
|  | return VK_BLEND_OP_SRC_EXT; | 
|  | } | 
|  | else | 
|  | { | 
|  | return VK_BLEND_OP_ADD; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if(destBlendFactor(index) == VK_BLEND_FACTOR_ZERO) | 
|  | { | 
|  | return VK_BLEND_OP_SRC_EXT; | 
|  | } | 
|  | else | 
|  | { | 
|  | return VK_BLEND_OP_ADD; | 
|  | } | 
|  | } | 
|  | case VK_BLEND_OP_SUBTRACT: | 
|  | if(sourceBlendFactor(index) == VK_BLEND_FACTOR_ZERO && allTargetsColorClamp()) | 
|  | { | 
|  | return VK_BLEND_OP_ZERO_EXT;   // Negative, clamped to zero | 
|  | } | 
|  | else if(sourceBlendFactor(index) == VK_BLEND_FACTOR_ONE) | 
|  | { | 
|  | if(destBlendFactor(index) == VK_BLEND_FACTOR_ZERO) | 
|  | { | 
|  | return VK_BLEND_OP_SRC_EXT; | 
|  | } | 
|  | else | 
|  | { | 
|  | return VK_BLEND_OP_SUBTRACT; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if(destBlendFactor(index) == VK_BLEND_FACTOR_ZERO) | 
|  | { | 
|  | return VK_BLEND_OP_SRC_EXT; | 
|  | } | 
|  | else | 
|  | { | 
|  | return VK_BLEND_OP_SUBTRACT; | 
|  | } | 
|  | } | 
|  | case VK_BLEND_OP_REVERSE_SUBTRACT: | 
|  | if(sourceBlendFactor(index) == VK_BLEND_FACTOR_ZERO) | 
|  | { | 
|  | if(destBlendFactor(index) == VK_BLEND_FACTOR_ZERO) | 
|  | { | 
|  | return VK_BLEND_OP_ZERO_EXT; | 
|  | } | 
|  | else | 
|  | { | 
|  | return VK_BLEND_OP_DST_EXT; | 
|  | } | 
|  | } | 
|  | else if(sourceBlendFactor(index) == VK_BLEND_FACTOR_ONE) | 
|  | { | 
|  | if(destBlendFactor(index) == VK_BLEND_FACTOR_ZERO && allTargetsColorClamp()) | 
|  | { | 
|  | return VK_BLEND_OP_ZERO_EXT;   // Negative, clamped to zero | 
|  | } | 
|  | else | 
|  | { | 
|  | return VK_BLEND_OP_REVERSE_SUBTRACT; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if(destBlendFactor(index) == VK_BLEND_FACTOR_ZERO && allTargetsColorClamp()) | 
|  | { | 
|  | 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 blendState[index].blendOperation; | 
|  | } | 
|  |  | 
|  | VkBlendFactor Context::sourceBlendFactorAlpha(int index) const | 
|  | { | 
|  | ASSERT((index >= 0) && (index < RENDERTARGETS)); | 
|  |  | 
|  | switch (blendState[index].blendOperationAlpha) | 
|  | { | 
|  | case VK_BLEND_OP_ADD: | 
|  | case VK_BLEND_OP_SUBTRACT: | 
|  | case VK_BLEND_OP_REVERSE_SUBTRACT: | 
|  | return blendState[index].sourceBlendFactorAlpha; | 
|  | case VK_BLEND_OP_MIN: | 
|  | return VK_BLEND_FACTOR_ONE; | 
|  | case VK_BLEND_OP_MAX: | 
|  | return VK_BLEND_FACTOR_ONE; | 
|  | default: | 
|  | ASSERT(false); | 
|  | } | 
|  |  | 
|  | return blendState[index].sourceBlendFactorAlpha; | 
|  | } | 
|  |  | 
|  | VkBlendFactor Context::destBlendFactorAlpha(int index) const | 
|  | { | 
|  | ASSERT((index >= 0) && (index < RENDERTARGETS)); | 
|  |  | 
|  | switch (blendState[index].blendOperationAlpha) | 
|  | { | 
|  | case VK_BLEND_OP_ADD: | 
|  | case VK_BLEND_OP_SUBTRACT: | 
|  | case VK_BLEND_OP_REVERSE_SUBTRACT: | 
|  | return blendState[index].destBlendFactorAlpha; | 
|  | case VK_BLEND_OP_MIN: | 
|  | return VK_BLEND_FACTOR_ONE; | 
|  | case VK_BLEND_OP_MAX: | 
|  | return VK_BLEND_FACTOR_ONE; | 
|  | default: | 
|  | ASSERT(false); | 
|  | } | 
|  |  | 
|  | return blendState[index].destBlendFactorAlpha; | 
|  | } | 
|  |  | 
|  | VkBlendOp Context::blendOperationAlpha(int index) const | 
|  | { | 
|  | ASSERT((index >= 0) && (index < RENDERTARGETS)); | 
|  |  | 
|  | switch (blendState[index].blendOperationAlpha) | 
|  | { | 
|  | case VK_BLEND_OP_ADD: | 
|  | if (sourceBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO) | 
|  | { | 
|  | if (destBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO) | 
|  | { | 
|  | return VK_BLEND_OP_ZERO_EXT; | 
|  | } | 
|  | else | 
|  | { | 
|  | return VK_BLEND_OP_DST_EXT; | 
|  | } | 
|  | } | 
|  | else if (sourceBlendFactorAlpha(index) == VK_BLEND_FACTOR_ONE) | 
|  | { | 
|  | if (destBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO) | 
|  | { | 
|  | return VK_BLEND_OP_SRC_EXT; | 
|  | } | 
|  | else | 
|  | { | 
|  | return VK_BLEND_OP_ADD; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if (destBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO) | 
|  | { | 
|  | return VK_BLEND_OP_SRC_EXT; | 
|  | } | 
|  | else | 
|  | { | 
|  | return VK_BLEND_OP_ADD; | 
|  | } | 
|  | } | 
|  | case VK_BLEND_OP_SUBTRACT: | 
|  | if (sourceBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO && allTargetsColorClamp()) | 
|  | { | 
|  | return VK_BLEND_OP_ZERO_EXT;   // Negative, clamped to zero | 
|  | } | 
|  | else if (sourceBlendFactorAlpha(index) == VK_BLEND_FACTOR_ONE) | 
|  | { | 
|  | if (destBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO) | 
|  | { | 
|  | return VK_BLEND_OP_SRC_EXT; | 
|  | } | 
|  | else | 
|  | { | 
|  | return VK_BLEND_OP_SUBTRACT; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if (destBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO) | 
|  | { | 
|  | return VK_BLEND_OP_SRC_EXT; | 
|  | } | 
|  | else | 
|  | { | 
|  | return VK_BLEND_OP_SUBTRACT; | 
|  | } | 
|  | } | 
|  | case VK_BLEND_OP_REVERSE_SUBTRACT: | 
|  | if (sourceBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO) | 
|  | { | 
|  | if (destBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO) | 
|  | { | 
|  | return VK_BLEND_OP_ZERO_EXT; | 
|  | } | 
|  | else | 
|  | { | 
|  | return VK_BLEND_OP_DST_EXT; | 
|  | } | 
|  | } | 
|  | else if (sourceBlendFactorAlpha(index) == VK_BLEND_FACTOR_ONE) | 
|  | { | 
|  | if (destBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO && allTargetsColorClamp()) | 
|  | { | 
|  | return VK_BLEND_OP_ZERO_EXT;   // Negative, clamped to zero | 
|  | } | 
|  | else | 
|  | { | 
|  | return VK_BLEND_OP_REVERSE_SUBTRACT; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if (destBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO && allTargetsColorClamp()) | 
|  | { | 
|  | 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 blendState[index].blendOperationAlpha; | 
|  | } | 
|  |  | 
|  | VkFormat Context::renderTargetInternalFormat(int index) const | 
|  | { | 
|  | ASSERT((index >= 0) && (index < RENDERTARGETS)); | 
|  |  | 
|  | if(renderTarget[index]) | 
|  | { | 
|  | return renderTarget[index]->getFormat(); | 
|  | } | 
|  | else | 
|  | { | 
|  | return VK_FORMAT_UNDEFINED; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool Context::colorWriteActive() const | 
|  | { | 
|  | for (int i = 0; i < RENDERTARGETS; i++) | 
|  | { | 
|  | if (colorWriteActive(i)) | 
|  | { | 
|  | return true; | 
|  | } | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | int Context::colorWriteActive(int index) const | 
|  | { | 
|  | ASSERT((index >= 0) && (index < RENDERTARGETS)); | 
|  |  | 
|  | if(!renderTarget[index] || renderTarget[index]->getFormat() == VK_FORMAT_UNDEFINED) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if(blendOperation(index) == VK_BLEND_OP_DST_EXT && destBlendFactor(index) == VK_BLEND_FACTOR_ONE && | 
|  | (blendOperationAlpha(index) == VK_BLEND_OP_DST_EXT && destBlendFactorAlpha(index) == VK_BLEND_FACTOR_ONE)) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | return colorWriteMask[index]; | 
|  | } | 
|  |  | 
|  | bool Context::colorUsed() const | 
|  | { | 
|  | return colorWriteActive() || (pixelShader && pixelShader->getModes().ContainsKill); | 
|  | } | 
|  | } |