blob: a75db3420a5a57be31360943c0e54176afeb43fc [file] [log] [blame]
//
// Copyright 2021 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.
//
// ShaderInterfaceVariableInfoMap: Maps shader interface variable SPIR-V ids to their Vulkan
// mapping.
//
#include "libANGLE/renderer/vulkan/ShaderInterfaceVariableInfoMap.h"
namespace rx
{
namespace
{
uint32_t HashSPIRVId(uint32_t id)
{
ASSERT(id >= sh::vk::spirv::kIdShaderVariablesBegin);
return id - sh::vk::spirv::kIdShaderVariablesBegin;
}
void LoadShaderInterfaceVariableXfbInfo(gl::BinaryInputStream *stream,
ShaderInterfaceVariableXfbInfo *xfb)
{
stream->readStruct(&xfb->pod);
xfb->arrayElements.resize(stream->readInt<size_t>());
for (ShaderInterfaceVariableXfbInfo &arrayElement : xfb->arrayElements)
{
LoadShaderInterfaceVariableXfbInfo(stream, &arrayElement);
}
}
void SaveShaderInterfaceVariableXfbInfo(const ShaderInterfaceVariableXfbInfo &xfb,
gl::BinaryOutputStream *stream)
{
stream->writeStruct(xfb.pod);
stream->writeInt(xfb.arrayElements.size());
for (const ShaderInterfaceVariableXfbInfo &arrayElement : xfb.arrayElements)
{
SaveShaderInterfaceVariableXfbInfo(arrayElement, stream);
}
}
} // anonymous namespace
// ShaderInterfaceVariableInfoMap implementation.
ShaderInterfaceVariableInfoMap::ShaderInterfaceVariableInfoMap()
{
// Reserve storage for most common use case
mData.reserve(64);
}
ShaderInterfaceVariableInfoMap::~ShaderInterfaceVariableInfoMap() = default;
void ShaderInterfaceVariableInfoMap::clear()
{
mData.clear();
mXFBData.clear();
memset(&mPod, 0, sizeof(mPod));
for (gl::ShaderType shaderType : gl::AllShaderTypes())
{
mIdToIndexMap[shaderType].clear();
}
}
void ShaderInterfaceVariableInfoMap::save(gl::BinaryOutputStream *stream)
{
ASSERT(mXFBData.size() <= mData.size());
stream->writeStruct(mPod);
for (const IdToIndexMap &idToIndexMap : mIdToIndexMap)
{
stream->writeInt(idToIndexMap.size());
if (idToIndexMap.size() > 0)
{
stream->writeBytes(reinterpret_cast<const uint8_t *>(idToIndexMap.data()),
idToIndexMap.size() * sizeof(*idToIndexMap.data()));
}
}
stream->writeVector(mData);
if (mPod.xfbInfoCount > 0)
{
uint32_t xfbInfoCount = 0;
for (size_t xfbIndex = 0; xfbIndex < mXFBData.size(); xfbIndex++)
{
if (!mXFBData[xfbIndex])
{
continue;
}
stream->writeInt(xfbIndex);
xfbInfoCount++;
XFBInterfaceVariableInfo &info = *mXFBData[xfbIndex];
SaveShaderInterfaceVariableXfbInfo(info.xfb, stream);
stream->writeInt(info.fieldXfb.size());
for (const ShaderInterfaceVariableXfbInfo &xfb : info.fieldXfb)
{
SaveShaderInterfaceVariableXfbInfo(xfb, stream);
}
}
ASSERT(xfbInfoCount == mPod.xfbInfoCount);
}
}
void ShaderInterfaceVariableInfoMap::load(gl::BinaryInputStream *stream)
{
stream->readStruct(&mPod);
for (IdToIndexMap &idToIndexMap : mIdToIndexMap)
{
// ASSERT(idToIndexMap.empty());
size_t count = stream->readInt<size_t>();
if (count > 0)
{
idToIndexMap.resetWithRawData(count,
stream->getBytes(count * sizeof(*idToIndexMap.data())));
}
}
stream->readVector(&mData);
ASSERT(mXFBData.empty());
ASSERT(mPod.xfbInfoCount <= mData.size());
if (mPod.xfbInfoCount > 0)
{
mXFBData.resize(mData.size());
for (uint32_t i = 0; i < mPod.xfbInfoCount; ++i)
{
size_t xfbIndex = stream->readInt<size_t>();
mXFBData[xfbIndex] = std::make_unique<XFBInterfaceVariableInfo>();
XFBInterfaceVariableInfo &info = *mXFBData[xfbIndex];
LoadShaderInterfaceVariableXfbInfo(stream, &info.xfb);
info.fieldXfb.resize(stream->readInt<size_t>());
for (ShaderInterfaceVariableXfbInfo &xfb : info.fieldXfb)
{
LoadShaderInterfaceVariableXfbInfo(stream, &xfb);
}
}
}
}
void ShaderInterfaceVariableInfoMap::setInputPerVertexActiveMembers(
gl::ShaderType shaderType,
gl::PerVertexMemberBitSet activeMembers)
{
// Input gl_PerVertex is only meaningful for tessellation and geometry stages
ASSERT(shaderType == gl::ShaderType::TessControl ||
shaderType == gl::ShaderType::TessEvaluation || shaderType == gl::ShaderType::Geometry ||
activeMembers.none());
mPod.inputPerVertexActiveMembers[shaderType] = activeMembers;
}
void ShaderInterfaceVariableInfoMap::setOutputPerVertexActiveMembers(
gl::ShaderType shaderType,
gl::PerVertexMemberBitSet activeMembers)
{
// Output gl_PerVertex is only meaningful for vertex, tessellation and geometry stages
ASSERT(shaderType == gl::ShaderType::Vertex || shaderType == gl::ShaderType::TessControl ||
shaderType == gl::ShaderType::TessEvaluation || shaderType == gl::ShaderType::Geometry ||
activeMembers.none());
mPod.outputPerVertexActiveMembers[shaderType] = activeMembers;
}
void ShaderInterfaceVariableInfoMap::setVariableIndex(gl::ShaderType shaderType,
uint32_t id,
VariableIndex index)
{
mIdToIndexMap[shaderType][HashSPIRVId(id)] = index;
}
const VariableIndex &ShaderInterfaceVariableInfoMap::getVariableIndex(gl::ShaderType shaderType,
uint32_t id) const
{
return mIdToIndexMap[shaderType].at(HashSPIRVId(id));
}
ShaderInterfaceVariableInfo &ShaderInterfaceVariableInfoMap::getMutable(gl::ShaderType shaderType,
uint32_t id)
{
ASSERT(hasVariable(shaderType, id));
uint32_t index = getVariableIndex(shaderType, id).index;
return mData[index];
}
XFBInterfaceVariableInfo *ShaderInterfaceVariableInfoMap::getXFBMutable(gl::ShaderType shaderType,
uint32_t id)
{
ASSERT(hasVariable(shaderType, id));
uint32_t index = getVariableIndex(shaderType, id).index;
if (index >= mXFBData.size())
{
mXFBData.resize(index + 1);
}
if (!mXFBData[index])
{
mXFBData[index] = std::make_unique<XFBInterfaceVariableInfo>();
mData[index].hasTransformFeedback = true;
mPod.xfbInfoCount++;
}
return mXFBData[index].get();
}
ShaderInterfaceVariableInfo &ShaderInterfaceVariableInfoMap::add(gl::ShaderType shaderType,
uint32_t id)
{
ASSERT(!hasVariable(shaderType, id));
uint32_t index = static_cast<uint32_t>(mData.size());
setVariableIndex(shaderType, id, {index});
mData.resize(index + 1);
return mData[index];
}
void ShaderInterfaceVariableInfoMap::addResource(gl::ShaderBitSet shaderTypes,
const gl::ShaderMap<uint32_t> &idInShaderTypes,
uint32_t descriptorSet,
uint32_t binding)
{
uint32_t index = static_cast<uint32_t>(mData.size());
mData.resize(index + 1);
ShaderInterfaceVariableInfo *info = &mData[index];
info->descriptorSet = descriptorSet;
info->binding = binding;
info->activeStages = shaderTypes;
for (const gl::ShaderType shaderType : shaderTypes)
{
const uint32_t id = idInShaderTypes[shaderType];
ASSERT(!hasVariable(shaderType, id));
setVariableIndex(shaderType, id, {index});
}
}
ShaderInterfaceVariableInfo &ShaderInterfaceVariableInfoMap::addOrGet(gl::ShaderType shaderType,
uint32_t id)
{
if (!hasVariable(shaderType, id))
{
return add(shaderType, id);
}
else
{
uint32_t index = getVariableIndex(shaderType, id).index;
return mData[index];
}
}
bool ShaderInterfaceVariableInfoMap::hasVariable(gl::ShaderType shaderType, uint32_t id) const
{
const uint32_t hashedId = HashSPIRVId(id);
return hashedId < mIdToIndexMap[shaderType].size() &&
mIdToIndexMap[shaderType].at(hashedId).index != VariableIndex::kInvalid;
}
bool ShaderInterfaceVariableInfoMap::hasTransformFeedbackInfo(gl::ShaderType shaderType,
uint32_t bufferIndex) const
{
return hasVariable(shaderType, SpvGetXfbBufferBlockId(bufferIndex));
}
} // namespace rx