vk: refactor VulkanProgram (#7221)
This commit is contained in:
@@ -237,11 +237,12 @@ void VulkanBlitter::lazyInit() noexcept {
|
||||
|
||||
VkShaderModule vertexShader = decode(VKSHADERS_BLITDEPTHVS_DATA, VKSHADERS_BLITDEPTHVS_SIZE);
|
||||
VkShaderModule fragmentShader = decode(VKSHADERS_BLITDEPTHFS_DATA, VKSHADERS_BLITDEPTHFS_SIZE);
|
||||
mDepthResolveProgram = new VulkanProgram(mDevice, vertexShader, fragmentShader);
|
||||
|
||||
// Allocate one anonymous sampler at slot 0.
|
||||
mDepthResolveProgram->samplerGroupInfo[0].samplers.reserve(1);
|
||||
mDepthResolveProgram->samplerGroupInfo[0].samplers.resize(1);
|
||||
VulkanProgram::CustomSamplerInfoList samplers = {
|
||||
{0, 0, ShaderStageFlags::FRAGMENT},
|
||||
};
|
||||
mDepthResolveProgram = new VulkanProgram(mDevice, vertexShader, fragmentShader, samplers);
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_BLITTER)
|
||||
utils::slog.d << "Created Shader Module for VulkanBlitter "
|
||||
@@ -359,7 +360,7 @@ void VulkanBlitter::blitSlowDepth(VkFilter filter, const VkExtent2D srcExtent, V
|
||||
// DRAW THE TRIANGLE
|
||||
// -----------------
|
||||
|
||||
mPipelineCache.bindProgram(*mDepthResolveProgram);
|
||||
mPipelineCache.bindProgram(mDepthResolveProgram);
|
||||
mPipelineCache.bindPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
|
||||
|
||||
auto vkraster = mPipelineCache.getCurrentRasterState();
|
||||
|
||||
@@ -1548,7 +1548,7 @@ void VulkanDriver::draw(PipelineState pipelineState, Handle<HwRenderPrimitive> r
|
||||
VkDeviceSize const* offsets = prim.vertexBuffer->getOffsets();
|
||||
|
||||
// Push state changes to the VulkanPipelineCache instance. This is fast and does not make VK calls.
|
||||
mPipelineCache.bindProgram(*program);
|
||||
mPipelineCache.bindProgram(program);
|
||||
mPipelineCache.bindRasterState(mPipelineCache.getCurrentRasterState());
|
||||
mPipelineCache.bindPrimitiveTopology(prim.primitiveTopology);
|
||||
mPipelineCache.bindVertexArray(attribDesc, bufferDesc, bufferCount);
|
||||
@@ -1560,68 +1560,69 @@ void VulkanDriver::draw(PipelineState pipelineState, Handle<HwRenderPrimitive> r
|
||||
VkDescriptorImageInfo samplerInfo[VulkanPipelineCache::SAMPLER_BINDING_COUNT] = {};
|
||||
VulkanTexture* samplerTextures[VulkanPipelineCache::SAMPLER_BINDING_COUNT] = {nullptr};
|
||||
|
||||
VulkanPipelineCache::UsageFlags usage;
|
||||
auto const& bindingToSamplerIndex = program->getBindingToSamplerIndex();
|
||||
VulkanPipelineCache::UsageFlags usage = program->getUsage();
|
||||
|
||||
UTILS_NOUNROLL
|
||||
for (uint8_t samplerGroupIdx = 0; samplerGroupIdx < Program::SAMPLER_BINDING_COUNT; samplerGroupIdx++) {
|
||||
const auto& samplerGroup = program->samplerGroupInfo[samplerGroupIdx];
|
||||
const auto& samplers = samplerGroup.samplers;
|
||||
if (samplers.empty()) {
|
||||
for (uint8_t binding = 0; binding < VulkanPipelineCache::SAMPLER_BINDING_COUNT; binding++) {
|
||||
uint16_t const indexPair = bindingToSamplerIndex[binding];
|
||||
|
||||
if (indexPair == 0xffff) {
|
||||
usage = VulkanPipelineCache::disableUsageFlags(binding, usage);
|
||||
continue;
|
||||
}
|
||||
VulkanSamplerGroup* vksb = mSamplerBindings[samplerGroupIdx];
|
||||
|
||||
uint16_t const samplerGroupInd = (indexPair >> 8) & 0xff;
|
||||
uint16_t const samplerInd = (indexPair & 0xff);
|
||||
|
||||
VulkanSamplerGroup* vksb = mSamplerBindings[samplerGroupInd];
|
||||
if (!vksb) {
|
||||
usage = VulkanPipelineCache::disableUsageFlags(binding, usage);
|
||||
continue;
|
||||
}
|
||||
SamplerGroup* sb = vksb->sb.get();
|
||||
assert_invariant(sb->getSize() == samplers.size());
|
||||
size_t samplerIdx = 0;
|
||||
for (auto& sampler : samplers) {
|
||||
const SamplerDescriptor* boundSampler = sb->data() + samplerIdx;
|
||||
samplerIdx++;
|
||||
SamplerDescriptor const* boundSampler = ((SamplerDescriptor*) vksb->sb->data()) + samplerInd;
|
||||
|
||||
if (UTILS_LIKELY(boundSampler->t)) {
|
||||
VulkanTexture* texture = mResourceAllocator.handle_cast<VulkanTexture*>(boundSampler->t);
|
||||
VkImageViewType const expectedType = texture->getViewType();
|
||||
|
||||
// TODO: can this uninitialized check be checked in a higher layer?
|
||||
// This fallback path is very flaky because the dummy texture might not have
|
||||
// matching characteristics. (e.g. if the missing texture is a 3D texture)
|
||||
if (UTILS_UNLIKELY(texture->getPrimaryImageLayout() == VulkanLayout::UNDEFINED)) {
|
||||
#if FVK_ENABLED(FVK_DEBUG_TEXTURE)
|
||||
utils::slog.w << "Uninitialized texture bound to '" << sampler.name.c_str() << "'";
|
||||
utils::slog.w << " in material '" << program->name.c_str() << "'";
|
||||
utils::slog.w << " at binding point " << +sampler.binding << utils::io::endl;
|
||||
#endif
|
||||
texture = mEmptyTexture.get();
|
||||
}
|
||||
|
||||
const SamplerParams& samplerParams = boundSampler->s;
|
||||
VkSampler vksampler = mSamplerCache.getSampler(samplerParams);
|
||||
|
||||
usage = VulkanPipelineCache::getUsageFlags(sampler.binding, samplerGroup.stageFlags, usage);
|
||||
|
||||
VkImageView imageView = VK_NULL_HANDLE;
|
||||
VkImageSubresourceRange const range = texture->getPrimaryViewRange();
|
||||
if (any(texture->usage & TextureUsage::DEPTH_ATTACHMENT)
|
||||
&& expectedType == VK_IMAGE_VIEW_TYPE_2D) {
|
||||
// If the sampler is part of a mipmapped depth texture, where one of the level
|
||||
// *can* be an attachment, then the sampler for this texture has the same view
|
||||
// properties as a view for an attachment. Therefore, we can use
|
||||
// getAttachmentView to get a corresponding VkImageView.
|
||||
imageView = texture->getAttachmentView(range);
|
||||
} else {
|
||||
imageView = texture->getViewForType(range, expectedType);
|
||||
}
|
||||
|
||||
samplerInfo[sampler.binding] = {
|
||||
.sampler = vksampler,
|
||||
.imageView = imageView,
|
||||
.imageLayout = ImgUtil::getVkLayout(texture->getPrimaryImageLayout())
|
||||
};
|
||||
samplerTextures[sampler.binding] = texture;
|
||||
}
|
||||
if (UTILS_UNLIKELY(!boundSampler->t)) {
|
||||
usage = VulkanPipelineCache::disableUsageFlags(binding, usage);
|
||||
continue;
|
||||
}
|
||||
|
||||
VulkanTexture* texture = mResourceAllocator.handle_cast<VulkanTexture*>(boundSampler->t);
|
||||
VkImageViewType const expectedType = texture->getViewType();
|
||||
|
||||
// TODO: can this uninitialized check be checked in a higher layer?
|
||||
// This fallback path is very flaky because the dummy texture might not have
|
||||
// matching characteristics. (e.g. if the missing texture is a 3D texture)
|
||||
if (UTILS_UNLIKELY(texture->getPrimaryImageLayout() == VulkanLayout::UNDEFINED)) {
|
||||
#if FVK_ENABLED(FVK_DEBUG_TEXTURE)
|
||||
utils::slog.w << "Uninitialized texture bound to '" << sampler.name.c_str() << "'";
|
||||
utils::slog.w << " in material '" << program->name.c_str() << "'";
|
||||
utils::slog.w << " at binding point " << +sampler.binding << utils::io::endl;
|
||||
#endif
|
||||
texture = mEmptyTexture.get();
|
||||
}
|
||||
|
||||
SamplerParams const& samplerParams = boundSampler->s;
|
||||
VkSampler const vksampler = mSamplerCache.getSampler(samplerParams);
|
||||
VkImageView imageView = VK_NULL_HANDLE;
|
||||
VkImageSubresourceRange const range = texture->getPrimaryViewRange();
|
||||
if (any(texture->usage & TextureUsage::DEPTH_ATTACHMENT) &&
|
||||
expectedType == VK_IMAGE_VIEW_TYPE_2D) {
|
||||
// If the sampler is part of a mipmapped depth texture, where one of the level *can* be
|
||||
// an attachment, then the sampler for this texture has the same view properties as a
|
||||
// view for an attachment. Therefore, we can use getAttachmentView to get a
|
||||
// corresponding VkImageView.
|
||||
imageView = texture->getAttachmentView(range);
|
||||
} else {
|
||||
imageView = texture->getViewForType(range, expectedType);
|
||||
}
|
||||
|
||||
samplerInfo[binding] = {
|
||||
.sampler = vksampler,
|
||||
.imageView = imageView,
|
||||
.imageLayout = ImgUtil::getVkLayout(texture->getPrimaryImageLayout())
|
||||
};
|
||||
samplerTextures[binding] = texture;
|
||||
}
|
||||
|
||||
mPipelineCache.bindSamplers(samplerInfo, samplerTextures, usage);
|
||||
|
||||
@@ -49,88 +49,100 @@ static void clampToFramebuffer(VkRect2D* rect, uint32_t fbWidth, uint32_t fbHeig
|
||||
VulkanProgram::VulkanProgram(VkDevice device, const Program& builder) noexcept
|
||||
: HwProgram(builder.getName()),
|
||||
VulkanResource(VulkanResourceType::PROGRAM),
|
||||
mInfo(new PipelineInfo(builder.getSpecializationConstants().size())),
|
||||
mDevice(device) {
|
||||
auto const& blobs = builder.getShadersSource();
|
||||
VkShaderModule* modules[2] = {&bundle.vertex, &bundle.fragment};
|
||||
// TODO: handle compute shaders.
|
||||
for (size_t i = 0; i < 2; i++) {
|
||||
auto& blobs = builder.getShadersSource();
|
||||
auto& modules = mInfo->shaders;
|
||||
for (size_t i = 0; i < MAX_SHADER_MODULES; i++) {
|
||||
const auto& blob = blobs[i];
|
||||
VkShaderModule* module = modules[i];
|
||||
VkShaderModuleCreateInfo moduleInfo = {};
|
||||
moduleInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
moduleInfo.codeSize = blob.size();
|
||||
moduleInfo.pCode = (uint32_t*) blob.data();
|
||||
VkResult result = vkCreateShaderModule(mDevice, &moduleInfo, VKALLOC, module);
|
||||
uint32_t* data = (uint32_t*)blob.data();
|
||||
VkShaderModule& module = modules[i];
|
||||
VkShaderModuleCreateInfo moduleInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
||||
.codeSize = blob.size(),
|
||||
.pCode = data,
|
||||
};
|
||||
VkResult result = vkCreateShaderModule(mDevice, &moduleInfo, VKALLOC, &module);
|
||||
ASSERT_POSTCONDITION(result == VK_SUCCESS, "Unable to create shader module.");
|
||||
}
|
||||
|
||||
// Note that bools are 4-bytes in Vulkan
|
||||
// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkBool32.html
|
||||
constexpr uint32_t const CONSTANT_SIZE = 4;
|
||||
|
||||
// populate the specialization constants requirements right now
|
||||
auto const& specializationConstants = builder.getSpecializationConstants();
|
||||
if (!specializationConstants.empty()) {
|
||||
// Allocate a single heap block to store all the specialization constants structures
|
||||
// our supported types are int32, float and bool, so we use 4 bytes per data. bool will
|
||||
// just use the first byte.
|
||||
char* pStorage = (char*)malloc(
|
||||
sizeof(VkSpecializationInfo) +
|
||||
specializationConstants.size() * sizeof(VkSpecializationMapEntry) +
|
||||
specializationConstants.size() * 4);
|
||||
|
||||
VkSpecializationInfo* const pInfo = (VkSpecializationInfo*)pStorage;
|
||||
VkSpecializationMapEntry* const pEntries =
|
||||
(VkSpecializationMapEntry*)(pStorage + sizeof(VkSpecializationInfo));
|
||||
void* pData = pStorage + sizeof(VkSpecializationInfo) +
|
||||
specializationConstants.size() * sizeof(VkSpecializationMapEntry);
|
||||
|
||||
*pInfo = {
|
||||
.mapEntryCount = specializationConstants.size(),
|
||||
.pMapEntries = pEntries,
|
||||
.dataSize = specializationConstants.size() * 4,
|
||||
.pData = pData,
|
||||
uint32_t const specConstCount = static_cast<uint32_t>(specializationConstants.size());
|
||||
char* specData = mInfo->specConstData.get();
|
||||
if (specConstCount > 0) {
|
||||
mInfo->specializationInfo = {
|
||||
.mapEntryCount = specConstCount,
|
||||
.pMapEntries = mInfo->specConsts.data(),
|
||||
.dataSize = specConstCount * CONSTANT_SIZE,
|
||||
.pData = specData,
|
||||
};
|
||||
}
|
||||
for (uint32_t i = 0; i < specConstCount; ++i) {
|
||||
uint32_t const offset = i * CONSTANT_SIZE;
|
||||
mInfo->specConsts[i] = {
|
||||
.constantID = specializationConstants[i].id,
|
||||
.offset = offset,
|
||||
.size = CONSTANT_SIZE,
|
||||
};
|
||||
using SpecConstant = Program::SpecializationConstant::Type;
|
||||
char const* addr = (char*)specData + offset;
|
||||
SpecConstant const& arg = specializationConstants[i].value;
|
||||
if (std::holds_alternative<bool>(arg)) {
|
||||
*((VkBool32*)addr) = std::get<bool>(arg) ? VK_TRUE : VK_FALSE;
|
||||
} else if (std::holds_alternative<float>(arg)) {
|
||||
*((float*)addr) = std::get<float>(arg);
|
||||
} else {
|
||||
*((int32_t*)addr) = std::get<int32_t>(arg);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < specializationConstants.size(); i++) {
|
||||
uint32_t const offset = uint32_t(i) * 4;
|
||||
pEntries[i] = {
|
||||
.constantID = specializationConstants[i].id,
|
||||
.offset = offset,
|
||||
// Note that bools are 4-bytes in Vulkan
|
||||
// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkBool32.html
|
||||
.size = 4,
|
||||
};
|
||||
|
||||
using SpecConstant = Program::SpecializationConstant::Type;
|
||||
char const* addr = (char*)pData + offset;
|
||||
SpecConstant const& arg = specializationConstants[i].value;
|
||||
if (std::holds_alternative<bool>(arg)) {
|
||||
*((VkBool32*)addr) = std::get<bool>(arg) ? VK_TRUE : VK_FALSE;
|
||||
} else if (std::holds_alternative<float>(arg)) {
|
||||
*((float*)addr) = std::get<float>(arg);
|
||||
} else {
|
||||
*((int32_t*)addr) = std::get<int32_t>(arg);
|
||||
}
|
||||
auto& groupInfo = builder.getSamplerGroupInfo();
|
||||
auto& bindingToSamplerIndex = mInfo->bindingToSamplerIndex;
|
||||
auto& usage = mInfo->usage;
|
||||
for (uint8_t groupInd = 0; groupInd < Program::SAMPLER_BINDING_COUNT; groupInd++) {
|
||||
auto const& group = groupInfo[groupInd];
|
||||
auto const& samplers = group.samplers;
|
||||
for (size_t i = 0; i < samplers.size(); ++i) {
|
||||
uint32_t const binding = samplers[i].binding;
|
||||
bindingToSamplerIndex[binding] = (groupInd << 8) | (0xff & i);
|
||||
usage = VulkanPipelineCache::getUsageFlags(binding, group.stageFlags, usage);
|
||||
}
|
||||
bundle.specializationInfos = pInfo;
|
||||
}
|
||||
|
||||
// Make a copy of the binding map
|
||||
samplerGroupInfo = builder.getSamplerGroupInfo();
|
||||
#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
|
||||
utils::slog.d << "Created VulkanProgram " << builder << ", shaders = (" << bundle.vertex
|
||||
<< ", " << bundle.fragment << ")" << utils::io::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
VulkanProgram::VulkanProgram(VkDevice device, VkShaderModule vs, VkShaderModule fs) noexcept
|
||||
VulkanProgram::VulkanProgram(VkDevice device, VkShaderModule vs, VkShaderModule fs,
|
||||
CustomSamplerInfoList const& samplerInfo) noexcept
|
||||
: VulkanResource(VulkanResourceType::PROGRAM),
|
||||
mInfo(new PipelineInfo(0)),
|
||||
mDevice(device) {
|
||||
bundle.vertex = vs;
|
||||
bundle.fragment = fs;
|
||||
mInfo->shaders[0] = vs;
|
||||
mInfo->shaders[1] = fs;
|
||||
auto& bindingToSamplerIndex = mInfo->bindingToSamplerIndex;
|
||||
auto& usage = mInfo->usage;
|
||||
bindingToSamplerIndex.resize(samplerInfo.size());
|
||||
for (uint16_t binding = 0; binding < samplerInfo.size(); ++binding) {
|
||||
auto const& sampler = samplerInfo[binding];
|
||||
bindingToSamplerIndex[binding]
|
||||
= (sampler.groupIndex << 8) | (0xff & sampler.samplerIndex);
|
||||
usage = VulkanPipelineCache::getUsageFlags(binding, sampler.flags, usage);
|
||||
}
|
||||
}
|
||||
|
||||
VulkanProgram::~VulkanProgram() {
|
||||
vkDestroyShaderModule(mDevice, bundle.vertex, VKALLOC);
|
||||
vkDestroyShaderModule(mDevice, bundle.fragment, VKALLOC);
|
||||
free(bundle.specializationInfos);
|
||||
for (auto shader: mInfo->shaders) {
|
||||
vkDestroyShaderModule(mDevice, shader, VKALLOC);
|
||||
}
|
||||
delete mInfo;
|
||||
}
|
||||
|
||||
// Creates a special "default" render target (i.e. associated with the swap chain)
|
||||
|
||||
@@ -37,14 +37,64 @@ namespace filament::backend {
|
||||
class VulkanTimestamps;
|
||||
|
||||
struct VulkanProgram : public HwProgram, VulkanResource {
|
||||
|
||||
VulkanProgram(VkDevice device, const Program& builder) noexcept;
|
||||
VulkanProgram(VkDevice device, VkShaderModule vs, VkShaderModule fs) noexcept;
|
||||
|
||||
struct CustomSamplerInfo {
|
||||
uint8_t groupIndex;
|
||||
uint8_t samplerIndex;
|
||||
ShaderStageFlags flags;
|
||||
};
|
||||
using CustomSamplerInfoList = utils::FixedCapacityVector<CustomSamplerInfo>;
|
||||
|
||||
// We allow custom descriptor of the samplers within shaders. This is needed if we want to use
|
||||
// a program that exists only in the backend - for example, for shader-based bliting.
|
||||
VulkanProgram(VkDevice device, VkShaderModule vs, VkShaderModule fs,
|
||||
CustomSamplerInfoList const& samplerInfo) noexcept;
|
||||
~VulkanProgram();
|
||||
VulkanPipelineCache::ProgramBundle bundle;
|
||||
Program::SamplerGroupInfo samplerGroupInfo;
|
||||
|
||||
inline VkShaderModule getVertexShader() const {
|
||||
return mInfo->shaders[0];
|
||||
}
|
||||
|
||||
inline VkShaderModule getFragmentShader() const { return mInfo->shaders[1]; }
|
||||
|
||||
inline VulkanPipelineCache::UsageFlags getUsage() const { return mInfo->usage; }
|
||||
|
||||
inline utils::FixedCapacityVector<uint16_t> const& getBindingToSamplerIndex() const {
|
||||
return mInfo->bindingToSamplerIndex;
|
||||
}
|
||||
|
||||
inline VkSpecializationInfo const& getSpecConstInfo() const {
|
||||
return mInfo->specializationInfo;
|
||||
}
|
||||
|
||||
private:
|
||||
VkDevice mDevice;
|
||||
// TODO: handle compute shaders.
|
||||
// The expected order of shaders - from frontend to backend - is vertex, fragment, compute.
|
||||
static constexpr uint8_t MAX_SHADER_MODULES = 2;
|
||||
|
||||
struct PipelineInfo {
|
||||
PipelineInfo(size_t specConstsCount) :
|
||||
bindingToSamplerIndex(MAX_SAMPLER_COUNT, 0xffff),
|
||||
specConsts(specConstsCount, VkSpecializationMapEntry{}),
|
||||
specConstData(new char[specConstsCount * 4])
|
||||
{}
|
||||
|
||||
// This bitset maps to each of the sampler in the sampler groups associated with this
|
||||
// program, and whether each sampler is used in which shader (i.e. vert, frag, compute).
|
||||
VulkanPipelineCache::UsageFlags usage;
|
||||
|
||||
// We store the samplerGroupIndex as the top 8-bit and the index within each group as the lower 8-bit.
|
||||
utils::FixedCapacityVector<uint16_t> bindingToSamplerIndex;
|
||||
VkShaderModule shaders[MAX_SHADER_MODULES] = {VK_NULL_HANDLE};
|
||||
VkSpecializationInfo specializationInfo = {};
|
||||
utils::FixedCapacityVector<VkSpecializationMapEntry> specConsts;
|
||||
std::unique_ptr<char[]> specConstData;
|
||||
};
|
||||
|
||||
PipelineInfo* mInfo;
|
||||
VkDevice mDevice = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
// The render target bundles together a set of attachments, each of which can have one of the
|
||||
|
||||
@@ -65,6 +65,13 @@ VulkanPipelineCache::getUsageFlags(uint16_t binding, ShaderStageFlags flags, Usa
|
||||
return src;
|
||||
}
|
||||
|
||||
VulkanPipelineCache::UsageFlags VulkanPipelineCache::disableUsageFlags(uint16_t binding,
|
||||
UsageFlags src) {
|
||||
src.unset(binding);
|
||||
src.unset(MAX_SAMPLER_COUNT + binding);
|
||||
return src;
|
||||
}
|
||||
|
||||
VulkanPipelineCache::VulkanPipelineCache(VulkanResourceAllocator* allocator)
|
||||
: mCurrentRasterState(createDefaultRasterState()),
|
||||
mResourceAllocator(allocator),
|
||||
@@ -558,12 +565,10 @@ VulkanPipelineCache::PipelineLayoutCacheEntry* VulkanPipelineCache::getOrCreateP
|
||||
return &mPipelineLayouts.emplace(mPipelineRequirements.layout, cacheEntry).first.value();
|
||||
}
|
||||
|
||||
void VulkanPipelineCache::bindProgram(const VulkanProgram& program) noexcept {
|
||||
const VkShaderModule shaders[2] = { program.bundle.vertex, program.bundle.fragment };
|
||||
for (uint32_t ssi = 0; ssi < SHADER_MODULE_COUNT; ssi++) {
|
||||
mPipelineRequirements.shaders[ssi] = shaders[ssi];
|
||||
}
|
||||
mSpecializationRequirements = program.bundle.specializationInfos;
|
||||
void VulkanPipelineCache::bindProgram(VulkanProgram* program) noexcept {
|
||||
mPipelineRequirements.shaders[0] = program->getVertexShader();
|
||||
mPipelineRequirements.shaders[1] = program->getFragmentShader();
|
||||
mSpecializationRequirements = &program->getSpecConstInfo();
|
||||
}
|
||||
|
||||
void VulkanPipelineCache::bindRasterState(const RasterState& rasterState) noexcept {
|
||||
|
||||
@@ -91,6 +91,7 @@ public:
|
||||
|
||||
using UsageFlags = utils::bitset128;
|
||||
static UsageFlags getUsageFlags(uint16_t binding, ShaderStageFlags stages, UsageFlags src = {});
|
||||
static UsageFlags disableUsageFlags(uint16_t binding, UsageFlags src);
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic warning "-Wpadded"
|
||||
@@ -150,7 +151,7 @@ public:
|
||||
void bindScissor(VkCommandBuffer cmdbuffer, VkRect2D scissor) noexcept;
|
||||
|
||||
// Each of the following methods are fast and do not make Vulkan calls.
|
||||
void bindProgram(const VulkanProgram& program) noexcept;
|
||||
void bindProgram(VulkanProgram* program) noexcept;
|
||||
void bindRasterState(const RasterState& rasterState) noexcept;
|
||||
void bindRenderPass(VkRenderPass renderPass, int subpassIndex) noexcept;
|
||||
void bindPrimitiveTopology(VkPrimitiveTopology topology) noexcept;
|
||||
@@ -415,7 +416,7 @@ private:
|
||||
RasterState mCurrentRasterState;
|
||||
PipelineKey mPipelineRequirements = {};
|
||||
DescriptorKey mDescriptorRequirements = {};
|
||||
VkSpecializationInfo* mSpecializationRequirements = {};
|
||||
VkSpecializationInfo const* mSpecializationRequirements = nullptr;
|
||||
|
||||
// Current bindings for the pipeline and descriptor sets.
|
||||
PipelineKey mBoundPipeline = {};
|
||||
|
||||
Reference in New Issue
Block a user