Skip to content

Commit

Permalink
lgc: extend InputAssemlyState::enableMultiView to an enum
Browse files Browse the repository at this point in the history
Vulkan view index is used to set RT layer when multiview extension is
enabled. But HLSL SV_ViewID stands for a combination of viewport index,
RT layer and view index. To support HLSL and future Vulkan
extension, this bool enableMultiView is expandede as an enum which is one of:

- Disabled
- Simple: Current Vulkan behavior, i.e. RT layer set to view index, viewport
  index set by shader
- PerView: both RT layer and viewport index set by shader (with shader output
  defaulting to 0), offset by a base that's taken from the ViewId userdata

There is also key change in RegisterMetadataBuilder because even the
viewport index is written when multiView is PerView mode, vertex reuse
can still be enabled because the viewport index is uniform.
  • Loading branch information
xazhangAMD committed Oct 23, 2023
1 parent a0ffb64 commit 686608c
Show file tree
Hide file tree
Showing 13 changed files with 128 additions and 54 deletions.
10 changes: 6 additions & 4 deletions lgc/builder/ImageBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1964,7 +1964,7 @@ Value *BuilderImpl::patchCubeDescriptor(Value *desc, unsigned dim) {
Value *BuilderImpl::handleFragCoordViewIndex(Value *coord, unsigned flags, unsigned &dim) {
bool useViewIndex = false;
if (flags & ImageFlagCheckMultiView) {
if (getPipelineState()->getInputAssemblyState().enableMultiView) {
if (getPipelineState()->getInputAssemblyState().multiView != MultiViewModeDisable) {
useViewIndex = true;
dim = Dim2DArray;
unsigned coordCount = cast<FixedVectorType>(coord->getType())->getNumElements();
Expand Down Expand Up @@ -2031,9 +2031,11 @@ Value *BuilderImpl::handleFragCoordViewIndex(Value *coord, unsigned flags, unsig
std::string callName = lgcName::InputImportBuiltIn;
Type *builtInTy = getInt32Ty();
addTypeMangling(builtInTy, {}, callName);
Value *viewIndex = CreateNamedCall(callName, builtInTy, getInt32(BuiltInViewIndex), {});
viewIndex->setName("ViewIndex");
coord = CreateInsertElement(coord, viewIndex, 2);
Value *rtLayer = CreateNamedCall(callName, builtInTy, getInt32(BuiltInViewIndex), {});
if (getPipelineState()->getInputAssemblyState().multiView == MultiViewModePerView)
rtLayer = CreateLShr(rtLayer, getInt32(8)); // RT layer id is in the high 24 bits of view index.
rtLayer->setName("Layer");
coord = CreateInsertElement(coord, rtLayer, 2);
}

return coord;
Expand Down
8 changes: 6 additions & 2 deletions lgc/builder/InOutBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -837,7 +837,11 @@ Value *BuilderImpl::CreateReadBaryCoord(BuiltInKind builtIn, InOutInfo inputInfo
Value *BuilderImpl::CreateReadBuiltInInput(BuiltInKind builtIn, InOutInfo inputInfo, Value *vertexIndex, Value *index,
const Twine &instName) {
assert(isBuiltInInput(builtIn));
return readBuiltIn(false, builtIn, inputInfo, vertexIndex, index, instName);
Value *builtInVal = readBuiltIn(false, builtIn, inputInfo, vertexIndex, index, instName);
if (builtIn == BuiltInViewIndex)
// View index can only use bit[3:0] of view id register.
builtInVal = CreateAnd(builtInVal, getInt32(0xF));
return builtInVal;
}

// =====================================================================================================================
Expand Down Expand Up @@ -1306,7 +1310,7 @@ Value *BuilderImpl::readVsBuiltIn(BuiltInKind builtIn, const Twine &instName) {
case BuiltInInstanceIndex:
return ShaderInputs::getInstanceIndex(builder, *getLgcContext());
case BuiltInViewIndex:
if (m_pipelineState->getInputAssemblyState().enableMultiView)
if (m_pipelineState->getInputAssemblyState().multiView != MultiViewModeDisable)
return ShaderInputs::getSpecialUserData(UserDataMapping::ViewId, builder);
return builder.getInt32(0);
case BuiltInVertexId:
Expand Down
2 changes: 1 addition & 1 deletion lgc/include/lgc/patch/PatchInOutImportExport.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ class PatchInOutImportExport : public Patch, public llvm::PassInfoMixin<PatchInO
// and gl_Layer is 16-bit low part). Thus, the export is delayed with them merged together.
llvm::Value *m_viewportIndex; // Correspond to "out int gl_ViewportIndex"
llvm::Value *m_layer; // Correspond to "out int gl_Layer"
llvm::Value *m_viewIndex; // Correspond to "in int gl_Layer"
llvm::Value *m_viewIndex; // Correspond to "in int gl_ViewIndex"
llvm::Value *m_edgeFlag; // Correspond to "EdgeFlag output"

bool m_hasTs; // Whether the pipeline has tessellation shaders
Expand Down
10 changes: 9 additions & 1 deletion lgc/interface/lgc/Pipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -463,12 +463,20 @@ struct ColorExportState {
unsigned dynamicDualSourceBlendEnable; // Dynamic dual source blend enable
};

// MultiView supporting mode
enum MultiViewMode : unsigned {
MultiViewModeDisable = 0, // Disabled
MultiViewModeSimple = 1, // Current Vulkan behavior, i.e. RT layer set to view index, viewport index set by shader
MultiViewModePerView = 2, // Both RT layer and viewport index set by shader (with shader output defaulting to 0),
// offset by a base that's taken from the ViewId userdata
};

// Struct to pass to SetInputAssemblyState.
struct InputAssemblyState {
PrimitiveType primitiveType; // Primitive type
unsigned disableVertexReuse; // Disable reusing vertex shader output for indexed draws
unsigned switchWinding; // Whether to reverse vertex ordering for tessellation
unsigned enableMultiView; // Whether to enable multi-view support
MultiViewMode multiView; // MultiView mode
unsigned useVertexBufferDescArray; // Whether vertex buffer descriptors are in a descriptor array binding instead of
// the VertexBufferTable
};
Expand Down
6 changes: 5 additions & 1 deletion lgc/patch/Gfx6ConfigBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,10 @@ template <typename T> void ConfigBuilder::buildVsRegConfig(ShaderStage shaderSta
cullDistanceCount = builtInUsage.gs.cullDistance;
}

// In this mode, API shader may not export viewport index but LGC does so.
if (m_pipelineState->getInputAssemblyState().multiView == MultiViewModePerView)
useViewportIndex = true;

SET_REG_FIELD(&config->vsRegs, VGT_PRIMITIVEID_EN, PRIMITIVEID_EN, usePrimitiveId);
SET_REG_FIELD(&config->vsRegs, SPI_VS_OUT_CONFIG, VS_EXPORT_COUNT, resUsage->inOutUsage.expCount - 1);
setUsesViewportArrayIndex(useViewportIndex);
Expand All @@ -472,7 +476,7 @@ template <typename T> void ConfigBuilder::buildVsRegConfig(ShaderStage shaderSta

SET_REG_FIELD(&config->vsRegs, VGT_VERTEX_REUSE_BLOCK_CNTL, VTX_REUSE_DEPTH, 14);

useLayer = useLayer || m_pipelineState->getInputAssemblyState().enableMultiView;
useLayer = useLayer || m_pipelineState->getInputAssemblyState().multiView != MultiViewModeDisable;

bool miscExport = usePointSize || useLayer || useViewportIndex || useEdgeFlag;
if (miscExport) {
Expand Down
6 changes: 4 additions & 2 deletions lgc/patch/Gfx9ConfigBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1864,7 +1864,7 @@ template <typename T> void ConfigBuilder::buildMeshRegConfig(ShaderStage shaderS
SET_REG_FIELD(&config->meshRegs, GE_NGG_SUBGRP_CNTL, PRIM_AMP_FACTOR, calcFactor.primAmpFactor);
SET_REG_FIELD(&config->meshRegs, GE_NGG_SUBGRP_CNTL, THDS_PER_SUBGRP, calcFactor.primAmpFactor);

const bool enableMultiView = m_pipelineState->getInputAssemblyState().enableMultiView;
const bool enableMultiView = m_pipelineState->getInputAssemblyState().multiView != MultiViewModeDisable;
bool hasPrimitivePayload =
builtInUsage.layer || builtInUsage.viewportIndex || builtInUsage.primitiveShadingRate || enableMultiView;
if (m_gfxIp.major < 11)
Expand Down Expand Up @@ -2166,7 +2166,9 @@ template <typename T> void ConfigBuilder::setupPaSpecificRegisters(T *config) {
expCount = resUsage->inOutUsage.expCount;
}

useLayer = useLayer || m_pipelineState->getInputAssemblyState().enableMultiView;
useLayer = useLayer || m_pipelineState->getInputAssemblyState().multiView != MultiViewModeDisable;
if (m_pipelineState->getInputAssemblyState().multiView == MultiViewModePerView)
useViewportIndex = true;

if (usePrimitiveId) {
SET_REG_FIELD(config, VGT_PRIMITIVEID_EN, PRIMITIVEID_EN, true);
Expand Down
53 changes: 37 additions & 16 deletions lgc/patch/MeshTaskShader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1242,7 +1242,7 @@ void MeshTaskShader::lowerGetMeshBuiltinInput(GetMeshBuiltinInputOp &getMeshBuil
break;
}
case BuiltInViewIndex: {
if (m_pipelineState->getInputAssemblyState().enableMultiView) {
if (m_pipelineState->getInputAssemblyState().multiView != MultiViewModeDisable) {
auto &entryArgIdxs = m_pipelineState->getShaderInterfaceData(ShaderStageMesh)->entryArgIdxs.mesh;
input = getFunctionArgument(entryPoint, entryArgIdxs.viewIndex);
} else {
Expand Down Expand Up @@ -1754,34 +1754,55 @@ void MeshTaskShader::exportPrimitive() {
if (builtInUsage.layer)
layer = readMeshBuiltInFromLds(BuiltInLayer);

Value *viewIndex = nullptr;
const bool enableMultiView = m_pipelineState->getInputAssemblyState().enableMultiView;
Value *viewportIndex = nullptr;
if (builtInUsage.viewportIndex)
viewportIndex = readMeshBuiltInFromLds(BuiltInViewportIndex);

Value *layerForFs = layer;
Value *viewportIndexForFs = viewportIndex;

const bool enableMultiView = m_pipelineState->getInputAssemblyState().multiView != MultiViewModeDisable;
if (enableMultiView) {
auto entryPoint = m_builder.GetInsertBlock()->getParent();
const auto entryArgIdxs = m_pipelineState->getShaderInterfaceData(ShaderStageMesh)->entryArgIdxs.mesh;
viewIndex = getFunctionArgument(entryPoint, entryArgIdxs.viewIndex);
Value *viewId = getFunctionArgument(entryPoint, entryArgIdxs.viewIndex);

// RT layer id is view id in simple mode (view index only).
Value *layerFromViewId = viewId;
if (m_pipelineState->getInputAssemblyState().multiView == MultiViewModePerView) {
// RT layer id is in the high 24 bits of view id in per-view mode.
layerFromViewId = m_builder.CreateLShr(viewId, m_builder.getInt32(8));
if (layer)
layerFromViewId = m_builder.CreateAdd(layerFromViewId, layer);
// Viewport index is in [7:4] of view id.
Value *viewportIndexFromViewId =
m_builder.CreateAnd(m_builder.CreateLShr(viewId, m_builder.getInt32(4)), m_builder.getInt32(0xF));
if (viewportIndex)
viewportIndexFromViewId = m_builder.CreateAdd(viewportIndexFromViewId, viewportIndex);
viewportIndex = viewportIndexFromViewId;
}

layer = layerFromViewId;
}

if (enableMultiView || builtInUsage.layer) {
if (layer) {
// [19:17] = RT slice index (on GFX11, [12:0] = RT slice index)
// When multi-view is enabled, the input view index is treated as the output layer.
Value *layerMaskAndShift = nullptr;
if (m_gfxIp.major < 11) {
layerMaskAndShift = m_builder.CreateAnd(enableMultiView ? viewIndex : layer, 0x7);
layerMaskAndShift = m_builder.CreateAnd(layer, 0x7);
layerMaskAndShift = m_builder.CreateShl(layerMaskAndShift, 17);
} else {
layerMaskAndShift = m_builder.CreateAnd(enableMultiView ? viewIndex : layer, 0x1FFF);
layerMaskAndShift = m_builder.CreateAnd(layer, 0x1FFF);
}
if (primitivePayload)
primitivePayload = m_builder.CreateOr(primitivePayload, layerMaskAndShift);
else
primitivePayload = layerMaskAndShift;
}

Value *viewportIndex = nullptr;
if (builtInUsage.viewportIndex) {
if (viewportIndex) {
// [23:20] = Viewport index
viewportIndex = readMeshBuiltInFromLds(BuiltInViewportIndex);
auto viewportIndexMaskAndShift = m_builder.CreateAnd(viewportIndex, 0xF);
viewportIndexMaskAndShift = m_builder.CreateShl(viewportIndexMaskAndShift, 20);
if (primitivePayload)
Expand Down Expand Up @@ -1853,17 +1874,17 @@ void MeshTaskShader::exportPrimitive() {
if (fsBuiltInUsage.layer) {
// NOTE: In such case, mesh shader doesn't export layer while fragment shader expects to read it. We
// export 0 to fragment shader, which is required by the spec.
layer = m_builder.getInt32(0);
layerForFs = m_builder.getInt32(0);
exportLayer = true;
}
}
}

if (exportLayer) {
if (inOutUsage.mesh.perPrimitiveBuiltInExportLocs.count(BuiltInLayer) > 0) {
assert(layer);
assert(layerForFs);
const unsigned exportLoc = inOutUsage.mesh.perPrimitiveBuiltInExportLocs[BuiltInLayer];
primAttrExports.push_back({startLoc + exportLoc, layer});
primAttrExports.push_back({startLoc + exportLoc, layerForFs});
++inOutUsage.primExpCount;
}
}
Expand All @@ -1878,17 +1899,17 @@ void MeshTaskShader::exportPrimitive() {
if (fsBuiltInUsage.viewportIndex) {
// NOTE: In such case, mesh shader doesn't export viewport index while fragment shader expects to read it. We
// export 0 to fragment shader, which is required by spec.
viewportIndex = m_builder.getInt32(0);
viewportIndexForFs = m_builder.getInt32(0);
exportViewportIndex = true;
}
}
}

if (exportViewportIndex) {
if (inOutUsage.mesh.perPrimitiveBuiltInExportLocs.count(BuiltInViewportIndex) > 0) {
assert(viewportIndex);
assert(viewportIndexForFs);
const unsigned exportLoc = inOutUsage.mesh.perPrimitiveBuiltInExportLocs[BuiltInViewportIndex];
primAttrExports.push_back({startLoc + exportLoc, viewportIndex});
primAttrExports.push_back({startLoc + exportLoc, viewportIndexForFs});
++inOutUsage.primExpCount;
}
}
Expand Down
2 changes: 1 addition & 1 deletion lgc/patch/PatchCopyShader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ void PatchCopyShader::exportOutput(unsigned streamId, BuilderBase &builder) {
if (builtInUsage.viewportIndex)
builtInPairs.push_back(std::make_pair(BuiltInViewportIndex, builder.getInt32Ty()));

if (m_pipelineState->getInputAssemblyState().enableMultiView)
if (m_pipelineState->getInputAssemblyState().multiView != MultiViewModeDisable)
builtInPairs.push_back(std::make_pair(BuiltInViewIndex, builder.getInt32Ty()));

if (builtInUsage.primitiveShadingRate)
Expand Down
6 changes: 3 additions & 3 deletions lgc/patch/PatchEntryPointMutate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1459,7 +1459,7 @@ void PatchEntryPointMutate::addSpecialUserDataArgs(SmallVectorImpl<UserDataArg>

// NOTE: The user data to emulate gl_ViewIndex is somewhat common. To make it consistent for GFX9
// merged shader, we place it prior to any other special user data.
if (m_pipelineState->getInputAssemblyState().enableMultiView) {
if (m_pipelineState->getInputAssemblyState().multiView != MultiViewModeDisable) {
unsigned *argIdx = nullptr;
auto userDataValue = UserDataMapping::ViewId;
switch (m_shaderStage) {
Expand Down Expand Up @@ -1571,7 +1571,7 @@ void PatchEntryPointMutate::addSpecialUserDataArgs(SmallVectorImpl<UserDataArg>
specialUserDataArgs.push_back(UserDataArg(builder.getInt32Ty(), "drawIndex", UserDataMapping::DrawIndex,
&intfData->entryArgIdxs.mesh.drawIndex));
}
if (m_pipelineState->getInputAssemblyState().enableMultiView) {
if (m_pipelineState->getInputAssemblyState().multiView != MultiViewModeDisable) {
specialUserDataArgs.push_back(
UserDataArg(builder.getInt32Ty(), "viewId", UserDataMapping::ViewId, &intfData->entryArgIdxs.mesh.viewIndex));
}
Expand All @@ -1587,7 +1587,7 @@ void PatchEntryPointMutate::addSpecialUserDataArgs(SmallVectorImpl<UserDataArg>
&intfData->entryArgIdxs.mesh.pipeStatsBuf));
}
} else if (m_shaderStage == ShaderStageFragment) {
if (m_pipelineState->getInputAssemblyState().enableMultiView &&
if (m_pipelineState->getInputAssemblyState().multiView != MultiViewModeDisable &&
m_pipelineState->getShaderResourceUsage(ShaderStageFragment)->builtInUsage.fs.viewIndex) {
// NOTE: Only add special user data of view index when multi-view is enabled and gl_ViewIndex is used in fragment
// shader.
Expand Down
Loading

0 comments on commit 686608c

Please sign in to comment.