Use a scoped helper class to push and pop CodeGenerator::fOut changes.
This mirrors other "AutoXxxxxxx" classes used in SkSL to push and pop temporary changes into member variables, such as AutoSymbolTable or AutoLoopLevel. Metal and Pipeline code generators were updated to use this class. SkSL was left as-is for now; it modifies fOut more extensively than the others and will need special care. Change-Id: Icf505b9b55e3458de349e35e3b812dd005f9afed Reviewed-on: https://skia-review.googlesource.com/c/skia/+/341457 Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
parent
1b27c3d7a3
commit
4453237e52
@ -28,13 +28,47 @@ public:
|
||||
|
||||
virtual bool generateCode() = 0;
|
||||
|
||||
protected:
|
||||
// Intended for use by AutoOutputStream.
|
||||
OutputStream* outputStream() { return fOut; }
|
||||
void setOutputStream(OutputStream* output) { fOut = output; }
|
||||
|
||||
protected:
|
||||
const Program& fProgram;
|
||||
ErrorReporter& fErrors;
|
||||
OutputStream* fOut;
|
||||
};
|
||||
|
||||
class AutoOutputStream {
|
||||
public:
|
||||
// Maintains the current indentation level while writing to the new output stream.
|
||||
AutoOutputStream(CodeGenerator* codeGen, OutputStream* newOutput)
|
||||
: fCodeGen(codeGen)
|
||||
, fOldOutput(codeGen->outputStream()) {
|
||||
fCodeGen->setOutputStream(newOutput);
|
||||
}
|
||||
// Resets the indentation when entering the scope, and restores it when leaving.
|
||||
AutoOutputStream(CodeGenerator* codeGen, OutputStream* newOutput, int *indentationPtr)
|
||||
: fCodeGen(codeGen)
|
||||
, fOldOutput(codeGen->outputStream())
|
||||
, fIndentationPtr(indentationPtr)
|
||||
, fOldIndentation(indentationPtr ? *indentationPtr : 0) {
|
||||
fCodeGen->setOutputStream(newOutput);
|
||||
*fIndentationPtr = 0;
|
||||
}
|
||||
~AutoOutputStream() {
|
||||
fCodeGen->setOutputStream(fOldOutput);
|
||||
if (fIndentationPtr) {
|
||||
*fIndentationPtr = fOldIndentation;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
CodeGenerator* fCodeGen = nullptr;
|
||||
OutputStream* fOldOutput = nullptr;
|
||||
int *fIndentationPtr = nullptr;
|
||||
int fOldIndentation = 0;
|
||||
};
|
||||
|
||||
} // namespace SkSL
|
||||
|
||||
#endif
|
||||
|
@ -1216,27 +1216,26 @@ void MetalCodeGenerator::writeFunction(const FunctionDefinition& f) {
|
||||
}
|
||||
|
||||
fFunctionHeader = "";
|
||||
OutputStream* oldOut = fOut;
|
||||
StringStream buffer;
|
||||
fOut = &buffer;
|
||||
fIndentation++;
|
||||
for (const std::unique_ptr<Statement>& stmt : f.body()->as<Block>().children()) {
|
||||
if (!stmt->isEmpty()) {
|
||||
this->writeStatement(*stmt);
|
||||
this->writeLine();
|
||||
{
|
||||
AutoOutputStream outputToBuffer(this, &buffer);
|
||||
fIndentation++;
|
||||
for (const std::unique_ptr<Statement>& stmt : f.body()->as<Block>().children()) {
|
||||
if (!stmt->isEmpty()) {
|
||||
this->writeStatement(*stmt);
|
||||
this->writeLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (f.declaration().name() == "main") {
|
||||
// If the main function doesn't end with a return, we need to synthesize one here.
|
||||
if (!is_block_ending_with_return(f.body().get())) {
|
||||
this->writeReturnStatementFromMain();
|
||||
this->writeLine("");
|
||||
if (f.declaration().name() == "main") {
|
||||
// If the main function doesn't end with a return, we need to synthesize one here.
|
||||
if (!is_block_ending_with_return(f.body().get())) {
|
||||
this->writeReturnStatementFromMain();
|
||||
this->writeLine("");
|
||||
}
|
||||
}
|
||||
fIndentation--;
|
||||
this->writeLine("}");
|
||||
}
|
||||
fIndentation--;
|
||||
this->writeLine("}");
|
||||
|
||||
fOut = oldOut;
|
||||
this->write(fFunctionHeader);
|
||||
this->write(buffer.str());
|
||||
}
|
||||
@ -2019,26 +2018,29 @@ MetalCodeGenerator::Requirements MetalCodeGenerator::requirements(const Function
|
||||
}
|
||||
|
||||
bool MetalCodeGenerator::generateCode() {
|
||||
OutputStream* rawOut = fOut;
|
||||
fOut = &fHeader;
|
||||
fProgramKind = fProgram.fKind;
|
||||
this->writeHeader();
|
||||
this->writeStructDefinitions();
|
||||
this->writeUniformStruct();
|
||||
this->writeInputStruct();
|
||||
this->writeOutputStruct();
|
||||
this->writeInterfaceBlocks();
|
||||
this->writeGlobalStruct();
|
||||
StringStream body;
|
||||
fOut = &body;
|
||||
for (const ProgramElement* e : fProgram.elements()) {
|
||||
this->writeProgramElement(*e);
|
||||
}
|
||||
fOut = rawOut;
|
||||
|
||||
write_stringstream(fHeader, *rawOut);
|
||||
write_stringstream(fExtraFunctions, *rawOut);
|
||||
write_stringstream(body, *rawOut);
|
||||
StringStream header;
|
||||
{
|
||||
AutoOutputStream outputToHeader(this, &header, &fIndentation);
|
||||
this->writeHeader();
|
||||
this->writeStructDefinitions();
|
||||
this->writeUniformStruct();
|
||||
this->writeInputStruct();
|
||||
this->writeOutputStruct();
|
||||
this->writeInterfaceBlocks();
|
||||
this->writeGlobalStruct();
|
||||
}
|
||||
StringStream body;
|
||||
{
|
||||
AutoOutputStream outputToBody(this, &body, &fIndentation);
|
||||
for (const ProgramElement* e : fProgram.elements()) {
|
||||
this->writeProgramElement(*e);
|
||||
}
|
||||
}
|
||||
write_stringstream(header, *fOut);
|
||||
write_stringstream(fExtraFunctions, *fOut);
|
||||
write_stringstream(body, *fOut);
|
||||
return 0 == fErrors.errorCount();
|
||||
}
|
||||
|
||||
|
@ -67,11 +67,9 @@ void PipelineStageCodeGenerator::writeFunctionCall(const FunctionCall& c) {
|
||||
: Compiler::FormatArg::Kind::kChildProcessor,
|
||||
index));
|
||||
if (arguments.size() > 1) {
|
||||
OutputStream* oldOut = fOut;
|
||||
StringStream buffer;
|
||||
fOut = &buffer;
|
||||
AutoOutputStream outputToBuffer(this, &buffer);
|
||||
this->writeExpression(*arguments[1], kSequence_Precedence);
|
||||
fOut = oldOut;
|
||||
fArgs->fFormatArgs[childCallIndex].fCoords = buffer.str();
|
||||
}
|
||||
return;
|
||||
@ -185,48 +183,50 @@ void PipelineStageCodeGenerator::writeSwitchStatement(const SwitchStatement& s)
|
||||
|
||||
void PipelineStageCodeGenerator::writeFunction(const FunctionDefinition& f) {
|
||||
fFunctionHeader = "";
|
||||
OutputStream* oldOut = fOut;
|
||||
StringStream buffer;
|
||||
fOut = &buffer;
|
||||
Compiler::GLSLFunction result;
|
||||
if (f.declaration().name() == "main") {
|
||||
// We allow public SkSL's main() to return half4 -or- float4 (ie vec4). When we emit
|
||||
// our code in the processor, the surrounding code is going to expect half4, so we
|
||||
// explicitly cast any returns (from main) to half4. This is only strictly necessary
|
||||
// if the return type is float4 - injecting it unconditionally reduces the risk of an
|
||||
// obscure bug.
|
||||
fCastReturnsToHalf = true;
|
||||
for (const std::unique_ptr<Statement>& stmt : f.body()->as<Block>().children()) {
|
||||
this->writeStatement(*stmt);
|
||||
this->writeLine();
|
||||
{
|
||||
AutoOutputStream streamToBuffer(this, &buffer);
|
||||
// We allow public SkSL's main() to return half4 -or- float4 (ie vec4). When we emit
|
||||
// our code in the processor, the surrounding code is going to expect half4, so we
|
||||
// explicitly cast any returns (from main) to half4. This is only strictly necessary
|
||||
// if the return type is float4 - injecting it unconditionally reduces the risk of an
|
||||
// obscure bug.
|
||||
fCastReturnsToHalf = true;
|
||||
for (const std::unique_ptr<Statement>& stmt : f.body()->as<Block>().children()) {
|
||||
this->writeStatement(*stmt);
|
||||
this->writeLine();
|
||||
}
|
||||
fCastReturnsToHalf = false;
|
||||
}
|
||||
fCastReturnsToHalf = false;
|
||||
fOut = oldOut;
|
||||
this->write(fFunctionHeader);
|
||||
this->write(buffer.str());
|
||||
} else {
|
||||
const FunctionDeclaration& decl = f.declaration();
|
||||
Compiler::GLSLFunction result;
|
||||
if (!type_to_grsltype(fContext, decl.returnType(), &result.fReturnType)) {
|
||||
fErrors.error(f.fOffset, "unsupported return type");
|
||||
return;
|
||||
}
|
||||
result.fName = decl.name();
|
||||
for (const Variable* v : decl.parameters()) {
|
||||
GrSLType paramSLType;
|
||||
if (!type_to_grsltype(fContext, v->type(), ¶mSLType)) {
|
||||
fErrors.error(v->fOffset, "unsupported parameter type");
|
||||
{
|
||||
AutoOutputStream streamToBuffer(this, &buffer);
|
||||
const FunctionDeclaration& decl = f.declaration();
|
||||
if (!type_to_grsltype(fContext, decl.returnType(), &result.fReturnType)) {
|
||||
fErrors.error(f.fOffset, "unsupported return type");
|
||||
return;
|
||||
}
|
||||
result.fParameters.emplace_back(v->name(), paramSLType);
|
||||
result.fName = decl.name();
|
||||
for (const Variable* v : decl.parameters()) {
|
||||
GrSLType paramSLType;
|
||||
if (!type_to_grsltype(fContext, v->type(), ¶mSLType)) {
|
||||
fErrors.error(v->fOffset, "unsupported parameter type");
|
||||
return;
|
||||
}
|
||||
result.fParameters.emplace_back(v->name(), paramSLType);
|
||||
}
|
||||
for (const std::unique_ptr<Statement>& stmt : f.body()->as<Block>().children()) {
|
||||
this->writeStatement(*stmt);
|
||||
this->writeLine();
|
||||
}
|
||||
}
|
||||
for (const std::unique_ptr<Statement>& stmt : f.body()->as<Block>().children()) {
|
||||
this->writeStatement(*stmt);
|
||||
this->writeLine();
|
||||
}
|
||||
fOut = oldOut;
|
||||
result.fBody = buffer.str();
|
||||
result.fFormatArgs = std::move(fArgs->fFormatArgs);
|
||||
fArgs->fFunctions.push_back(result);
|
||||
fArgs->fFunctions.push_back(std::move(result));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user