blob: 47e114049c72c270cde6f25f4c2fde759a8dd428 [file] [log] [blame]
/*
* Copyright 2022 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/core/SkTypes.h"
#include "include/private/SkSLProgramElement.h"
#include "include/private/SkTHash.h"
#include "src/sksl/SkSLBuiltinMap.h"
#include "src/sksl/SkSLContext.h"
#include "src/sksl/SkSLProgramSettings.h"
#include "src/sksl/analysis/SkSLProgramUsage.h"
#include "src/sksl/ir/SkSLFunctionDeclaration.h"
#include "src/sksl/ir/SkSLFunctionDefinition.h"
#include "src/sksl/ir/SkSLProgram.h"
#include "src/sksl/transform/SkSLTransform.h"
#include <algorithm>
#include <cstddef>
#include <memory>
#include <string>
#include <string_view>
#include <vector>
namespace SkSL {
void Transform::FindAndDeclareBuiltinFunctions(Program& program) {
ProgramUsage* usage = program.fUsage.get();
Context& context = *program.fContext;
std::vector<const FunctionDefinition*> addedBuiltins;
for (;;) {
// Find all the built-ins referenced by the program but not yet included in the code.
size_t numBuiltinsAtStart = addedBuiltins.size();
for (const auto& [fn, count] : usage->fCallCounts) {
if (!fn->isBuiltin() || count == 0) {
// Not a built-in; skip it.
continue;
}
if (fn->intrinsicKind() == k_dFdy_IntrinsicKind) {
// Programs that invoke the `dFdy` intrinsic will need the RTFlip input.
program.fInputs.fUseFlipRTUniform = !context.fConfig->fSettings.fForceNoRTFlip;
}
const ProgramElement* added = context.fBuiltins->findAndInclude(fn->description());
if (!added) {
// This built-in has already been dealt with; skip it.
continue;
}
addedBuiltins.push_back(&added->as<FunctionDefinition>());
}
if (addedBuiltins.size() == numBuiltinsAtStart) {
// If we didn't reference any more built-in functions than before, we're done.
break;
}
// Sort the referenced builtin functions into a consistent order; otherwise our output will
// become non-deterministic. The exact order isn't particularly important; we sort backwards
// because we add elements to the shared-elements in reverse order at the end.
std::sort(addedBuiltins.begin() + numBuiltinsAtStart,
addedBuiltins.end(),
[](const FunctionDefinition* aDefinition, const FunctionDefinition* bDefinition) {
const FunctionDeclaration& a = aDefinition->declaration();
const FunctionDeclaration& b = bDefinition->declaration();
if (a.name() != b.name()) {
return a.name() > b.name();
}
return a.description() > b.description();
});
// Update the ProgramUsage to track all these newly discovered functions.
int usageCallCounts = usage->fCallCounts.count();
for (size_t index = numBuiltinsAtStart; index < addedBuiltins.size(); ++index) {
usage->add(*addedBuiltins[index]);
}
if (usage->fCallCounts.count() == usageCallCounts) {
// If we aren't making any more unique function calls than before, we're done.
break;
}
}
// Insert the new functions into the program's shared elements, right at the front.
// They are added in reverse so that the deepest dependencies are added to the top.
program.fSharedElements.insert(program.fSharedElements.begin(),
addedBuiltins.rbegin(), addedBuiltins.rend());
}
} // namespace SkSL