blob: 963cdae56d794509bd994e8abc42ea633bf29bfb [file] [log] [blame] [edit]
//
// Copyright 2025 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.
//
#include "compiler/translator/wgsl/WGSLProgramPrelude.h"
#include "common/log_utils.h"
#include "compiler/translator/BaseTypes.h"
#include "compiler/translator/ImmutableString.h"
#include "compiler/translator/ImmutableStringBuilder.h"
#include "compiler/translator/Operator_autogen.h"
#include "compiler/translator/util.h"
#include "compiler/translator/wgsl/Utils.h"
namespace sh
{
namespace
{
constexpr ImmutableString kEndParanthesis = ImmutableString(")");
void EmitConstructorList(TInfoSinkBase &sink, const TType &type, ImmutableString scalar)
{
ASSERT(!type.isArray());
ASSERT(!type.getStruct());
sink << "(";
size_t numScalars = 1;
if (type.isMatrix())
{
numScalars = type.getCols() * type.getRows();
}
for (size_t i = 0; i < numScalars; i++)
{
if (i != 0)
{
sink << ", ";
}
sink << scalar;
}
sink << ")";
}
ImmutableString ConcatId(const char *prefix, uint64_t funcId)
{
return BuildConcatenatedImmutableString("ANGLE_", prefix, "_", funcId);
}
template <typename T>
uint64_t InsertIntoMapWithUniqueId(uint64_t &idCounter, TMap<T, uint64_t> &map, const T &key)
{
auto [iterator, inserted] = map.try_emplace(key, idCounter);
if (inserted)
{
idCounter++;
}
return iterator->second;
}
} // namespace
WGSLWrapperFunction WGSLProgramPrelude::preIncrement(const TType &incrementedType)
{
ASSERT(incrementedType.getBasicType() == EbtInt || incrementedType.getBasicType() == EbtUInt ||
incrementedType.getBasicType() == EbtFloat);
uint64_t uniqueId =
InsertIntoMapWithUniqueId(mUniqueFuncId, mPreIncrementedTypes, incrementedType);
switch (GetWgslAddressSpaceForPointer(incrementedType))
{
case WgslPointerAddressSpace::Function:
return {BuildConcatenatedImmutableString(ConcatId("preIncFunc", uniqueId), "(&"),
kEndParanthesis};
case WgslPointerAddressSpace::Private:
// EvqGlobal and various other shader outputs/builtins are all globals.
return {BuildConcatenatedImmutableString(ConcatId("preIncPriv", uniqueId), "(&"),
kEndParanthesis};
}
}
WGSLWrapperFunction WGSLProgramPrelude::preDecrement(const TType &decrementedType)
{
uint64_t uniqueId =
InsertIntoMapWithUniqueId(mUniqueFuncId, mPreDecrementedTypes, decrementedType);
switch (GetWgslAddressSpaceForPointer(decrementedType))
{
case WgslPointerAddressSpace::Function:
return {BuildConcatenatedImmutableString(ConcatId("preDecFunc", uniqueId), "(&"),
kEndParanthesis};
case WgslPointerAddressSpace::Private:
// EvqGlobal and various other shader outputs/builtins are all globals.
return {BuildConcatenatedImmutableString(ConcatId("preDecPriv", uniqueId), "(&"),
kEndParanthesis};
}
}
WGSLWrapperFunction WGSLProgramPrelude::postIncrement(const TType &incrementedType)
{
uint64_t uniqueId =
InsertIntoMapWithUniqueId(mUniqueFuncId, mPostIncrementedTypes, incrementedType);
switch (GetWgslAddressSpaceForPointer(incrementedType))
{
case WgslPointerAddressSpace::Function:
return {BuildConcatenatedImmutableString(ConcatId("postIncFunc", uniqueId), "(&"),
kEndParanthesis};
case WgslPointerAddressSpace::Private:
// EvqGlobal and various other shader outputs/builtins are all globals.
return {BuildConcatenatedImmutableString(ConcatId("postIncPriv", uniqueId), "(&"),
kEndParanthesis};
}
}
WGSLWrapperFunction WGSLProgramPrelude::postDecrement(const TType &decrementedType)
{
uint64_t uniqueId =
InsertIntoMapWithUniqueId(mUniqueFuncId, mPostDecrementedTypes, decrementedType);
switch (GetWgslAddressSpaceForPointer(decrementedType))
{
case WgslPointerAddressSpace::Function:
return {BuildConcatenatedImmutableString(ConcatId("postDecFunc", uniqueId), "(&"),
kEndParanthesis};
case WgslPointerAddressSpace::Private:
// EvqGlobal and various other shader outputs/builtins are all globals.
return {BuildConcatenatedImmutableString(ConcatId("postDecPriv", uniqueId), "(&"),
kEndParanthesis};
}
}
WGSLWrapperFunction WGSLProgramPrelude::assign(const TType &dest, const TType &src, TOperator op)
{
uint64_t uniqueId = InsertIntoMapWithUniqueId(mUniqueFuncId, mAssigned, {dest, src, op});
switch (GetWgslAddressSpaceForPointer(dest))
{
case WgslPointerAddressSpace::Function:
return {BuildConcatenatedImmutableString(ConcatId("assignFunc", uniqueId), "(&"),
kEndParanthesis};
case WgslPointerAddressSpace::Private:
// EvqGlobal and various other shader outputs/builtins are all globals.
return {BuildConcatenatedImmutableString(ConcatId("assignPriv", uniqueId), "(&"),
kEndParanthesis};
}
}
void WGSLProgramPrelude::outputPrelude(TInfoSinkBase &sink)
{
auto genPreIncOrDec = [&](ImmutableString addressSpace, const TType &type, ImmutableString op,
ImmutableString funcName) {
TStringStream typeStr;
WriteWgslType(typeStr, type, {});
sink << "fn " << funcName << "(x : ptr<" << addressSpace << ", " << typeStr.str()
<< ">) -> " << typeStr.str() << " {\n";
sink << " (*x) " << op << " " << typeStr.str();
EmitConstructorList(sink, type, ImmutableString("1"));
sink << ";\n";
sink << " return *x;\n";
sink << "}\n";
};
for (const std::pair<const TType, FuncId> &elem : mPreIncrementedTypes)
{
// NOTE: it's easiest just to generate increments and decrements functions for variables
// that live in either the function-local scope or the module-local scope. TType holds a
// qualifier, but its operator== and operator< ignore the qualifier. We could keep track of
// the qualifiers used but that's overkill.
genPreIncOrDec(ImmutableString("private"), elem.first, ImmutableString("+="),
ConcatId("preIncPriv", elem.second));
genPreIncOrDec(ImmutableString("function"), elem.first, ImmutableString("+="),
ConcatId("preIncFunc", elem.second));
}
for (const std::pair<const TType, FuncId> &elem : mPreDecrementedTypes)
{
// NOTE: it's easiest just to generate increments and decrements functions for variables
// that live in either the function-local scope or the module-local scope. TType holds a
// qualifier, but its operator== and operator< ignore the qualifier. We could keep track of
// the qualifiers used but that's overkill.
genPreIncOrDec(ImmutableString("private"), elem.first, ImmutableString("-="),
ConcatId("preDecPriv", elem.second));
genPreIncOrDec(ImmutableString("function"), elem.first, ImmutableString("-="),
ConcatId("preDecFunc", elem.second));
}
auto genPostIncOrDec = [&](ImmutableString addressSpace, const TType &type, ImmutableString op,
ImmutableString funcName) {
TStringStream typeStr;
WriteWgslType(typeStr, type, {});
sink << "fn " << funcName << "(x : ptr<" << addressSpace << ", " << typeStr.str()
<< ">) -> " << typeStr.str() << " {\n";
sink << " var old = *x;\n";
sink << " (*x) " << op << " " << typeStr.str();
EmitConstructorList(sink, type, ImmutableString("1"));
sink << ";\n";
sink << " return old;\n";
sink << "}\n";
};
for (const std::pair<const TType, FuncId> &elem : mPostIncrementedTypes)
{
// NOTE: it's easiest just to generate increments and decrements functions for variables
// that live in either the function-local scope or the module-local scope. TType holds a
// qualifier, but its operator== and operator< ignore the qualifier. We could keep track of
// the qualifiers used but that's overkill.
genPostIncOrDec(ImmutableString("private"), elem.first, ImmutableString("+="),
ConcatId("postIncPriv", elem.second));
genPostIncOrDec(ImmutableString("function"), elem.first, ImmutableString("+="),
ConcatId("postIncFunc", elem.second));
}
for (const std::pair<const TType, FuncId> &elem : mPostDecrementedTypes)
{
// NOTE: it's easiest just to generate increments and decrements functions for variables
// that live in either the function-local scope or the module-local scope. TType holds a
// qualifier, but its operator== and operator< ignore the qualifier. We could keep track of
// the qualifiers used but that's overkill.
genPostIncOrDec(ImmutableString("private"), elem.first, ImmutableString("-="),
ConcatId("postDecPriv", elem.second));
genPostIncOrDec(ImmutableString("function"), elem.first, ImmutableString("-="),
ConcatId("postDecFunc", elem.second));
}
for (const auto &assigned : mAssigned)
{
auto genAssignment = [&](ImmutableString addressSpace, ImmutableString funcName) {
TStringStream destTypeStr;
WriteWgslType(destTypeStr, assigned.first.dest, {});
TStringStream srcTypeStr;
WriteWgslType(srcTypeStr, assigned.first.src, {});
sink << "fn " << funcName << "(dest : ptr<" << addressSpace << ", " << destTypeStr.str()
<< ">, src : " << srcTypeStr.str() << ") -> " << destTypeStr.str() << " {\n";
sink << " *dest " << GetOperatorString(assigned.first.op) << " src;\n";
sink << " return *dest;\n";
sink << "}\n";
};
genAssignment(ImmutableString("private"), ConcatId("assignPriv", assigned.second));
genAssignment(ImmutableString("function"), ConcatId("assignFunc", assigned.second));
}
}
} // namespace sh