blob: d3ab8a91a348a10cf06e0feda3abbb0dc879d570 [file] [log] [blame]
//
// Copyright 2024 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 "libANGLE/renderer/wgpu/wgpu_wgsl_util.h"
#include <sstream>
#include "common/PackedEnums.h"
#include "common/PackedGLEnums_autogen.h"
#include "libANGLE/Program.h"
#include "libANGLE/ProgramExecutable.h"
namespace rx
{
namespace webgpu
{
namespace
{
const bool kOutputReplacements = false;
std::string WgslReplaceLocationMarkers(const std::string &shaderSource,
std::map<std::string, int> varNameToLocation)
{
const char *marker = "@location(@@@@@@) ";
const char *endOfName = " : ";
std::string newSource;
newSource.reserve(shaderSource.size());
size_t currPos = 0;
while (true)
{
size_t nextMarker = shaderSource.find(marker, currPos, strlen(marker));
if (nextMarker == std::string::npos)
{
// Copy the rest of the shader and end the loop.
newSource.append(shaderSource, currPos);
break;
}
else
{
// Copy up to the next marker
newSource.append(shaderSource, currPos, nextMarker - currPos);
// Extract name from something like `@location(@@@@@@) NAME : TYPE`.
size_t startOfNamePos = nextMarker + strlen(marker);
size_t endOfNamePos = shaderSource.find(endOfName, startOfNamePos, strlen(endOfName));
std::string name(shaderSource.c_str() + startOfNamePos, endOfNamePos - startOfNamePos);
// Use the shader variable's name to get the assigned location
auto locationIter = varNameToLocation.find(name);
if (locationIter == varNameToLocation.end())
{
ASSERT(false);
return "";
}
// TODO(anglebug.com/42267100): if the GLSL input is a matrix there should be multiple
// WGSL input variables (multiple vectors representing the columns of the matrix).
int location = locationIter->second;
std::ostringstream locationReplacementStream;
locationReplacementStream << "@location(" << location << ") " << name;
if (kOutputReplacements)
{
std::cout << "Replace \"" << marker << name << "\" with \""
<< locationReplacementStream.str() << "\"" << std::endl;
}
// Append the new `@location(N) name` and then continue from the ` : type`.
newSource.append(locationReplacementStream.str());
currPos = endOfNamePos;
}
}
return newSource;
}
} // namespace
template <typename T>
std::string WgslAssignLocations(const std::string &shaderSource,
const std::vector<T> shaderVars,
const gl::ProgramMergedVaryings &mergedVaryings,
gl::ShaderType shaderType)
{
std::map<std::string, int> varNameToLocation;
for (const T &shaderVar : shaderVars)
{
if (shaderVar.isBuiltIn())
{
continue;
}
varNameToLocation[shaderVar.name] = shaderVar.getLocation();
}
int currLocMarker = 0;
for (const gl::ProgramVaryingRef &linkedVarying : mergedVaryings)
{
gl::ShaderBitSet supportedShaderStages =
gl::ShaderBitSet({gl::ShaderType::Vertex, gl::ShaderType::Fragment});
ASSERT(linkedVarying.frontShaderStage == gl::ShaderType::InvalidEnum ||
supportedShaderStages.test(linkedVarying.frontShaderStage));
ASSERT(linkedVarying.backShaderStage == gl::ShaderType::InvalidEnum ||
supportedShaderStages.test(linkedVarying.backShaderStage));
if (!linkedVarying.frontShader && !linkedVarying.backShader)
{
continue;
}
const sh::ShaderVariable *shaderVar = shaderType == gl::ShaderType::Vertex
? linkedVarying.frontShader
: linkedVarying.backShader;
if (shaderVar)
{
if (shaderVar->isBuiltIn())
{
continue;
}
ASSERT(varNameToLocation.find(shaderVar->name) == varNameToLocation.end());
varNameToLocation[shaderVar->name] = currLocMarker++;
}
else
{
const sh::ShaderVariable *otherShaderVar = shaderType == gl::ShaderType::Vertex
? linkedVarying.backShader
: linkedVarying.frontShader;
if (!otherShaderVar->isBuiltIn())
{
// Increment `currLockMarker` to keep locations in sync with the WGSL source
// generated for the other shader stage, which will also have incremented
// `currLocMarker` when seeing this variable.
currLocMarker++;
}
}
}
return WgslReplaceLocationMarkers(shaderSource, varNameToLocation);
}
template std::string WgslAssignLocations<gl::ProgramInput>(
const std::string &shaderSource,
const std::vector<gl::ProgramInput> shaderVars,
const gl::ProgramMergedVaryings &mergedVaryings,
gl::ShaderType shaderType);
template std::string WgslAssignLocations<gl::ProgramOutput>(
const std::string &shaderSource,
const std::vector<gl::ProgramOutput> shaderVars,
const gl::ProgramMergedVaryings &mergedVaryings,
gl::ShaderType shaderType);
} // namespace webgpu
} // namespace rx