Hash :
c07ef602
Author :
Date :
2021-01-05T12:26:05
Vulkan: Move xfb buffer decl to translator in emulation path This makes @@ XFB-DECL @@ empty on this path. Ultimately, this is working towards removing both @@ XFB-DECL @@ and @@ XFB-OUT @@ macros for both the emulation and extension paths, allowing the shaders to be compiled at compile time rather than link time. Bug: angleproject:3606 Change-Id: If16e9d92c419a04ecd3094481ed546d0708cdb43 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2611305 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Tim Van Patten <timvp@google.com>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
//
// Copyright 2017 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.
//
// ProgramPipelineVk.cpp:
// Implements the class methods for ProgramPipelineVk.
//
#include "libANGLE/renderer/vulkan/ProgramPipelineVk.h"
#include "libANGLE/renderer/glslang_wrapper_utils.h"
#include "libANGLE/renderer/vulkan/GlslangWrapperVk.h"
namespace rx
{
ProgramPipelineVk::ProgramPipelineVk(const gl::ProgramPipelineState &state)
: ProgramPipelineImpl(state)
{
mExecutable.setProgramPipeline(this);
}
ProgramPipelineVk::~ProgramPipelineVk() {}
void ProgramPipelineVk::destroy(const gl::Context *context)
{
ContextVk *contextVk = vk::GetImpl(context);
reset(contextVk);
}
void ProgramPipelineVk::reset(ContextVk *contextVk)
{
mExecutable.reset(contextVk);
}
// TODO: http://anglebug.com/3570: Move/Copy all of the necessary information into
// the ProgramExecutable, so this function can be removed.
void ProgramPipelineVk::fillProgramStateMap(
const ContextVk *contextVk,
gl::ShaderMap<const gl::ProgramState *> *programStatesOut)
{
for (gl::ShaderType shaderType : gl::AllShaderTypes())
{
(*programStatesOut)[shaderType] = nullptr;
ProgramVk *programVk = getShaderProgram(contextVk->getState(), shaderType);
if (programVk)
{
(*programStatesOut)[shaderType] = &programVk->getState();
}
}
}
angle::Result ProgramPipelineVk::link(const gl::Context *glContext,
const gl::ProgramMergedVaryings &mergedVaryings,
const gl::ProgramVaryingPacking &varyingPacking)
{
ContextVk *contextVk = vk::GetImpl(glContext);
const gl::State &glState = glContext->getState();
const gl::ProgramPipeline *glPipeline = glState.getProgramPipeline();
const gl::ProgramExecutable &glExecutable = glPipeline->getExecutable();
GlslangSourceOptions options =
GlslangWrapperVk::CreateSourceOptions(contextVk->getRenderer()->getFeatures());
GlslangProgramInterfaceInfo glslangProgramInterfaceInfo;
GlslangWrapperVk::ResetGlslangProgramInterfaceInfo(&glslangProgramInterfaceInfo);
mExecutable.clearVariableInfoMap();
// Now that the program pipeline has all of the programs attached, the various descriptor
// set/binding locations need to be re-assigned to their correct values.
const gl::ShaderType linkedTransformFeedbackStage =
glExecutable.getLinkedTransformFeedbackStage();
gl::ShaderType frontShaderType = gl::ShaderType::InvalidEnum;
for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
{
gl::Program *glProgram =
const_cast<gl::Program *>(glPipeline->getShaderProgram(shaderType));
if (glProgram)
{
// The program interface info must survive across shaders, except
// for some program-specific values.
ProgramVk *programVk = vk::GetImpl(glProgram);
const GlslangProgramInterfaceInfo &programProgramInterfaceInfo =
programVk->getGlslangProgramInterfaceInfo();
glslangProgramInterfaceInfo.locationsUsedForXfbExtension =
programProgramInterfaceInfo.locationsUsedForXfbExtension;
const bool isTransformFeedbackStage =
shaderType == linkedTransformFeedbackStage &&
!glProgram->getState().getLinkedTransformFeedbackVaryings().empty();
GlslangAssignLocations(options, glProgram->getState(), varyingPacking, shaderType,
frontShaderType, isTransformFeedbackStage,
&glslangProgramInterfaceInfo, &mExecutable.mVariableInfoMap);
frontShaderType = shaderType;
}
}
if (contextVk->getFeatures().enablePrecisionQualifiers.enabled)
{
mExecutable.resolvePrecisionMismatch(mergedVaryings);
}
return mExecutable.createPipelineLayout(glContext, nullptr);
}
size_t ProgramPipelineVk::calcUniformUpdateRequiredSpace(
ContextVk *contextVk,
const gl::ProgramExecutable &glExecutable,
const gl::State &glState,
gl::ShaderMap<VkDeviceSize> *uniformOffsets) const
{
size_t requiredSpace = 0;
for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
{
ProgramVk *programVk = getShaderProgram(glState, shaderType);
ASSERT(programVk);
if (programVk->isShaderUniformDirty(shaderType))
{
(*uniformOffsets)[shaderType] = requiredSpace;
requiredSpace += programVk->getDefaultUniformAlignedSize(contextVk, shaderType);
}
}
return requiredSpace;
}
angle::Result ProgramPipelineVk::updateUniforms(ContextVk *contextVk)
{
const gl::State &glState = contextVk->getState();
const gl::ProgramExecutable &glExecutable = *glState.getProgramExecutable();
vk::DynamicBuffer *defaultUniformStorage = contextVk->getDefaultUniformStorage();
uint8_t *bufferData = nullptr;
VkDeviceSize bufferOffset = 0;
uint32_t offsetIndex = 0;
bool anyNewBufferAllocated = false;
gl::ShaderMap<VkDeviceSize> offsets; // offset to the beginning of bufferData
size_t requiredSpace;
// We usually only update uniform data for shader stages that are actually dirty. But when the
// buffer for uniform data have switched, because all shader stages are using the same buffer,
// we then must update uniform data for all shader stages to keep all shader stages' unform data
// in the same buffer.
requiredSpace = calcUniformUpdateRequiredSpace(contextVk, glExecutable, glState, &offsets);
ASSERT(requiredSpace > 0);
// Allocate space from dynamicBuffer. Always try to allocate from the current buffer first.
// If that failed, we deal with fall out and try again.
if (!defaultUniformStorage->allocateFromCurrentBuffer(requiredSpace, &bufferData,
&bufferOffset))
{
setAllDefaultUniformsDirty(contextVk->getState());
requiredSpace = calcUniformUpdateRequiredSpace(contextVk, glExecutable, glState, &offsets);
ANGLE_TRY(defaultUniformStorage->allocate(contextVk, requiredSpace, &bufferData, nullptr,
&bufferOffset, &anyNewBufferAllocated));
}
for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
{
ProgramVk *programVk = getShaderProgram(glState, shaderType);
ASSERT(programVk);
if (programVk->isShaderUniformDirty(shaderType))
{
const angle::MemoryBuffer &uniformData =
programVk->getDefaultUniformBlocks()[shaderType].uniformData;
memcpy(&bufferData[offsets[shaderType]], uniformData.data(), uniformData.size());
mExecutable.mDynamicBufferOffsets[offsetIndex] =
static_cast<uint32_t>(bufferOffset + offsets[shaderType]);
programVk->clearShaderUniformDirtyBit(shaderType);
}
++offsetIndex;
}
ANGLE_TRY(defaultUniformStorage->flush(contextVk));
// Because the uniform buffers are per context, we can't rely on dynamicBuffer's allocate
// function to tell us if you have got a new buffer or not. Other program's use of the buffer
// might already pushed dynamicBuffer to a new buffer. We record which buffer (represented by
// the unique BufferSerial number) we were using with the current descriptor set and then we
// use that recorded BufferSerial compare to the current uniform buffer to quickly detect if
// there is a buffer switch or not. We need to retrieve from the descriptor set cache or
// allocate a new descriptor set whenever there is uniform buffer switch.
vk::BufferHelper *defaultUniformBuffer = defaultUniformStorage->getCurrentBuffer();
if (mExecutable.getCurrentDefaultUniformBufferSerial() !=
defaultUniformBuffer->getBufferSerial())
{
// We need to reinitialize the descriptor sets if we newly allocated buffers since we can't
// modify the descriptor sets once initialized.
vk::UniformsAndXfbDesc defaultUniformsDesc;
vk::UniformsAndXfbDesc *uniformsAndXfbBufferDesc;
if (glExecutable.hasTransformFeedbackOutput())
{
TransformFeedbackVk *transformFeedbackVk =
vk::GetImpl(glState.getCurrentTransformFeedback());
uniformsAndXfbBufferDesc = &transformFeedbackVk->getTransformFeedbackDesc();
uniformsAndXfbBufferDesc->updateDefaultUniformBuffer(
defaultUniformBuffer->getBufferSerial());
}
else
{
defaultUniformsDesc.updateDefaultUniformBuffer(defaultUniformBuffer->getBufferSerial());
uniformsAndXfbBufferDesc = &defaultUniformsDesc;
}
bool newDescriptorSetAllocated;
ANGLE_TRY(mExecutable.allocUniformAndXfbDescriptorSet(contextVk, *uniformsAndXfbBufferDesc,
&newDescriptorSetAllocated));
if (newDescriptorSetAllocated)
{
for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
{
ProgramVk *programVk = getShaderProgram(glState, shaderType);
mExecutable.updateDefaultUniformsDescriptorSet(
shaderType, programVk->getDefaultUniformBlocks()[shaderType],
defaultUniformBuffer, contextVk);
mExecutable.updateTransformFeedbackDescriptorSetImpl(programVk->getState(),
contextVk);
}
}
}
return angle::Result::Continue;
}
bool ProgramPipelineVk::dirtyUniforms(const gl::State &glState)
{
for (const gl::ShaderType shaderType : gl::AllShaderTypes())
{
const ProgramVk *program = getShaderProgram(glState, shaderType);
if (program && program->dirtyUniforms())
{
return true;
}
}
return false;
}
void ProgramPipelineVk::setAllDefaultUniformsDirty(const gl::State &glState)
{
const gl::ProgramExecutable &glExecutable = *glState.getProgramExecutable();
for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
{
ProgramVk *programVk = getShaderProgram(glState, shaderType);
ASSERT(programVk);
programVk->setShaderUniformDirtyBit(shaderType);
}
}
void ProgramPipelineVk::onProgramBind(ContextVk *contextVk)
{
setAllDefaultUniformsDirty(contextVk->getState());
}
} // namespace rx