Commit 77637f2d by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Generate xfb support code in SPIR-V for emulation path

This change moves the code generation at link time from source code to SPIR-V. As a result, transform feedback extension and emulation paths are more similarly handled before SPIR-V transformation (they both store information identically in the ShaderInterfaceVariableInfoMap). This change gets rid of the @@ XFB-OUT @@ marker. With no source code generation at link time, shader compilation can be moved to glCompileShader time. Bug: angleproject:4888 Change-Id: I8cdb89c22b57ce48cf5d226b8e41622d9d550d46 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2713269 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com>
parent b3fb450c
......@@ -892,6 +892,7 @@ extern const char kLineRasterEmulationPosition[];
// Transform feedback emulation support
extern const char kXfbEmulationGetOffsetsFunctionName[];
extern const char kXfbEmulationCaptureFunctionName[];
extern const char kXfbEmulationBufferBlockName[];
extern const char kXfbEmulationBufferName[];
extern const char kXfbEmulationBufferFieldName[];
......
{
"src/common/gen_uniform_type_table.py":
"f1f6e52f3897773667c714c8da626122",
"714cdb13f7c30af4890922a856456ddb",
"src/common/uniform_type_info_autogen.cpp":
"4903e2a4c6c34e65b0f0c0d6eb2b470d"
"85b351f2d5525d1af422a880e361a2bd"
}
\ No newline at end of file
......@@ -101,7 +101,7 @@ const UniformTypeInfo &GetUniformTypeInfo(GLenum uniformType)
}} // namespace gl
"""
type_info_data_template = """{{{type}, {component_type}, {texture_type}, {transposed_type}, {bool_type}, {sampler_format}, {rows}, {columns}, {components}, {component_size}, {internal_size}, {external_size}, {is_sampler}, {is_matrix}, {is_image}, {glsl_asfloat} }}"""
type_info_data_template = """{{{type}, {component_type}, {texture_type}, {transposed_type}, {bool_type}, {sampler_format}, {rows}, {columns}, {components}, {component_size}, {internal_size}, {external_size}, {is_sampler}, {is_matrix}, {is_image} }}"""
type_index_case_template = """case {enum_value}: return {index_value};"""
......@@ -224,22 +224,6 @@ def get_is_image(uniform_type):
return cpp_bool("_VIDEO_" not in uniform_type and "_IMAGE_" in uniform_type)
def get_glsl_asfloat(uniform_type):
component_type = get_component_type(uniform_type)
if component_type == "GL_BOOL":
return '""'
elif component_type == "GL_FLOAT":
return '""'
elif component_type == "GL_INT":
return '"intBitsToFloat"'
elif component_type == "GL_UNSIGNED_INT":
return '"uintBitsToFloat"'
elif component_type == "GL_NONE":
return '""'
else:
raise "Invalid component type: " + component_type
def gen_type_info(uniform_type):
return type_info_data_template.format(
type=uniform_type,
......@@ -256,8 +240,7 @@ def gen_type_info(uniform_type):
external_size=get_external_size(uniform_type),
is_sampler=get_is_sampler(uniform_type),
is_matrix=get_is_matrix(uniform_type),
is_image=get_is_image(uniform_type),
glsl_asfloat=get_glsl_asfloat(uniform_type))
is_image=get_is_image(uniform_type))
def gen_type_index_case(index, uniform_type):
......
......@@ -148,8 +148,7 @@ struct UniformTypeInfo final : angle::NonCopyable
size_t externalSize,
bool isSampler,
bool isMatrixType,
bool isImageType,
const char *glslAsFloat);
bool isImageType);
GLenum type;
GLenum componentType;
......@@ -166,7 +165,6 @@ struct UniformTypeInfo final : angle::NonCopyable
bool isSampler;
bool isMatrixType;
bool isImageType;
const char *glslAsFloat;
};
inline constexpr UniformTypeInfo::UniformTypeInfo(GLenum type,
......@@ -183,8 +181,7 @@ inline constexpr UniformTypeInfo::UniformTypeInfo(GLenum type,
size_t externalSize,
bool isSampler,
bool isMatrixType,
bool isImageType,
const char *glslAsFloat)
bool isImageType)
: type(type),
componentType(componentType),
textureType(textureType),
......@@ -199,8 +196,7 @@ inline constexpr UniformTypeInfo::UniformTypeInfo(GLenum type,
externalSize(externalSize),
isSampler(isSampler),
isMatrixType(isMatrixType),
isImageType(isImageType),
glslAsFloat(glslAsFloat)
isImageType(isImageType)
{}
const UniformTypeInfo &GetUniformTypeInfo(GLenum uniformType);
......
......@@ -927,6 +927,7 @@ const char kAtomicCountersBlockName[] = "ANGLEAtomicCounters";
const char kLineRasterEmulationPosition[] = "ANGLEPosition";
const char kXfbEmulationGetOffsetsFunctionName[] = "ANGLEGetXfbOffsets";
const char kXfbEmulationCaptureFunctionName[] = "ANGLECaptureXfb";
const char kXfbEmulationBufferBlockName[] = "ANGLEXfbBuffer";
const char kXfbEmulationBufferName[] = "ANGLEXfb";
const char kXfbEmulationBufferFieldName[] = "xfbOut";
......
......@@ -271,17 +271,6 @@ ANGLE_NO_DISCARD bool ReplaceGLDepthRangeWithDriverUniform(TCompiler *compiler,
return ReplaceVariableWithTyped(compiler, root, depthRangeVar, angleEmulatedDepthRangeRef);
}
ANGLE_NO_DISCARD bool AppendTransformFeedbackOutputToMain(TCompiler *compiler,
TIntermBlock *root,
TSymbolTable *symbolTable)
{
TVariable *xfbPlaceholder = new TVariable(symbolTable, ImmutableString("@@ XFB-OUT @@"),
new TType(), SymbolType::AngleInternal);
// Append the assignment as a statement at the end of the shader.
return RunAtTheEndOfShader(compiler, root, new TIntermSymbol(xfbPlaceholder), symbolTable);
}
TVariable *AddANGLEPositionVaryingDeclaration(TIntermBlock *root,
TSymbolTable *symbolTable,
TQualifier qualifier)
......@@ -442,6 +431,67 @@ ANGLE_NO_DISCARD bool AddXfbEmulationSupport(TCompiler *compiler,
const size_t mainIndex = FindMainIndex(root);
root->insertChildNodes(mainIndex, {functionDef});
// Generate the following function and place it before main(). This function will be filled
// with transform feedback capture code at link time.
//
// void ANGLECaptureXfb()
// {
// }
const TType *voidType = StaticType::GetBasic<EbtVoid>();
// Create the function body, which is empty.
body = new TIntermBlock;
// Declare the function
TFunction *xfbCaptureFunction =
new TFunction(symbolTable, ImmutableString(vk::kXfbEmulationCaptureFunctionName),
SymbolType::AngleInternal, voidType, false);
// Insert the function declaration before main().
root->insertChildNodes(mainIndex,
{CreateInternalFunctionDefinitionNode(*xfbCaptureFunction, body)});
// Create the following logic and add it at the end of main():
//
// if (ANGLEUniforms.xfbActiveUnpaused)
// {
// ANGLECaptureXfb();
// }
//
// Create a reference ANGLEUniforms.xfbActiveUnpaused
TIntermBinary *xfbActiveUnpaused = driverUniforms->getXfbActiveUnpaused();
// ANGLEUniforms.xfbActiveUnpaused != 0
TIntermBinary *isXfbActiveUnpaused =
new TIntermBinary(EOpNotEqual, xfbActiveUnpaused, CreateUIntNode(0));
// Create the function call
TIntermAggregate *captureXfbCall =
TIntermAggregate::CreateFunctionCall(*xfbCaptureFunction, {});
TIntermBlock *captureXfbBlock = new TIntermBlock;
captureXfbBlock->appendStatement(captureXfbCall);
// Create a call to ANGLEGetXfbOffsets too, for the sole purpose of preventing it from being
// culled as unused by glslang.
TIntermSequence zero;
zero.push_back(CreateIndexNode(0));
TIntermSequence ivec4Zero;
ivec4Zero.push_back(TIntermAggregate::CreateConstructor(*ivec4Type, &zero));
TIntermAggregate *getOffsetsCall =
TIntermAggregate::CreateFunctionCall(*getOffsetsFunction, &ivec4Zero);
captureXfbBlock->appendStatement(getOffsetsCall);
// Create the if
TIntermIfElse *captureXfb = new TIntermIfElse(isXfbActiveUnpaused, captureXfbBlock, nullptr);
// Run it at the end of the shader.
if (!RunAtTheEndOfShader(compiler, root, captureXfb, symbolTable))
{
return false;
}
// Additionally, generate the following storage buffer declarations used to capture transform
// feedback output. Again, there's a maximum of four buffers.
//
......@@ -951,15 +1001,6 @@ bool TranslatorVulkan::translateImpl(TIntermBlock *root,
return false;
}
}
// Append a macro for transform feedback substitution prior to modifying depth.
if ((compileOptions & SH_ADD_VULKAN_XFB_EMULATION_SUPPORT_CODE) != 0)
{
if (!AppendTransformFeedbackOutputToMain(this, root, &getSymbolTable()))
{
return false;
}
}
}
switch (packedShaderType)
......
......@@ -178,6 +178,11 @@ TIntermBinary *DriverUniform::getAbcBufferOffsets() const
return createDriverUniformRef(kAcbBufferOffsets);
}
TIntermBinary *DriverUniform::getXfbActiveUnpaused() const
{
return createDriverUniformRef(kXfbActiveUnpaused);
}
TIntermBinary *DriverUniform::getXfbVerticesPerInstance() const
{
return createDriverUniformRef(kXfbVerticesPerInstance);
......
......@@ -34,6 +34,7 @@ class DriverUniform
TIntermBinary *getViewportRef() const;
TIntermBinary *getAbcBufferOffsets() const;
TIntermBinary *getXfbActiveUnpaused() const;
TIntermBinary *getXfbVerticesPerInstance() const;
TIntermBinary *getXfbBufferOffsets() const;
TIntermBinary *getClipDistancesEnabled() const;
......
......@@ -65,6 +65,7 @@ struct GlslangSpirvOptions
bool removeEarlyFragmentTestsOptimization = false;
bool removeDebugInfo = false;
bool isTransformFeedbackStage = false;
bool isTransformFeedbackEmulated = false;
};
using SpirvBlob = std::vector<uint32_t>;
......@@ -75,9 +76,19 @@ struct ShaderInterfaceVariableXfbInfo
{
static constexpr uint32_t kInvalid = std::numeric_limits<uint32_t>::max();
// Used by both extension and emulation
uint32_t buffer = kInvalid;
uint32_t offset = kInvalid;
uint32_t stride = kInvalid;
// Used only by emulation (array index support is missing from VK_EXT_transform_feedback)
uint32_t arraySize = kInvalid;
uint32_t columnCount = kInvalid;
uint32_t rowCount = kInvalid;
uint32_t arrayIndex = kInvalid;
GLenum componentType = GL_FLOAT;
// If empty, the whole array is captured. Otherwise only the specified members are captured.
std::vector<ShaderInterfaceVariableXfbInfo> arrayElements;
};
// Information for each shader interface variable. Not all fields are relevant to each shader
......@@ -169,14 +180,6 @@ bool GetImageNameWithoutIndices(std::string *name);
std::string GlslangGetMappedSamplerName(const std::string &originalName);
std::string GetXfbBufferName(const uint32_t bufferIndex);
// NOTE: options.emulateTransformFeedback is ignored in this case. It is assumed to be always true.
void GlslangGenTransformFeedbackEmulationOutputs(
const GlslangSourceOptions &options,
const gl::ProgramState &programState,
GlslangProgramInterfaceInfo *programInterfaceInfo,
std::string *vertexShader,
ShaderInterfaceVariableInfoMap *variableInfoMapOut);
void GlslangAssignLocations(const GlslangSourceOptions &options,
const gl::ProgramState &programState,
const gl::ProgramVaryingPacking &varyingPacking,
......
......@@ -317,11 +317,9 @@ angle::Result ProgramMtl::linkImpl(const gl::Context *glContext,
// Gather variable info and transform sources.
gl::ShaderMap<std::string> shaderSources;
gl::ShaderMap<std::string> xfbOnlyShaderSources;
ShaderInterfaceVariableInfoMap variableInfoMap;
ShaderInterfaceVariableInfoMap xfbOnlyVariableInfoMap;
mtl::GlslangGetShaderSource(mState, resources, &shaderSources,
&xfbOnlyShaderSources[gl::ShaderType::Vertex], &variableInfoMap,
mtl::GlslangGetShaderSource(mState, resources, &shaderSources, &variableInfoMap,
&xfbOnlyVariableInfoMap);
// Convert GLSL to spirv code
......@@ -329,14 +327,14 @@ angle::Result ProgramMtl::linkImpl(const gl::Context *glContext,
gl::ShaderMap<std::vector<uint32_t>> xfbOnlyShaderCodes; // only vertex shader is needed.
ANGLE_TRY(mtl::GlslangGetShaderSpirvCode(
contextMtl, mState.getExecutable().getLinkedShaderStages(), contextMtl->getCaps(),
shaderSources, variableInfoMap, &shaderCodes));
shaderSources, false, variableInfoMap, &shaderCodes));
if (!mState.getLinkedTransformFeedbackVaryings().empty())
{
gl::ShaderBitSet onlyVS;
onlyVS.set(gl::ShaderType::Vertex);
ANGLE_TRY(mtl::GlslangGetShaderSpirvCode(contextMtl, onlyVS, contextMtl->getCaps(),
xfbOnlyShaderSources, xfbOnlyVariableInfoMap,
shaderSources, true, xfbOnlyVariableInfoMap,
&xfbOnlyShaderCodes));
}
......
......@@ -41,12 +41,10 @@ struct TranslatedShaderInfo
bool hasUBOArgumentBuffer;
};
// - shaderSourcesOut is result GLSL code per shader stage when XFB emulation is turned off.
// - xfbOnlyShaderSourceOut will contain vertex shader's GLSL code when XFB emulation is turned on.
// shaderSourcesOut is result GLSL code per shader stage.
void GlslangGetShaderSource(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
gl::ShaderMap<std::string> *shaderSourcesOut,
std::string *xfbOnlyShaderSourceOut,
ShaderInterfaceVariableInfoMap *variableInfoMapOut,
ShaderInterfaceVariableInfoMap *xfbOnlyVSVariableInfoMapOut);
......@@ -54,6 +52,7 @@ angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context,
const gl::ShaderBitSet &linkedShaderStages,
const gl::Caps &glCaps,
const gl::ShaderMap<std::string> &shaderSources,
bool isTransformFeedbackEnabled,
const ShaderInterfaceVariableInfoMap &variableInfoMap,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut);
......
......@@ -406,7 +406,6 @@ void TranslatedShaderInfo::reset()
void GlslangGetShaderSource(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
gl::ShaderMap<std::string> *shaderSourcesOut,
std::string *xfbOnlyShaderSourceOut,
ShaderInterfaceVariableInfoMap *variableInfoMapOut,
ShaderInterfaceVariableInfoMap *xfbOnlyVSVariableInfoMapOut)
{
......@@ -416,32 +415,21 @@ void GlslangGetShaderSource(const gl::ProgramState &programState,
options.supportsTransformFeedbackEmulation = true;
// This will generate shader source WITHOUT XFB emulated outputs.
// Get shader sources and fill variable info map with transform feedback disabled.
rx::GlslangGetShaderSource(options, programState, resources, &programInterfaceInfo,
shaderSourcesOut, variableInfoMapOut);
// This will generate vertex shader source WITH XFB emulated outputs.
if (xfbOnlyShaderSourceOut && !programState.getLinkedTransformFeedbackVaryings().empty())
// Fill variable info map with transform feedback enabled.
if (!programState.getLinkedTransformFeedbackVaryings().empty())
{
gl::Shader *glShader = programState.getAttachedShader(gl::ShaderType::Vertex);
*xfbOnlyShaderSourceOut = glShader ? glShader->getTranslatedSource() : "";
GlslangProgramInterfaceInfo xfbOnlyInterfaceInfo;
ResetGlslangProgramInterfaceInfo(&xfbOnlyInterfaceInfo);
options.enableTransformFeedbackEmulation = true;
rx::GlslangGenTransformFeedbackEmulationOutputs(
options, programState, &xfbOnlyInterfaceInfo, xfbOnlyShaderSourceOut,
xfbOnlyVSVariableInfoMapOut);
const bool isTransformFeedbackStage =
!programState.getLinkedTransformFeedbackVaryings().empty();
GlslangAssignLocations(options, programState, resources.varyingPacking,
gl::ShaderType::Vertex, gl::ShaderType::InvalidEnum,
isTransformFeedbackStage, &xfbOnlyInterfaceInfo,
xfbOnlyVSVariableInfoMapOut);
gl::ShaderType::Vertex, gl::ShaderType::InvalidEnum, true,
&xfbOnlyInterfaceInfo, xfbOnlyVSVariableInfoMapOut);
}
}
......@@ -449,6 +437,7 @@ angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context,
const gl::ShaderBitSet &linkedShaderStages,
const gl::Caps &glCaps,
const gl::ShaderMap<std::string> &shaderSources,
bool isTransformFeedbackEnabled,
const ShaderInterfaceVariableInfoMap &variableInfoMap,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut)
{
......@@ -463,7 +452,9 @@ angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context,
GlslangSpirvOptions options;
options.shaderType = shaderType;
options.transformPositionToVulkanClipSpace = true;
options.isTransformFeedbackStage = shaderType == gl::ShaderType::Vertex;
options.isTransformFeedbackStage =
shaderType == gl::ShaderType::Vertex && isTransformFeedbackEnabled;
options.isTransformFeedbackEmulated = true;
angle::Result status = GlslangTransformSpirvCode(
[context](GlslangError error) { return HandleError(context, error); }, options,
......
......@@ -24,6 +24,42 @@ namespace rx
{
namespace
{
void LoadShaderInterfaceVariableXfbInfo(gl::BinaryInputStream *stream,
ShaderInterfaceVariableXfbInfo *xfb)
{
xfb->buffer = stream->readInt<uint32_t>();
xfb->offset = stream->readInt<uint32_t>();
xfb->stride = stream->readInt<uint32_t>();
xfb->arraySize = stream->readInt<uint32_t>();
xfb->columnCount = stream->readInt<uint32_t>();
xfb->rowCount = stream->readInt<uint32_t>();
xfb->arrayIndex = stream->readInt<uint32_t>();
xfb->componentType = stream->readInt<uint32_t>();
xfb->arrayElements.resize(stream->readInt<size_t>());
for (ShaderInterfaceVariableXfbInfo &arrayElement : xfb->arrayElements)
{
LoadShaderInterfaceVariableXfbInfo(stream, &arrayElement);
}
}
void SaveShaderInterfaceVariableXfbInfo(const ShaderInterfaceVariableXfbInfo &xfb,
gl::BinaryOutputStream *stream)
{
stream->writeInt(xfb.buffer);
stream->writeInt(xfb.offset);
stream->writeInt(xfb.stride);
stream->writeInt(xfb.arraySize);
stream->writeInt(xfb.columnCount);
stream->writeInt(xfb.rowCount);
stream->writeInt(xfb.arrayIndex);
stream->writeInt(xfb.componentType);
stream->writeInt(xfb.arrayElements.size());
for (const ShaderInterfaceVariableXfbInfo &arrayElement : xfb.arrayElements)
{
SaveShaderInterfaceVariableXfbInfo(arrayElement, stream);
}
}
bool ValidateTransformedSpirV(ContextVk *contextVk,
const gl::ShaderBitSet &linkedShaderStages,
const ShaderInterfaceVariableInfoMap &variableInfoMap,
......@@ -125,6 +161,7 @@ ProgramInfo::~ProgramInfo() = default;
angle::Result ProgramInfo::initProgram(ContextVk *contextVk,
const gl::ShaderType shaderType,
bool isLastPreFragmentStage,
bool isTransformFeedbackProgram,
const ShaderInfo &shaderInfo,
ProgramTransformOptions optionBits,
const ShaderInterfaceVariableInfoMap &variableInfoMap)
......@@ -138,9 +175,10 @@ angle::Result ProgramInfo::initProgram(ContextVk *contextVk,
options.shaderType = shaderType;
options.removeEarlyFragmentTestsOptimization =
shaderType == gl::ShaderType::Fragment && optionBits.removeEarlyFragmentTestsOptimization;
options.removeDebugInfo = !contextVk->getRenderer()->getEnableValidationLayers();
options.isTransformFeedbackStage = isLastPreFragmentStage;
options.negativeViewportSupported = contextVk->getFeatures().supportsNegativeViewport.enabled;
options.removeDebugInfo = !contextVk->getRenderer()->getEnableValidationLayers();
options.isTransformFeedbackStage = isLastPreFragmentStage && isTransformFeedbackProgram;
options.isTransformFeedbackEmulated = contextVk->getFeatures().emulateTransformFeedback.enabled;
options.negativeViewportSupported = contextVk->getFeatures().supportsNegativeViewport.enabled;
if (isLastPreFragmentStage)
{
......@@ -245,15 +283,11 @@ std::unique_ptr<rx::LinkEvent> ProgramExecutableVk::load(gl::BinaryInputStream *
info.component = stream->readInt<uint32_t>();
// PackedEnumBitSet uses uint8_t
info.activeStages = gl::ShaderBitSet(stream->readInt<uint8_t>());
info.xfb.buffer = stream->readInt<uint32_t>();
info.xfb.offset = stream->readInt<uint32_t>();
info.xfb.stride = stream->readInt<uint32_t>();
LoadShaderInterfaceVariableXfbInfo(stream, &info.xfb);
info.fieldXfb.resize(stream->readInt<size_t>());
for (ShaderInterfaceVariableXfbInfo &xfb : info.fieldXfb)
{
xfb.buffer = stream->readInt<uint32_t>();
xfb.offset = stream->readInt<uint32_t>();
xfb.stride = stream->readInt<uint32_t>();
LoadShaderInterfaceVariableXfbInfo(stream, &xfb);
}
info.useRelaxedPrecision = stream->readBool();
info.varyingIsInput = stream->readBool();
......@@ -283,15 +317,11 @@ void ProgramExecutableVk::save(gl::BinaryOutputStream *stream)
stream->writeInt(info.component);
// PackedEnumBitSet uses uint8_t
stream->writeInt(info.activeStages.bits());
stream->writeInt(info.xfb.buffer);
stream->writeInt(info.xfb.offset);
stream->writeInt(info.xfb.stride);
SaveShaderInterfaceVariableXfbInfo(info.xfb, stream);
stream->writeInt(info.fieldXfb.size());
for (const ShaderInterfaceVariableXfbInfo &xfb : info.fieldXfb)
{
stream->writeInt(xfb.buffer);
stream->writeInt(xfb.offset);
stream->writeInt(xfb.stride);
SaveShaderInterfaceVariableXfbInfo(xfb, stream);
}
stream->writeBool(info.useRelaxedPrecision);
stream->writeBool(info.varyingIsInput);
......
......@@ -69,6 +69,7 @@ class ProgramInfo final : angle::NonCopyable
angle::Result initProgram(ContextVk *contextVk,
const gl::ShaderType shaderType,
bool isLastPreFragmentStage,
bool isTransformFeedbackProgram,
const ShaderInfo &shaderInfo,
ProgramTransformOptions optionBits,
const ShaderInterfaceVariableInfoMap &variableInfoMap);
......
......@@ -269,7 +269,7 @@ std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context,
// Gather variable info and transform sources.
gl::ShaderMap<std::string> shaderSources;
GlslangWrapperVk::GetShaderSource(contextVk->getRenderer()->getFeatures(), mState, resources,
GlslangWrapperVk::GetShaderSource(contextVk->getFeatures(), mState, resources,
&mGlslangProgramInterfaceInfo, &shaderSources,
&mExecutable.mVariableInfoMap);
......
......@@ -208,8 +208,11 @@ class ProgramVk : public ProgramImpl
// specialization constants.
if (!programInfo->valid(shaderType))
{
const bool isTransformFeedbackProgram =
!mState.getLinkedTransformFeedbackVaryings().empty();
ANGLE_TRY(programInfo->initProgram(contextVk, shaderType, isLastPreFragmentStage,
mOriginalShaderInfo, optionBits, variableInfoMap));
isTransformFeedbackProgram, mOriginalShaderInfo,
optionBits, variableInfoMap));
}
ASSERT(programInfo->valid(shaderType));
......
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