Commit 3c424b48 by Jamie Madill Committed by Commit Bot

Vulkan: Add vk_cache_utils.h.

This file contains the Pipeline and RenderPass cache utils. Also renames renderervk_utils.h to vk_utils.h and the format utils file. Refactoring change only. Bug: angleproject:2163 Change-Id: I5113a9a2c6f0b0960d38e6c2d8e391fa2d9f5f6a Reviewed-on: https://chromium-review.googlesource.com/876505Reviewed-by: 's avatarFrank Henigman <fjhenigman@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 4e36db8c
......@@ -11,7 +11,7 @@
#define LIBANGLE_RENDERER_VULKAN_BUFFERVK_H_
#include "libANGLE/renderer/BufferImpl.h"
#include "libANGLE/renderer/vulkan/renderervk_utils.h"
#include "libANGLE/renderer/vulkan/vk_utils.h"
namespace rx
{
......
......@@ -11,7 +11,7 @@
#include "libANGLE/renderer/vulkan/RenderTargetVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/formatutilsvk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h"
namespace rx
{
......
......@@ -10,7 +10,7 @@
#ifndef LIBANGLE_RENDERER_VULKAN_COMMAND_BUFFER_NODE_H_
#define LIBANGLE_RENDERER_VULKAN_COMMAND_BUFFER_NODE_H_
#include "libANGLE/renderer/vulkan/renderervk_utils.h"
#include "libANGLE/renderer/vulkan/vk_cache_utils.h"
namespace rx
{
......
......@@ -32,7 +32,7 @@
#include "libANGLE/renderer/vulkan/TextureVk.h"
#include "libANGLE/renderer/vulkan/TransformFeedbackVk.h"
#include "libANGLE/renderer/vulkan/VertexArrayVk.h"
#include "libANGLE/renderer/vulkan/formatutilsvk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h"
namespace rx
{
......
......@@ -13,7 +13,7 @@
#include <vulkan/vulkan.h>
#include "libANGLE/renderer/ContextImpl.h"
#include "libANGLE/renderer/vulkan/renderervk_utils.h"
#include "libANGLE/renderer/vulkan/vk_cache_utils.h"
namespace rx
{
......
......@@ -24,7 +24,7 @@
#include "libANGLE/renderer/vulkan/RenderTargetVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/SurfaceVk.h"
#include "libANGLE/renderer/vulkan/formatutilsvk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h"
namespace rx
{
......
......@@ -11,7 +11,7 @@
#define LIBANGLE_RENDERER_VULKAN_FRAMEBUFFERVK_H_
#include "libANGLE/renderer/FramebufferImpl.h"
#include "libANGLE/renderer/vulkan/renderervk_utils.h"
#include "libANGLE/renderer/vulkan/vk_cache_utils.h"
namespace rx
{
......
......@@ -12,7 +12,7 @@
#include "libANGLE/Constants.h"
#include "libANGLE/renderer/ProgramImpl.h"
#include "libANGLE/renderer/vulkan/renderervk_utils.h"
#include "libANGLE/renderer/vulkan/vk_utils.h"
#include <array>
......
......@@ -10,7 +10,7 @@
#include "libANGLE/renderer/vulkan/RendererVk.h"
// Placing this first seems to solve an intellisense bug.
#include "libANGLE/renderer/vulkan/renderervk_utils.h"
#include "libANGLE/renderer/vulkan/vk_utils.h"
#include <EGL/eglext.h>
......@@ -23,7 +23,7 @@
#include "libANGLE/renderer/vulkan/GlslangWrapper.h"
#include "libANGLE/renderer/vulkan/TextureVk.h"
#include "libANGLE/renderer/vulkan/VertexArrayVk.h"
#include "libANGLE/renderer/vulkan/formatutilsvk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h"
#include "platform/Platform.h"
namespace rx
......@@ -85,101 +85,6 @@ VkBool32 VKAPI_CALL DebugReportCallback(VkDebugReportFlagsEXT flags,
} // anonymous namespace
// RenderPassCache implementation.
RenderPassCache::RenderPassCache()
{
}
RenderPassCache::~RenderPassCache()
{
ASSERT(mPayload.empty());
}
void RenderPassCache::destroy(VkDevice device)
{
for (auto &outerIt : mPayload)
{
for (auto &innerIt : outerIt.second)
{
innerIt.second.get().destroy(device);
}
}
mPayload.clear();
}
vk::Error RenderPassCache::getCompatibleRenderPass(VkDevice device,
Serial serial,
const vk::RenderPassDesc &desc,
vk::RenderPass **renderPassOut)
{
auto outerIt = mPayload.find(desc);
if (outerIt != mPayload.end())
{
InnerCache &innerCache = outerIt->second;
ASSERT(!innerCache.empty());
// Find the first element and return it.
*renderPassOut = &innerCache.begin()->second.get();
return vk::NoError();
}
// Insert some dummy attachment ops.
// TODO(jmadill): Pre-populate the cache in the Renderer so we rarely miss here.
vk::AttachmentOpsArray ops;
for (uint32_t colorIndex = 0; colorIndex < desc.colorAttachmentCount(); ++colorIndex)
{
ops.initDummyOp(colorIndex, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
}
if (desc.depthStencilAttachmentCount() > 0)
{
ops.initDummyOp(desc.colorAttachmentCount(),
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
}
return getRenderPassWithOps(device, serial, desc, ops, renderPassOut);
}
vk::Error RenderPassCache::getRenderPassWithOps(VkDevice device,
Serial serial,
const vk::RenderPassDesc &desc,
const vk::AttachmentOpsArray &attachmentOps,
vk::RenderPass **renderPassOut)
{
auto outerIt = mPayload.find(desc);
if (outerIt != mPayload.end())
{
InnerCache &innerCache = outerIt->second;
auto innerIt = innerCache.find(attachmentOps);
if (innerIt != innerCache.end())
{
// Update the serial before we return.
// TODO(jmadill): Could possibly use an MRU cache here.
innerIt->second.updateSerial(serial);
*renderPassOut = &innerIt->second.get();
return vk::NoError();
}
}
else
{
auto emplaceResult = mPayload.emplace(desc, InnerCache());
outerIt = emplaceResult.first;
}
vk::RenderPass newRenderPass;
ANGLE_TRY(vk::InitializeRenderPassFromDesc(device, desc, attachmentOps, &newRenderPass));
vk::RenderPassAndSerial withSerial(std::move(newRenderPass), serial);
InnerCache &innerCache = outerIt->second;
auto insertPos = innerCache.emplace(attachmentOps, std::move(withSerial));
*renderPassOut = &insertPos.first->second.get();
// TODO(jmadill): Trim cache, and pre-populate with the most common RPs on startup.
return vk::NoError();
}
// CommandBatch implementation.
RendererVk::CommandBatch::CommandBatch()
{
......
......@@ -15,8 +15,8 @@
#include "common/angleutils.h"
#include "libANGLE/Caps.h"
#include "libANGLE/renderer/vulkan/formatutilsvk.h"
#include "libANGLE/renderer/vulkan/renderervk_utils.h"
#include "libANGLE/renderer/vulkan/vk_cache_utils.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h"
namespace egl
{
......@@ -33,34 +33,6 @@ namespace vk
struct Format;
}
// TODO(jmadill): Add cache trimming.
class RenderPassCache
{
public:
RenderPassCache();
~RenderPassCache();
void destroy(VkDevice device);
vk::Error getCompatibleRenderPass(VkDevice device,
Serial serial,
const vk::RenderPassDesc &desc,
vk::RenderPass **renderPassOut);
vk::Error getRenderPassWithOps(VkDevice device,
Serial serial,
const vk::RenderPassDesc &desc,
const vk::AttachmentOpsArray &attachmentOps,
vk::RenderPass **renderPassOut);
private:
// Use a two-layer caching scheme. The top level matches the "compatible" RenderPass elements.
// The second layer caches the attachment load/store ops and initial/final layout.
using InnerCache = std::unordered_map<vk::AttachmentOpsArray, vk::RenderPassAndSerial>;
using OuterCache = std::unordered_map<vk::RenderPassDesc, InnerCache>;
OuterCache mPayload;
};
class RendererVk : angle::NonCopyable
{
public:
......
......@@ -16,7 +16,7 @@
#include "libANGLE/renderer/vulkan/DisplayVk.h"
#include "libANGLE/renderer/vulkan/FramebufferVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/formatutilsvk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h"
namespace rx
{
......
......@@ -14,7 +14,7 @@
#include "libANGLE/renderer/SurfaceImpl.h"
#include "libANGLE/renderer/vulkan/RenderTargetVk.h"
#include "libANGLE/renderer/vulkan/renderervk_utils.h"
#include "libANGLE/renderer/vulkan/vk_utils.h"
namespace rx
{
......
......@@ -13,7 +13,7 @@
#include "libANGLE/Context.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/formatutilsvk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h"
namespace rx
{
......
......@@ -12,7 +12,7 @@
#include "libANGLE/renderer/TextureImpl.h"
#include "libANGLE/renderer/vulkan/RenderTargetVk.h"
#include "libANGLE/renderer/vulkan/renderervk_utils.h"
#include "libANGLE/renderer/vulkan/vk_utils.h"
namespace rx
{
......
......@@ -15,7 +15,7 @@
#include "libANGLE/renderer/vulkan/BufferVk.h"
#include "libANGLE/renderer/vulkan/CommandBufferNode.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/formatutilsvk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h"
namespace rx
{
......
......@@ -11,10 +11,15 @@
#define LIBANGLE_RENDERER_VULKAN_VERTEXARRAYVK_H_
#include "libANGLE/renderer/VertexArrayImpl.h"
#include "libANGLE/renderer/vulkan/renderervk_utils.h"
#include "libANGLE/renderer/vulkan/vk_utils.h"
namespace rx
{
namespace vk
{
class PipelineDesc;
} // namespace vk
class BufferVk;
class VertexArrayVk : public VertexArrayImpl
......
//
// Copyright 2018 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// vk_cache_utils.cpp:
// Contains the classes for the Pipeline State Object cache as well as the RenderPass cache.
// Also contains the structures for the packed descriptions for the RenderPass and Pipeline.
//
#include "libANGLE/renderer/vulkan/vk_cache_utils.h"
#include "common/aligned_memory.h"
#include "libANGLE/SizedMRUCache.h"
#include "libANGLE/VertexAttribute.h"
#include "libANGLE/renderer/vulkan/ProgramVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h"
namespace rx
{
namespace vk
{
namespace
{
VkSampleCountFlagBits ConvertSamples(GLint sampleCount)
{
switch (sampleCount)
{
case 0:
case 1:
return VK_SAMPLE_COUNT_1_BIT;
case 2:
return VK_SAMPLE_COUNT_2_BIT;
case 4:
return VK_SAMPLE_COUNT_4_BIT;
case 8:
return VK_SAMPLE_COUNT_8_BIT;
case 16:
return VK_SAMPLE_COUNT_16_BIT;
case 32:
return VK_SAMPLE_COUNT_32_BIT;
default:
UNREACHABLE();
return VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM;
}
}
void UnpackAttachmentDesc(VkAttachmentDescription *desc,
const vk::PackedAttachmentDesc &packedDesc,
const vk::PackedAttachmentOpsDesc &ops)
{
desc->flags = static_cast<VkAttachmentDescriptionFlags>(packedDesc.flags);
desc->format = static_cast<VkFormat>(packedDesc.format);
desc->samples = ConvertSamples(packedDesc.samples);
desc->loadOp = static_cast<VkAttachmentLoadOp>(ops.loadOp);
desc->storeOp = static_cast<VkAttachmentStoreOp>(ops.storeOp);
desc->stencilLoadOp = static_cast<VkAttachmentLoadOp>(ops.stencilLoadOp);
desc->stencilStoreOp = static_cast<VkAttachmentStoreOp>(ops.stencilStoreOp);
desc->initialLayout = static_cast<VkImageLayout>(ops.initialLayout);
desc->finalLayout = static_cast<VkImageLayout>(ops.finalLayout);
}
void UnpackStencilState(const vk::PackedStencilOpState &packedState, VkStencilOpState *stateOut)
{
stateOut->failOp = static_cast<VkStencilOp>(packedState.failOp);
stateOut->passOp = static_cast<VkStencilOp>(packedState.passOp);
stateOut->depthFailOp = static_cast<VkStencilOp>(packedState.depthFailOp);
stateOut->compareOp = static_cast<VkCompareOp>(packedState.compareOp);
stateOut->compareMask = packedState.compareMask;
stateOut->writeMask = packedState.writeMask;
stateOut->reference = packedState.reference;
}
void UnpackBlendAttachmentState(vk::PackedColorBlendAttachmentState &packedState,
VkPipelineColorBlendAttachmentState *stateOut)
{
stateOut->blendEnable = static_cast<VkBool32>(packedState.blendEnable);
stateOut->srcColorBlendFactor = static_cast<VkBlendFactor>(packedState.srcColorBlendFactor);
stateOut->dstColorBlendFactor = static_cast<VkBlendFactor>(packedState.dstColorBlendFactor);
stateOut->colorBlendOp = static_cast<VkBlendOp>(packedState.colorBlendOp);
stateOut->srcAlphaBlendFactor = static_cast<VkBlendFactor>(packedState.srcAlphaBlendFactor);
stateOut->dstAlphaBlendFactor = static_cast<VkBlendFactor>(packedState.dstAlphaBlendFactor);
stateOut->alphaBlendOp = static_cast<VkBlendOp>(packedState.alphaBlendOp);
stateOut->colorWriteMask = static_cast<VkColorComponentFlags>(packedState.colorWriteMask);
}
Error InitializeRenderPassFromDesc(VkDevice device,
const RenderPassDesc &desc,
const AttachmentOpsArray &ops,
RenderPass *renderPass)
{
uint32_t attachmentCount = desc.attachmentCount();
ASSERT(attachmentCount > 0);
gl::DrawBuffersArray<VkAttachmentReference> colorAttachmentRefs;
for (uint32_t colorIndex = 0; colorIndex < desc.colorAttachmentCount(); ++colorIndex)
{
VkAttachmentReference &colorRef = colorAttachmentRefs[colorIndex];
colorRef.attachment = colorIndex;
colorRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
}
VkAttachmentReference depthStencilAttachmentRef;
if (desc.depthStencilAttachmentCount() > 0)
{
ASSERT(desc.depthStencilAttachmentCount() == 1);
depthStencilAttachmentRef.attachment = desc.colorAttachmentCount();
depthStencilAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
}
VkSubpassDescription subpassDesc;
subpassDesc.flags = 0;
subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpassDesc.inputAttachmentCount = 0;
subpassDesc.pInputAttachments = nullptr;
subpassDesc.colorAttachmentCount = desc.colorAttachmentCount();
subpassDesc.pColorAttachments = colorAttachmentRefs.data();
subpassDesc.pResolveAttachments = nullptr;
subpassDesc.pDepthStencilAttachment =
(desc.depthStencilAttachmentCount() > 0 ? &depthStencilAttachmentRef : nullptr);
subpassDesc.preserveAttachmentCount = 0;
subpassDesc.pPreserveAttachments = nullptr;
// Unpack the packed and split representation into the format required by Vulkan.
gl::AttachmentArray<VkAttachmentDescription> attachmentDescs;
for (uint32_t colorIndex = 0; colorIndex < desc.colorAttachmentCount(); ++colorIndex)
{
UnpackAttachmentDesc(&attachmentDescs[colorIndex], desc[colorIndex], ops[colorIndex]);
}
if (desc.depthStencilAttachmentCount() > 0)
{
uint32_t depthStencilIndex = desc.colorAttachmentCount();
UnpackAttachmentDesc(&attachmentDescs[depthStencilIndex], desc[depthStencilIndex],
ops[depthStencilIndex]);
}
VkRenderPassCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.attachmentCount = attachmentCount;
createInfo.pAttachments = attachmentDescs.data();
createInfo.subpassCount = 1;
createInfo.pSubpasses = &subpassDesc;
createInfo.dependencyCount = 0;
createInfo.pDependencies = nullptr;
ANGLE_TRY(renderPass->init(device, createInfo));
return vk::NoError();
}
} // anonymous namespace
// RenderPassDesc implementation.
RenderPassDesc::RenderPassDesc()
{
UNUSED_VARIABLE(mPadding);
memset(this, 0, sizeof(RenderPassDesc));
}
RenderPassDesc::~RenderPassDesc()
{
}
RenderPassDesc::RenderPassDesc(const RenderPassDesc &other)
{
memcpy(this, &other, sizeof(RenderPassDesc));
}
void RenderPassDesc::packAttachment(uint32_t index, const vk::Format &format, GLsizei samples)
{
PackedAttachmentDesc &desc = mAttachmentDescs[index];
// TODO(jmadill): We would only need this flag for duplicated attachments.
desc.flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT;
ASSERT(desc.samples < std::numeric_limits<uint8_t>::max());
desc.samples = static_cast<uint8_t>(samples);
ASSERT(format.vkTextureFormat < std::numeric_limits<uint16_t>::max());
desc.format = static_cast<uint16_t>(format.vkTextureFormat);
}
void RenderPassDesc::packColorAttachment(const vk::Format &format, GLsizei samples)
{
ASSERT(mDepthStencilAttachmentCount == 0);
ASSERT(mColorAttachmentCount < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS);
packAttachment(mColorAttachmentCount++, format, samples);
}
void RenderPassDesc::packDepthStencilAttachment(const vk::Format &format, GLsizei samples)
{
ASSERT(mDepthStencilAttachmentCount == 0);
packAttachment(mDepthStencilAttachmentCount++, format, samples);
}
RenderPassDesc &RenderPassDesc::operator=(const RenderPassDesc &other)
{
memcpy(this, &other, sizeof(RenderPassDesc));
return *this;
}
size_t RenderPassDesc::hash() const
{
return angle::ComputeGenericHash(*this);
}
uint32_t RenderPassDesc::attachmentCount() const
{
return (mColorAttachmentCount + mDepthStencilAttachmentCount);
}
uint32_t RenderPassDesc::colorAttachmentCount() const
{
return mColorAttachmentCount;
}
uint32_t RenderPassDesc::depthStencilAttachmentCount() const
{
return mDepthStencilAttachmentCount;
}
const PackedAttachmentDesc &RenderPassDesc::operator[](size_t index) const
{
ASSERT(index < mAttachmentDescs.size());
return mAttachmentDescs[index];
}
bool operator==(const RenderPassDesc &lhs, const RenderPassDesc &rhs)
{
return (memcmp(&lhs, &rhs, sizeof(RenderPassDesc)) == 0);
}
// PipelineDesc implementation.
// Use aligned allocation and free so we can use the alignas keyword.
void *PipelineDesc::operator new(std::size_t size)
{
return angle::AlignedAlloc(size, 32);
}
void PipelineDesc::operator delete(void *ptr)
{
return angle::AlignedFree(ptr);
}
PipelineDesc::PipelineDesc()
{
memset(this, 0, sizeof(PipelineDesc));
}
PipelineDesc::~PipelineDesc()
{
}
PipelineDesc::PipelineDesc(const PipelineDesc &other)
{
memcpy(this, &other, sizeof(PipelineDesc));
}
PipelineDesc &PipelineDesc::operator=(const PipelineDesc &other)
{
memcpy(this, &other, sizeof(PipelineDesc));
return *this;
}
size_t PipelineDesc::hash() const
{
return angle::ComputeGenericHash(*this);
}
bool PipelineDesc::operator==(const PipelineDesc &other) const
{
return (memcmp(this, &other, sizeof(PipelineDesc)) == 0);
}
void PipelineDesc::initDefaults()
{
mInputAssemblyInfo.topology = static_cast<uint32_t>(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
mInputAssemblyInfo.primitiveRestartEnable = 0;
mRasterizationStateInfo.depthClampEnable = 0;
mRasterizationStateInfo.rasterizationDiscardEnable = 0;
mRasterizationStateInfo.polygonMode = static_cast<uint16_t>(VK_POLYGON_MODE_FILL);
mRasterizationStateInfo.cullMode = static_cast<uint16_t>(VK_CULL_MODE_NONE);
mRasterizationStateInfo.frontFace = static_cast<uint16_t>(VK_FRONT_FACE_CLOCKWISE);
mRasterizationStateInfo.depthBiasEnable = 0;
mRasterizationStateInfo.depthBiasConstantFactor = 0.0f;
mRasterizationStateInfo.depthBiasClamp = 0.0f;
mRasterizationStateInfo.depthBiasSlopeFactor = 0.0f;
mRasterizationStateInfo.lineWidth = 1.0f;
mMultisampleStateInfo.rasterizationSamples = 1;
mMultisampleStateInfo.sampleShadingEnable = 0;
mMultisampleStateInfo.minSampleShading = 0.0f;
for (int maskIndex = 0; maskIndex < gl::MAX_SAMPLE_MASK_WORDS; ++maskIndex)
{
mMultisampleStateInfo.sampleMask[maskIndex] = 0;
}
mMultisampleStateInfo.alphaToCoverageEnable = 0;
mMultisampleStateInfo.alphaToOneEnable = 0;
mDepthStencilStateInfo.depthTestEnable = 0;
mDepthStencilStateInfo.depthWriteEnable = 1;
mDepthStencilStateInfo.depthCompareOp = static_cast<uint8_t>(VK_COMPARE_OP_LESS);
mDepthStencilStateInfo.depthBoundsTestEnable = 0;
mDepthStencilStateInfo.stencilTestEnable = 0;
mDepthStencilStateInfo.minDepthBounds = 0.0f;
mDepthStencilStateInfo.maxDepthBounds = 0.0f;
mDepthStencilStateInfo.front.failOp = static_cast<uint8_t>(VK_STENCIL_OP_KEEP);
mDepthStencilStateInfo.front.passOp = static_cast<uint8_t>(VK_STENCIL_OP_KEEP);
mDepthStencilStateInfo.front.depthFailOp = static_cast<uint8_t>(VK_STENCIL_OP_KEEP);
mDepthStencilStateInfo.front.compareOp = static_cast<uint8_t>(VK_COMPARE_OP_ALWAYS);
mDepthStencilStateInfo.front.compareMask = static_cast<uint32_t>(-1);
mDepthStencilStateInfo.front.writeMask = static_cast<uint32_t>(-1);
mDepthStencilStateInfo.front.reference = 0;
mDepthStencilStateInfo.back.failOp = static_cast<uint8_t>(VK_STENCIL_OP_KEEP);
mDepthStencilStateInfo.back.passOp = static_cast<uint8_t>(VK_STENCIL_OP_KEEP);
mDepthStencilStateInfo.back.depthFailOp = static_cast<uint8_t>(VK_STENCIL_OP_KEEP);
mDepthStencilStateInfo.back.compareOp = static_cast<uint8_t>(VK_COMPARE_OP_ALWAYS);
mDepthStencilStateInfo.back.compareMask = static_cast<uint32_t>(-1);
mDepthStencilStateInfo.back.writeMask = static_cast<uint32_t>(-1);
mDepthStencilStateInfo.back.reference = 0;
// TODO(jmadill): Blend state/MRT.
PackedColorBlendAttachmentState blendAttachmentState;
blendAttachmentState.blendEnable = 0;
blendAttachmentState.srcColorBlendFactor = static_cast<uint8_t>(VK_BLEND_FACTOR_ONE);
blendAttachmentState.dstColorBlendFactor = static_cast<uint8_t>(VK_BLEND_FACTOR_ONE);
blendAttachmentState.colorBlendOp = static_cast<uint8_t>(VK_BLEND_OP_ADD);
blendAttachmentState.srcAlphaBlendFactor = static_cast<uint8_t>(VK_BLEND_FACTOR_ONE);
blendAttachmentState.dstAlphaBlendFactor = static_cast<uint8_t>(VK_BLEND_FACTOR_ONE);
blendAttachmentState.alphaBlendOp = static_cast<uint8_t>(VK_BLEND_OP_ADD);
blendAttachmentState.colorWriteMask =
static_cast<uint8_t>(VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
mColorBlendStateInfo.logicOpEnable = 0;
mColorBlendStateInfo.logicOp = static_cast<uint32_t>(VK_LOGIC_OP_CLEAR);
mColorBlendStateInfo.attachmentCount = 1;
mColorBlendStateInfo.blendConstants[0] = 0.0f;
mColorBlendStateInfo.blendConstants[1] = 0.0f;
mColorBlendStateInfo.blendConstants[2] = 0.0f;
mColorBlendStateInfo.blendConstants[3] = 0.0f;
std::fill(&mColorBlendStateInfo.attachments[0],
&mColorBlendStateInfo.attachments[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS],
blendAttachmentState);
}
Error PipelineDesc::initializePipeline(RendererVk *renderer,
ProgramVk *programVk,
Pipeline *pipelineOut)
{
VkPipelineShaderStageCreateInfo shaderStages[2];
VkPipelineVertexInputStateCreateInfo vertexInputState;
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState;
VkPipelineViewportStateCreateInfo viewportState;
VkPipelineRasterizationStateCreateInfo rasterState;
VkPipelineMultisampleStateCreateInfo multisampleState;
VkPipelineDepthStencilStateCreateInfo depthStencilState;
std::array<VkPipelineColorBlendAttachmentState, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS>
blendAttachmentState;
VkPipelineColorBlendStateCreateInfo blendState;
VkGraphicsPipelineCreateInfo createInfo;
ASSERT(programVk->getVertexModuleSerial() == mShaderStageInfo[0].moduleSerial);
shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
shaderStages[0].pNext = nullptr;
shaderStages[0].flags = 0;
shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
shaderStages[0].module = programVk->getLinkedVertexModule().getHandle();
shaderStages[0].pName = "main";
shaderStages[0].pSpecializationInfo = nullptr;
ASSERT(programVk->getFragmentModuleSerial() == mShaderStageInfo[1].moduleSerial);
shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
shaderStages[1].pNext = nullptr;
shaderStages[1].flags = 0;
shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
shaderStages[1].module = programVk->getLinkedFragmentModule().getHandle();
shaderStages[1].pName = "main";
shaderStages[1].pSpecializationInfo = nullptr;
// TODO(jmadill): Possibly use different path for ES 3.1 split bindings/attribs.
gl::AttribArray<VkVertexInputBindingDescription> bindingDescs;
gl::AttribArray<VkVertexInputAttributeDescription> attributeDescs;
uint32_t vertexAttribCount = 0;
for (uint32_t attribIndex = 0; attribIndex < gl::MAX_VERTEX_ATTRIBS; ++attribIndex)
{
VkVertexInputBindingDescription &bindingDesc = bindingDescs[attribIndex];
VkVertexInputAttributeDescription &attribDesc = attributeDescs[attribIndex];
const PackedVertexInputBindingDesc &packedBinding = mVertexInputBindings[attribIndex];
const PackedVertexInputAttributeDesc &packedAttrib = mVertexInputAttribs[attribIndex];
// TODO(jmadill): Support for gaps in vertex attribute specification.
if (packedAttrib.format == 0)
continue;
vertexAttribCount = attribIndex + 1;
bindingDesc.binding = attribIndex;
bindingDesc.inputRate = static_cast<VkVertexInputRate>(packedBinding.inputRate);
bindingDesc.stride = static_cast<uint32_t>(packedBinding.stride);
attribDesc.binding = attribIndex;
attribDesc.format = static_cast<VkFormat>(packedAttrib.format);
attribDesc.location = static_cast<uint32_t>(packedAttrib.location);
attribDesc.offset = packedAttrib.offset;
}
// The binding descriptions are filled in at draw time.
vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertexInputState.pNext = nullptr;
vertexInputState.flags = 0;
vertexInputState.vertexBindingDescriptionCount = vertexAttribCount;
vertexInputState.pVertexBindingDescriptions = bindingDescs.data();
vertexInputState.vertexAttributeDescriptionCount = vertexAttribCount;
vertexInputState.pVertexAttributeDescriptions = attributeDescs.data();
// Primitive topology is filled in at draw time.
inputAssemblyState.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssemblyState.pNext = nullptr;
inputAssemblyState.flags = 0;
inputAssemblyState.topology = static_cast<VkPrimitiveTopology>(mInputAssemblyInfo.topology);
inputAssemblyState.primitiveRestartEnable =
static_cast<VkBool32>(mInputAssemblyInfo.primitiveRestartEnable);
// Set initial viewport and scissor state.
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportState.pNext = nullptr;
viewportState.flags = 0;
viewportState.viewportCount = 1;
viewportState.pViewports = &mViewport;
viewportState.scissorCount = 1;
viewportState.pScissors = &mScissor;
// Rasterizer state.
rasterState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterState.pNext = nullptr;
rasterState.flags = 0;
rasterState.depthClampEnable = static_cast<VkBool32>(mRasterizationStateInfo.depthClampEnable);
rasterState.rasterizerDiscardEnable =
static_cast<VkBool32>(mRasterizationStateInfo.rasterizationDiscardEnable);
rasterState.polygonMode = static_cast<VkPolygonMode>(mRasterizationStateInfo.polygonMode);
rasterState.cullMode = static_cast<VkCullModeFlags>(mRasterizationStateInfo.cullMode);
rasterState.frontFace = static_cast<VkFrontFace>(mRasterizationStateInfo.frontFace);
rasterState.depthBiasEnable = static_cast<VkBool32>(mRasterizationStateInfo.depthBiasEnable);
rasterState.depthBiasConstantFactor = mRasterizationStateInfo.depthBiasConstantFactor;
rasterState.depthBiasClamp = mRasterizationStateInfo.depthBiasClamp;
rasterState.depthBiasSlopeFactor = mRasterizationStateInfo.depthBiasSlopeFactor;
rasterState.lineWidth = mRasterizationStateInfo.lineWidth;
// Multisample state.
multisampleState.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampleState.pNext = nullptr;
multisampleState.flags = 0;
multisampleState.rasterizationSamples =
ConvertSamples(mMultisampleStateInfo.rasterizationSamples);
multisampleState.sampleShadingEnable =
static_cast<VkBool32>(mMultisampleStateInfo.sampleShadingEnable);
multisampleState.minSampleShading = mMultisampleStateInfo.minSampleShading;
// TODO(jmadill): sample masks
multisampleState.pSampleMask = nullptr;
multisampleState.alphaToCoverageEnable =
static_cast<VkBool32>(mMultisampleStateInfo.alphaToCoverageEnable);
multisampleState.alphaToOneEnable =
static_cast<VkBool32>(mMultisampleStateInfo.alphaToOneEnable);
// Depth/stencil state.
depthStencilState.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depthStencilState.pNext = nullptr;
depthStencilState.flags = 0;
depthStencilState.depthTestEnable =
static_cast<VkBool32>(mDepthStencilStateInfo.depthTestEnable);
depthStencilState.depthWriteEnable =
static_cast<VkBool32>(mDepthStencilStateInfo.depthWriteEnable);
depthStencilState.depthCompareOp =
static_cast<VkCompareOp>(mDepthStencilStateInfo.depthCompareOp);
depthStencilState.depthBoundsTestEnable =
static_cast<VkBool32>(mDepthStencilStateInfo.depthBoundsTestEnable);
depthStencilState.stencilTestEnable =
static_cast<VkBool32>(mDepthStencilStateInfo.stencilTestEnable);
UnpackStencilState(mDepthStencilStateInfo.front, &depthStencilState.front);
UnpackStencilState(mDepthStencilStateInfo.back, &depthStencilState.back);
depthStencilState.minDepthBounds = mDepthStencilStateInfo.minDepthBounds;
depthStencilState.maxDepthBounds = mDepthStencilStateInfo.maxDepthBounds;
blendState.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
blendState.pNext = 0;
blendState.flags = 0;
blendState.logicOpEnable = static_cast<VkBool32>(mColorBlendStateInfo.logicOpEnable);
blendState.logicOp = static_cast<VkLogicOp>(mColorBlendStateInfo.logicOp);
blendState.attachmentCount = mColorBlendStateInfo.attachmentCount;
blendState.pAttachments = blendAttachmentState.data();
for (int i = 0; i < 4; i++)
{
blendState.blendConstants[i] = mColorBlendStateInfo.blendConstants[i];
}
for (uint32_t colorIndex = 0; colorIndex < blendState.attachmentCount; ++colorIndex)
{
UnpackBlendAttachmentState(mColorBlendStateInfo.attachments[colorIndex],
&blendAttachmentState[colorIndex]);
}
// TODO(jmadill): Dynamic state.
// Pull in a compatible RenderPass.
RenderPass *compatibleRenderPass = nullptr;
ANGLE_TRY(renderer->getCompatibleRenderPass(mRenderPassDesc, &compatibleRenderPass));
createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.stageCount = 2;
createInfo.pStages = shaderStages;
createInfo.pVertexInputState = &vertexInputState;
createInfo.pInputAssemblyState = &inputAssemblyState;
createInfo.pTessellationState = nullptr;
createInfo.pViewportState = &viewportState;
createInfo.pRasterizationState = &rasterState;
createInfo.pMultisampleState = &multisampleState;
createInfo.pDepthStencilState = &depthStencilState;
createInfo.pColorBlendState = &blendState;
createInfo.pDynamicState = nullptr;
createInfo.layout = renderer->getGraphicsPipelineLayout().getHandle();
createInfo.renderPass = compatibleRenderPass->getHandle();
createInfo.subpass = 0;
createInfo.basePipelineHandle = VK_NULL_HANDLE;
createInfo.basePipelineIndex = 0;
ANGLE_TRY(pipelineOut->initGraphics(renderer->getDevice(), createInfo));
return NoError();
}
void PipelineDesc::updateShaders(ProgramVk *programVk)
{
ASSERT(programVk->getVertexModuleSerial() < std::numeric_limits<uint32_t>::max());
mShaderStageInfo[0].moduleSerial =
static_cast<uint32_t>(programVk->getVertexModuleSerial().getValue());
ASSERT(programVk->getFragmentModuleSerial() < std::numeric_limits<uint32_t>::max());
mShaderStageInfo[1].moduleSerial =
static_cast<uint32_t>(programVk->getFragmentModuleSerial().getValue());
}
void PipelineDesc::updateViewport(const gl::Rectangle &viewport, float nearPlane, float farPlane)
{
mViewport.x = static_cast<float>(viewport.x);
mViewport.y = static_cast<float>(viewport.y);
mViewport.width = static_cast<float>(viewport.width);
mViewport.height = static_cast<float>(viewport.height);
mViewport.minDepth = nearPlane;
mViewport.maxDepth = farPlane;
// TODO(jmadill): Scissor.
mScissor.offset.x = viewport.x;
mScissor.offset.y = viewport.y;
mScissor.extent.width = viewport.width;
mScissor.extent.height = viewport.height;
}
void PipelineDesc::resetVertexInputState()
{
memset(&mVertexInputBindings, 0, sizeof(VertexInputBindings));
memset(&mVertexInputAttribs, 0, sizeof(VertexInputAttributes));
}
void PipelineDesc::updateVertexInputInfo(uint32_t attribIndex,
const gl::VertexBinding &binding,
const gl::VertexAttribute &attrib)
{
PackedVertexInputBindingDesc &bindingDesc = mVertexInputBindings[attribIndex];
size_t attribSize = gl::ComputeVertexAttributeTypeSize(attrib);
ASSERT(attribSize <= std::numeric_limits<uint16_t>::max());
bindingDesc.stride = static_cast<uint16_t>(attribSize);
bindingDesc.inputRate = static_cast<uint16_t>(
binding.getDivisor() > 0 ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX);
gl::VertexFormatType vertexFormatType = gl::GetVertexFormatType(attrib);
VkFormat vkFormat = vk::GetNativeVertexFormat(vertexFormatType);
ASSERT(vkFormat <= std::numeric_limits<uint16_t>::max());
PackedVertexInputAttributeDesc &attribDesc = mVertexInputAttribs[attribIndex];
attribDesc.format = static_cast<uint16_t>(vkFormat);
attribDesc.location = static_cast<uint16_t>(attribIndex);
attribDesc.offset = static_cast<uint32_t>(ComputeVertexAttributeOffset(attrib, binding));
}
void PipelineDesc::updateTopology(GLenum drawMode)
{
mInputAssemblyInfo.topology = static_cast<uint32_t>(gl_vk::GetPrimitiveTopology(drawMode));
}
void PipelineDesc::updateCullMode(const gl::RasterizerState &rasterState)
{
mRasterizationStateInfo.cullMode = static_cast<uint16_t>(gl_vk::GetCullMode(rasterState));
}
void PipelineDesc::updateFrontFace(const gl::RasterizerState &rasterState)
{
mRasterizationStateInfo.frontFace =
static_cast<uint16_t>(gl_vk::GetFrontFace(rasterState.frontFace));
}
void PipelineDesc::updateLineWidth(float lineWidth)
{
mRasterizationStateInfo.lineWidth = lineWidth;
}
void PipelineDesc::updateRenderPassDesc(const RenderPassDesc &renderPassDesc)
{
mRenderPassDesc = renderPassDesc;
}
// AttachmentOpsArray implementation.
AttachmentOpsArray::AttachmentOpsArray()
{
memset(&mOps, 0, sizeof(PackedAttachmentOpsDesc) * mOps.size());
}
AttachmentOpsArray::~AttachmentOpsArray()
{
}
AttachmentOpsArray::AttachmentOpsArray(const AttachmentOpsArray &other)
{
memcpy(&mOps, &other.mOps, sizeof(PackedAttachmentOpsDesc) * mOps.size());
}
AttachmentOpsArray &AttachmentOpsArray::operator=(const AttachmentOpsArray &other)
{
memcpy(&mOps, &other.mOps, sizeof(PackedAttachmentOpsDesc) * mOps.size());
return *this;
}
const PackedAttachmentOpsDesc &AttachmentOpsArray::operator[](size_t index) const
{
return mOps[index];
}
PackedAttachmentOpsDesc &AttachmentOpsArray::operator[](size_t index)
{
return mOps[index];
}
void AttachmentOpsArray::initDummyOp(size_t index, VkImageLayout finalLayout)
{
PackedAttachmentOpsDesc &ops = mOps[index];
ops.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
ops.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
ops.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
ops.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
ops.initialLayout = static_cast<uint16_t>(VK_IMAGE_LAYOUT_UNDEFINED);
ops.finalLayout = static_cast<uint16_t>(finalLayout);
}
size_t AttachmentOpsArray::hash() const
{
return angle::ComputeGenericHash(mOps);
}
bool operator==(const AttachmentOpsArray &lhs, const AttachmentOpsArray &rhs)
{
return (memcmp(&lhs, &rhs, sizeof(AttachmentOpsArray)) == 0);
}
} // namespace vk
// RenderPassCache implementation.
RenderPassCache::RenderPassCache()
{
}
RenderPassCache::~RenderPassCache()
{
ASSERT(mPayload.empty());
}
void RenderPassCache::destroy(VkDevice device)
{
for (auto &outerIt : mPayload)
{
for (auto &innerIt : outerIt.second)
{
innerIt.second.get().destroy(device);
}
}
mPayload.clear();
}
vk::Error RenderPassCache::getCompatibleRenderPass(VkDevice device,
Serial serial,
const vk::RenderPassDesc &desc,
vk::RenderPass **renderPassOut)
{
auto outerIt = mPayload.find(desc);
if (outerIt != mPayload.end())
{
InnerCache &innerCache = outerIt->second;
ASSERT(!innerCache.empty());
// Find the first element and return it.
*renderPassOut = &innerCache.begin()->second.get();
return vk::NoError();
}
// Insert some dummy attachment ops.
// TODO(jmadill): Pre-populate the cache in the Renderer so we rarely miss here.
vk::AttachmentOpsArray ops;
for (uint32_t colorIndex = 0; colorIndex < desc.colorAttachmentCount(); ++colorIndex)
{
ops.initDummyOp(colorIndex, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
}
if (desc.depthStencilAttachmentCount() > 0)
{
ops.initDummyOp(desc.colorAttachmentCount(),
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
}
return getRenderPassWithOps(device, serial, desc, ops, renderPassOut);
}
vk::Error RenderPassCache::getRenderPassWithOps(VkDevice device,
Serial serial,
const vk::RenderPassDesc &desc,
const vk::AttachmentOpsArray &attachmentOps,
vk::RenderPass **renderPassOut)
{
auto outerIt = mPayload.find(desc);
if (outerIt != mPayload.end())
{
InnerCache &innerCache = outerIt->second;
auto innerIt = innerCache.find(attachmentOps);
if (innerIt != innerCache.end())
{
// Update the serial before we return.
// TODO(jmadill): Could possibly use an MRU cache here.
innerIt->second.updateSerial(serial);
*renderPassOut = &innerIt->second.get();
return vk::NoError();
}
}
else
{
auto emplaceResult = mPayload.emplace(desc, InnerCache());
outerIt = emplaceResult.first;
}
vk::RenderPass newRenderPass;
ANGLE_TRY(vk::InitializeRenderPassFromDesc(device, desc, attachmentOps, &newRenderPass));
vk::RenderPassAndSerial withSerial(std::move(newRenderPass), serial);
InnerCache &innerCache = outerIt->second;
auto insertPos = innerCache.emplace(attachmentOps, std::move(withSerial));
*renderPassOut = &insertPos.first->second.get();
// TODO(jmadill): Trim cache, and pre-populate with the most common RPs on startup.
return vk::NoError();
}
} // namespace rx
//
// Copyright 2018 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// vk_cache_utils.h:
// Contains the classes for the Pipeline State Object cache as well as the RenderPass cache.
// Also contains the structures for the packed descriptions for the RenderPass and Pipeline.
//
#ifndef LIBANGLE_RENDERER_VULKAN_VK_CACHE_UTILS_H_
#define LIBANGLE_RENDERER_VULKAN_VK_CACHE_UTILS_H_
#include "libANGLE/renderer/vulkan/vk_utils.h"
namespace rx
{
namespace vk
{
// Packed Vk resource descriptions.
// Most Vk types use many more bits than required to represent the underlying data.
// Since ANGLE wants cache things like RenderPasses and Pipeline State Objects using
// hashing (and also needs to check equality) we can optimize these operations by
// using fewer bits. Hence the packed types.
//
// One implementation note: these types could potentially be improved by using even
// fewer bits. For example, boolean values could be represented by a single bit instead
// of a uint8_t. However at the current time there are concerns about the portability
// of bitfield operators, and complexity issues with using bit mask operations. This is
// something likely we will want to investigate as the Vulkan implementation progresses.
//
// Second implementation note: the struct packing is also a bit fragile, and some of the
// packing requirements depend on using alignas and field ordering to get the result of
// packing nicely into the desired space. This is something we could also potentially fix
// with a redesign to use bitfields or bit mask operations.
struct alignas(4) PackedAttachmentDesc
{
uint8_t flags;
uint8_t samples;
uint16_t format;
};
static_assert(sizeof(PackedAttachmentDesc) == 4, "Size check failed");
class RenderPassDesc final
{
public:
RenderPassDesc();
~RenderPassDesc();
RenderPassDesc(const RenderPassDesc &other);
RenderPassDesc &operator=(const RenderPassDesc &other);
// Depth stencil attachments must be packed after color attachments.
void packColorAttachment(const Format &format, GLsizei samples);
void packDepthStencilAttachment(const Format &format, GLsizei samples);
size_t hash() const;
uint32_t attachmentCount() const;
uint32_t colorAttachmentCount() const;
uint32_t depthStencilAttachmentCount() const;
const PackedAttachmentDesc &operator[](size_t index) const;
private:
void packAttachment(uint32_t index, const vk::Format &format, GLsizei samples);
uint32_t mColorAttachmentCount;
uint32_t mDepthStencilAttachmentCount;
gl::AttachmentArray<PackedAttachmentDesc> mAttachmentDescs;
uint32_t mPadding[4];
};
bool operator==(const RenderPassDesc &lhs, const RenderPassDesc &rhs);
static_assert(sizeof(RenderPassDesc) == 64, "Size check failed");
struct alignas(8) PackedAttachmentOpsDesc final
{
uint8_t loadOp;
uint8_t storeOp;
uint8_t stencilLoadOp;
uint8_t stencilStoreOp;
// 16-bits to force pad the structure to exactly 8 bytes.
uint16_t initialLayout;
uint16_t finalLayout;
};
static_assert(sizeof(PackedAttachmentOpsDesc) == 8, "Size check failed");
class AttachmentOpsArray final
{
public:
AttachmentOpsArray();
~AttachmentOpsArray();
AttachmentOpsArray(const AttachmentOpsArray &other);
AttachmentOpsArray &operator=(const AttachmentOpsArray &other);
const PackedAttachmentOpsDesc &operator[](size_t index) const;
PackedAttachmentOpsDesc &operator[](size_t index);
// Initializes an attachment op with whatever values. Used for compatible RenderPass checks.
void initDummyOp(size_t index, VkImageLayout finalLayout);
size_t hash() const;
private:
gl::AttachmentArray<PackedAttachmentOpsDesc> mOps;
};
bool operator==(const AttachmentOpsArray &lhs, const AttachmentOpsArray &rhs);
static_assert(sizeof(AttachmentOpsArray) == 80, "Size check failed");
struct alignas(8) PackedShaderStageInfo final
{
uint32_t stage;
uint32_t moduleSerial;
// TODO(jmadill): Do we want specialization constants?
};
static_assert(sizeof(PackedShaderStageInfo) == 8, "Size check failed");
struct alignas(4) PackedVertexInputBindingDesc final
{
// Although techncially stride can be any value in ES 2.0, in practice supporting stride
// greater than MAX_USHORT should not be that helpful. Note that stride limits are
// introduced in ES 3.1.
uint16_t stride;
uint16_t inputRate;
};
static_assert(sizeof(PackedVertexInputBindingDesc) == 4, "Size check failed");
struct alignas(8) PackedVertexInputAttributeDesc final
{
uint16_t location;
uint16_t format;
uint32_t offset;
};
static_assert(sizeof(PackedVertexInputAttributeDesc) == 8, "Size check failed");
struct alignas(8) PackedInputAssemblyInfo
{
uint32_t topology;
uint32_t primitiveRestartEnable;
};
static_assert(sizeof(PackedInputAssemblyInfo) == 8, "Size check failed");
struct alignas(32) PackedRasterizationStateInfo
{
// Padded to ensure there's no gaps in this structure or those that use it.
uint32_t depthClampEnable;
uint32_t rasterizationDiscardEnable;
uint16_t polygonMode;
uint16_t cullMode;
uint16_t frontFace;
uint16_t depthBiasEnable;
float depthBiasConstantFactor;
// Note: depth bias clamp is only exposed in a 3.1 extension, but left here for completeness.
float depthBiasClamp;
float depthBiasSlopeFactor;
float lineWidth;
};
static_assert(sizeof(PackedRasterizationStateInfo) == 32, "Size check failed");
struct alignas(16) PackedMultisampleStateInfo final
{
uint8_t rasterizationSamples;
uint8_t sampleShadingEnable;
uint8_t alphaToCoverageEnable;
uint8_t alphaToOneEnable;
float minSampleShading;
uint32_t sampleMask[gl::MAX_SAMPLE_MASK_WORDS];
};
static_assert(sizeof(PackedMultisampleStateInfo) == 16, "Size check failed");
struct alignas(16) PackedStencilOpState final
{
uint8_t failOp;
uint8_t passOp;
uint8_t depthFailOp;
uint8_t compareOp;
uint32_t compareMask;
uint32_t writeMask;
uint32_t reference;
};
static_assert(sizeof(PackedStencilOpState) == 16, "Size check failed");
struct PackedDepthStencilStateInfo final
{
uint8_t depthTestEnable;
uint8_t depthWriteEnable;
uint8_t depthCompareOp;
uint8_t depthBoundsTestEnable;
// 32-bits to pad the alignments.
uint32_t stencilTestEnable;
float minDepthBounds;
float maxDepthBounds;
PackedStencilOpState front;
PackedStencilOpState back;
};
static_assert(sizeof(PackedDepthStencilStateInfo) == 48, "Size check failed");
struct alignas(8) PackedColorBlendAttachmentState final
{
uint8_t blendEnable;
uint8_t srcColorBlendFactor;
uint8_t dstColorBlendFactor;
uint8_t colorBlendOp;
uint8_t srcAlphaBlendFactor;
uint8_t dstAlphaBlendFactor;
uint8_t alphaBlendOp;
uint8_t colorWriteMask;
};
static_assert(sizeof(PackedColorBlendAttachmentState) == 8, "Size check failed");
struct PackedColorBlendStateInfo final
{
// Padded to round the strut size.
uint32_t logicOpEnable;
uint32_t logicOp;
uint32_t attachmentCount;
float blendConstants[4];
PackedColorBlendAttachmentState attachments[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS];
};
static_assert(sizeof(PackedColorBlendStateInfo) == 96, "Size check failed");
using ShaderStageInfo = std::array<PackedShaderStageInfo, 2>;
using VertexInputBindings = gl::AttribArray<PackedVertexInputBindingDesc>;
using VertexInputAttributes = gl::AttribArray<PackedVertexInputAttributeDesc>;
class PipelineDesc final
{
public:
// Use aligned allocation and free so we can use the alignas keyword.
void *operator new(std::size_t size);
void operator delete(void *ptr);
PipelineDesc();
~PipelineDesc();
PipelineDesc(const PipelineDesc &other);
PipelineDesc &operator=(const PipelineDesc &other);
size_t hash() const;
bool operator==(const PipelineDesc &other) const;
void initDefaults();
Error initializePipeline(RendererVk *renderer, ProgramVk *programVk, Pipeline *pipelineOut);
void updateViewport(const gl::Rectangle &viewport, float nearPlane, float farPlane);
// Shader stage info
void updateShaders(ProgramVk *programVk);
// Vertex input state
void resetVertexInputState();
void updateVertexInputInfo(uint32_t attribIndex,
const gl::VertexBinding &binding,
const gl::VertexAttribute &attrib);
// Input assembly info
void updateTopology(GLenum drawMode);
// Raster states
void updateCullMode(const gl::RasterizerState &rasterState);
void updateFrontFace(const gl::RasterizerState &rasterState);
void updateLineWidth(float lineWidth);
// RenderPass description.
void updateRenderPassDesc(const RenderPassDesc &renderPassDesc);
private:
// TODO(jmadill): Handle Geometry/Compute shaders when necessary.
ShaderStageInfo mShaderStageInfo;
VertexInputBindings mVertexInputBindings;
VertexInputAttributes mVertexInputAttribs;
PackedInputAssemblyInfo mInputAssemblyInfo;
// TODO(jmadill): Consider using dynamic state for viewport/scissor.
VkViewport mViewport;
VkRect2D mScissor;
PackedRasterizationStateInfo mRasterizationStateInfo;
PackedMultisampleStateInfo mMultisampleStateInfo;
PackedDepthStencilStateInfo mDepthStencilStateInfo;
PackedColorBlendStateInfo mColorBlendStateInfo;
// TODO(jmadill): Dynamic state.
// TODO(jmadill): Pipeline layout
RenderPassDesc mRenderPassDesc;
};
// Verify the packed pipeline description has no gaps in the packing.
// This is not guaranteed by the spec, but is validated by a compile-time check.
// No gaps or padding at the end ensures that hashing and memcmp checks will not run
// into uninitialized memory regions.
constexpr size_t PipelineDescSumOfSizes =
sizeof(ShaderStageInfo) + sizeof(VertexInputBindings) + sizeof(VertexInputAttributes) +
sizeof(PackedInputAssemblyInfo) + sizeof(VkViewport) + sizeof(VkRect2D) +
sizeof(PackedRasterizationStateInfo) + sizeof(PackedMultisampleStateInfo) +
sizeof(PackedDepthStencilStateInfo) + sizeof(PackedColorBlendStateInfo) +
sizeof(RenderPassDesc);
static_assert(sizeof(PipelineDesc) == PipelineDescSumOfSizes, "Size mismatch");
} // namespace vk
} // namespace rx
// Introduce a std::hash for a RenderPassDesc
namespace std
{
template <>
struct hash<rx::vk::RenderPassDesc>
{
size_t operator()(const rx::vk::RenderPassDesc &key) const { return key.hash(); }
};
template <>
struct hash<rx::vk::AttachmentOpsArray>
{
size_t operator()(const rx::vk::AttachmentOpsArray &key) const { return key.hash(); }
};
} // namespace std
namespace rx
{
// TODO(jmadill): Add cache trimming.
class RenderPassCache
{
public:
RenderPassCache();
~RenderPassCache();
void destroy(VkDevice device);
vk::Error getCompatibleRenderPass(VkDevice device,
Serial serial,
const vk::RenderPassDesc &desc,
vk::RenderPass **renderPassOut);
vk::Error getRenderPassWithOps(VkDevice device,
Serial serial,
const vk::RenderPassDesc &desc,
const vk::AttachmentOpsArray &attachmentOps,
vk::RenderPass **renderPassOut);
private:
// Use a two-layer caching scheme. The top level matches the "compatible" RenderPass elements.
// The second layer caches the attachment load/store ops and initial/final layout.
using InnerCache = std::unordered_map<vk::AttachmentOpsArray, vk::RenderPassAndSerial>;
using OuterCache = std::unordered_map<vk::RenderPassDesc, InnerCache>;
OuterCache mPayload;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_VK_CACHE_UTILS_H_
......@@ -8,7 +8,7 @@
// vk_format_table:
// Queries for full Vulkan format information based on GL format.
#include "libANGLE/renderer/vulkan/formatutilsvk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h"
#include "image_util/copyimage.h"
#include "image_util/generatemip.h"
......
......@@ -3,10 +3,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// formatutilsvk:
// vk_format_utils:
// Helper for Vulkan format code.
#include "libANGLE/renderer/vulkan/formatutilsvk.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/load_functions_table.h"
......
......@@ -3,11 +3,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Vk::Format:
// Vulkan implementation of a storage format.
// vk_format_utils:
// Helper for Vulkan format code.
#ifndef LIBANGLE_RENDERER_VULKAN_FORMAT_H_
#define LIBANGLE_RENDERER_VULKAN_FORMAT_H_
#ifndef LIBANGLE_RENDERER_VULKAN_VK_FORMAT_UTILS_H_
#define LIBANGLE_RENDERER_VULKAN_VK_FORMAT_UTILS_H_
#include <vulkan/vulkan.h>
......@@ -70,4 +70,4 @@ VkFormat GetNativeVertexFormat(gl::VertexFormatType vertexFormat);
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_FORMAT_H_
#endif // LIBANGLE_RENDERER_VULKAN_VK_FORMAT_UTILS_H_
......@@ -3,23 +3,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// renderervk_utils:
// vk_utils:
// Helper functions for the Vulkan Renderer.
//
#include "libANGLE/renderer/vulkan/renderervk_utils.h"
#include "libANGLE/renderer/vulkan/vk_utils.h"
#include "common/aligned_memory.h"
#include "libANGLE/Context.h"
#include "libANGLE/SizedMRUCache.h"
#include "libANGLE/renderer/vulkan/CommandBufferNode.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/RenderTargetVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
// FIXME: remove if split file
#include "libANGLE/renderer/vulkan/ProgramVk.h"
namespace rx
{
......@@ -112,68 +107,6 @@ VkImageUsageFlags GetStagingBufferUsageFlags(vk::StagingUsage usage)
}
}
VkSampleCountFlagBits ConvertSamples(GLint sampleCount)
{
switch (sampleCount)
{
case 0:
case 1:
return VK_SAMPLE_COUNT_1_BIT;
case 2:
return VK_SAMPLE_COUNT_2_BIT;
case 4:
return VK_SAMPLE_COUNT_4_BIT;
case 8:
return VK_SAMPLE_COUNT_8_BIT;
case 16:
return VK_SAMPLE_COUNT_16_BIT;
case 32:
return VK_SAMPLE_COUNT_32_BIT;
default:
UNREACHABLE();
return VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM;
}
}
void UnpackAttachmentDesc(VkAttachmentDescription *desc,
const vk::PackedAttachmentDesc &packedDesc,
const vk::PackedAttachmentOpsDesc &ops)
{
desc->flags = static_cast<VkAttachmentDescriptionFlags>(packedDesc.flags);
desc->format = static_cast<VkFormat>(packedDesc.format);
desc->samples = ConvertSamples(packedDesc.samples);
desc->loadOp = static_cast<VkAttachmentLoadOp>(ops.loadOp);
desc->storeOp = static_cast<VkAttachmentStoreOp>(ops.storeOp);
desc->stencilLoadOp = static_cast<VkAttachmentLoadOp>(ops.stencilLoadOp);
desc->stencilStoreOp = static_cast<VkAttachmentStoreOp>(ops.stencilStoreOp);
desc->initialLayout = static_cast<VkImageLayout>(ops.initialLayout);
desc->finalLayout = static_cast<VkImageLayout>(ops.finalLayout);
}
void UnpackStencilState(const vk::PackedStencilOpState &packedState, VkStencilOpState *stateOut)
{
stateOut->failOp = static_cast<VkStencilOp>(packedState.failOp);
stateOut->passOp = static_cast<VkStencilOp>(packedState.passOp);
stateOut->depthFailOp = static_cast<VkStencilOp>(packedState.depthFailOp);
stateOut->compareOp = static_cast<VkCompareOp>(packedState.compareOp);
stateOut->compareMask = packedState.compareMask;
stateOut->writeMask = packedState.writeMask;
stateOut->reference = packedState.reference;
}
void UnpackBlendAttachmentState(vk::PackedColorBlendAttachmentState &packedState,
VkPipelineColorBlendAttachmentState *stateOut)
{
stateOut->blendEnable = static_cast<VkBool32>(packedState.blendEnable);
stateOut->srcColorBlendFactor = static_cast<VkBlendFactor>(packedState.srcColorBlendFactor);
stateOut->dstColorBlendFactor = static_cast<VkBlendFactor>(packedState.dstColorBlendFactor);
stateOut->colorBlendOp = static_cast<VkBlendOp>(packedState.colorBlendOp);
stateOut->srcAlphaBlendFactor = static_cast<VkBlendFactor>(packedState.srcAlphaBlendFactor);
stateOut->dstAlphaBlendFactor = static_cast<VkBlendFactor>(packedState.dstAlphaBlendFactor);
stateOut->alphaBlendOp = static_cast<VkBlendOp>(packedState.alphaBlendOp);
stateOut->colorWriteMask = static_cast<VkColorComponentFlags>(packedState.colorWriteMask);
}
} // anonymous namespace
// Mirrors std_validation_str in loader.h
......@@ -827,20 +760,20 @@ Error StagingImage::init(VkDevice device,
{
VkImageCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.imageType = VK_IMAGE_TYPE_2D;
createInfo.format = format;
createInfo.extent.width = static_cast<uint32_t>(extent.width);
createInfo.extent.height = static_cast<uint32_t>(extent.height);
createInfo.extent.depth = static_cast<uint32_t>(extent.depth);
createInfo.mipLevels = 1;
createInfo.arrayLayers = 1;
createInfo.samples = VK_SAMPLE_COUNT_1_BIT;
createInfo.tiling = VK_IMAGE_TILING_LINEAR;
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.imageType = VK_IMAGE_TYPE_2D;
createInfo.format = format;
createInfo.extent.width = static_cast<uint32_t>(extent.width);
createInfo.extent.height = static_cast<uint32_t>(extent.height);
createInfo.extent.depth = static_cast<uint32_t>(extent.depth);
createInfo.mipLevels = 1;
createInfo.arrayLayers = 1;
createInfo.samples = VK_SAMPLE_COUNT_1_BIT;
createInfo.tiling = VK_IMAGE_TILING_LINEAR;
createInfo.usage = GetStagingImageUsageFlags(usage);
createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.queueFamilyIndexCount = 1;
createInfo.pQueueFamilyIndices = &queueFamilyIndex;
......@@ -1274,594 +1207,6 @@ void GarbageObject::destroy(VkDevice device)
}
}
// RenderPassDesc implementation.
RenderPassDesc::RenderPassDesc()
{
UNUSED_VARIABLE(mPadding);
memset(this, 0, sizeof(RenderPassDesc));
}
RenderPassDesc::~RenderPassDesc()
{
}
RenderPassDesc::RenderPassDesc(const RenderPassDesc &other)
{
memcpy(this, &other, sizeof(RenderPassDesc));
}
void RenderPassDesc::packAttachment(uint32_t index, const vk::Format &format, GLsizei samples)
{
PackedAttachmentDesc &desc = mAttachmentDescs[index];
// TODO(jmadill): We would only need this flag for duplicated attachments.
desc.flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT;
ASSERT(desc.samples < std::numeric_limits<uint8_t>::max());
desc.samples = static_cast<uint8_t>(samples);
ASSERT(format.vkTextureFormat < std::numeric_limits<uint16_t>::max());
desc.format = static_cast<uint16_t>(format.vkTextureFormat);
}
void RenderPassDesc::packColorAttachment(const vk::Format &format, GLsizei samples)
{
ASSERT(mDepthStencilAttachmentCount == 0);
ASSERT(mColorAttachmentCount < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS);
packAttachment(mColorAttachmentCount++, format, samples);
}
void RenderPassDesc::packDepthStencilAttachment(const vk::Format &format, GLsizei samples)
{
ASSERT(mDepthStencilAttachmentCount == 0);
packAttachment(mDepthStencilAttachmentCount++, format, samples);
}
RenderPassDesc &RenderPassDesc::operator=(const RenderPassDesc &other)
{
memcpy(this, &other, sizeof(RenderPassDesc));
return *this;
}
size_t RenderPassDesc::hash() const
{
return angle::ComputeGenericHash(*this);
}
uint32_t RenderPassDesc::attachmentCount() const
{
return (mColorAttachmentCount + mDepthStencilAttachmentCount);
}
uint32_t RenderPassDesc::colorAttachmentCount() const
{
return mColorAttachmentCount;
}
uint32_t RenderPassDesc::depthStencilAttachmentCount() const
{
return mDepthStencilAttachmentCount;
}
const PackedAttachmentDesc &RenderPassDesc::operator[](size_t index) const
{
ASSERT(index < mAttachmentDescs.size());
return mAttachmentDescs[index];
}
bool operator==(const RenderPassDesc &lhs, const RenderPassDesc &rhs)
{
return (memcmp(&lhs, &rhs, sizeof(RenderPassDesc)) == 0);
}
// AttachmentOpsArray implementation.
AttachmentOpsArray::AttachmentOpsArray()
{
memset(&mOps, 0, sizeof(PackedAttachmentOpsDesc) * mOps.size());
}
AttachmentOpsArray::~AttachmentOpsArray()
{
}
AttachmentOpsArray::AttachmentOpsArray(const AttachmentOpsArray &other)
{
memcpy(&mOps, &other.mOps, sizeof(PackedAttachmentOpsDesc) * mOps.size());
}
AttachmentOpsArray &AttachmentOpsArray::operator=(const AttachmentOpsArray &other)
{
memcpy(&mOps, &other.mOps, sizeof(PackedAttachmentOpsDesc) * mOps.size());
return *this;
}
const PackedAttachmentOpsDesc &AttachmentOpsArray::operator[](size_t index) const
{
return mOps[index];
}
PackedAttachmentOpsDesc &AttachmentOpsArray::operator[](size_t index)
{
return mOps[index];
}
void AttachmentOpsArray::initDummyOp(size_t index, VkImageLayout finalLayout)
{
PackedAttachmentOpsDesc &ops = mOps[index];
ops.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
ops.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
ops.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
ops.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
ops.initialLayout = static_cast<uint16_t>(VK_IMAGE_LAYOUT_UNDEFINED);
ops.finalLayout = static_cast<uint16_t>(finalLayout);
}
size_t AttachmentOpsArray::hash() const
{
return angle::ComputeGenericHash(mOps);
}
bool operator==(const AttachmentOpsArray &lhs, const AttachmentOpsArray &rhs)
{
return (memcmp(&lhs, &rhs, sizeof(AttachmentOpsArray)) == 0);
}
Error InitializeRenderPassFromDesc(VkDevice device,
const RenderPassDesc &desc,
const AttachmentOpsArray &ops,
RenderPass *renderPass)
{
uint32_t attachmentCount = desc.attachmentCount();
ASSERT(attachmentCount > 0);
gl::DrawBuffersArray<VkAttachmentReference> colorAttachmentRefs;
for (uint32_t colorIndex = 0; colorIndex < desc.colorAttachmentCount(); ++colorIndex)
{
VkAttachmentReference &colorRef = colorAttachmentRefs[colorIndex];
colorRef.attachment = colorIndex;
colorRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
}
VkAttachmentReference depthStencilAttachmentRef;
if (desc.depthStencilAttachmentCount() > 0)
{
ASSERT(desc.depthStencilAttachmentCount() == 1);
depthStencilAttachmentRef.attachment = desc.colorAttachmentCount();
depthStencilAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
}
VkSubpassDescription subpassDesc;
subpassDesc.flags = 0;
subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpassDesc.inputAttachmentCount = 0;
subpassDesc.pInputAttachments = nullptr;
subpassDesc.colorAttachmentCount = desc.colorAttachmentCount();
subpassDesc.pColorAttachments = colorAttachmentRefs.data();
subpassDesc.pResolveAttachments = nullptr;
subpassDesc.pDepthStencilAttachment =
(desc.depthStencilAttachmentCount() > 0 ? &depthStencilAttachmentRef : nullptr);
subpassDesc.preserveAttachmentCount = 0;
subpassDesc.pPreserveAttachments = nullptr;
// Unpack the packed and split representation into the format required by Vulkan.
gl::AttachmentArray<VkAttachmentDescription> attachmentDescs;
for (uint32_t colorIndex = 0; colorIndex < desc.colorAttachmentCount(); ++colorIndex)
{
UnpackAttachmentDesc(&attachmentDescs[colorIndex], desc[colorIndex], ops[colorIndex]);
}
if (desc.depthStencilAttachmentCount() > 0)
{
uint32_t depthStencilIndex = desc.colorAttachmentCount();
UnpackAttachmentDesc(&attachmentDescs[depthStencilIndex], desc[depthStencilIndex],
ops[depthStencilIndex]);
}
VkRenderPassCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.attachmentCount = attachmentCount;
createInfo.pAttachments = attachmentDescs.data();
createInfo.subpassCount = 1;
createInfo.pSubpasses = &subpassDesc;
createInfo.dependencyCount = 0;
createInfo.pDependencies = nullptr;
ANGLE_TRY(renderPass->init(device, createInfo));
return vk::NoError();
}
// PipelineDesc implementation.
// Use aligned allocation and free so we can use the alignas keyword.
void *PipelineDesc::operator new(std::size_t size)
{
return angle::AlignedAlloc(size, 32);
}
void PipelineDesc::operator delete(void *ptr)
{
return angle::AlignedFree(ptr);
}
PipelineDesc::PipelineDesc()
{
memset(this, 0, sizeof(PipelineDesc));
}
PipelineDesc::~PipelineDesc()
{
}
PipelineDesc::PipelineDesc(const PipelineDesc &other)
{
memcpy(this, &other, sizeof(PipelineDesc));
}
PipelineDesc &PipelineDesc::operator=(const PipelineDesc &other)
{
memcpy(this, &other, sizeof(PipelineDesc));
return *this;
}
size_t PipelineDesc::hash() const
{
return angle::ComputeGenericHash(*this);
}
bool PipelineDesc::operator==(const PipelineDesc &other) const
{
return (memcmp(this, &other, sizeof(PipelineDesc)) == 0);
}
void PipelineDesc::initDefaults()
{
mInputAssemblyInfo.topology = static_cast<uint32_t>(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
mInputAssemblyInfo.primitiveRestartEnable = 0;
mRasterizationStateInfo.depthClampEnable = 0;
mRasterizationStateInfo.rasterizationDiscardEnable = 0;
mRasterizationStateInfo.polygonMode = static_cast<uint16_t>(VK_POLYGON_MODE_FILL);
mRasterizationStateInfo.cullMode = static_cast<uint16_t>(VK_CULL_MODE_NONE);
mRasterizationStateInfo.frontFace = static_cast<uint16_t>(VK_FRONT_FACE_CLOCKWISE);
mRasterizationStateInfo.depthBiasEnable = 0;
mRasterizationStateInfo.depthBiasConstantFactor = 0.0f;
mRasterizationStateInfo.depthBiasClamp = 0.0f;
mRasterizationStateInfo.depthBiasSlopeFactor = 0.0f;
mRasterizationStateInfo.lineWidth = 1.0f;
mMultisampleStateInfo.rasterizationSamples = 1;
mMultisampleStateInfo.sampleShadingEnable = 0;
mMultisampleStateInfo.minSampleShading = 0.0f;
for (int maskIndex = 0; maskIndex < gl::MAX_SAMPLE_MASK_WORDS; ++maskIndex)
{
mMultisampleStateInfo.sampleMask[maskIndex] = 0;
}
mMultisampleStateInfo.alphaToCoverageEnable = 0;
mMultisampleStateInfo.alphaToOneEnable = 0;
mDepthStencilStateInfo.depthTestEnable = 0;
mDepthStencilStateInfo.depthWriteEnable = 1;
mDepthStencilStateInfo.depthCompareOp = static_cast<uint8_t>(VK_COMPARE_OP_LESS);
mDepthStencilStateInfo.depthBoundsTestEnable = 0;
mDepthStencilStateInfo.stencilTestEnable = 0;
mDepthStencilStateInfo.minDepthBounds = 0.0f;
mDepthStencilStateInfo.maxDepthBounds = 0.0f;
mDepthStencilStateInfo.front.failOp = static_cast<uint8_t>(VK_STENCIL_OP_KEEP);
mDepthStencilStateInfo.front.passOp = static_cast<uint8_t>(VK_STENCIL_OP_KEEP);
mDepthStencilStateInfo.front.depthFailOp = static_cast<uint8_t>(VK_STENCIL_OP_KEEP);
mDepthStencilStateInfo.front.compareOp = static_cast<uint8_t>(VK_COMPARE_OP_ALWAYS);
mDepthStencilStateInfo.front.compareMask = static_cast<uint32_t>(-1);
mDepthStencilStateInfo.front.writeMask = static_cast<uint32_t>(-1);
mDepthStencilStateInfo.front.reference = 0;
mDepthStencilStateInfo.back.failOp = static_cast<uint8_t>(VK_STENCIL_OP_KEEP);
mDepthStencilStateInfo.back.passOp = static_cast<uint8_t>(VK_STENCIL_OP_KEEP);
mDepthStencilStateInfo.back.depthFailOp = static_cast<uint8_t>(VK_STENCIL_OP_KEEP);
mDepthStencilStateInfo.back.compareOp = static_cast<uint8_t>(VK_COMPARE_OP_ALWAYS);
mDepthStencilStateInfo.back.compareMask = static_cast<uint32_t>(-1);
mDepthStencilStateInfo.back.writeMask = static_cast<uint32_t>(-1);
mDepthStencilStateInfo.back.reference = 0;
// TODO(jmadill): Blend state/MRT.
PackedColorBlendAttachmentState blendAttachmentState;
blendAttachmentState.blendEnable = 0;
blendAttachmentState.srcColorBlendFactor = static_cast<uint8_t>(VK_BLEND_FACTOR_ONE);
blendAttachmentState.dstColorBlendFactor = static_cast<uint8_t>(VK_BLEND_FACTOR_ONE);
blendAttachmentState.colorBlendOp = static_cast<uint8_t>(VK_BLEND_OP_ADD);
blendAttachmentState.srcAlphaBlendFactor = static_cast<uint8_t>(VK_BLEND_FACTOR_ONE);
blendAttachmentState.dstAlphaBlendFactor = static_cast<uint8_t>(VK_BLEND_FACTOR_ONE);
blendAttachmentState.alphaBlendOp = static_cast<uint8_t>(VK_BLEND_OP_ADD);
blendAttachmentState.colorWriteMask =
static_cast<uint8_t>(VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
mColorBlendStateInfo.logicOpEnable = 0;
mColorBlendStateInfo.logicOp = static_cast<uint32_t>(VK_LOGIC_OP_CLEAR);
mColorBlendStateInfo.attachmentCount = 1;
mColorBlendStateInfo.blendConstants[0] = 0.0f;
mColorBlendStateInfo.blendConstants[1] = 0.0f;
mColorBlendStateInfo.blendConstants[2] = 0.0f;
mColorBlendStateInfo.blendConstants[3] = 0.0f;
std::fill(&mColorBlendStateInfo.attachments[0],
&mColorBlendStateInfo.attachments[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS],
blendAttachmentState);
}
Error PipelineDesc::initializePipeline(RendererVk *renderer,
ProgramVk *programVk,
Pipeline *pipelineOut)
{
VkPipelineShaderStageCreateInfo shaderStages[2];
VkPipelineVertexInputStateCreateInfo vertexInputState;
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState;
VkPipelineViewportStateCreateInfo viewportState;
VkPipelineRasterizationStateCreateInfo rasterState;
VkPipelineMultisampleStateCreateInfo multisampleState;
VkPipelineDepthStencilStateCreateInfo depthStencilState;
std::array<VkPipelineColorBlendAttachmentState, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS>
blendAttachmentState;
VkPipelineColorBlendStateCreateInfo blendState;
VkGraphicsPipelineCreateInfo createInfo;
ASSERT(programVk->getVertexModuleSerial() == mShaderStageInfo[0].moduleSerial);
shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
shaderStages[0].pNext = nullptr;
shaderStages[0].flags = 0;
shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
shaderStages[0].module = programVk->getLinkedVertexModule().getHandle();
shaderStages[0].pName = "main";
shaderStages[0].pSpecializationInfo = nullptr;
ASSERT(programVk->getFragmentModuleSerial() == mShaderStageInfo[1].moduleSerial);
shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
shaderStages[1].pNext = nullptr;
shaderStages[1].flags = 0;
shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
shaderStages[1].module = programVk->getLinkedFragmentModule().getHandle();
shaderStages[1].pName = "main";
shaderStages[1].pSpecializationInfo = nullptr;
// TODO(jmadill): Possibly use different path for ES 3.1 split bindings/attribs.
gl::AttribArray<VkVertexInputBindingDescription> bindingDescs;
gl::AttribArray<VkVertexInputAttributeDescription> attributeDescs;
uint32_t vertexAttribCount = 0;
for (uint32_t attribIndex = 0; attribIndex < gl::MAX_VERTEX_ATTRIBS; ++attribIndex)
{
VkVertexInputBindingDescription &bindingDesc = bindingDescs[attribIndex];
VkVertexInputAttributeDescription &attribDesc = attributeDescs[attribIndex];
const PackedVertexInputBindingDesc &packedBinding = mVertexInputBindings[attribIndex];
const PackedVertexInputAttributeDesc &packedAttrib = mVertexInputAttribs[attribIndex];
// TODO(jmadill): Support for gaps in vertex attribute specification.
if (packedAttrib.format == 0)
continue;
vertexAttribCount = attribIndex + 1;
bindingDesc.binding = attribIndex;
bindingDesc.inputRate = static_cast<VkVertexInputRate>(packedBinding.inputRate);
bindingDesc.stride = static_cast<uint32_t>(packedBinding.stride);
attribDesc.binding = attribIndex;
attribDesc.format = static_cast<VkFormat>(packedAttrib.format);
attribDesc.location = static_cast<uint32_t>(packedAttrib.location);
attribDesc.offset = packedAttrib.offset;
}
// The binding descriptions are filled in at draw time.
vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertexInputState.pNext = nullptr;
vertexInputState.flags = 0;
vertexInputState.vertexBindingDescriptionCount = vertexAttribCount;
vertexInputState.pVertexBindingDescriptions = bindingDescs.data();
vertexInputState.vertexAttributeDescriptionCount = vertexAttribCount;
vertexInputState.pVertexAttributeDescriptions = attributeDescs.data();
// Primitive topology is filled in at draw time.
inputAssemblyState.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssemblyState.pNext = nullptr;
inputAssemblyState.flags = 0;
inputAssemblyState.topology = static_cast<VkPrimitiveTopology>(mInputAssemblyInfo.topology);
inputAssemblyState.primitiveRestartEnable =
static_cast<VkBool32>(mInputAssemblyInfo.primitiveRestartEnable);
// Set initial viewport and scissor state.
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportState.pNext = nullptr;
viewportState.flags = 0;
viewportState.viewportCount = 1;
viewportState.pViewports = &mViewport;
viewportState.scissorCount = 1;
viewportState.pScissors = &mScissor;
// Rasterizer state.
rasterState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterState.pNext = nullptr;
rasterState.flags = 0;
rasterState.depthClampEnable = static_cast<VkBool32>(mRasterizationStateInfo.depthClampEnable);
rasterState.rasterizerDiscardEnable =
static_cast<VkBool32>(mRasterizationStateInfo.rasterizationDiscardEnable);
rasterState.polygonMode = static_cast<VkPolygonMode>(mRasterizationStateInfo.polygonMode);
rasterState.cullMode = static_cast<VkCullModeFlags>(mRasterizationStateInfo.cullMode);
rasterState.frontFace = static_cast<VkFrontFace>(mRasterizationStateInfo.frontFace);
rasterState.depthBiasEnable = static_cast<VkBool32>(mRasterizationStateInfo.depthBiasEnable);
rasterState.depthBiasConstantFactor = mRasterizationStateInfo.depthBiasConstantFactor;
rasterState.depthBiasClamp = mRasterizationStateInfo.depthBiasClamp;
rasterState.depthBiasSlopeFactor = mRasterizationStateInfo.depthBiasSlopeFactor;
rasterState.lineWidth = mRasterizationStateInfo.lineWidth;
// Multisample state.
multisampleState.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampleState.pNext = nullptr;
multisampleState.flags = 0;
multisampleState.rasterizationSamples =
ConvertSamples(mMultisampleStateInfo.rasterizationSamples);
multisampleState.sampleShadingEnable =
static_cast<VkBool32>(mMultisampleStateInfo.sampleShadingEnable);
multisampleState.minSampleShading = mMultisampleStateInfo.minSampleShading;
// TODO(jmadill): sample masks
multisampleState.pSampleMask = nullptr;
multisampleState.alphaToCoverageEnable =
static_cast<VkBool32>(mMultisampleStateInfo.alphaToCoverageEnable);
multisampleState.alphaToOneEnable =
static_cast<VkBool32>(mMultisampleStateInfo.alphaToOneEnable);
// Depth/stencil state.
depthStencilState.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depthStencilState.pNext = nullptr;
depthStencilState.flags = 0;
depthStencilState.depthTestEnable =
static_cast<VkBool32>(mDepthStencilStateInfo.depthTestEnable);
depthStencilState.depthWriteEnable =
static_cast<VkBool32>(mDepthStencilStateInfo.depthWriteEnable);
depthStencilState.depthCompareOp =
static_cast<VkCompareOp>(mDepthStencilStateInfo.depthCompareOp);
depthStencilState.depthBoundsTestEnable =
static_cast<VkBool32>(mDepthStencilStateInfo.depthBoundsTestEnable);
depthStencilState.stencilTestEnable =
static_cast<VkBool32>(mDepthStencilStateInfo.stencilTestEnable);
UnpackStencilState(mDepthStencilStateInfo.front, &depthStencilState.front);
UnpackStencilState(mDepthStencilStateInfo.back, &depthStencilState.back);
depthStencilState.minDepthBounds = mDepthStencilStateInfo.minDepthBounds;
depthStencilState.maxDepthBounds = mDepthStencilStateInfo.maxDepthBounds;
blendState.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
blendState.pNext = 0;
blendState.flags = 0;
blendState.logicOpEnable = static_cast<VkBool32>(mColorBlendStateInfo.logicOpEnable);
blendState.logicOp = static_cast<VkLogicOp>(mColorBlendStateInfo.logicOp);
blendState.attachmentCount = mColorBlendStateInfo.attachmentCount;
blendState.pAttachments = blendAttachmentState.data();
for (int i = 0; i < 4; i++)
{
blendState.blendConstants[i] = mColorBlendStateInfo.blendConstants[i];
}
for (uint32_t colorIndex = 0; colorIndex < blendState.attachmentCount; ++colorIndex)
{
UnpackBlendAttachmentState(mColorBlendStateInfo.attachments[colorIndex],
&blendAttachmentState[colorIndex]);
}
// TODO(jmadill): Dynamic state.
// Pull in a compatible RenderPass.
RenderPass *compatibleRenderPass = nullptr;
ANGLE_TRY(renderer->getCompatibleRenderPass(mRenderPassDesc, &compatibleRenderPass));
createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.stageCount = 2;
createInfo.pStages = shaderStages;
createInfo.pVertexInputState = &vertexInputState;
createInfo.pInputAssemblyState = &inputAssemblyState;
createInfo.pTessellationState = nullptr;
createInfo.pViewportState = &viewportState;
createInfo.pRasterizationState = &rasterState;
createInfo.pMultisampleState = &multisampleState;
createInfo.pDepthStencilState = &depthStencilState;
createInfo.pColorBlendState = &blendState;
createInfo.pDynamicState = nullptr;
createInfo.layout = renderer->getGraphicsPipelineLayout().getHandle();
createInfo.renderPass = compatibleRenderPass->getHandle();
createInfo.subpass = 0;
createInfo.basePipelineHandle = VK_NULL_HANDLE;
createInfo.basePipelineIndex = 0;
ANGLE_TRY(pipelineOut->initGraphics(renderer->getDevice(), createInfo));
return NoError();
}
void PipelineDesc::updateShaders(ProgramVk *programVk)
{
ASSERT(programVk->getVertexModuleSerial() < std::numeric_limits<uint32_t>::max());
mShaderStageInfo[0].moduleSerial =
static_cast<uint32_t>(programVk->getVertexModuleSerial().getValue());
ASSERT(programVk->getFragmentModuleSerial() < std::numeric_limits<uint32_t>::max());
mShaderStageInfo[1].moduleSerial =
static_cast<uint32_t>(programVk->getFragmentModuleSerial().getValue());
}
void PipelineDesc::updateViewport(const gl::Rectangle &viewport, float nearPlane, float farPlane)
{
mViewport.x = static_cast<float>(viewport.x);
mViewport.y = static_cast<float>(viewport.y);
mViewport.width = static_cast<float>(viewport.width);
mViewport.height = static_cast<float>(viewport.height);
mViewport.minDepth = nearPlane;
mViewport.maxDepth = farPlane;
// TODO(jmadill): Scissor.
mScissor.offset.x = viewport.x;
mScissor.offset.y = viewport.y;
mScissor.extent.width = viewport.width;
mScissor.extent.height = viewport.height;
}
void PipelineDesc::resetVertexInputState()
{
memset(&mVertexInputBindings, 0, sizeof(VertexInputBindings));
memset(&mVertexInputAttribs, 0, sizeof(VertexInputAttributes));
}
void PipelineDesc::updateVertexInputInfo(uint32_t attribIndex,
const gl::VertexBinding &binding,
const gl::VertexAttribute &attrib)
{
PackedVertexInputBindingDesc &bindingDesc = mVertexInputBindings[attribIndex];
size_t attribSize = gl::ComputeVertexAttributeTypeSize(attrib);
ASSERT(attribSize <= std::numeric_limits<uint16_t>::max());
bindingDesc.stride = static_cast<uint16_t>(attribSize);
bindingDesc.inputRate = static_cast<uint16_t>(
binding.getDivisor() > 0 ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX);
gl::VertexFormatType vertexFormatType = gl::GetVertexFormatType(attrib);
VkFormat vkFormat = vk::GetNativeVertexFormat(vertexFormatType);
ASSERT(vkFormat <= std::numeric_limits<uint16_t>::max());
PackedVertexInputAttributeDesc &attribDesc = mVertexInputAttribs[attribIndex];
attribDesc.format = static_cast<uint16_t>(vkFormat);
attribDesc.location = static_cast<uint16_t>(attribIndex);
attribDesc.offset = static_cast<uint32_t>(ComputeVertexAttributeOffset(attrib, binding));
}
void PipelineDesc::updateTopology(GLenum drawMode)
{
mInputAssemblyInfo.topology = static_cast<uint32_t>(gl_vk::GetPrimitiveTopology(drawMode));
}
void PipelineDesc::updateCullMode(const gl::RasterizerState &rasterState)
{
mRasterizationStateInfo.cullMode = static_cast<uint16_t>(gl_vk::GetCullMode(rasterState));
}
void PipelineDesc::updateFrontFace(const gl::RasterizerState &rasterState)
{
mRasterizationStateInfo.frontFace =
static_cast<uint16_t>(gl_vk::GetFrontFace(rasterState.frontFace));
}
void PipelineDesc::updateLineWidth(float lineWidth)
{
mRasterizationStateInfo.lineWidth = lineWidth;
}
void PipelineDesc::updateRenderPassDesc(const RenderPassDesc &renderPassDesc)
{
mRenderPassDesc = renderPassDesc;
}
} // namespace vk
namespace gl_vk
......
......@@ -3,12 +3,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// renderervk_utils:
// vk_utils:
// Helper functions for the Vulkan Renderer.
//
#ifndef LIBANGLE_RENDERER_VULKAN_RENDERERVK_UTILS_H_
#define LIBANGLE_RENDERER_VULKAN_RENDERERVK_UTILS_H_
#ifndef LIBANGLE_RENDERER_VULKAN_VK_UTILS_H_
#define LIBANGLE_RENDERER_VULKAN_VK_UTILS_H_
#include <limits>
......@@ -654,304 +654,6 @@ struct BufferAndMemory final : private angle::NonCopyable
using RenderPassAndSerial = ObjectAndSerial<RenderPass>;
// Packed Vk resource descriptions.
// Most Vk types use many more bits than required to represent the underlying data.
// Since ANGLE wants cache things like RenderPasses and Pipeline State Objects using
// hashing (and also needs to check equality) we can optimize these operations by
// using fewer bits. Hence the packed types.
//
// One implementation note: these types could potentially be improved by using even
// fewer bits. For example, boolean values could be represented by a single bit instead
// of a uint8_t. However at the current time there are concerns about the portability
// of bitfield operators, and complexity issues with using bit mask operations. This is
// something likely we will want to investigate as the Vulkan implementation progresses.
//
// Second implementation note: the struct packing is also a bit fragile, and some of the
// packing requirements depend on using alignas and field ordering to get the result of
// packing nicely into the desired space. This is something we could also potentially fix
// with a redesign to use bitfields or bit mask operations.
struct alignas(4) PackedAttachmentDesc
{
uint8_t flags;
uint8_t samples;
uint16_t format;
};
static_assert(sizeof(PackedAttachmentDesc) == 4, "Size check failed");
class RenderPassDesc final
{
public:
RenderPassDesc();
~RenderPassDesc();
RenderPassDesc(const RenderPassDesc &other);
RenderPassDesc &operator=(const RenderPassDesc &other);
// Depth stencil attachments must be packed after color attachments.
void packColorAttachment(const Format &format, GLsizei samples);
void packDepthStencilAttachment(const Format &format, GLsizei samples);
size_t hash() const;
uint32_t attachmentCount() const;
uint32_t colorAttachmentCount() const;
uint32_t depthStencilAttachmentCount() const;
const PackedAttachmentDesc &operator[](size_t index) const;
private:
void packAttachment(uint32_t index, const vk::Format &format, GLsizei samples);
uint32_t mColorAttachmentCount;
uint32_t mDepthStencilAttachmentCount;
gl::AttachmentArray<PackedAttachmentDesc> mAttachmentDescs;
uint32_t mPadding[4];
};
bool operator==(const RenderPassDesc &lhs, const RenderPassDesc &rhs);
static_assert(sizeof(RenderPassDesc) == 64, "Size check failed");
struct alignas(8) PackedAttachmentOpsDesc final
{
uint8_t loadOp;
uint8_t storeOp;
uint8_t stencilLoadOp;
uint8_t stencilStoreOp;
// 16-bits to force pad the structure to exactly 8 bytes.
uint16_t initialLayout;
uint16_t finalLayout;
};
static_assert(sizeof(PackedAttachmentOpsDesc) == 8, "Size check failed");
class AttachmentOpsArray final
{
public:
AttachmentOpsArray();
~AttachmentOpsArray();
AttachmentOpsArray(const AttachmentOpsArray &other);
AttachmentOpsArray &operator=(const AttachmentOpsArray &other);
const PackedAttachmentOpsDesc &operator[](size_t index) const;
PackedAttachmentOpsDesc &operator[](size_t index);
// Initializes an attachment op with whatever values. Used for compatible RenderPass checks.
void initDummyOp(size_t index, VkImageLayout finalLayout);
size_t hash() const;
private:
gl::AttachmentArray<PackedAttachmentOpsDesc> mOps;
};
bool operator==(const AttachmentOpsArray &lhs, const AttachmentOpsArray &rhs);
static_assert(sizeof(AttachmentOpsArray) == 80, "Size check failed");
Error InitializeRenderPassFromDesc(VkDevice device,
const RenderPassDesc &desc,
const AttachmentOpsArray &ops,
RenderPass *renderPass);
struct alignas(8) PackedShaderStageInfo final
{
uint32_t stage;
uint32_t moduleSerial;
// TODO(jmadill): Do we want specialization constants?
};
static_assert(sizeof(PackedShaderStageInfo) == 8, "Size check failed");
struct alignas(4) PackedVertexInputBindingDesc final
{
// Although techncially stride can be any value in ES 2.0, in practice supporting stride
// greater than MAX_USHORT should not be that helpful. Note that stride limits are
// introduced in ES 3.1.
uint16_t stride;
uint16_t inputRate;
};
static_assert(sizeof(PackedVertexInputBindingDesc) == 4, "Size check failed");
struct alignas(8) PackedVertexInputAttributeDesc final
{
uint16_t location;
uint16_t format;
uint32_t offset;
};
static_assert(sizeof(PackedVertexInputAttributeDesc) == 8, "Size check failed");
struct alignas(8) PackedInputAssemblyInfo
{
uint32_t topology;
uint32_t primitiveRestartEnable;
};
static_assert(sizeof(PackedInputAssemblyInfo) == 8, "Size check failed");
struct alignas(32) PackedRasterizationStateInfo
{
// Padded to ensure there's no gaps in this structure or those that use it.
uint32_t depthClampEnable;
uint32_t rasterizationDiscardEnable;
uint16_t polygonMode;
uint16_t cullMode;
uint16_t frontFace;
uint16_t depthBiasEnable;
float depthBiasConstantFactor;
// Note: depth bias clamp is only exposed in a 3.1 extension, but left here for completeness.
float depthBiasClamp;
float depthBiasSlopeFactor;
float lineWidth;
};
static_assert(sizeof(PackedRasterizationStateInfo) == 32, "Size check failed");
struct alignas(16) PackedMultisampleStateInfo final
{
uint8_t rasterizationSamples;
uint8_t sampleShadingEnable;
uint8_t alphaToCoverageEnable;
uint8_t alphaToOneEnable;
float minSampleShading;
uint32_t sampleMask[gl::MAX_SAMPLE_MASK_WORDS];
};
static_assert(sizeof(PackedMultisampleStateInfo) == 16, "Size check failed");
struct alignas(16) PackedStencilOpState final
{
uint8_t failOp;
uint8_t passOp;
uint8_t depthFailOp;
uint8_t compareOp;
uint32_t compareMask;
uint32_t writeMask;
uint32_t reference;
};
static_assert(sizeof(PackedStencilOpState) == 16, "Size check failed");
struct PackedDepthStencilStateInfo final
{
uint8_t depthTestEnable;
uint8_t depthWriteEnable;
uint8_t depthCompareOp;
uint8_t depthBoundsTestEnable;
// 32-bits to pad the alignments.
uint32_t stencilTestEnable;
float minDepthBounds;
float maxDepthBounds;
PackedStencilOpState front;
PackedStencilOpState back;
};
static_assert(sizeof(PackedDepthStencilStateInfo) == 48, "Size check failed");
struct alignas(8) PackedColorBlendAttachmentState final
{
uint8_t blendEnable;
uint8_t srcColorBlendFactor;
uint8_t dstColorBlendFactor;
uint8_t colorBlendOp;
uint8_t srcAlphaBlendFactor;
uint8_t dstAlphaBlendFactor;
uint8_t alphaBlendOp;
uint8_t colorWriteMask;
};
static_assert(sizeof(PackedColorBlendAttachmentState) == 8, "Size check failed");
struct PackedColorBlendStateInfo final
{
// Padded to round the strut size.
uint32_t logicOpEnable;
uint32_t logicOp;
uint32_t attachmentCount;
float blendConstants[4];
PackedColorBlendAttachmentState attachments[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS];
};
static_assert(sizeof(PackedColorBlendStateInfo) == 96, "Size check failed");
using ShaderStageInfo = std::array<PackedShaderStageInfo, 2>;
using VertexInputBindings = gl::AttribArray<PackedVertexInputBindingDesc>;
using VertexInputAttributes = gl::AttribArray<PackedVertexInputAttributeDesc>;
class PipelineDesc final
{
public:
// Use aligned allocation and free so we can use the alignas keyword.
void *operator new(std::size_t size);
void operator delete(void *ptr);
PipelineDesc();
~PipelineDesc();
PipelineDesc(const PipelineDesc &other);
PipelineDesc &operator=(const PipelineDesc &other);
size_t hash() const;
bool operator==(const PipelineDesc &other) const;
void initDefaults();
Error initializePipeline(RendererVk *renderer, ProgramVk *programVk, Pipeline *pipelineOut);
void updateViewport(const gl::Rectangle &viewport, float nearPlane, float farPlane);
// Shader stage info
void updateShaders(ProgramVk *programVk);
// Vertex input state
void resetVertexInputState();
void updateVertexInputInfo(uint32_t attribIndex,
const gl::VertexBinding &binding,
const gl::VertexAttribute &attrib);
// Input assembly info
void updateTopology(GLenum drawMode);
// Raster states
void updateCullMode(const gl::RasterizerState &rasterState);
void updateFrontFace(const gl::RasterizerState &rasterState);
void updateLineWidth(float lineWidth);
// RenderPass description.
void updateRenderPassDesc(const RenderPassDesc &renderPassDesc);
private:
// TODO(jmadill): Handle Geometry/Compute shaders when necessary.
ShaderStageInfo mShaderStageInfo;
VertexInputBindings mVertexInputBindings;
VertexInputAttributes mVertexInputAttribs;
PackedInputAssemblyInfo mInputAssemblyInfo;
// TODO(jmadill): Consider using dynamic state for viewport/scissor.
VkViewport mViewport;
VkRect2D mScissor;
PackedRasterizationStateInfo mRasterizationStateInfo;
PackedMultisampleStateInfo mMultisampleStateInfo;
PackedDepthStencilStateInfo mDepthStencilStateInfo;
PackedColorBlendStateInfo mColorBlendStateInfo;
// TODO(jmadill): Dynamic state.
// TODO(jmadill): Pipeline layout
RenderPassDesc mRenderPassDesc;
};
// Verify the packed pipeline description has no gaps in the packing.
// This is not guaranteed by the spec, but is validated by a compile-time check.
// No gaps or padding at the end ensures that hashing and memcmp checks will not run
// into uninitialized memory regions.
constexpr size_t PipelineDescSumOfSizes =
sizeof(ShaderStageInfo) + sizeof(VertexInputBindings) + sizeof(VertexInputAttributes) +
sizeof(PackedInputAssemblyInfo) + sizeof(VkViewport) + sizeof(VkRect2D) +
sizeof(PackedRasterizationStateInfo) + sizeof(PackedMultisampleStateInfo) +
sizeof(PackedDepthStencilStateInfo) + sizeof(PackedColorBlendStateInfo) +
sizeof(RenderPassDesc);
static_assert(sizeof(PipelineDesc) == PipelineDescSumOfSizes, "Size mismatch");
} // namespace vk
namespace gl_vk
......@@ -1017,20 +719,4 @@ class ResourceVk
std::ostream &operator<<(std::ostream &stream, const rx::vk::Error &error);
// Introduce a std::hash for a RenderPassDesc
namespace std
{
template <>
struct hash<rx::vk::RenderPassDesc>
{
size_t operator()(const rx::vk::RenderPassDesc &key) const { return key.hash(); }
};
template <>
struct hash<rx::vk::AttachmentOpsArray>
{
size_t operator()(const rx::vk::AttachmentOpsArray &key) const { return key.hash(); }
};
} // namespace std
#endif // LIBANGLE_RENDERER_VULKAN_RENDERERVK_UTILS_H_
#endif // LIBANGLE_RENDERER_VULKAN_VK_UTILS_H_
......@@ -755,11 +755,13 @@
'libANGLE/renderer/vulkan/TransformFeedbackVk.h',
'libANGLE/renderer/vulkan/VertexArrayVk.cpp',
'libANGLE/renderer/vulkan/VertexArrayVk.h',
'libANGLE/renderer/vulkan/formatutilsvk.h',
'libANGLE/renderer/vulkan/formatutilsvk.cpp',
'libANGLE/renderer/vulkan/renderervk_utils.cpp',
'libANGLE/renderer/vulkan/renderervk_utils.h',
'libANGLE/renderer/vulkan/vk_cache_utils.cpp',
'libANGLE/renderer/vulkan/vk_cache_utils.h',
'libANGLE/renderer/vulkan/vk_format_table_autogen.cpp',
'libANGLE/renderer/vulkan/vk_format_utils.h',
'libANGLE/renderer/vulkan/vk_format_utils.cpp',
'libANGLE/renderer/vulkan/vk_utils.cpp',
'libANGLE/renderer/vulkan/vk_utils.h',
],
'libangle_vulkan_win32_sources':
[
......
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