blob: 0421d4a1d0402ad9ae8287d7aa0f1563e412ca49 [file] [log] [blame]
/*
* Copyright 2020 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/sksl/dsl/priv/DSLWriter.h"
#include "include/core/SkTypes.h"
#include "include/private/SkSLDefines.h"
#include "include/private/SkSLProgramElement.h"
#include "include/private/SkSLStatement.h"
#include "include/sksl/DSLCore.h"
#include "include/sksl/DSLExpression.h"
#include "include/sksl/DSLModifiers.h"
#include "include/sksl/DSLStatement.h"
#include "include/sksl/DSLSymbols.h"
#include "include/sksl/DSLType.h"
#include "include/sksl/DSLVar.h"
#include "include/sksl/SkSLPosition.h"
#include "src/sksl/SkSLModifiersPool.h"
#include "src/sksl/SkSLThreadContext.h"
#include "src/sksl/ir/SkSLBlock.h"
#include "src/sksl/ir/SkSLExpression.h"
#include "src/sksl/ir/SkSLNop.h"
#include "src/sksl/ir/SkSLType.h"
#include "src/sksl/ir/SkSLVarDeclarations.h"
#include "src/sksl/ir/SkSLVariable.h"
#include <utility>
#include <vector>
namespace SkSL {
namespace dsl {
const SkSL::Variable* DSLWriter::Var(DSLVarBase& var) {
// fInitialized is true if we have attempted to create a var, whether or not we actually
// succeeded. If it's true, we don't want to try again, to avoid reporting the same error
// multiple times.
if (!var.fInitialized) {
// We haven't even attempted to create a var yet, so fVar ought to be null
SkASSERT(!var.fVar);
var.fInitialized = true;
if (var.storage() != SkSL::VariableStorage::kParameter) {
const SkSL::Type* baseType = &var.fType.skslType();
if (baseType->isArray()) {
baseType = &baseType->componentType();
}
}
std::unique_ptr<SkSL::Variable> skslvar = SkSL::Variable::Convert(ThreadContext::Context(),
var.fPosition, var.fModifiers.fPosition, var.fModifiers.fModifiers,
&var.fType.skslType(), var.fNamePosition, var.fName, /*isArray=*/false,
/*arraySize=*/nullptr, var.storage());
SkSL::Variable* varPtr = skslvar.get();
if (var.storage() != SkSL::VariableStorage::kParameter) {
var.fDeclaration = VarDeclaration::Convert(ThreadContext::Context(), std::move(skslvar),
var.fInitialValue.releaseIfPossible(), /*addToSymbolTable=*/false);
if (var.fDeclaration) {
var.fVar = varPtr;
var.fInitialized = true;
}
}
}
return var.fVar;
}
std::unique_ptr<SkSL::Variable> DSLWriter::CreateParameterVar(DSLParameter& var) {
// This should only be called on undeclared parameter variables, but we allow the creation to go
// ahead regardless so we don't have to worry about null pointers potentially sneaking in and
// breaking things. DSLFunction is responsible for reporting errors for invalid parameters.
return SkSL::Variable::Convert(ThreadContext::Context(), var.fPosition,
var.fModifiers.fPosition, var.fModifiers.fModifiers, &var.fType.skslType(),
var.fNamePosition, var.fName, /*isArray=*/false, /*arraySize=*/nullptr, var.storage());
}
std::unique_ptr<SkSL::Statement> DSLWriter::Declaration(DSLVarBase& var) {
Var(var);
if (!var.fDeclaration) {
// We should have already reported an error before ending up here, just clean up the
// initial value so it doesn't assert and return a nop.
var.fInitialValue.releaseIfPossible();
return SkSL::Nop::Make();
}
return std::move(var.fDeclaration);
}
void DSLWriter::AddVarDeclaration(DSLStatement& existing, DSLVar& additional) {
if (existing.fStatement->is<Block>()) {
SkSL::Block& block = existing.fStatement->as<Block>();
SkASSERT(!block.isScope());
block.children().push_back(Declare(additional).release());
} else if (existing.fStatement->is<VarDeclaration>()) {
Position pos = existing.fStatement->fPosition;
StatementArray stmts;
stmts.reserve_back(2);
stmts.push_back(std::move(existing.fStatement));
stmts.push_back(Declare(additional).release());
existing.fStatement = SkSL::Block::Make(pos, std::move(stmts),
Block::Kind::kCompoundStatement);
} else if (existing.fStatement->isEmpty()) {
// If the variable declaration generated an error, we can end up with a Nop statement here.
existing.fStatement = Declare(additional).release();
}
}
void DSLWriter::Reset() {
dsl::PopSymbolTable();
dsl::PushSymbolTable();
ThreadContext::ProgramElements().clear();
ThreadContext::GetModifiersPool()->clear();
}
} // namespace dsl
} // namespace SkSL