Context refactor: from OpenGL-like state to Vulkan-like state

Overview of the changes: The Context class has been split into more Vulkan related functional elements: - The IndexBuffer class, which contains the index buffer information and has been extended to also the functionality to support primitive restart. Should we need primitive restart related caching in the future, this would be the place to do it. - The Attachments class, which contains information about render targets and depth and stencil buffers - The Inputs class, which contains information about descriptor sets and input streams. - The GraphicsState is a completely constant class which can only be modified in the constructor, which represents the state of a graphics pipeline, which never changes past construction. The GraphicsState can be combined with a DynamicState structure in order to create a complete state used by rendering. Also to note: - The DynamicState class in now in Context.hpp, in order for the GraphicsState to have functionality related to it. - PushConstantStorage was moved to vk::Pipeline, as it is used by both the Graphics Pipeline and the Compute Pipeline. - Viewport/scissor functionality is contained in the GraphicsState and was removed from the Renderer. - All *Processor::update() functions now receive only the information that they require, rather that having access to the entire context. Bug: b/132280877 Change-Id: I74f2582d34e45aa1e7b192dbd2b9b770e7af118d Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/48830Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com> Tested-by: 's avatarAlexis Hétu <sugoi@google.com> Commit-Queue: Alexis Hétu <sugoi@google.com> Kokoro-Result: kokoro <noreply+kokoro@google.com>
parent d94a77b3
// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
// Copyright 2020 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.
......@@ -13,18 +13,513 @@
// limitations under the License.
#include "Context.hpp"
#include "Primitive.hpp"
#include "Pipeline/SpirvShader.hpp"
#include "System/Debug.hpp"
#include "System/Memory.hpp"
#include "Vulkan/VkBuffer.hpp"
#include "Vulkan/VkDevice.hpp"
#include "Vulkan/VkImageView.hpp"
#include "Vulkan/VkRenderPass.hpp"
#include "Vulkan/VkStringify.hpp"
namespace {
#include <string.h>
uint32_t ComputePrimitiveCount(VkPrimitiveTopology topology, uint32_t vertexCount)
{
switch(topology)
{
case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
return vertexCount;
case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
return vertexCount / 2;
case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
return std::max<uint32_t>(vertexCount, 1) - 1;
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
return vertexCount / 3;
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
return std::max<uint32_t>(vertexCount, 2) - 2;
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
return std::max<uint32_t>(vertexCount, 2) - 2;
default:
UNSUPPORTED("VkPrimitiveTopology %d", int(topology));
}
namespace sw {
return 0;
}
bool Context::isDrawPoint(bool polygonModeAware) const
template<typename T>
void ProcessPrimitiveRestart(T *indexBuffer,
VkPrimitiveTopology topology,
uint32_t count,
std::vector<std::pair<uint32_t, void *>> *indexBuffers)
{
static const T RestartIndex = static_cast<T>(-1);
T *indexBufferStart = indexBuffer;
uint32_t vertexCount = 0;
for(uint32_t i = 0; i < count; i++)
{
if(indexBuffer[i] == RestartIndex)
{
// Record previous segment
if(vertexCount > 0)
{
uint32_t primitiveCount = ComputePrimitiveCount(topology, vertexCount);
if(primitiveCount > 0)
{
indexBuffers->push_back({ primitiveCount, indexBufferStart });
}
}
vertexCount = 0;
}
else
{
if(vertexCount == 0)
{
indexBufferStart = indexBuffer + i;
}
vertexCount++;
}
}
// Record last segment
if(vertexCount > 0)
{
uint32_t primitiveCount = ComputePrimitiveCount(topology, vertexCount);
if(primitiveCount > 0)
{
indexBuffers->push_back({ primitiveCount, indexBufferStart });
}
}
}
} // namespace
namespace vk {
int IndexBuffer::bytesPerIndex() const
{
return indexType == VK_INDEX_TYPE_UINT16 ? 2 : 4;
}
void IndexBuffer::setIndexBufferBinding(const VertexInputBinding &indexBufferBinding, VkIndexType type)
{
binding = indexBufferBinding;
indexType = type;
}
void IndexBuffer::getIndexBuffers(VkPrimitiveTopology topology, uint32_t count, uint32_t first, bool indexed, bool hasPrimitiveRestartEnable, std::vector<std::pair<uint32_t, void *>> *indexBuffers) const
{
if(indexed)
{
void *indexBuffer = binding.buffer->getOffsetPointer(binding.offset + first * bytesPerIndex());
if(hasPrimitiveRestartEnable)
{
switch(indexType)
{
case VK_INDEX_TYPE_UINT16:
ProcessPrimitiveRestart(static_cast<uint16_t *>(indexBuffer), topology, count, indexBuffers);
break;
case VK_INDEX_TYPE_UINT32:
ProcessPrimitiveRestart(static_cast<uint32_t *>(indexBuffer), topology, count, indexBuffers);
break;
default:
UNSUPPORTED("VkIndexType %d", int(indexType));
}
}
else
{
indexBuffers->push_back({ ComputePrimitiveCount(topology, count), indexBuffer });
}
}
else
{
indexBuffers->push_back({ ComputePrimitiveCount(topology, count), nullptr });
}
}
bool Attachments::isColorClamped(int index) const
{
if(renderTarget[index] && renderTarget[index]->getFormat().isFloatFormat())
{
return false;
}
return true;
}
VkFormat Attachments::renderTargetInternalFormat(int index) const
{
ASSERT((index >= 0) && (index < sw::RENDERTARGETS));
if(renderTarget[index])
{
return renderTarget[index]->getFormat();
}
else
{
return VK_FORMAT_UNDEFINED;
}
}
Inputs::Inputs(const VkPipelineVertexInputStateCreateInfo *vertexInputState)
{
if(vertexInputState->flags != 0)
{
// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
UNSUPPORTED("vertexInputState->flags");
}
// Temporary in-binding-order representation of buffer strides, to be consumed below
// when considering attributes. TODO: unfuse buffers from attributes in backend, is old GL model.
uint32_t vertexStrides[MAX_VERTEX_INPUT_BINDINGS];
uint32_t instanceStrides[MAX_VERTEX_INPUT_BINDINGS];
for(uint32_t i = 0; i < vertexInputState->vertexBindingDescriptionCount; i++)
{
auto const &desc = vertexInputState->pVertexBindingDescriptions[i];
vertexStrides[desc.binding] = desc.inputRate == VK_VERTEX_INPUT_RATE_VERTEX ? desc.stride : 0;
instanceStrides[desc.binding] = desc.inputRate == VK_VERTEX_INPUT_RATE_INSTANCE ? desc.stride : 0;
}
for(uint32_t i = 0; i < vertexInputState->vertexAttributeDescriptionCount; i++)
{
auto const &desc = vertexInputState->pVertexAttributeDescriptions[i];
sw::Stream &input = stream[desc.location];
input.format = desc.format;
input.offset = desc.offset;
input.binding = desc.binding;
input.vertexStride = vertexStrides[desc.binding];
input.instanceStride = instanceStrides[desc.binding];
}
}
void Inputs::updateDescriptorSets(const DescriptorSet::Array &dso,
const DescriptorSet::Bindings &ds,
const DescriptorSet::DynamicOffsets &ddo)
{
descriptorSetObjects = dso;
descriptorSets = ds;
descriptorDynamicOffsets = ddo;
}
void Inputs::bindVertexInputs(int firstInstance)
{
for(uint32_t i = 0; i < MAX_VERTEX_INPUT_BINDINGS; i++)
{
auto &attrib = stream[i];
if(attrib.format != VK_FORMAT_UNDEFINED)
{
const auto &vertexInput = vertexInputBindings[attrib.binding];
VkDeviceSize offset = attrib.offset + vertexInput.offset +
attrib.instanceStride * firstInstance;
attrib.buffer = vertexInput.buffer ? vertexInput.buffer->getOffsetPointer(offset) : nullptr;
VkDeviceSize size = vertexInput.buffer ? vertexInput.buffer->getSize() : 0;
attrib.robustnessSize = (size > offset) ? size - offset : 0;
}
}
}
void Inputs::setVertexInputBinding(const VertexInputBinding bindings[])
{
for(uint32_t i = 0; i < MAX_VERTEX_INPUT_BINDINGS; ++i)
{
vertexInputBindings[i] = bindings[i];
}
}
// TODO(b/137740918): Optimize instancing to use a single draw call.
void Inputs::advanceInstanceAttributes()
{
for(uint32_t i = 0; i < vk::MAX_VERTEX_INPUT_BINDINGS; i++)
{
auto &attrib = stream[i];
if((attrib.format != VK_FORMAT_UNDEFINED) && attrib.instanceStride && (attrib.instanceStride < attrib.robustnessSize))
{
// Under the casts: attrib.buffer += attrib.instanceStride
attrib.buffer = (void const *)((uintptr_t)attrib.buffer + attrib.instanceStride);
attrib.robustnessSize -= attrib.instanceStride;
}
}
}
GraphicsState::GraphicsState(const Device *device, const VkGraphicsPipelineCreateInfo *pCreateInfo,
const PipelineLayout *layout, bool robustBufferAccess)
: pipelineLayout(layout)
, robustBufferAccess(robustBufferAccess)
{
if((pCreateInfo->flags &
~(VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT |
VK_PIPELINE_CREATE_DERIVATIVE_BIT |
VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT)) != 0)
{
UNSUPPORTED("pCreateInfo->flags %d", int(pCreateInfo->flags));
}
if(pCreateInfo->pDynamicState)
{
if(pCreateInfo->pDynamicState->flags != 0)
{
// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
UNSUPPORTED("pCreateInfo->pDynamicState->flags %d", int(pCreateInfo->pDynamicState->flags));
}
for(uint32_t i = 0; i < pCreateInfo->pDynamicState->dynamicStateCount; i++)
{
VkDynamicState dynamicState = pCreateInfo->pDynamicState->pDynamicStates[i];
switch(dynamicState)
{
case VK_DYNAMIC_STATE_VIEWPORT:
case VK_DYNAMIC_STATE_SCISSOR:
case VK_DYNAMIC_STATE_LINE_WIDTH:
case VK_DYNAMIC_STATE_DEPTH_BIAS:
case VK_DYNAMIC_STATE_BLEND_CONSTANTS:
case VK_DYNAMIC_STATE_DEPTH_BOUNDS:
case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK:
case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK:
case VK_DYNAMIC_STATE_STENCIL_REFERENCE:
ASSERT(dynamicState < (sizeof(dynamicStateFlags) * 8));
dynamicStateFlags |= (1 << dynamicState);
break;
default:
UNSUPPORTED("VkDynamicState %d", int(dynamicState));
}
}
}
const VkPipelineVertexInputStateCreateInfo *vertexInputState = pCreateInfo->pVertexInputState;
if(vertexInputState->flags != 0)
{
// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
UNSUPPORTED("vertexInputState->flags");
}
const VkPipelineInputAssemblyStateCreateInfo *inputAssemblyState = pCreateInfo->pInputAssemblyState;
if(inputAssemblyState->flags != 0)
{
// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
UNSUPPORTED("pCreateInfo->pInputAssemblyState->flags %d", int(pCreateInfo->pInputAssemblyState->flags));
}
primitiveRestartEnable = (inputAssemblyState->primitiveRestartEnable != VK_FALSE);
topology = inputAssemblyState->topology;
const VkPipelineRasterizationStateCreateInfo *rasterizationState = pCreateInfo->pRasterizationState;
if(rasterizationState->flags != 0)
{
// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
UNSUPPORTED("pCreateInfo->pRasterizationState->flags %d", int(pCreateInfo->pRasterizationState->flags));
}
if(rasterizationState->depthClampEnable != VK_FALSE)
{
UNSUPPORTED("VkPhysicalDeviceFeatures::depthClamp");
}
rasterizerDiscard = (rasterizationState->rasterizerDiscardEnable != VK_FALSE);
cullMode = rasterizationState->cullMode;
frontFace = rasterizationState->frontFace;
polygonMode = rasterizationState->polygonMode;
constantDepthBias = (rasterizationState->depthBiasEnable != VK_FALSE) ? rasterizationState->depthBiasConstantFactor : 0.0f;
slopeDepthBias = (rasterizationState->depthBiasEnable != VK_FALSE) ? rasterizationState->depthBiasSlopeFactor : 0.0f;
depthBiasClamp = (rasterizationState->depthBiasEnable != VK_FALSE) ? rasterizationState->depthBiasClamp : 0.0f;
depthRangeUnrestricted = device->hasExtension(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME);
// From the Vulkan spec for vkCmdSetDepthBias:
// The bias value O for a polygon is:
// O = dbclamp(...)
// where dbclamp(x) =
// * x depthBiasClamp = 0 or NaN
// * min(x, depthBiasClamp) depthBiasClamp > 0
// * max(x, depthBiasClamp) depthBiasClamp < 0
// So it should be safe to resolve NaNs to 0.0f.
if(std::isnan(depthBiasClamp))
{
depthBiasClamp = 0.0f;
}
lineWidth = rasterizationState->lineWidth;
const VkBaseInStructure *extensionCreateInfo = reinterpret_cast<const VkBaseInStructure *>(rasterizationState->pNext);
while(extensionCreateInfo)
{
// Casting to a long since some structures, such as
// VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT
// are not enumerated in the official Vulkan header
switch((long)(extensionCreateInfo->sType))
{
case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT:
{
const VkPipelineRasterizationLineStateCreateInfoEXT *lineStateCreateInfo = reinterpret_cast<const VkPipelineRasterizationLineStateCreateInfoEXT *>(extensionCreateInfo);
lineRasterizationMode = lineStateCreateInfo->lineRasterizationMode;
}
break;
case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT:
{
const VkPipelineRasterizationProvokingVertexStateCreateInfoEXT *provokingVertexModeCreateInfo =
reinterpret_cast<const VkPipelineRasterizationProvokingVertexStateCreateInfoEXT *>(extensionCreateInfo);
provokingVertexMode = provokingVertexModeCreateInfo->provokingVertexMode;
}
break;
default:
WARN("pCreateInfo->pRasterizationState->pNext sType = %s", vk::Stringify(extensionCreateInfo->sType).c_str());
break;
}
extensionCreateInfo = extensionCreateInfo->pNext;
}
// The sample count affects the batch size, so it needs initialization even if rasterization is disabled.
// TODO(b/147812380): Eliminate the dependency between multisampling and batch size.
sampleCount = 1;
// Only access rasterization state if rasterization is not disabled.
if(rasterizationState->rasterizerDiscardEnable == VK_FALSE)
{
const VkPipelineViewportStateCreateInfo *viewportState = pCreateInfo->pViewportState;
const VkPipelineMultisampleStateCreateInfo *multisampleState = pCreateInfo->pMultisampleState;
const VkPipelineDepthStencilStateCreateInfo *depthStencilState = pCreateInfo->pDepthStencilState;
const VkPipelineColorBlendStateCreateInfo *colorBlendState = pCreateInfo->pColorBlendState;
if(viewportState->flags != 0)
{
// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
UNSUPPORTED("pCreateInfo->pViewportState->flags %d", int(pCreateInfo->pViewportState->flags));
}
if((viewportState->viewportCount != 1) ||
(viewportState->scissorCount != 1))
{
UNSUPPORTED("VkPhysicalDeviceFeatures::multiViewport");
}
if(!hasDynamicState(VK_DYNAMIC_STATE_SCISSOR))
{
scissor = viewportState->pScissors[0];
}
if(!hasDynamicState(VK_DYNAMIC_STATE_VIEWPORT))
{
viewport = viewportState->pViewports[0];
}
if(multisampleState->flags != 0)
{
// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
UNSUPPORTED("pCreateInfo->pMultisampleState->flags %d", int(pCreateInfo->pMultisampleState->flags));
}
if(multisampleState->sampleShadingEnable != VK_FALSE)
{
UNSUPPORTED("VkPhysicalDeviceFeatures::sampleRateShading");
}
if(multisampleState->alphaToOneEnable != VK_FALSE)
{
UNSUPPORTED("VkPhysicalDeviceFeatures::alphaToOne");
}
switch(multisampleState->rasterizationSamples)
{
case VK_SAMPLE_COUNT_1_BIT:
sampleCount = 1;
break;
case VK_SAMPLE_COUNT_4_BIT:
sampleCount = 4;
break;
default:
UNSUPPORTED("Unsupported sample count");
}
VkSampleMask sampleMask;
if(multisampleState->pSampleMask)
{
sampleMask = multisampleState->pSampleMask[0];
}
else // "If pSampleMask is NULL, it is treated as if the mask has all bits set to 1."
{
sampleMask = ~0;
}
alphaToCoverage = (multisampleState->alphaToCoverageEnable != VK_FALSE);
multiSampleMask = sampleMask & ((unsigned)0xFFFFFFFF >> (32 - sampleCount));
const vk::RenderPass *renderPass = vk::Cast(pCreateInfo->renderPass);
const VkSubpassDescription &subpass = renderPass->getSubpass(pCreateInfo->subpass);
// Ignore pDepthStencilState when "the subpass of the render pass the pipeline is created against does not use a depth/stencil attachment"
if(subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)
{
if(depthStencilState->flags != 0)
{
// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
UNSUPPORTED("pCreateInfo->pDepthStencilState->flags %d", int(pCreateInfo->pDepthStencilState->flags));
}
if(depthStencilState->depthBoundsTestEnable != VK_FALSE)
{
UNSUPPORTED("VkPhysicalDeviceFeatures::depthBounds");
}
depthBoundsTestEnable = (depthStencilState->depthBoundsTestEnable != VK_FALSE);
depthBufferEnable = (depthStencilState->depthTestEnable != VK_FALSE);
depthWriteEnable = (depthStencilState->depthWriteEnable != VK_FALSE);
depthCompareMode = depthStencilState->depthCompareOp;
stencilEnable = (depthStencilState->stencilTestEnable != VK_FALSE);
if(stencilEnable)
{
frontStencil = depthStencilState->front;
backStencil = depthStencilState->back;
}
}
bool colorAttachmentUsed = false;
for(uint32_t i = 0; i < subpass.colorAttachmentCount; i++)
{
if(subpass.pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED)
{
colorAttachmentUsed = true;
break;
}
}
// Ignore pColorBlendState when "the subpass of the render pass the pipeline is created against does not use any color attachments"
if(colorAttachmentUsed)
{
if(colorBlendState->flags != 0)
{
// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
UNSUPPORTED("pCreateInfo->pColorBlendState->flags %d", int(pCreateInfo->pColorBlendState->flags));
}
if(colorBlendState->logicOpEnable != VK_FALSE)
{
UNSUPPORTED("VkPhysicalDeviceFeatures::logicOp");
}
if(!hasDynamicState(VK_DYNAMIC_STATE_BLEND_CONSTANTS))
{
blendConstants.x = colorBlendState->blendConstants[0];
blendConstants.y = colorBlendState->blendConstants[1];
blendConstants.z = colorBlendState->blendConstants[2];
blendConstants.w = colorBlendState->blendConstants[3];
}
ASSERT(colorBlendState->attachmentCount <= sw::RENDERTARGETS);
for(auto i = 0u; i < colorBlendState->attachmentCount; i++)
{
const VkPipelineColorBlendAttachmentState &attachment = colorBlendState->pAttachments[i];
colorWriteMask[i] = attachment.colorWriteMask;
blendState[i] = { (attachment.blendEnable != VK_FALSE),
attachment.srcColorBlendFactor, attachment.dstColorBlendFactor, attachment.colorBlendOp,
attachment.srcAlphaBlendFactor, attachment.dstAlphaBlendFactor, attachment.alphaBlendOp };
}
}
}
}
bool GraphicsState::isDrawPoint(bool polygonModeAware) const
{
switch(topology)
{
......@@ -43,7 +538,7 @@ bool Context::isDrawPoint(bool polygonModeAware) const
return false;
}
bool Context::isDrawLine(bool polygonModeAware) const
bool GraphicsState::isDrawLine(bool polygonModeAware) const
{
switch(topology)
{
......@@ -62,7 +557,7 @@ bool Context::isDrawLine(bool polygonModeAware) const
return false;
}
bool Context::isDrawTriangle(bool polygonModeAware) const
bool GraphicsState::isDrawTriangle(bool polygonModeAware) const
{
switch(topology)
{
......@@ -80,78 +575,121 @@ bool Context::isDrawTriangle(bool polygonModeAware) const
return false;
}
bool Context::depthWriteActive() const
bool GraphicsState::depthWriteActive(const Attachments &attachments) const
{
if(!depthBufferActive()) return false;
if(!depthBufferActive(attachments)) return false;
return depthWriteEnable;
}
bool Context::depthBufferActive() const
bool GraphicsState::depthBufferActive(const Attachments &attachments) const
{
return depthBuffer && depthBufferEnable;
return attachments.depthBuffer && depthBufferEnable;
}
bool Context::stencilActive() const
bool GraphicsState::stencilActive(const Attachments &attachments) const
{
return stencilBuffer && stencilEnable;
return attachments.stencilBuffer && stencilEnable;
}
void Context::setBlendState(int index, BlendState state)
const GraphicsState GraphicsState::combineStates(const DynamicState &dynamicState) const
{
ASSERT((index >= 0) && (index < RENDERTARGETS));
GraphicsState combinedState = *this;
// Apply either pipeline state or dynamic state
if(hasDynamicState(VK_DYNAMIC_STATE_SCISSOR))
{
combinedState.scissor = dynamicState.scissor;
}
if(hasDynamicState(VK_DYNAMIC_STATE_VIEWPORT))
{
combinedState.viewport = dynamicState.viewport;
}
if(hasDynamicState(VK_DYNAMIC_STATE_BLEND_CONSTANTS))
{
combinedState.blendConstants = dynamicState.blendConstants;
}
if(hasDynamicState(VK_DYNAMIC_STATE_DEPTH_BIAS))
{
combinedState.constantDepthBias = dynamicState.depthBiasConstantFactor;
combinedState.slopeDepthBias = dynamicState.depthBiasSlopeFactor;
combinedState.depthBiasClamp = dynamicState.depthBiasClamp;
}
if(hasDynamicState(VK_DYNAMIC_STATE_DEPTH_BOUNDS) && depthBoundsTestEnable)
{
// Unless the VK_EXT_depth_range_unrestricted extension is enabled,
// minDepthBounds and maxDepthBounds must be between 0.0 and 1.0, inclusive
ASSERT(dynamicState.minDepthBounds >= 0.0f && dynamicState.minDepthBounds <= 1.0f);
ASSERT(dynamicState.maxDepthBounds >= 0.0f && dynamicState.maxDepthBounds <= 1.0f);
UNSUPPORTED("VkPhysicalDeviceFeatures::depthBounds");
}
blendState[index] = state;
if(hasDynamicState(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK) && stencilEnable)
{
combinedState.frontStencil.compareMask = dynamicState.compareMask[0];
combinedState.backStencil.compareMask = dynamicState.compareMask[1];
}
if(hasDynamicState(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK) && stencilEnable)
{
combinedState.frontStencil.writeMask = dynamicState.writeMask[0];
combinedState.backStencil.writeMask = dynamicState.writeMask[1];
}
if(hasDynamicState(VK_DYNAMIC_STATE_STENCIL_REFERENCE) && stencilEnable)
{
combinedState.frontStencil.reference = dynamicState.reference[0];
combinedState.backStencil.reference = dynamicState.reference[1];
}
return combinedState;
}
BlendState Context::getBlendState(int index) const
BlendState GraphicsState::getBlendState(int index, const Attachments &attachments, bool fragmentContainsKill) const
{
ASSERT((index >= 0) && (index < RENDERTARGETS));
ASSERT((index >= 0) && (index < sw::RENDERTARGETS));
BlendState activeBlendState;
activeBlendState.alphaBlendEnable = alphaBlendActive(index);
activeBlendState.alphaBlendEnable = alphaBlendActive(index, attachments, fragmentContainsKill);
activeBlendState.sourceBlendFactor = sourceBlendFactor(index);
activeBlendState.destBlendFactor = destBlendFactor(index);
activeBlendState.blendOperation = blendOperation(index);
activeBlendState.blendOperation = blendOperation(index, attachments);
activeBlendState.sourceBlendFactorAlpha = sourceBlendFactorAlpha(index);
activeBlendState.destBlendFactorAlpha = destBlendFactorAlpha(index);
activeBlendState.blendOperationAlpha = blendOperationAlpha(index);
activeBlendState.blendOperationAlpha = blendOperationAlpha(index, attachments);
return activeBlendState;
}
bool Context::isColorClamped(int index) const
{
if(renderTarget[index] && renderTarget[index]->getFormat().isFloatFormat())
{
return false;
}
return true;
}
bool Context::alphaBlendActive(int index) const
bool GraphicsState::alphaBlendActive(int index, const Attachments &attachments, bool fragmentContainsKill) const
{
ASSERT((index >= 0) && (index < RENDERTARGETS));
ASSERT((index >= 0) && (index < sw::RENDERTARGETS));
if(!blendState[index].alphaBlendEnable)
{
return false;
}
if(!colorUsed())
if(!(colorWriteActive(attachments) || fragmentContainsKill))
{
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);
bool colorBlend = !(blendOperation(index, attachments) == VK_BLEND_OP_SRC_EXT &&
sourceBlendFactor(index) == VK_BLEND_FACTOR_ONE);
bool alphaBlend = !(blendOperationAlpha(index, attachments) == VK_BLEND_OP_SRC_EXT &&
sourceBlendFactorAlpha(index) == VK_BLEND_FACTOR_ONE);
return colorBlend || alphaBlend;
}
VkBlendFactor Context::sourceBlendFactor(int index) const
VkBlendFactor GraphicsState::sourceBlendFactor(int index) const
{
ASSERT((index >= 0) && (index < RENDERTARGETS));
ASSERT((index >= 0) && (index < sw::RENDERTARGETS));
if(!blendState[index].alphaBlendEnable) return VK_BLEND_FACTOR_ONE;
......@@ -172,9 +710,9 @@ VkBlendFactor Context::sourceBlendFactor(int index) const
return blendState[index].sourceBlendFactor;
}
VkBlendFactor Context::destBlendFactor(int index) const
VkBlendFactor GraphicsState::destBlendFactor(int index) const
{
ASSERT((index >= 0) && (index < RENDERTARGETS));
ASSERT((index >= 0) && (index < sw::RENDERTARGETS));
if(!blendState[index].alphaBlendEnable) return VK_BLEND_FACTOR_ONE;
......@@ -195,9 +733,9 @@ VkBlendFactor Context::destBlendFactor(int index) const
return blendState[index].destBlendFactor;
}
VkBlendOp Context::blendOperation(int index) const
VkBlendOp GraphicsState::blendOperation(int index, const Attachments &attachments) const
{
ASSERT((index >= 0) && (index < RENDERTARGETS));
ASSERT((index >= 0) && (index < sw::RENDERTARGETS));
if(!blendState[index].alphaBlendEnable) return VK_BLEND_OP_SRC_EXT;
......@@ -238,7 +776,7 @@ VkBlendOp Context::blendOperation(int index) const
}
}
case VK_BLEND_OP_SUBTRACT:
if(sourceBlendFactor(index) == VK_BLEND_FACTOR_ZERO && isColorClamped(index))
if(sourceBlendFactor(index) == VK_BLEND_FACTOR_ZERO && attachments.isColorClamped(index))
{
return VK_BLEND_OP_ZERO_EXT; // Negative, clamped to zero
}
......@@ -278,7 +816,7 @@ VkBlendOp Context::blendOperation(int index) const
}
else if(sourceBlendFactor(index) == VK_BLEND_FACTOR_ONE)
{
if(destBlendFactor(index) == VK_BLEND_FACTOR_ZERO && isColorClamped(index))
if(destBlendFactor(index) == VK_BLEND_FACTOR_ZERO && attachments.isColorClamped(index))
{
return VK_BLEND_OP_ZERO_EXT; // Negative, clamped to zero
}
......@@ -289,7 +827,7 @@ VkBlendOp Context::blendOperation(int index) const
}
else
{
if(destBlendFactor(index) == VK_BLEND_FACTOR_ZERO && isColorClamped(index))
if(destBlendFactor(index) == VK_BLEND_FACTOR_ZERO && attachments.isColorClamped(index))
{
return VK_BLEND_OP_ZERO_EXT; // Negative, clamped to zero
}
......@@ -309,9 +847,9 @@ VkBlendOp Context::blendOperation(int index) const
return blendState[index].blendOperation;
}
VkBlendFactor Context::sourceBlendFactorAlpha(int index) const
VkBlendFactor GraphicsState::sourceBlendFactorAlpha(int index) const
{
ASSERT((index >= 0) && (index < RENDERTARGETS));
ASSERT((index >= 0) && (index < sw::RENDERTARGETS));
switch(blendState[index].blendOperationAlpha)
{
......@@ -330,9 +868,9 @@ VkBlendFactor Context::sourceBlendFactorAlpha(int index) const
return blendState[index].sourceBlendFactorAlpha;
}
VkBlendFactor Context::destBlendFactorAlpha(int index) const
VkBlendFactor GraphicsState::destBlendFactorAlpha(int index) const
{
ASSERT((index >= 0) && (index < RENDERTARGETS));
ASSERT((index >= 0) && (index < sw::RENDERTARGETS));
switch(blendState[index].blendOperationAlpha)
{
......@@ -351,9 +889,9 @@ VkBlendFactor Context::destBlendFactorAlpha(int index) const
return blendState[index].destBlendFactorAlpha;
}
VkBlendOp Context::blendOperationAlpha(int index) const
VkBlendOp GraphicsState::blendOperationAlpha(int index, const Attachments &attachments) const
{
ASSERT((index >= 0) && (index < RENDERTARGETS));
ASSERT((index >= 0) && (index < sw::RENDERTARGETS));
switch(blendState[index].blendOperationAlpha)
{
......@@ -392,7 +930,7 @@ VkBlendOp Context::blendOperationAlpha(int index) const
}
}
case VK_BLEND_OP_SUBTRACT:
if(sourceBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO && isColorClamped(index))
if(sourceBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO && attachments.isColorClamped(index))
{
return VK_BLEND_OP_ZERO_EXT; // Negative, clamped to zero
}
......@@ -432,7 +970,7 @@ VkBlendOp Context::blendOperationAlpha(int index) const
}
else if(sourceBlendFactorAlpha(index) == VK_BLEND_FACTOR_ONE)
{
if(destBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO && isColorClamped(index))
if(destBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO && attachments.isColorClamped(index))
{
return VK_BLEND_OP_ZERO_EXT; // Negative, clamped to zero
}
......@@ -443,7 +981,7 @@ VkBlendOp Context::blendOperationAlpha(int index) const
}
else
{
if(destBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO && isColorClamped(index))
if(destBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO && attachments.isColorClamped(index))
{
return VK_BLEND_OP_ZERO_EXT; // Negative, clamped to zero
}
......@@ -463,25 +1001,11 @@ VkBlendOp Context::blendOperationAlpha(int index) const
return blendState[index].blendOperationAlpha;
}
VkFormat Context::renderTargetInternalFormat(int index) const
bool GraphicsState::colorWriteActive(const Attachments &attachments) const
{
ASSERT((index >= 0) && (index < RENDERTARGETS));
if(renderTarget[index])
for(int i = 0; i < sw::RENDERTARGETS; i++)
{
return renderTarget[index]->getFormat();
}
else
{
return VK_FORMAT_UNDEFINED;
}
}
bool Context::colorWriteActive() const
{
for(int i = 0; i < RENDERTARGETS; i++)
{
if(colorWriteActive(i))
if(colorWriteActive(i, attachments))
{
return true;
}
......@@ -490,17 +1014,17 @@ bool Context::colorWriteActive() const
return false;
}
int Context::colorWriteActive(int index) const
int GraphicsState::colorWriteActive(int index, const Attachments &attachments) const
{
ASSERT((index >= 0) && (index < RENDERTARGETS));
ASSERT((index >= 0) && (index < sw::RENDERTARGETS));
if(!renderTarget[index] || renderTarget[index]->getFormat() == VK_FORMAT_UNDEFINED)
if(!attachments.renderTarget[index] || attachments.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))
if(blendOperation(index, attachments) == VK_BLEND_OP_DST_EXT && destBlendFactor(index) == VK_BLEND_FACTOR_ONE &&
(blendOperationAlpha(index, attachments) == VK_BLEND_OP_DST_EXT && destBlendFactorAlpha(index) == VK_BLEND_FACTOR_ONE))
{
return 0;
}
......@@ -508,9 +1032,4 @@ int Context::colorWriteActive(int index) const
return colorWriteMask[index];
}
bool Context::colorUsed() const
{
return colorWriteActive() || (pixelShader && pixelShader->getModes().ContainsKill);
}
} // namespace sw
} // namespace vk
\ No newline at end of file
// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
// Copyright 2020 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.
......@@ -12,33 +12,78 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef sw_Context_hpp
#define sw_Context_hpp
#ifndef vk_Context_hpp
#define vk_Context_hpp
#include "Config.hpp"
#include "Memset.hpp"
#include "Stream.hpp"
#include "System/Types.hpp"
#include "Vulkan/VkConfig.hpp"
#include "Vulkan/VkDescriptorSet.hpp"
#include <vector>
namespace vk {
class Buffer;
class Device;
class ImageView;
class PipelineLayout;
} // namespace vk
struct VertexInputBinding
{
Buffer *buffer;
VkDeviceSize offset;
};
namespace sw {
struct IndexBuffer
{
inline VkIndexType getIndexType() const { return indexType; }
void setIndexBufferBinding(const VertexInputBinding &indexBufferBinding, VkIndexType type);
void getIndexBuffers(VkPrimitiveTopology topology, uint32_t count, uint32_t first, bool indexed, bool hasPrimitiveRestartEnable, std::vector<std::pair<uint32_t, void *>> *indexBuffers) const;
private:
int bytesPerIndex() const;
class SpirvShader;
VertexInputBinding binding;
VkIndexType indexType;
};
struct PushConstantStorage
struct Attachments
{
unsigned char data[vk::MAX_PUSH_CONSTANT_SIZE];
ImageView *renderTarget[sw::RENDERTARGETS] = {};
ImageView *depthBuffer = nullptr;
ImageView *stencilBuffer = nullptr;
bool isColorClamped(int index) const;
VkFormat renderTargetInternalFormat(int index) const;
};
struct Inputs
{
Inputs(const VkPipelineVertexInputStateCreateInfo *vertexInputState);
void updateDescriptorSets(const DescriptorSet::Array &dso,
const DescriptorSet::Bindings &ds,
const DescriptorSet::DynamicOffsets &ddo);
inline const DescriptorSet::Array &getDescriptorSetObjects() const { return descriptorSetObjects; }
inline const DescriptorSet::Bindings &getDescriptorSets() const { return descriptorSets; }
inline const DescriptorSet::DynamicOffsets &getDescriptorDynamicOffsets() const { return descriptorDynamicOffsets; }
inline const sw::Stream &getStream(uint32_t i) const { return stream[i]; }
void bindVertexInputs(int firstInstance);
void setVertexInputBinding(const VertexInputBinding vertexInputBindings[]);
void advanceInstanceAttributes();
private:
VertexInputBinding vertexInputBindings[MAX_VERTEX_INPUT_BINDINGS] = {};
DescriptorSet::Array descriptorSetObjects = {};
DescriptorSet::Bindings descriptorSets = {};
DescriptorSet::DynamicOffsets descriptorDynamicOffsets = {};
sw::Stream stream[sw::MAX_INTERFACE_COMPONENTS / 4];
};
struct BlendState : Memset<BlendState>
struct BlendState : sw::Memset<BlendState>
{
BlendState()
: Memset(this, 0)
......@@ -70,24 +115,93 @@ struct BlendState : Memset<BlendState>
VkBlendOp blendOperationAlpha;
};
class Context
struct DynamicState
{
VkViewport viewport;
VkRect2D scissor;
sw::float4 blendConstants;
float depthBiasConstantFactor = 0.0f;
float depthBiasClamp = 0.0f;
float depthBiasSlopeFactor = 0.0f;
float minDepthBounds = 0.0f;
float maxDepthBounds = 0.0f;
uint32_t compareMask[2] = { 0 };
uint32_t writeMask[2] = { 0 };
uint32_t reference[2] = { 0 };
};
struct GraphicsState
{
public:
Context() = default;
GraphicsState(const Device *device, const VkGraphicsPipelineCreateInfo *pCreateInfo, const PipelineLayout *layout, bool robustBufferAccess);
const GraphicsState combineStates(const DynamicState &dynamicState) const;
inline const PipelineLayout *getPipelineLayout() const { return pipelineLayout; }
inline bool getRobustBufferAccess() const { return robustBufferAccess; }
inline VkPrimitiveTopology getTopology() const { return topology; }
inline VkProvokingVertexModeEXT getProvokingVertexMode() const { return provokingVertexMode; }
inline VkStencilOpState getFrontStencil() const { return frontStencil; }
inline VkStencilOpState getBackStencil() const { return backStencil; }
// Pixel processor states
inline VkCullModeFlags getCullMode() const { return cullMode; }
inline VkFrontFace getFrontFace() const { return frontFace; }
inline VkPolygonMode getPolygonMode() const { return polygonMode; }
inline VkLineRasterizationModeEXT getLineRasterizationMode() const { return lineRasterizationMode; }
inline float getConstantDepthBias() const { return constantDepthBias; }
inline float getSlopeDepthBias() const { return slopeDepthBias; }
inline float getDepthBiasClamp() const { return depthBiasClamp; }
inline bool hasDepthRangeUnrestricted() const { return depthRangeUnrestricted; }
// Pixel processor states
inline bool hasRasterizerDiscard() const { return rasterizerDiscard; }
inline VkCompareOp getDepthCompareMode() const { return depthCompareMode; }
inline float getLineWidth() const { return lineWidth; }
inline unsigned int getMultiSampleMask() const { return multiSampleMask; }
inline int getSampleCount() const { return sampleCount; }
inline bool hasAlphaToCoverage() const { return alphaToCoverage; }
inline bool hasPrimitiveRestartEnable() const { return primitiveRestartEnable; }
inline const VkRect2D &getScissor() const { return scissor; }
inline const VkViewport &getViewport() const { return viewport; }
inline const sw::float4 &getBlendConstants() const { return blendConstants; }
bool isDrawPoint(bool polygonModeAware) const;
bool isDrawLine(bool polygonModeAware) const;
bool isDrawTriangle(bool polygonModeAware) const;
bool depthWriteActive() const;
bool depthBufferActive() const;
bool stencilActive() const;
BlendState getBlendState(int index, const Attachments &attachments, bool fragmentContainsKill) const;
void setBlendState(int index, BlendState state);
BlendState getBlendState(int index) const;
bool isColorClamped(int index) const;
int colorWriteActive(int index, const Attachments &attachments) const;
bool depthWriteActive(const Attachments &attachments) const;
bool depthBufferActive(const Attachments &attachments) const;
bool stencilActive(const Attachments &attachments) const;
private:
inline bool hasDynamicState(VkDynamicState dynamicState) const { return (dynamicStateFlags & (1 << dynamicState)) != 0; }
VkBlendFactor sourceBlendFactor(int index) const;
VkBlendFactor destBlendFactor(int index) const;
VkBlendOp blendOperation(int index, const Attachments &attachments) const;
VkBlendFactor sourceBlendFactorAlpha(int index) const;
VkBlendFactor destBlendFactorAlpha(int index) const;
VkBlendOp blendOperationAlpha(int index, const Attachments &attachments) const;
bool alphaBlendActive(int index, const Attachments &attachments, bool fragmentContainsKill) const;
bool colorWriteActive(const Attachments &attachments) const;
const PipelineLayout *pipelineLayout;
const bool robustBufferAccess = true;
uint32_t dynamicStateFlags = 0;
VkPrimitiveTopology topology;
VkProvokingVertexModeEXT provokingVertexMode;
bool stencilEnable;
......@@ -105,27 +219,6 @@ public:
float depthBiasClamp;
bool depthRangeUnrestricted;
VkFormat renderTargetInternalFormat(int index) const;
int colorWriteActive(int index) const;
vk::DescriptorSet::Array descriptorSetObjects = {};
vk::DescriptorSet::Bindings descriptorSets = {};
vk::DescriptorSet::DynamicOffsets descriptorDynamicOffsets = {};
Stream input[MAX_INTERFACE_COMPONENTS / 4];
bool robustBufferAccess;
vk::ImageView *renderTarget[RENDERTARGETS];
vk::ImageView *depthBuffer;
vk::ImageView *stencilBuffer;
vk::PipelineLayout const *pipelineLayout;
// Shaders
const SpirvShader *pixelShader;
const SpirvShader *vertexShader;
bool occlusionEnabled;
// Pixel processor states
bool rasterizerDiscard;
bool depthBoundsTestEnable;
......@@ -135,28 +228,19 @@ public:
float lineWidth;
int colorWriteMask[RENDERTARGETS]; // RGBA
unsigned int sampleMask;
int colorWriteMask[sw::RENDERTARGETS]; // RGBA
unsigned int multiSampleMask;
int sampleCount;
bool alphaToCoverage;
private:
bool colorWriteActive() const;
bool colorUsed() const;
bool alphaBlendActive(int index) const;
VkBlendFactor sourceBlendFactor(int index) const;
VkBlendFactor destBlendFactor(int index) const;
VkBlendOp blendOperation(int index) const;
bool primitiveRestartEnable = false;
VkRect2D scissor;
VkViewport viewport;
sw::float4 blendConstants;
VkBlendFactor sourceBlendFactorAlpha(int index) const;
VkBlendFactor destBlendFactorAlpha(int index) const;
VkBlendOp blendOperationAlpha(int index) const;
BlendState blendState[RENDERTARGETS];
BlendState blendState[sw::RENDERTARGETS];
};
} // namespace sw
} // namespace vk
#endif // sw_Context_hpp
#endif // vk_Context_hpp
......@@ -82,17 +82,17 @@ void PixelProcessor::setRoutineCacheSize(int cacheSize)
routineCache = std::make_unique<RoutineCacheType>(clamp(cacheSize, 1, 65536));
}
const PixelProcessor::State PixelProcessor::update(const Context *context) const
const PixelProcessor::State PixelProcessor::update(const vk::GraphicsState &pipelineState, const sw::SpirvShader *fragmentShader, const sw::SpirvShader *vertexShader, const vk::Attachments &attachments, bool occlusionEnabled) const
{
State state;
state.numClipDistances = context->vertexShader->getNumOutputClipDistances();
state.numCullDistances = context->vertexShader->getNumOutputCullDistances();
state.numClipDistances = vertexShader->getNumOutputClipDistances();
state.numCullDistances = vertexShader->getNumOutputCullDistances();
if(context->pixelShader)
if(fragmentShader)
{
state.shaderID = context->pixelShader->getSerialID();
state.pipelineLayoutIdentifier = context->pipelineLayout->identifier;
state.shaderID = fragmentShader->getSerialID();
state.pipelineLayoutIdentifier = pipelineState.getPipelineLayout()->identifier;
}
else
{
......@@ -100,49 +100,50 @@ const PixelProcessor::State PixelProcessor::update(const Context *context) const
state.pipelineLayoutIdentifier = 0;
}
state.alphaToCoverage = context->alphaToCoverage;
state.depthWriteEnable = context->depthWriteActive();
state.alphaToCoverage = pipelineState.hasAlphaToCoverage();
state.depthWriteEnable = pipelineState.depthWriteActive(attachments);
if(context->stencilActive())
if(pipelineState.stencilActive(attachments))
{
state.stencilActive = true;
state.frontStencil = context->frontStencil;
state.backStencil = context->backStencil;
state.frontStencil = pipelineState.getFrontStencil();
state.backStencil = pipelineState.getBackStencil();
}
if(context->depthBufferActive())
if(pipelineState.depthBufferActive(attachments))
{
state.depthTestActive = true;
state.depthCompareMode = context->depthCompareMode;
state.depthFormat = context->depthBuffer->getFormat();
state.depthCompareMode = pipelineState.getDepthCompareMode();
state.depthFormat = attachments.depthBuffer->getFormat();
state.depthBias = (context->constantDepthBias != 0.0f) || (context->slopeDepthBias != 0.0f);
state.depthBias = (pipelineState.getConstantDepthBias() != 0.0f) || (pipelineState.getSlopeDepthBias() != 0.0f);
// "For fixed-point depth buffers, fragment depth values are always limited to the range [0,1] by clamping after depth bias addition is performed.
// Unless the VK_EXT_depth_range_unrestricted extension is enabled, fragment depth values are clamped even when the depth buffer uses a floating-point representation."
state.depthClamp = !state.depthFormat.isFloatFormat() || !context->depthRangeUnrestricted;
state.depthClamp = !state.depthFormat.isFloatFormat() || !pipelineState.hasDepthRangeUnrestricted();
}
state.occlusionEnabled = context->occlusionEnabled;
state.occlusionEnabled = occlusionEnabled;
bool fragmentContainsKill = (fragmentShader && fragmentShader->getModes().ContainsKill);
for(int i = 0; i < RENDERTARGETS; i++)
{
state.colorWriteMask |= context->colorWriteActive(i) << (4 * i);
state.targetFormat[i] = context->renderTargetInternalFormat(i);
state.blendState[i] = context->getBlendState(i);
state.colorWriteMask |= pipelineState.colorWriteActive(i, attachments) << (4 * i);
state.targetFormat[i] = attachments.renderTargetInternalFormat(i);
state.blendState[i] = pipelineState.getBlendState(i, attachments, fragmentContainsKill);
}
state.multiSampleCount = static_cast<unsigned int>(context->sampleCount);
state.multiSampleMask = context->multiSampleMask;
state.multiSampleCount = static_cast<unsigned int>(pipelineState.getSampleCount());
state.multiSampleMask = pipelineState.getMultiSampleMask();
state.enableMultiSampling = (state.multiSampleCount > 1) &&
!(context->isDrawLine(true) && (context->lineRasterizationMode == VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT));
!(pipelineState.isDrawLine(true) && (pipelineState.getLineRasterizationMode() == VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT));
if(state.enableMultiSampling && context->pixelShader)
if(state.enableMultiSampling && fragmentShader)
{
state.centroid = context->pixelShader->getModes().NeedsCentroid;
state.centroid = fragmentShader->getModes().NeedsCentroid;
}
state.frontFace = context->frontFace;
state.frontFace = pipelineState.getFrontFace();
state.hash = state.computeHash();
......@@ -150,8 +151,8 @@ const PixelProcessor::State PixelProcessor::update(const Context *context) const
}
PixelProcessor::RoutineType PixelProcessor::routine(const State &state,
vk::PipelineLayout const *pipelineLayout,
SpirvShader const *pixelShader,
const vk::PipelineLayout *pipelineLayout,
const SpirvShader *pixelShader,
const vk::DescriptorSet::Bindings &descriptorSets)
{
auto routine = routineCache->lookup(state);
......
......@@ -24,11 +24,9 @@
namespace sw {
class PixelShader;
class Rasterizer;
struct Texture;
struct DrawData;
struct Primitive;
class SpirvShader;
using RasterizerFunction = FunctionT<void(const Primitive *primitive, int count, int cluster, int clusterCount, DrawData *draw)>;
......@@ -82,7 +80,7 @@ public:
bool occlusionEnabled;
bool perspective;
BlendState blendState[RENDERTARGETS];
vk::BlendState blendState[RENDERTARGETS];
unsigned int colorWriteMask;
vk::Format targetFormat[RENDERTARGETS];
......@@ -153,9 +151,9 @@ public:
void setBlendConstant(const float4 &blendConstant);
const State update(const Context *context) const;
RoutineType routine(const State &state, vk::PipelineLayout const *pipelineLayout,
SpirvShader const *pixelShader, const vk::DescriptorSet::Bindings &descriptorSets);
const State update(const vk::GraphicsState &pipelineState, const sw::SpirvShader *fragmentShader, const sw::SpirvShader *vertexShader, const vk::Attachments &attachments, bool occlusionEnabled) const;
RoutineType routine(const State &state, const vk::PipelineLayout *pipelineLayout,
const SpirvShader *pixelShader, const vk::DescriptorSet::Bindings &descriptorSets);
void setRoutineCacheSize(int routineCacheSize);
// Other semi-constants
......
......@@ -15,7 +15,6 @@
#ifndef sw_Rasterizer_hpp
#define sw_Rasterizer_hpp
#include "Context.hpp"
#include "PixelProcessor.hpp"
#include "Device/Config.hpp"
......
......@@ -180,9 +180,9 @@ void Renderer::operator delete(void *mem)
vk::deallocate(mem, vk::DEVICE_MEMORY);
}
void Renderer::draw(const sw::Context *context, VkIndexType indexType, unsigned int count, int baseVertex,
void Renderer::draw(const vk::GraphicsPipeline *pipeline, const vk::DynamicState &dynamicState, unsigned int count, int baseVertex,
CountedEvent *events, int instanceID, int viewID, void *indexBuffer, const VkExtent3D &framebufferExtent,
PushConstantStorage const &pushConstants, bool update)
vk::Pipeline::PushConstantStorage const &pushConstants, bool update)
{
if(count == 0) { return; }
......@@ -196,28 +196,38 @@ void Renderer::draw(const sw::Context *context, VkIndexType indexType, unsigned
}
draw->id = id;
const vk::GraphicsState &pipelineState = pipeline->getState(dynamicState);
pixelProcessor.setBlendConstant(pipelineState.getBlendConstants());
const vk::Inputs &inputs = pipeline->getInputs();
if(update)
{
MARL_SCOPED_EVENT("update");
vertexState = vertexProcessor.update(context);
setupState = setupProcessor.update(context);
pixelState = pixelProcessor.update(context);
vertexRoutine = vertexProcessor.routine(vertexState, context->pipelineLayout, context->vertexShader, context->descriptorSets);
const sw::SpirvShader *fragmentShader = pipeline->getShader(VK_SHADER_STAGE_FRAGMENT_BIT).get();
const sw::SpirvShader *vertexShader = pipeline->getShader(VK_SHADER_STAGE_VERTEX_BIT).get();
const vk::Attachments attachments = pipeline->getAttachments();
vertexState = vertexProcessor.update(pipelineState, vertexShader, inputs);
setupState = setupProcessor.update(pipelineState, fragmentShader, vertexShader, attachments);
pixelState = pixelProcessor.update(pipelineState, fragmentShader, vertexShader, attachments, hasOcclusionQuery());
vertexRoutine = vertexProcessor.routine(vertexState, pipelineState.getPipelineLayout(), vertexShader, inputs.getDescriptorSets());
setupRoutine = setupProcessor.routine(setupState);
pixelRoutine = pixelProcessor.routine(pixelState, context->pipelineLayout, context->pixelShader, context->descriptorSets);
pixelRoutine = pixelProcessor.routine(pixelState, pipelineState.getPipelineLayout(), fragmentShader, inputs.getDescriptorSets());
}
draw->containsImageWrite = (context->vertexShader && context->vertexShader->containsImageWrite()) ||
(context->pixelShader && context->pixelShader->containsImageWrite());
draw->containsImageWrite = pipeline->containsImageWrite();
DrawCall::SetupFunction setupPrimitives = nullptr;
int ms = context->sampleCount;
int ms = pipelineState.getSampleCount();
unsigned int numPrimitivesPerBatch = MaxBatchSize / ms;
if(context->isDrawTriangle(false))
if(pipelineState.isDrawTriangle(false))
{
switch(context->polygonMode)
switch(pipelineState.getPolygonMode())
{
case VK_POLYGON_MODE_FILL:
setupPrimitives = &DrawCall::setupSolidTriangles;
......@@ -231,11 +241,11 @@ void Renderer::draw(const sw::Context *context, VkIndexType indexType, unsigned
numPrimitivesPerBatch /= 3;
break;
default:
UNSUPPORTED("polygon mode: %d", int(context->polygonMode));
UNSUPPORTED("polygon mode: %d", int(pipelineState.getPolygonMode()));
return;
}
}
else if(context->isDrawLine(false))
else if(pipelineState.isDrawLine(false))
{
setupPrimitives = &DrawCall::setupLines;
}
......@@ -251,12 +261,12 @@ void Renderer::draw(const sw::Context *context, VkIndexType indexType, unsigned
draw->numPrimitives = count;
draw->numPrimitivesPerBatch = numPrimitivesPerBatch;
draw->numBatches = (count + draw->numPrimitivesPerBatch - 1) / draw->numPrimitivesPerBatch;
draw->topology = context->topology;
draw->provokingVertexMode = context->provokingVertexMode;
draw->indexType = indexType;
draw->lineRasterizationMode = context->lineRasterizationMode;
draw->descriptorSetObjects = context->descriptorSetObjects;
draw->pipelineLayout = context->pipelineLayout;
draw->topology = pipelineState.getTopology();
draw->provokingVertexMode = pipelineState.getProvokingVertexMode();
draw->indexType = pipeline->getIndexBuffer().getIndexType();
draw->lineRasterizationMode = pipelineState.getLineRasterizationMode();
draw->descriptorSetObjects = inputs.getDescriptorSetObjects();
draw->pipelineLayout = pipelineState.getPipelineLayout();
draw->vertexRoutine = vertexRoutine;
draw->setupRoutine = setupRoutine;
......@@ -264,14 +274,15 @@ void Renderer::draw(const sw::Context *context, VkIndexType indexType, unsigned
draw->setupPrimitives = setupPrimitives;
draw->setupState = setupState;
data->descriptorSets = context->descriptorSets;
data->descriptorDynamicOffsets = context->descriptorDynamicOffsets;
data->descriptorSets = inputs.getDescriptorSets();
data->descriptorDynamicOffsets = inputs.getDescriptorDynamicOffsets();
for(int i = 0; i < MAX_INTERFACE_COMPONENTS / 4; i++)
{
data->input[i] = context->input[i].buffer;
data->robustnessSize[i] = context->input[i].robustnessSize;
data->stride[i] = context->input[i].vertexStride;
const sw::Stream &stream = inputs.getStream(i);
data->input[i] = stream.buffer;
data->robustnessSize[i] = stream.robustnessSize;
data->stride[i] = stream.vertexStride;
}
data->indices = indexBuffer;
......@@ -281,11 +292,11 @@ void Renderer::draw(const sw::Context *context, VkIndexType indexType, unsigned
if(pixelState.stencilActive)
{
data->stencil[0].set(context->frontStencil.reference, context->frontStencil.compareMask, context->frontStencil.writeMask);
data->stencil[1].set(context->backStencil.reference, context->backStencil.compareMask, context->backStencil.writeMask);
data->stencil[0].set(pipelineState.getFrontStencil().reference, pipelineState.getFrontStencil().compareMask, pipelineState.getFrontStencil().writeMask);
data->stencil[1].set(pipelineState.getBackStencil().reference, pipelineState.getBackStencil().compareMask, pipelineState.getBackStencil().writeMask);
}
data->lineWidth = context->lineWidth;
data->lineWidth = pipelineState.getLineWidth();
data->factor = pixelProcessor.factor;
......@@ -321,6 +332,8 @@ void Renderer::draw(const sw::Context *context, VkIndexType indexType, unsigned
// Viewport
{
const VkViewport &viewport = pipelineState.getViewport();
float W = 0.5f * viewport.width;
float H = 0.5f * viewport.height;
float X0 = viewport.x + W;
......@@ -339,13 +352,14 @@ void Renderer::draw(const sw::Context *context, VkIndexType indexType, unsigned
data->viewportHeight = abs(viewport.height);
data->depthRange = Z;
data->depthNear = N;
data->constantDepthBias = context->constantDepthBias;
data->slopeDepthBias = context->slopeDepthBias;
data->depthBiasClamp = context->depthBiasClamp;
data->constantDepthBias = pipelineState.getConstantDepthBias();
data->slopeDepthBias = pipelineState.getSlopeDepthBias();
data->depthBiasClamp = pipelineState.getDepthBiasClamp();
if(context->depthBuffer)
const vk::Attachments attachments = pipeline->getAttachments();
if(attachments.depthBuffer)
{
switch(context->depthBuffer->getFormat(VK_IMAGE_ASPECT_DEPTH_BIT))
switch(attachments.depthBuffer->getFormat(VK_IMAGE_ASPECT_DEPTH_BIT))
{
case VK_FORMAT_D16_UNORM:
data->minimumResolvableDepthDifference = 1.0f / 0xFFFF;
......@@ -355,45 +369,49 @@ void Renderer::draw(const sw::Context *context, VkIndexType indexType, unsigned
// buffers. DrawData::minimumResolvableDepthDifference is unused.
break;
default:
UNSUPPORTED("Depth format: %d", int(context->depthBuffer->getFormat(VK_IMAGE_ASPECT_DEPTH_BIT)));
UNSUPPORTED("Depth format: %d", int(attachments.depthBuffer->getFormat(VK_IMAGE_ASPECT_DEPTH_BIT)));
}
}
}
// Target
{
const vk::Attachments attachments = pipeline->getAttachments();
for(int index = 0; index < RENDERTARGETS; index++)
{
draw->renderTarget[index] = context->renderTarget[index];
draw->renderTarget[index] = attachments.renderTarget[index];
if(draw->renderTarget[index])
{
data->colorBuffer[index] = (unsigned int *)context->renderTarget[index]->getOffsetPointer({ 0, 0, 0 }, VK_IMAGE_ASPECT_COLOR_BIT, 0, data->viewID);
data->colorPitchB[index] = context->renderTarget[index]->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0);
data->colorSliceB[index] = context->renderTarget[index]->slicePitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0);
data->colorBuffer[index] = (unsigned int *)attachments.renderTarget[index]->getOffsetPointer({ 0, 0, 0 }, VK_IMAGE_ASPECT_COLOR_BIT, 0, data->viewID);
data->colorPitchB[index] = attachments.renderTarget[index]->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0);
data->colorSliceB[index] = attachments.renderTarget[index]->slicePitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0);
}
}
draw->depthBuffer = context->depthBuffer;
draw->stencilBuffer = context->stencilBuffer;
draw->depthBuffer = attachments.depthBuffer;
draw->stencilBuffer = attachments.stencilBuffer;
if(draw->depthBuffer)
{
data->depthBuffer = (float *)context->depthBuffer->getOffsetPointer({ 0, 0, 0 }, VK_IMAGE_ASPECT_DEPTH_BIT, 0, data->viewID);
data->depthPitchB = context->depthBuffer->rowPitchBytes(VK_IMAGE_ASPECT_DEPTH_BIT, 0);
data->depthSliceB = context->depthBuffer->slicePitchBytes(VK_IMAGE_ASPECT_DEPTH_BIT, 0);
data->depthBuffer = (float *)attachments.depthBuffer->getOffsetPointer({ 0, 0, 0 }, VK_IMAGE_ASPECT_DEPTH_BIT, 0, data->viewID);
data->depthPitchB = attachments.depthBuffer->rowPitchBytes(VK_IMAGE_ASPECT_DEPTH_BIT, 0);
data->depthSliceB = attachments.depthBuffer->slicePitchBytes(VK_IMAGE_ASPECT_DEPTH_BIT, 0);
}
if(draw->stencilBuffer)
{
data->stencilBuffer = (unsigned char *)context->stencilBuffer->getOffsetPointer({ 0, 0, 0 }, VK_IMAGE_ASPECT_STENCIL_BIT, 0, data->viewID);
data->stencilPitchB = context->stencilBuffer->rowPitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT, 0);
data->stencilSliceB = context->stencilBuffer->slicePitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT, 0);
data->stencilBuffer = (unsigned char *)attachments.stencilBuffer->getOffsetPointer({ 0, 0, 0 }, VK_IMAGE_ASPECT_STENCIL_BIT, 0, data->viewID);
data->stencilPitchB = attachments.stencilBuffer->rowPitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT, 0);
data->stencilSliceB = attachments.stencilBuffer->slicePitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT, 0);
}
}
// Scissor
{
const VkRect2D &scissor = pipelineState.getScissor();
data->scissorX0 = clamp<int>(scissor.offset.x, 0, framebufferExtent.width);
data->scissorX1 = clamp<int>(scissor.offset.x + scissor.extent.width, 0, framebufferExtent.width);
data->scissorY0 = clamp<int>(scissor.offset.y, 0, framebufferExtent.height);
......@@ -1193,34 +1211,4 @@ void Renderer::removeQuery(vk::Query *query)
occlusionQuery = nullptr;
}
// TODO(b/137740918): Optimize instancing to use a single draw call.
void Renderer::advanceInstanceAttributes(Stream *inputs)
{
for(uint32_t i = 0; i < vk::MAX_VERTEX_INPUT_BINDINGS; i++)
{
auto &attrib = inputs[i];
if((attrib.format != VK_FORMAT_UNDEFINED) && attrib.instanceStride && (attrib.instanceStride < attrib.robustnessSize))
{
// Under the casts: attrib.buffer += attrib.instanceStride
attrib.buffer = (void const *)((uintptr_t)attrib.buffer + attrib.instanceStride);
attrib.robustnessSize -= attrib.instanceStride;
}
}
}
void Renderer::setViewport(const VkViewport &viewport)
{
this->viewport = viewport;
}
void Renderer::setScissor(const VkRect2D &scissor)
{
this->scissor = scissor;
}
void Renderer::setBlendConstant(const float4 &blendConstant)
{
pixelProcessor.setBlendConstant(blendConstant);
}
} // namespace sw
......@@ -20,8 +20,8 @@
#include "Primitive.hpp"
#include "SetupProcessor.hpp"
#include "VertexProcessor.hpp"
#include "Device/Config.hpp"
#include "Vulkan/VkDescriptorSet.hpp"
#include "Vulkan/VkPipeline.hpp"
#include "marl/finally.h"
#include "marl/pool.h"
......@@ -114,7 +114,7 @@ struct DrawData
float4 a2c2;
float4 a2c3;
PushConstantStorage pushConstants;
vk::Pipeline::PushConstantStorage pushConstants;
};
struct DrawCall
......@@ -209,27 +209,16 @@ public:
bool hasOcclusionQuery() const { return occlusionQuery != nullptr; }
void draw(const sw::Context *context, VkIndexType indexType, unsigned int count, int baseVertex,
void draw(const vk::GraphicsPipeline *pipeline, const vk::DynamicState &dynamicState, unsigned int count, int baseVertex,
CountedEvent *events, int instanceID, int viewID, void *indexBuffer, const VkExtent3D &framebufferExtent,
PushConstantStorage const &pushConstants, bool update = true);
// Viewport & Clipper
void setViewport(const VkViewport &viewport);
void setScissor(const VkRect2D &scissor);
void setBlendConstant(const float4 &blendConstant);
vk::Pipeline::PushConstantStorage const &pushConstants, bool update = true);
void addQuery(vk::Query *query);
void removeQuery(vk::Query *query);
void advanceInstanceAttributes(Stream *inputs);
void synchronize();
private:
VkViewport viewport;
VkRect2D scissor;
DrawCall::Pool drawCallPool;
DrawCall::BatchData::Pool batchDataPool;
......
......@@ -14,7 +14,6 @@
#include "SetupProcessor.hpp"
#include "Context.hpp"
#include "Polygon.hpp"
#include "Primitive.hpp"
#include "Renderer.hpp"
......@@ -56,37 +55,37 @@ SetupProcessor::SetupProcessor()
setRoutineCacheSize(1024);
}
SetupProcessor::State SetupProcessor::update(const sw::Context *context) const
SetupProcessor::State SetupProcessor::update(const vk::GraphicsState &pipelineState, const sw::SpirvShader *fragmentShader, const sw::SpirvShader *vertexShader, const vk::Attachments &attachments) const
{
State state;
bool vPosZW = (context->pixelShader && context->pixelShader->hasBuiltinInput(spv::BuiltInFragCoord));
state.isDrawPoint = context->isDrawPoint(true);
state.isDrawLine = context->isDrawLine(true);
state.isDrawTriangle = context->isDrawTriangle(true);
state.fixedPointDepthBuffer = context->depthBuffer && !context->depthBuffer->getFormat(VK_IMAGE_ASPECT_DEPTH_BIT).isFloatFormat();
state.applyConstantDepthBias = context->isDrawTriangle(false) && (context->constantDepthBias != 0.0f);
state.applySlopeDepthBias = context->isDrawTriangle(false) && (context->slopeDepthBias != 0.0f);
state.applyDepthBiasClamp = context->isDrawTriangle(false) && (context->depthBiasClamp != 0.0f);
state.interpolateZ = context->depthBufferActive() || vPosZW;
state.interpolateW = context->pixelShader != nullptr;
state.frontFace = context->frontFace;
state.cullMode = context->cullMode;
state.multiSampleCount = context->sampleCount;
bool vPosZW = (fragmentShader && fragmentShader->hasBuiltinInput(spv::BuiltInFragCoord));
state.isDrawPoint = pipelineState.isDrawPoint(true);
state.isDrawLine = pipelineState.isDrawLine(true);
state.isDrawTriangle = pipelineState.isDrawTriangle(true);
state.fixedPointDepthBuffer = attachments.depthBuffer && !attachments.depthBuffer->getFormat(VK_IMAGE_ASPECT_DEPTH_BIT).isFloatFormat();
state.applyConstantDepthBias = pipelineState.isDrawTriangle(false) && (pipelineState.getConstantDepthBias() != 0.0f);
state.applySlopeDepthBias = pipelineState.isDrawTriangle(false) && (pipelineState.getSlopeDepthBias() != 0.0f);
state.applyDepthBiasClamp = pipelineState.isDrawTriangle(false) && (pipelineState.getDepthBiasClamp() != 0.0f);
state.interpolateZ = pipelineState.depthBufferActive(attachments) || vPosZW;
state.interpolateW = fragmentShader != nullptr;
state.frontFace = pipelineState.getFrontFace();
state.cullMode = pipelineState.getCullMode();
state.multiSampleCount = pipelineState.getSampleCount();
state.enableMultiSampling = (state.multiSampleCount > 1) &&
!(context->isDrawLine(true) && (context->lineRasterizationMode == VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT));
state.rasterizerDiscard = context->rasterizerDiscard;
!(pipelineState.isDrawLine(true) && (pipelineState.getLineRasterizationMode() == VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT));
state.rasterizerDiscard = pipelineState.hasRasterizerDiscard();
state.numClipDistances = context->vertexShader->getNumOutputClipDistances();
state.numCullDistances = context->vertexShader->getNumOutputCullDistances();
state.numClipDistances = vertexShader->getNumOutputClipDistances();
state.numCullDistances = vertexShader->getNumOutputCullDistances();
if(context->pixelShader)
if(fragmentShader)
{
for(int interpolant = 0; interpolant < MAX_INTERFACE_COMPONENTS; interpolant++)
{
state.gradient[interpolant] = context->pixelShader->inputs[interpolant];
state.gradient[interpolant] = fragmentShader->inputs[interpolant];
}
}
......
......@@ -76,7 +76,7 @@ public:
SetupProcessor();
State update(const sw::Context *context) const;
State update(const vk::GraphicsState &pipelineState, const sw::SpirvShader *fragmentShader, const sw::SpirvShader *vertexShader, const vk::Attachments &attachments) const;
RoutineType routine(const State &state);
void setRoutineCacheSize(int cacheSize);
......
......@@ -65,21 +65,21 @@ void VertexProcessor::setRoutineCacheSize(int cacheSize)
routineCache = std::make_unique<RoutineCacheType>(clamp(cacheSize, 1, 65536));
}
const VertexProcessor::State VertexProcessor::update(const sw::Context *context)
const VertexProcessor::State VertexProcessor::update(const vk::GraphicsState &pipelineState, const sw::SpirvShader *vertexShader, const vk::Inputs &inputs)
{
State state;
state.shaderID = context->vertexShader->getSerialID();
state.pipelineLayoutIdentifier = context->pipelineLayout->identifier;
state.robustBufferAccess = context->robustBufferAccess;
state.isPoint = context->topology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
state.shaderID = vertexShader->getSerialID();
state.pipelineLayoutIdentifier = pipelineState.getPipelineLayout()->identifier;
state.robustBufferAccess = pipelineState.getRobustBufferAccess();
state.isPoint = pipelineState.getTopology() == VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
for(int i = 0; i < MAX_INTERFACE_COMPONENTS / 4; i++)
for(size_t i = 0; i < MAX_INTERFACE_COMPONENTS / 4; i++)
{
state.input[i].format = context->input[i].format;
state.input[i].format = inputs.getStream(i).format;
// TODO: get rid of attribType -- just keep the VK format all the way through, this fully determines
// how to handle the attribute.
state.input[i].attribType = context->vertexShader->inputs[i * 4].Type;
state.input[i].attribType = vertexShader->inputs[i * 4].Type;
}
state.hash = state.computeHash();
......
......@@ -94,7 +94,7 @@ public:
VertexProcessor();
const State update(const sw::Context *context);
const State update(const vk::GraphicsState &pipelineState, const sw::SpirvShader *vertexShader, const vk::Inputs &inputs);
RoutineType routine(const State &state, vk::PipelineLayout const *pipelineLayout,
SpirvShader const *vertexShader, const vk::DescriptorSet::Bindings &descriptorSets);
......
......@@ -209,7 +209,7 @@ void ComputeProgram::run(
vk::DescriptorSet::Array const &descriptorSetObjects,
vk::DescriptorSet::Bindings const &descriptorSets,
vk::DescriptorSet::DynamicOffsets const &descriptorDynamicOffsets,
PushConstantStorage const &pushConstants,
vk::Pipeline::PushConstantStorage const &pushConstants,
uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ,
uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ)
{
......
......@@ -17,9 +17,9 @@
#include "SpirvShader.hpp"
#include "Device/Context.hpp"
#include "Reactor/Coroutine.hpp"
#include "Vulkan/VkDescriptorSet.hpp"
#include "Vulkan/VkPipeline.hpp"
#include <functional>
......@@ -58,7 +58,7 @@ public:
vk::DescriptorSet::Array const &descriptorSetObjects,
vk::DescriptorSet::Bindings const &descriptorSetBindings,
vk::DescriptorSet::DynamicOffsets const &descriptorDynamicOffsets,
PushConstantStorage const &pushConstants,
vk::Pipeline::PushConstantStorage const &pushConstants,
uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ,
uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
......@@ -76,7 +76,7 @@ protected:
uint32_t invocationsPerSubgroup; // SPIR-V: "SubgroupSize"
uint32_t subgroupsPerWorkgroup; // SPIR-V: "NumSubgroups"
uint32_t invocationsPerWorkgroup; // Total number of invocations per workgroup.
PushConstantStorage pushConstants;
vk::Pipeline::PushConstantStorage pushConstants;
const Constants *constants;
};
......
......@@ -466,56 +466,6 @@ private:
class CmdDrawBase : public vk::CommandBuffer::Command
{
public:
int bytesPerIndex(vk::CommandBuffer::ExecutionState const &executionState)
{
return executionState.indexType == VK_INDEX_TYPE_UINT16 ? 2 : 4;
}
template<typename T>
void processPrimitiveRestart(T *indexBuffer,
uint32_t count,
vk::GraphicsPipeline *pipeline,
std::vector<std::pair<uint32_t, void *>> &indexBuffers)
{
static const T RestartIndex = static_cast<T>(-1);
T *indexBufferStart = indexBuffer;
uint32_t vertexCount = 0;
for(uint32_t i = 0; i < count; i++)
{
if(indexBuffer[i] == RestartIndex)
{
// Record previous segment
if(vertexCount > 0)
{
uint32_t primitiveCount = pipeline->computePrimitiveCount(vertexCount);
if(primitiveCount > 0)
{
indexBuffers.push_back({ primitiveCount, indexBufferStart });
}
}
vertexCount = 0;
}
else
{
if(vertexCount == 0)
{
indexBufferStart = indexBuffer + i;
}
vertexCount++;
}
}
// Record last segment
if(vertexCount > 0)
{
uint32_t primitiveCount = pipeline->computePrimitiveCount(vertexCount);
if(primitiveCount > 0)
{
indexBuffers.push_back({ primitiveCount, indexBufferStart });
}
}
}
void draw(vk::CommandBuffer::ExecutionState &executionState, bool indexed,
uint32_t count, uint32_t instanceCount, uint32_t first, int32_t vertexOffset, uint32_t firstInstance)
{
......@@ -523,87 +473,21 @@ public:
auto *pipeline = static_cast<vk::GraphicsPipeline *>(pipelineState.pipeline);
sw::Context context = pipeline->getContext();
executionState.bindVertexInputs(context, firstInstance);
context.descriptorSetObjects = pipelineState.descriptorSetObjects;
context.descriptorSets = pipelineState.descriptorSets;
context.descriptorDynamicOffsets = pipelineState.descriptorDynamicOffsets;
// Apply either pipeline state or dynamic state
executionState.renderer->setScissor(pipeline->hasDynamicState(VK_DYNAMIC_STATE_SCISSOR) ? executionState.dynamicState.scissor : pipeline->getScissor());
executionState.renderer->setViewport(pipeline->hasDynamicState(VK_DYNAMIC_STATE_VIEWPORT) ? executionState.dynamicState.viewport : pipeline->getViewport());
executionState.renderer->setBlendConstant(pipeline->hasDynamicState(VK_DYNAMIC_STATE_BLEND_CONSTANTS) ? executionState.dynamicState.blendConstants : pipeline->getBlendConstants());
if(pipeline->hasDynamicState(VK_DYNAMIC_STATE_DEPTH_BIAS))
{
context.constantDepthBias = executionState.dynamicState.depthBiasConstantFactor;
context.slopeDepthBias = executionState.dynamicState.depthBiasSlopeFactor;
context.depthBiasClamp = executionState.dynamicState.depthBiasClamp;
}
if(pipeline->hasDynamicState(VK_DYNAMIC_STATE_DEPTH_BOUNDS) && context.depthBoundsTestEnable)
{
// Unless the VK_EXT_depth_range_unrestricted extension is enabled, minDepthBounds and maxDepthBounds must be between 0.0 and 1.0, inclusive
ASSERT(executionState.dynamicState.minDepthBounds >= 0.0f &&
executionState.dynamicState.minDepthBounds <= 1.0f);
ASSERT(executionState.dynamicState.maxDepthBounds >= 0.0f &&
executionState.dynamicState.maxDepthBounds <= 1.0f);
UNSUPPORTED("VkPhysicalDeviceFeatures::depthBounds");
}
vk::Attachments &attachments = pipeline->getAttachments();
executionState.bindAttachments(&attachments);
if(pipeline->hasDynamicState(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK) && context.stencilEnable)
{
context.frontStencil.compareMask = executionState.dynamicState.compareMask[0];
context.backStencil.compareMask = executionState.dynamicState.compareMask[1];
}
vk::Inputs &inputs = pipeline->getInputs();
inputs.updateDescriptorSets(pipelineState.descriptorSetObjects,
pipelineState.descriptorSets,
pipelineState.descriptorDynamicOffsets);
inputs.setVertexInputBinding(executionState.vertexInputBindings);
inputs.bindVertexInputs(firstInstance);
if(pipeline->hasDynamicState(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK) && context.stencilEnable)
{
context.frontStencil.writeMask = executionState.dynamicState.writeMask[0];
context.backStencil.writeMask = executionState.dynamicState.writeMask[1];
}
if(pipeline->hasDynamicState(VK_DYNAMIC_STATE_STENCIL_REFERENCE) && context.stencilEnable)
{
context.frontStencil.reference = executionState.dynamicState.reference[0];
context.backStencil.reference = executionState.dynamicState.reference[1];
}
executionState.bindAttachments(context);
context.occlusionEnabled = executionState.renderer->hasOcclusionQuery();
vk::IndexBuffer &indexBuffer = pipeline->getIndexBuffer();
indexBuffer.setIndexBufferBinding(executionState.indexBufferBinding, executionState.indexType);
std::vector<std::pair<uint32_t, void *>> indexBuffers;
if(indexed)
{
void *indexBuffer = executionState.indexBufferBinding.buffer->getOffsetPointer(
executionState.indexBufferBinding.offset + first * bytesPerIndex(executionState));
if(pipeline->hasPrimitiveRestartEnable())
{
switch(executionState.indexType)
{
case VK_INDEX_TYPE_UINT16:
processPrimitiveRestart(static_cast<uint16_t *>(indexBuffer), count, pipeline, indexBuffers);
break;
case VK_INDEX_TYPE_UINT32:
processPrimitiveRestart(static_cast<uint32_t *>(indexBuffer), count, pipeline, indexBuffers);
break;
default:
UNSUPPORTED("VkIndexType %d", int(executionState.indexType));
}
}
else
{
indexBuffers.push_back({ pipeline->computePrimitiveCount(count), indexBuffer });
}
}
else
{
indexBuffers.push_back({ pipeline->computePrimitiveCount(count), nullptr });
}
pipeline->getIndexBuffers(count, first, indexed, &indexBuffers);
for(uint32_t instance = firstInstance; instance != firstInstance + instanceCount; instance++)
{
......@@ -616,14 +500,14 @@ public:
for(auto indexBuffer : indexBuffers)
{
executionState.renderer->draw(&context, executionState.indexType, indexBuffer.first, vertexOffset,
executionState.renderer->draw(pipeline, executionState.dynamicState, indexBuffer.first, vertexOffset,
executionState.events, instance, viewID, indexBuffer.second,
executionState.renderPassFramebuffer->getExtent(),
executionState.pushConstants);
}
}
executionState.renderer->advanceInstanceAttributes(context.input);
inputs.advanceInstanceAttributes();
}
}
};
......@@ -1840,25 +1724,7 @@ void CommandBuffer::submitSecondary(CommandBuffer::ExecutionState &executionStat
}
}
void CommandBuffer::ExecutionState::bindVertexInputs(sw::Context &context, int firstInstance)
{
for(uint32_t i = 0; i < MAX_VERTEX_INPUT_BINDINGS; i++)
{
auto &attrib = context.input[i];
if(attrib.format != VK_FORMAT_UNDEFINED)
{
const auto &vertexInput = vertexInputBindings[attrib.binding];
VkDeviceSize offset = attrib.offset + vertexInput.offset +
attrib.instanceStride * firstInstance;
attrib.buffer = vertexInput.buffer ? vertexInput.buffer->getOffsetPointer(offset) : nullptr;
VkDeviceSize size = vertexInput.buffer ? vertexInput.buffer->getSize() : 0;
attrib.robustnessSize = (size > offset) ? size - offset : 0;
}
}
}
void CommandBuffer::ExecutionState::bindAttachments(sw::Context &context)
void CommandBuffer::ExecutionState::bindAttachments(Attachments *attachments)
{
// Binds all the attachments for the current subpass
// Ideally this would be performed by BeginRenderPass and NextSubpass, but
......@@ -1872,7 +1738,7 @@ void CommandBuffer::ExecutionState::bindAttachments(sw::Context &context)
auto attachmentReference = subpass.pColorAttachments[i];
if(attachmentReference.attachment != VK_ATTACHMENT_UNUSED)
{
context.renderTarget[i] = renderPassFramebuffer->getAttachment(attachmentReference.attachment);
attachments->renderTarget[i] = renderPassFramebuffer->getAttachment(attachmentReference.attachment);
}
}
......@@ -1882,11 +1748,11 @@ void CommandBuffer::ExecutionState::bindAttachments(sw::Context &context)
auto attachment = renderPassFramebuffer->getAttachment(attachmentReference->attachment);
if(attachment->hasDepthAspect())
{
context.depthBuffer = attachment;
attachments->depthBuffer = attachment;
}
if(attachment->hasStencilAspect())
{
context.stencilBuffer = attachment;
attachments->stencilBuffer = attachment;
}
}
}
......
......@@ -17,8 +17,7 @@
#include "VkConfig.hpp"
#include "VkDescriptorSet.hpp"
#include "VkObject.hpp"
#include "Device/Context.hpp"
#include "VkPipeline.hpp"
#include "System/Synchronization.hpp"
#include <memory>
......@@ -155,38 +154,17 @@ public:
Framebuffer *renderPassFramebuffer = nullptr;
std::array<PipelineState, vk::VK_PIPELINE_BIND_POINT_RANGE_SIZE> pipelineState;
struct DynamicState
{
VkViewport viewport;
VkRect2D scissor;
sw::float4 blendConstants;
float depthBiasConstantFactor = 0.0f;
float depthBiasClamp = 0.0f;
float depthBiasSlopeFactor = 0.0f;
float minDepthBounds = 0.0f;
float maxDepthBounds = 0.0f;
uint32_t compareMask[2] = { 0 };
uint32_t writeMask[2] = { 0 };
uint32_t reference[2] = { 0 };
};
DynamicState dynamicState;
vk::DynamicState dynamicState;
sw::PushConstantStorage pushConstants;
vk::Pipeline::PushConstantStorage pushConstants;
struct VertexInputBinding
{
Buffer *buffer;
VkDeviceSize offset;
};
VertexInputBinding vertexInputBindings[MAX_VERTEX_INPUT_BINDINGS] = {};
VertexInputBinding indexBufferBinding;
VkIndexType indexType;
uint32_t subpassIndex = 0;
void bindAttachments(sw::Context &context);
void bindVertexInputs(sw::Context &context, int firstInstance);
void bindAttachments(Attachments *attachments);
};
void submit(CommandBuffer::ExecutionState &executionState);
......
......@@ -147,305 +147,9 @@ void Pipeline::destroy(const VkAllocationCallbacks *pAllocator)
GraphicsPipeline::GraphicsPipeline(const VkGraphicsPipelineCreateInfo *pCreateInfo, void *mem, Device *device)
: Pipeline(vk::Cast(pCreateInfo->layout), device)
, state(device, pCreateInfo, layout, robustBufferAccess)
, inputs(pCreateInfo->pVertexInputState)
{
context.robustBufferAccess = robustBufferAccess;
if((pCreateInfo->flags &
~(VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT |
VK_PIPELINE_CREATE_DERIVATIVE_BIT |
VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT)) != 0)
{
UNSUPPORTED("pCreateInfo->flags %d", int(pCreateInfo->flags));
}
if(pCreateInfo->pDynamicState)
{
if(pCreateInfo->pDynamicState->flags != 0)
{
// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
UNSUPPORTED("pCreateInfo->pDynamicState->flags %d", int(pCreateInfo->pDynamicState->flags));
}
for(uint32_t i = 0; i < pCreateInfo->pDynamicState->dynamicStateCount; i++)
{
VkDynamicState dynamicState = pCreateInfo->pDynamicState->pDynamicStates[i];
switch(dynamicState)
{
case VK_DYNAMIC_STATE_VIEWPORT:
case VK_DYNAMIC_STATE_SCISSOR:
case VK_DYNAMIC_STATE_LINE_WIDTH:
case VK_DYNAMIC_STATE_DEPTH_BIAS:
case VK_DYNAMIC_STATE_BLEND_CONSTANTS:
case VK_DYNAMIC_STATE_DEPTH_BOUNDS:
case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK:
case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK:
case VK_DYNAMIC_STATE_STENCIL_REFERENCE:
ASSERT(dynamicState < (sizeof(dynamicStateFlags) * 8));
dynamicStateFlags |= (1 << dynamicState);
break;
default:
UNSUPPORTED("VkDynamicState %d", int(dynamicState));
}
}
}
const VkPipelineVertexInputStateCreateInfo *vertexInputState = pCreateInfo->pVertexInputState;
if(vertexInputState->flags != 0)
{
// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
UNSUPPORTED("vertexInputState->flags");
}
// Context must always have a PipelineLayout set.
context.pipelineLayout = layout;
// Temporary in-binding-order representation of buffer strides, to be consumed below
// when considering attributes. TODO: unfuse buffers from attributes in backend, is old GL model.
uint32_t vertexStrides[MAX_VERTEX_INPUT_BINDINGS];
uint32_t instanceStrides[MAX_VERTEX_INPUT_BINDINGS];
for(uint32_t i = 0; i < vertexInputState->vertexBindingDescriptionCount; i++)
{
auto const &desc = vertexInputState->pVertexBindingDescriptions[i];
vertexStrides[desc.binding] = desc.inputRate == VK_VERTEX_INPUT_RATE_VERTEX ? desc.stride : 0;
instanceStrides[desc.binding] = desc.inputRate == VK_VERTEX_INPUT_RATE_INSTANCE ? desc.stride : 0;
}
for(uint32_t i = 0; i < vertexInputState->vertexAttributeDescriptionCount; i++)
{
auto const &desc = vertexInputState->pVertexAttributeDescriptions[i];
sw::Stream &input = context.input[desc.location];
input.format = desc.format;
input.offset = desc.offset;
input.binding = desc.binding;
input.vertexStride = vertexStrides[desc.binding];
input.instanceStride = instanceStrides[desc.binding];
}
const VkPipelineInputAssemblyStateCreateInfo *inputAssemblyState = pCreateInfo->pInputAssemblyState;
if(inputAssemblyState->flags != 0)
{
// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
UNSUPPORTED("pCreateInfo->pInputAssemblyState->flags %d", int(pCreateInfo->pInputAssemblyState->flags));
}
primitiveRestartEnable = (inputAssemblyState->primitiveRestartEnable != VK_FALSE);
context.topology = inputAssemblyState->topology;
const VkPipelineRasterizationStateCreateInfo *rasterizationState = pCreateInfo->pRasterizationState;
if(rasterizationState->flags != 0)
{
// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
UNSUPPORTED("pCreateInfo->pRasterizationState->flags %d", int(pCreateInfo->pRasterizationState->flags));
}
if(rasterizationState->depthClampEnable != VK_FALSE)
{
UNSUPPORTED("VkPhysicalDeviceFeatures::depthClamp");
}
context.rasterizerDiscard = (rasterizationState->rasterizerDiscardEnable != VK_FALSE);
context.cullMode = rasterizationState->cullMode;
context.frontFace = rasterizationState->frontFace;
context.polygonMode = rasterizationState->polygonMode;
context.constantDepthBias = (rasterizationState->depthBiasEnable != VK_FALSE) ? rasterizationState->depthBiasConstantFactor : 0.0f;
context.slopeDepthBias = (rasterizationState->depthBiasEnable != VK_FALSE) ? rasterizationState->depthBiasSlopeFactor : 0.0f;
context.depthBiasClamp = (rasterizationState->depthBiasEnable != VK_FALSE) ? rasterizationState->depthBiasClamp : 0.0f;
context.depthRangeUnrestricted = device->hasExtension(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME);
// From the Vulkan spec for vkCmdSetDepthBias:
// The bias value O for a polygon is:
// O = dbclamp(...)
// where dbclamp(x) =
// * x depthBiasClamp = 0 or NaN
// * min(x, depthBiasClamp) depthBiasClamp > 0
// * max(x, depthBiasClamp) depthBiasClamp < 0
// So it should be safe to resolve NaNs to 0.0f.
if(std::isnan(context.depthBiasClamp))
{
context.depthBiasClamp = 0.0f;
}
context.lineWidth = rasterizationState->lineWidth;
const VkBaseInStructure *extensionCreateInfo = reinterpret_cast<const VkBaseInStructure *>(rasterizationState->pNext);
while(extensionCreateInfo)
{
// Casting to a long since some structures, such as
// VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT
// are not enumerated in the official Vulkan header
switch((long)(extensionCreateInfo->sType))
{
case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT:
{
const VkPipelineRasterizationLineStateCreateInfoEXT *lineStateCreateInfo = reinterpret_cast<const VkPipelineRasterizationLineStateCreateInfoEXT *>(extensionCreateInfo);
context.lineRasterizationMode = lineStateCreateInfo->lineRasterizationMode;
}
break;
case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT:
{
const VkPipelineRasterizationProvokingVertexStateCreateInfoEXT *provokingVertexModeCreateInfo =
reinterpret_cast<const VkPipelineRasterizationProvokingVertexStateCreateInfoEXT *>(extensionCreateInfo);
context.provokingVertexMode = provokingVertexModeCreateInfo->provokingVertexMode;
}
break;
default:
WARN("pCreateInfo->pRasterizationState->pNext sType = %s", vk::Stringify(extensionCreateInfo->sType).c_str());
break;
}
extensionCreateInfo = extensionCreateInfo->pNext;
}
// The sample count affects the batch size, so it needs initialization even if rasterization is disabled.
// TODO(b/147812380): Eliminate the dependency between multisampling and batch size.
context.sampleCount = 1;
// Only access rasterization state if rasterization is not disabled.
if(rasterizationState->rasterizerDiscardEnable == VK_FALSE)
{
const VkPipelineViewportStateCreateInfo *viewportState = pCreateInfo->pViewportState;
const VkPipelineMultisampleStateCreateInfo *multisampleState = pCreateInfo->pMultisampleState;
const VkPipelineDepthStencilStateCreateInfo *depthStencilState = pCreateInfo->pDepthStencilState;
const VkPipelineColorBlendStateCreateInfo *colorBlendState = pCreateInfo->pColorBlendState;
if(viewportState->flags != 0)
{
// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
UNSUPPORTED("pCreateInfo->pViewportState->flags %d", int(pCreateInfo->pViewportState->flags));
}
if((viewportState->viewportCount != 1) ||
(viewportState->scissorCount != 1))
{
UNSUPPORTED("VkPhysicalDeviceFeatures::multiViewport");
}
if(!hasDynamicState(VK_DYNAMIC_STATE_SCISSOR))
{
scissor = viewportState->pScissors[0];
}
if(!hasDynamicState(VK_DYNAMIC_STATE_VIEWPORT))
{
viewport = viewportState->pViewports[0];
}
if(multisampleState->flags != 0)
{
// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
UNSUPPORTED("pCreateInfo->pMultisampleState->flags %d", int(pCreateInfo->pMultisampleState->flags));
}
if(multisampleState->sampleShadingEnable != VK_FALSE)
{
UNSUPPORTED("VkPhysicalDeviceFeatures::sampleRateShading");
}
if(multisampleState->alphaToOneEnable != VK_FALSE)
{
UNSUPPORTED("VkPhysicalDeviceFeatures::alphaToOne");
}
switch(multisampleState->rasterizationSamples)
{
case VK_SAMPLE_COUNT_1_BIT:
context.sampleCount = 1;
break;
case VK_SAMPLE_COUNT_4_BIT:
context.sampleCount = 4;
break;
default:
UNSUPPORTED("Unsupported sample count");
}
if(multisampleState->pSampleMask)
{
context.sampleMask = multisampleState->pSampleMask[0];
}
else // "If pSampleMask is NULL, it is treated as if the mask has all bits set to 1."
{
context.sampleMask = ~0;
}
context.alphaToCoverage = (multisampleState->alphaToCoverageEnable != VK_FALSE);
context.multiSampleMask = context.sampleMask & ((unsigned)0xFFFFFFFF >> (32 - context.sampleCount));
const vk::RenderPass *renderPass = vk::Cast(pCreateInfo->renderPass);
const VkSubpassDescription &subpass = renderPass->getSubpass(pCreateInfo->subpass);
// Ignore pDepthStencilState when "the subpass of the render pass the pipeline is created against does not use a depth/stencil attachment"
if(subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)
{
if(depthStencilState->flags != 0)
{
// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
UNSUPPORTED("pCreateInfo->pDepthStencilState->flags %d", int(pCreateInfo->pDepthStencilState->flags));
}
if(depthStencilState->depthBoundsTestEnable != VK_FALSE)
{
UNSUPPORTED("VkPhysicalDeviceFeatures::depthBounds");
}
context.depthBoundsTestEnable = (depthStencilState->depthBoundsTestEnable != VK_FALSE);
context.depthBufferEnable = (depthStencilState->depthTestEnable != VK_FALSE);
context.depthWriteEnable = (depthStencilState->depthWriteEnable != VK_FALSE);
context.depthCompareMode = depthStencilState->depthCompareOp;
context.stencilEnable = (depthStencilState->stencilTestEnable != VK_FALSE);
if(context.stencilEnable)
{
context.frontStencil = depthStencilState->front;
context.backStencil = depthStencilState->back;
}
}
bool colorAttachmentUsed = false;
for(uint32_t i = 0; i < subpass.colorAttachmentCount; i++)
{
if(subpass.pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED)
{
colorAttachmentUsed = true;
break;
}
}
// Ignore pColorBlendState when "the subpass of the render pass the pipeline is created against does not use any color attachments"
if(colorAttachmentUsed)
{
if(colorBlendState->flags != 0)
{
// Vulkan 1.2: "flags is reserved for future use." "flags must be 0"
UNSUPPORTED("pCreateInfo->pColorBlendState->flags %d", int(pCreateInfo->pColorBlendState->flags));
}
if(colorBlendState->logicOpEnable != VK_FALSE)
{
UNSUPPORTED("VkPhysicalDeviceFeatures::logicOp");
}
if(!hasDynamicState(VK_DYNAMIC_STATE_BLEND_CONSTANTS))
{
blendConstants.x = colorBlendState->blendConstants[0];
blendConstants.y = colorBlendState->blendConstants[1];
blendConstants.z = colorBlendState->blendConstants[2];
blendConstants.w = colorBlendState->blendConstants[3];
}
for(auto i = 0u; i < colorBlendState->attachmentCount; i++)
{
const VkPipelineColorBlendAttachmentState &attachment = colorBlendState->pAttachments[i];
context.colorWriteMask[i] = attachment.colorWriteMask;
context.setBlendState(i, { (attachment.blendEnable != VK_FALSE),
attachment.srcColorBlendFactor, attachment.dstColorBlendFactor, attachment.colorBlendOp,
attachment.srcAlphaBlendFactor, attachment.dstAlphaBlendFactor, attachment.alphaBlendOp });
}
}
}
}
void GraphicsPipeline::destroyPipeline(const VkAllocationCallbacks *pAllocator)
......@@ -459,6 +163,17 @@ size_t GraphicsPipeline::ComputeRequiredAllocationSize(const VkGraphicsPipelineC
return 0;
}
void GraphicsPipeline::getIndexBuffers(uint32_t count, uint32_t first, bool indexed, std::vector<std::pair<uint32_t, void *>> *indexBuffers) const
{
indexBuffer.getIndexBuffers(state.getTopology(), count, first, indexed, state.hasPrimitiveRestartEnable(), indexBuffers);
}
bool GraphicsPipeline::containsImageWrite() const
{
return (vertexShader.get() && vertexShader->containsImageWrite()) ||
(fragmentShader.get() && fragmentShader->containsImageWrite());
}
void GraphicsPipeline::setShader(const VkShaderStageFlagBits &stage, const std::shared_ptr<sw::SpirvShader> spirvShader)
{
switch(stage)
......@@ -466,13 +181,11 @@ void GraphicsPipeline::setShader(const VkShaderStageFlagBits &stage, const std::
case VK_SHADER_STAGE_VERTEX_BIT:
ASSERT(vertexShader.get() == nullptr);
vertexShader = spirvShader;
context.vertexShader = vertexShader.get();
break;
case VK_SHADER_STAGE_FRAGMENT_BIT:
ASSERT(fragmentShader.get() == nullptr);
fragmentShader = spirvShader;
context.pixelShader = fragmentShader.get();
break;
default:
......@@ -526,54 +239,6 @@ void GraphicsPipeline::compileShaders(const VkAllocationCallbacks *pAllocator, c
}
}
uint32_t GraphicsPipeline::computePrimitiveCount(uint32_t vertexCount) const
{
switch(context.topology)
{
case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
return vertexCount;
case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
return vertexCount / 2;
case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
return std::max<uint32_t>(vertexCount, 1) - 1;
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
return vertexCount / 3;
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
return std::max<uint32_t>(vertexCount, 2) - 2;
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
return std::max<uint32_t>(vertexCount, 2) - 2;
default:
UNSUPPORTED("VkPrimitiveTopology %d", int(context.topology));
}
return 0;
}
const sw::Context &GraphicsPipeline::getContext() const
{
return context;
}
const VkRect2D &GraphicsPipeline::getScissor() const
{
return scissor;
}
const VkViewport &GraphicsPipeline::getViewport() const
{
return viewport;
}
const sw::float4 &GraphicsPipeline::getBlendConstants() const
{
return blendConstants;
}
bool GraphicsPipeline::hasDynamicState(VkDynamicState dynamicState) const
{
return (dynamicStateFlags & (1 << dynamicState)) != 0;
}
ComputePipeline::ComputePipeline(const VkComputePipelineCreateInfo *pCreateInfo, void *mem, Device *device)
: Pipeline(vk::Cast(pCreateInfo->layout), device)
{
......@@ -624,7 +289,7 @@ void ComputePipeline::run(uint32_t baseGroupX, uint32_t baseGroupY, uint32_t bas
vk::DescriptorSet::Array const &descriptorSetObjects,
vk::DescriptorSet::Bindings const &descriptorSets,
vk::DescriptorSet::DynamicOffsets const &descriptorDynamicOffsets,
sw::PushConstantStorage const &pushConstants)
vk::Pipeline::PushConstantStorage const &pushConstants)
{
ASSERT_OR_RETURN(program != nullptr);
program->run(
......
......@@ -15,9 +15,7 @@
#ifndef VK_PIPELINE_HPP_
#define VK_PIPELINE_HPP_
#include "VkObject.hpp"
#include "Device/Renderer.hpp"
#include "Vulkan/VkDescriptorSet.hpp"
#include "Device/Context.hpp"
#include "Vulkan/VkPipelineCache.hpp"
#include <memory>
......@@ -34,10 +32,7 @@ namespace dbg {
class Context;
} // namespace dbg
class PipelineCache;
class PipelineLayout;
class ShaderModule;
class Device;
class Pipeline
{
......@@ -67,6 +62,11 @@ public:
return layout;
}
struct PushConstantStorage
{
unsigned char data[vk::MAX_PUSH_CONSTANT_SIZE];
};
protected:
PipelineLayout *layout = nullptr;
Device *const device;
......@@ -95,26 +95,31 @@ public:
void compileShaders(const VkAllocationCallbacks *pAllocator, const VkGraphicsPipelineCreateInfo *pCreateInfo, PipelineCache *pipelineCache);
uint32_t computePrimitiveCount(uint32_t vertexCount) const;
const sw::Context &getContext() const;
const VkRect2D &getScissor() const;
const VkViewport &getViewport() const;
const sw::float4 &getBlendConstants() const;
bool hasDynamicState(VkDynamicState dynamicState) const;
bool hasPrimitiveRestartEnable() const { return primitiveRestartEnable; }
const GraphicsState getState(const DynamicState &ds) const { return state.combineStates(ds); }
void getIndexBuffers(uint32_t count, uint32_t first, bool indexed, std::vector<std::pair<uint32_t, void *>> *indexBuffers) const;
IndexBuffer &getIndexBuffer() { return indexBuffer; }
const IndexBuffer &getIndexBuffer() const { return indexBuffer; }
Attachments &getAttachments() { return attachments; }
const Attachments &getAttachments() const { return attachments; }
Inputs &getInputs() { return inputs; }
const Inputs &getInputs() const { return inputs; }
bool containsImageWrite() const;
const std::shared_ptr<sw::SpirvShader> getShader(const VkShaderStageFlagBits &stage) const;
private:
void setShader(const VkShaderStageFlagBits &stage, const std::shared_ptr<sw::SpirvShader> spirvShader);
const std::shared_ptr<sw::SpirvShader> getShader(const VkShaderStageFlagBits &stage) const;
std::shared_ptr<sw::SpirvShader> vertexShader;
std::shared_ptr<sw::SpirvShader> fragmentShader;
uint32_t dynamicStateFlags = 0;
bool primitiveRestartEnable = false;
sw::Context context;
VkRect2D scissor;
VkViewport viewport;
sw::float4 blendConstants;
const GraphicsState state;
IndexBuffer indexBuffer;
Attachments attachments;
Inputs inputs;
};
class ComputePipeline : public Pipeline, public ObjectBase<ComputePipeline, VkPipeline>
......@@ -141,7 +146,7 @@ public:
vk::DescriptorSet::Array const &descriptorSetObjects,
vk::DescriptorSet::Bindings const &descriptorSets,
vk::DescriptorSet::DynamicOffsets const &descriptorDynamicOffsets,
sw::PushConstantStorage const &pushConstants);
vk::Pipeline::PushConstantStorage const &pushConstants);
protected:
std::shared_ptr<sw::SpirvShader> shader;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment