Source code
Revision control
Copy as Markdown
Other Tools
//
// Copyright 2020 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.
//
// DriverUniform.cpp: Add code to support driver uniforms
//
#include "compiler/translator/tree_util/DriverUniform.h"
#include "compiler/translator/Compiler.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/StaticType.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/tree_util/FindMain.h"
#include "compiler/translator/tree_util/IntermNode_util.h"
#include "compiler/translator/tree_util/IntermTraverse.h"
#include "compiler/translator/util.h"
namespace sh
{
namespace
{
constexpr ImmutableString kEmulatedDepthRangeParams = ImmutableString("ANGLEDepthRangeParams");
constexpr const char kAcbBufferOffsets[] = "acbBufferOffsets";
constexpr const char kDepthRange[] = "depthRange";
constexpr const char kRenderArea[] = "renderArea";
constexpr const char kFlipXY[] = "flipXY";
constexpr const char kDither[] = "dither";
constexpr const char kMisc[] = "misc";
// Extended uniforms
constexpr const char kXfbBufferOffsets[] = "xfbBufferOffsets";
constexpr const char kXfbVerticesPerInstance[] = "xfbVerticesPerInstance";
constexpr const char kUnused[] = "unused";
constexpr const char kUnused2[] = "unused2";
} // anonymous namespace
// Class DriverUniform
bool DriverUniform::addComputeDriverUniformsToShader(TIntermBlock *root, TSymbolTable *symbolTable)
{
constexpr size_t kNumComputeDriverUniforms = 1;
constexpr std::array<const char *, kNumComputeDriverUniforms> kComputeDriverUniformNames = {
{kAcbBufferOffsets}};
ASSERT(!mDriverUniforms);
// This field list mirrors the structure of ComputeDriverUniforms in ContextVk.cpp.
TFieldList *driverFieldList = new TFieldList;
const std::array<TType *, kNumComputeDriverUniforms> kDriverUniformTypes = {{
new TType(EbtUInt, EbpHigh, EvqGlobal, 4),
}};
for (size_t uniformIndex = 0; uniformIndex < kNumComputeDriverUniforms; ++uniformIndex)
{
TField *driverUniformField =
new TField(kDriverUniformTypes[uniformIndex],
ImmutableString(kComputeDriverUniformNames[uniformIndex]), TSourceLoc(),
SymbolType::AngleInternal);
driverFieldList->push_back(driverUniformField);
}
// Define a driver uniform block "ANGLEUniformBlock" with instance name "ANGLEUniforms".
TLayoutQualifier layoutQualifier = TLayoutQualifier::Create();
layoutQualifier.blockStorage = EbsStd140;
layoutQualifier.pushConstant = true;
mDriverUniforms = DeclareInterfaceBlock(root, symbolTable, driverFieldList, EvqUniform,
layoutQualifier, TMemoryQualifier::Create(), 0,
ImmutableString(vk::kDriverUniformsBlockName),
ImmutableString(vk::kDriverUniformsVarName));
return mDriverUniforms != nullptr;
}
TFieldList *DriverUniform::createUniformFields(TSymbolTable *symbolTable)
{
constexpr size_t kNumGraphicsDriverUniforms = 6;
constexpr std::array<const char *, kNumGraphicsDriverUniforms> kGraphicsDriverUniformNames = {{
kAcbBufferOffsets,
kDepthRange,
kRenderArea,
kFlipXY,
kDither,
kMisc,
}};
// This field list mirrors the structure of GraphicsDriverUniforms in ContextVk.cpp.
TFieldList *driverFieldList = new TFieldList;
const std::array<TType *, kNumGraphicsDriverUniforms> kDriverUniformTypes = {{
// acbBufferOffsets: Packed ubyte8
new TType(EbtUInt, EbpHigh, EvqGlobal, 2),
// depthRange: Near and far depth
new TType(EbtFloat, EbpHigh, EvqGlobal, 2),
// renderArea: Packed ushort2
new TType(EbtUInt, EbpHigh, EvqGlobal),
// flipXY: Packed snorm4
new TType(EbtUInt, EbpHigh, EvqGlobal),
// dither: ushort
new TType(EbtUInt, EbpHigh, EvqGlobal),
// misc: Various bits of state
new TType(EbtUInt, EbpHigh, EvqGlobal),
}};
for (size_t uniformIndex = 0; uniformIndex < kNumGraphicsDriverUniforms; ++uniformIndex)
{
TField *driverUniformField =
new TField(kDriverUniformTypes[uniformIndex],
ImmutableString(kGraphicsDriverUniformNames[uniformIndex]), TSourceLoc(),
SymbolType::AngleInternal);
driverFieldList->push_back(driverUniformField);
}
return driverFieldList;
}
const TType *DriverUniform::createEmulatedDepthRangeType(TSymbolTable *symbolTable)
{
// If already defined, return it immediately.
if (mEmulatedDepthRangeType != nullptr)
{
return mEmulatedDepthRangeType;
}
// Create the depth range type.
TFieldList *depthRangeParamsFields = new TFieldList();
TType *floatType = new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1);
depthRangeParamsFields->push_back(
new TField(floatType, ImmutableString("near"), TSourceLoc(), SymbolType::AngleInternal));
depthRangeParamsFields->push_back(
new TField(floatType, ImmutableString("far"), TSourceLoc(), SymbolType::AngleInternal));
depthRangeParamsFields->push_back(
new TField(floatType, ImmutableString("diff"), TSourceLoc(), SymbolType::AngleInternal));
TStructure *emulatedDepthRangeParams = new TStructure(
symbolTable, kEmulatedDepthRangeParams, depthRangeParamsFields, SymbolType::AngleInternal);
mEmulatedDepthRangeType = new TType(emulatedDepthRangeParams, false);
return mEmulatedDepthRangeType;
}
// The Add*DriverUniformsToShader operation adds an internal uniform block to a shader. The driver
// block is used to implement Vulkan-specific features and workarounds. Returns the driver uniforms
// variable.
//
// There are Graphics and Compute variations as they require different uniforms.
bool DriverUniform::addGraphicsDriverUniformsToShader(TIntermBlock *root, TSymbolTable *symbolTable)
{
ASSERT(!mDriverUniforms);
// Declare the depth range struct type.
const TType *emulatedDepthRangeType = createEmulatedDepthRangeType(symbolTable);
const TType *emulatedDepthRangeDeclType = new TType(emulatedDepthRangeType->getStruct(), true);
const TVariable *depthRangeVar =
new TVariable(symbolTable->nextUniqueId(), kEmptyImmutableString, SymbolType::Empty,
TExtension::UNDEFINED, emulatedDepthRangeDeclType);
DeclareGlobalVariable(root, depthRangeVar);
TFieldList *driverFieldList = createUniformFields(symbolTable);
if (mMode == DriverUniformMode::InterfaceBlock)
{
// Define a driver uniform block "ANGLEUniformBlock" with instance name "ANGLEUniforms".
TLayoutQualifier layoutQualifier = TLayoutQualifier::Create();
layoutQualifier.blockStorage = EbsStd140;
layoutQualifier.pushConstant = true;
mDriverUniforms = DeclareInterfaceBlock(root, symbolTable, driverFieldList, EvqUniform,
layoutQualifier, TMemoryQualifier::Create(), 0,
ImmutableString(vk::kDriverUniformsBlockName),
ImmutableString(vk::kDriverUniformsVarName));
}
else
{
// Declare a structure "ANGLEUniformBlock" with instance name "ANGLE_angleUniforms".
// This code path is taken only by the direct-to-Metal backend, and the assumptions
// about the naming conventions of ANGLE-internal variables run too deeply to rename
// this one.
auto varName = ImmutableString("ANGLE_angleUniforms");
auto result = DeclareStructure(root, symbolTable, driverFieldList, EvqUniform,
TMemoryQualifier::Create(), 0,
ImmutableString(vk::kDriverUniformsBlockName), &varName);
mDriverUniforms = result.second;
}
return mDriverUniforms != nullptr;
}
TIntermTyped *DriverUniform::createDriverUniformRef(const char *fieldName) const
{
size_t fieldIndex = 0;
if (mMode == DriverUniformMode::InterfaceBlock)
{
fieldIndex =
FindFieldIndex(mDriverUniforms->getType().getInterfaceBlock()->fields(), fieldName);
}
else
{
fieldIndex = FindFieldIndex(mDriverUniforms->getType().getStruct()->fields(), fieldName);
}
TIntermSymbol *angleUniformsRef = new TIntermSymbol(mDriverUniforms);
TConstantUnion *uniformIndex = new TConstantUnion;
uniformIndex->setIConst(static_cast<int>(fieldIndex));
TIntermConstantUnion *indexRef =
new TIntermConstantUnion(uniformIndex, *StaticType::GetBasic<EbtInt, EbpLow>());
if (mMode == DriverUniformMode::InterfaceBlock)
{
return new TIntermBinary(EOpIndexDirectInterfaceBlock, angleUniformsRef, indexRef);
}
return new TIntermBinary(EOpIndexDirectStruct, angleUniformsRef, indexRef);
}
TIntermTyped *DriverUniform::getAcbBufferOffsets() const
{
return createDriverUniformRef(kAcbBufferOffsets);
}
TIntermTyped *DriverUniform::getDepthRange() const
{
ASSERT(mEmulatedDepthRangeType != nullptr);
TIntermTyped *depthRangeRef = createDriverUniformRef(kDepthRange);
TIntermTyped *nearRef = new TIntermSwizzle(depthRangeRef, {0});
TIntermTyped *farRef = new TIntermSwizzle(depthRangeRef->deepCopy(), {1});
TIntermTyped *diff = new TIntermBinary(EOpSub, farRef, nearRef);
TIntermSequence args = {
nearRef->deepCopy(),
farRef->deepCopy(),
diff,
};
return TIntermAggregate::CreateConstructor(*mEmulatedDepthRangeType, &args);
}
TIntermTyped *DriverUniform::getViewportZScale() const
{
ASSERT(mEmulatedDepthRangeType != nullptr);
TIntermTyped *depthRangeRef = createDriverUniformRef(kDepthRange);
TIntermTyped *nearRef = new TIntermSwizzle(depthRangeRef, {0});
TIntermTyped *farRef = new TIntermSwizzle(depthRangeRef->deepCopy(), {1});
TIntermTyped *isNegative = new TIntermBinary(EOpLessThan, farRef, nearRef);
return new TIntermTernary(isNegative, CreateFloatNode(-1, EbpMedium),
CreateFloatNode(1, EbpMedium));
}
TIntermTyped *DriverUniform::getHalfRenderArea() const
{
TIntermTyped *renderAreaRef = createDriverUniformRef(kRenderArea);
TIntermTyped *width = new TIntermBinary(EOpBitwiseAnd, renderAreaRef, CreateUIntNode(0xFFFF));
TIntermTyped *height =
new TIntermBinary(EOpBitShiftRight, renderAreaRef->deepCopy(), CreateUIntNode(16));
TIntermSequence widthArgs = {
width,
};
TIntermTyped *widthAsFloat =
TIntermAggregate::CreateConstructor(*StaticType::GetBasic<EbtFloat, EbpHigh>(), &widthArgs);
TIntermSequence heightArgs = {
height,
};
TIntermTyped *heightAsFloat = TIntermAggregate::CreateConstructor(
*StaticType::GetBasic<EbtFloat, EbpHigh>(), &heightArgs);
TIntermSequence args = {
widthAsFloat,
heightAsFloat,
};
TIntermTyped *renderArea =
TIntermAggregate::CreateConstructor(*StaticType::GetBasic<EbtFloat, EbpHigh, 2>(), &args);
return new TIntermBinary(EOpVectorTimesScalar, renderArea, CreateFloatNode(0.5, EbpMedium));
}
TIntermTyped *DriverUniform::getFlipXY(TSymbolTable *symbolTable, DriverUniformFlip stage) const
{
TIntermTyped *flipXY = createDriverUniformRef(kFlipXY);
TIntermTyped *values = CreateBuiltInUnaryFunctionCallNode(
"unpackSnorm4x8", flipXY, *symbolTable,
GetESSLOrGLSLVersion(symbolTable->getShaderSpec(), 310, 400));
if (stage == DriverUniformFlip::Fragment)
{
return new TIntermSwizzle(values, {0, 1});
}
return new TIntermSwizzle(values, {2, 3});
}
TIntermTyped *DriverUniform::getNegFlipXY(TSymbolTable *symbolTable, DriverUniformFlip stage) const
{
TIntermTyped *flipXY = getFlipXY(symbolTable, stage);
constexpr std::array<float, 2> kMultiplier = {1, -1};
return new TIntermBinary(EOpMul, flipXY, CreateVecNode(kMultiplier.data(), 2, EbpLow));
}
TIntermTyped *DriverUniform::getDither() const
{
return createDriverUniformRef(kDither);
}
TIntermTyped *DriverUniform::getSwapXY() const
{
TIntermTyped *miscRef = createDriverUniformRef(kMisc);
TIntermTyped *swapXY = new TIntermBinary(EOpBitwiseAnd, miscRef,
CreateUIntNode(vk::kDriverUniformsMiscSwapXYMask));
TIntermSequence args = {
swapXY,
};
return TIntermAggregate::CreateConstructor(*StaticType::GetBasic<EbtBool, EbpUndefined>(),
&args);
}
TIntermTyped *DriverUniform::getAdvancedBlendEquation() const
{
TIntermTyped *miscRef = createDriverUniformRef(kMisc);
TIntermTyped *equation =
new TIntermBinary(EOpBitShiftRight, miscRef,
CreateUIntNode(vk::kDriverUniformsMiscAdvancedBlendEquationOffset));
equation = new TIntermBinary(EOpBitwiseAnd, equation,
CreateUIntNode(vk::kDriverUniformsMiscAdvancedBlendEquationMask));
return equation;
}
TIntermTyped *DriverUniform::getNumSamples() const
{
TIntermTyped *miscRef = createDriverUniformRef(kMisc);
TIntermTyped *sampleCount = new TIntermBinary(
EOpBitShiftRight, miscRef, CreateUIntNode(vk::kDriverUniformsMiscSampleCountOffset));
sampleCount = new TIntermBinary(EOpBitwiseAnd, sampleCount,
CreateUIntNode(vk::kDriverUniformsMiscSampleCountMask));
return sampleCount;
}
TIntermTyped *DriverUniform::getClipDistancesEnabled() const
{
TIntermTyped *miscRef = createDriverUniformRef(kMisc);
TIntermTyped *enabledMask = new TIntermBinary(
EOpBitShiftRight, miscRef, CreateUIntNode(vk::kDriverUniformsMiscEnabledClipPlanesOffset));
enabledMask = new TIntermBinary(EOpBitwiseAnd, enabledMask,
CreateUIntNode(vk::kDriverUniformsMiscEnabledClipPlanesMask));
return enabledMask;
}
TIntermTyped *DriverUniform::getTransformDepth() const
{
TIntermTyped *miscRef = createDriverUniformRef(kMisc);
TIntermTyped *transformDepth = new TIntermBinary(
EOpBitShiftRight, miscRef, CreateUIntNode(vk::kDriverUniformsMiscTransformDepthOffset));
transformDepth = new TIntermBinary(EOpBitwiseAnd, transformDepth,
CreateUIntNode(vk::kDriverUniformsMiscTransformDepthMask));
TIntermSequence args = {
transformDepth,
};
return TIntermAggregate::CreateConstructor(*StaticType::GetBasic<EbtBool, EbpUndefined>(),
&args);
}
//
// Class DriverUniformExtended
//
TFieldList *DriverUniformExtended::createUniformFields(TSymbolTable *symbolTable)
{
TFieldList *driverFieldList = DriverUniform::createUniformFields(symbolTable);
constexpr size_t kNumGraphicsDriverUniformsExt = 4;
constexpr std::array<const char *, kNumGraphicsDriverUniformsExt>
kGraphicsDriverUniformNamesExt = {
{kXfbBufferOffsets, kXfbVerticesPerInstance, kUnused, kUnused2}};
const std::array<TType *, kNumGraphicsDriverUniformsExt> kDriverUniformTypesExt = {{
// xfbBufferOffsets: uvec4
new TType(EbtInt, EbpHigh, EvqGlobal, 4),
// xfbVerticesPerInstance: uint
new TType(EbtInt, EbpHigh, EvqGlobal),
// unused: uvec3
new TType(EbtUInt, EbpHigh, EvqGlobal),
new TType(EbtUInt, EbpHigh, EvqGlobal, 2),
}};
for (size_t uniformIndex = 0; uniformIndex < kNumGraphicsDriverUniformsExt; ++uniformIndex)
{
TField *driverUniformField =
new TField(kDriverUniformTypesExt[uniformIndex],
ImmutableString(kGraphicsDriverUniformNamesExt[uniformIndex]), TSourceLoc(),
SymbolType::AngleInternal);
driverFieldList->push_back(driverUniformField);
}
return driverFieldList;
}
TIntermTyped *DriverUniformExtended::getXfbBufferOffsets() const
{
return createDriverUniformRef(kXfbBufferOffsets);
}
TIntermTyped *DriverUniformExtended::getXfbVerticesPerInstance() const
{
return createDriverUniformRef(kXfbVerticesPerInstance);
}
TIntermTyped *MakeSwapXMultiplier(TIntermTyped *swapped)
{
// float(!swapped)
TIntermSequence args = {
new TIntermUnary(EOpLogicalNot, swapped, nullptr),
};
return TIntermAggregate::CreateConstructor(*StaticType::GetBasic<EbtFloat, EbpLow>(), &args);
}
TIntermTyped *MakeSwapYMultiplier(TIntermTyped *swapped)
{
// float(swapped)
TIntermSequence args = {
swapped,
};
return TIntermAggregate::CreateConstructor(*StaticType::GetBasic<EbtFloat, EbpLow>(), &args);
}
} // namespace sh