mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
SPIR-V Transpiler Control Flow (flutter/engine#31451)
This commit is contained in:
parent
36fa2a0924
commit
e7ddebd2cb
@ -19,9 +19,13 @@ the code will need to adhere to the following rules.
|
||||
- The output can only be written to from the main function.
|
||||
- `gl_FragCoord` can only be read from the main function, and its z and w components
|
||||
have no meaning.
|
||||
- Control flow is prohibited (`if`, `while`, `for`, `switch`, etc.) aside from function calls and `return`.
|
||||
- `if`, `else`, and `for` and function calls are the only permitted control
|
||||
flow operations. `for` loops must initialize a float variable to a constant
|
||||
value, compare it against a constant value, and increment/modify it by a
|
||||
constant value.
|
||||
- `while` and `switch` statements are not supported.
|
||||
- No inputs from other shader stages.
|
||||
- Only sampler2D, float, float-vector types, and square float-matrix types.
|
||||
- Only sampler2D, bool, float, float-vector types, and square float-matrix types.
|
||||
- Only square matrices are supported.
|
||||
- Only built-in functions present in GLSL ES 100 are used.
|
||||
- Only the `texture` function is supported for sampling from a sampler2D object.
|
||||
|
||||
@ -44,10 +44,10 @@ class TranspileResult {
|
||||
final int samplerCount;
|
||||
|
||||
TranspileResult._(
|
||||
this.src,
|
||||
this.uniformFloatCount,
|
||||
this.samplerCount,
|
||||
this.language,
|
||||
this.src,
|
||||
this.uniformFloatCount,
|
||||
this.samplerCount,
|
||||
this.language,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -70,7 +70,6 @@ const int _opFunction = 54;
|
||||
const int _opFunctionParameter = 55;
|
||||
const int _opFunctionEnd = 56;
|
||||
const int _opFunctionCall = 57;
|
||||
const int _opFUnordNotEqual = 183;
|
||||
const int _opVariable = 59;
|
||||
const int _opLoad = 61;
|
||||
const int _opStore = 62;
|
||||
@ -95,8 +94,23 @@ const int _opVectorTimesMatrix = 144;
|
||||
const int _opMatrixTimesVector = 145;
|
||||
const int _opMatrixTimesMatrix = 146;
|
||||
const int _opDot = 148;
|
||||
const int _opFOrdEqual = 180;
|
||||
const int _opFUnordNotEqual = 183;
|
||||
const int _opFOrdLessThan = 184;
|
||||
const int _opFOrdGreaterThan = 186;
|
||||
const int _opFOrdLessThanEqual = 188;
|
||||
const int _opFOrdGreaterThanEqual = 190;
|
||||
const int _opLogicalEqual = 164;
|
||||
const int _opLogicalNotEqual = 165;
|
||||
const int _opLogicalOr = 166;
|
||||
const int _opLogicalAnd = 167;
|
||||
const int _opLogicalNot = 168;
|
||||
const int _opSelect = 169;
|
||||
const int _opLoopMerge = 246;
|
||||
const int _opSelectionMerge = 247;
|
||||
const int _opLabel = 248;
|
||||
const int _opBranch = 249;
|
||||
const int _opBranchConditional = 250;
|
||||
const int _opReturn = 253;
|
||||
const int _opReturnValue = 254;
|
||||
|
||||
@ -212,3 +226,55 @@ const Map<int, int> _glslStd450OpArgc = <int, int>{
|
||||
_glslStd450FaceForward: 3,
|
||||
_glslStd450Reflect: 2,
|
||||
};
|
||||
|
||||
enum _Operator {
|
||||
addition,
|
||||
subtraction,
|
||||
division,
|
||||
multiplication,
|
||||
modulo,
|
||||
negation,
|
||||
equality,
|
||||
inequality,
|
||||
and,
|
||||
or,
|
||||
not,
|
||||
lessThan,
|
||||
greaterThan,
|
||||
lessThanEqual,
|
||||
greaterThanEqual,
|
||||
}
|
||||
|
||||
const Set<_Operator> _compoundAssignmentOperators = <_Operator>{
|
||||
_Operator.addition,
|
||||
_Operator.subtraction,
|
||||
_Operator.division,
|
||||
_Operator.multiplication,
|
||||
_Operator.modulo,
|
||||
};
|
||||
|
||||
const Map<_Operator, String> _operatorStrings = <_Operator, String>{
|
||||
_Operator.addition: '+',
|
||||
_Operator.subtraction: '-',
|
||||
_Operator.division: '/',
|
||||
_Operator.multiplication: '*',
|
||||
_Operator.modulo: '%',
|
||||
_Operator.negation: '-',
|
||||
_Operator.equality: '==',
|
||||
_Operator.inequality: '!=',
|
||||
_Operator.and: '&&',
|
||||
_Operator.or: '||',
|
||||
_Operator.not: '!',
|
||||
_Operator.lessThan: '<',
|
||||
_Operator.greaterThan: '>',
|
||||
_Operator.lessThanEqual: '<=',
|
||||
_Operator.greaterThanEqual: '>=',
|
||||
};
|
||||
|
||||
String _operatorString(_Operator op) {
|
||||
return _operatorStrings[op]!;
|
||||
}
|
||||
|
||||
bool _isCompoundAssignment(_Operator op) {
|
||||
return _compoundAssignmentOperators.contains(op);
|
||||
}
|
||||
|
||||
@ -4,14 +4,25 @@
|
||||
|
||||
part of spirv;
|
||||
|
||||
class _Variable {
|
||||
_Variable(this.id, this.type);
|
||||
|
||||
final int id;
|
||||
final int type;
|
||||
|
||||
bool initialized = false;
|
||||
int liftToBlock = 0;
|
||||
}
|
||||
|
||||
class _Function {
|
||||
_Function(this.transpiler, this.type, this.name)
|
||||
: params = List<int>.filled(type.params.length, 0);
|
||||
|
||||
final _Transpiler transpiler;
|
||||
final int name;
|
||||
final _FunctionType type;
|
||||
final List<int> params;
|
||||
|
||||
_Function(this.type, this.name) :
|
||||
params = List<int>.filled(type.params.length, 0);
|
||||
|
||||
// entry point for the function
|
||||
_Block? entry;
|
||||
|
||||
@ -20,46 +31,76 @@ class _Function {
|
||||
|
||||
final Map<int, _Block> blocks = <int, _Block>{};
|
||||
final List<int> deps = <int>[];
|
||||
final Map<int, _Variable> variables = <int, _Variable>{};
|
||||
|
||||
_Block addBlock(int id) {
|
||||
final _Block b = _Block();
|
||||
final _Block b = _Block(id, this);
|
||||
blocks[id] = b;
|
||||
entry ??= b;
|
||||
return b;
|
||||
}
|
||||
|
||||
_Block block(int id) {
|
||||
return blocks[id]!;
|
||||
}
|
||||
|
||||
void declareVariable(int id, int type) {
|
||||
variables[id] = _Variable(id, type);
|
||||
}
|
||||
|
||||
_Variable? variable(int id) {
|
||||
return variables[id];
|
||||
}
|
||||
|
||||
void declareParam(int id, int paramType) {
|
||||
final int i = declaredParams;
|
||||
if (paramType != type.params[i]) {
|
||||
throw TranspileException._(_opFunctionParameter,
|
||||
'type mismatch for param $i of function $name');
|
||||
throw TranspileException._(
|
||||
_opFunctionParameter, 'type mismatch for param $i of function $name');
|
||||
}
|
||||
params[i] = id;
|
||||
declaredParams++;
|
||||
}
|
||||
|
||||
void write(_Transpiler t, StringBuffer out) {
|
||||
/// Returns deps of result `id` that are variables.
|
||||
List<_Variable> variableDeps(int id) {
|
||||
final _Instruction? result = transpiler.results[id];
|
||||
if (result == null) {
|
||||
return <_Variable>[];
|
||||
}
|
||||
final Set<int> deps = <int>{};
|
||||
transpiler.collectDeps(deps, id);
|
||||
return deps
|
||||
.where(variables.containsKey)
|
||||
.map((int id) => variables[id]!)
|
||||
.toList();
|
||||
}
|
||||
|
||||
void write(StringBuffer out) {
|
||||
if (declaredParams != params.length) {
|
||||
throw t.failure('not all parameters declared for function $name');
|
||||
throw transpiler
|
||||
.failure('not all parameters declared for function $name');
|
||||
}
|
||||
if (entry == null) {
|
||||
throw t.failure('function $name has no entry block');
|
||||
throw transpiler.failure('function $name has no entry block');
|
||||
}
|
||||
String returnTypeString = t.resolveType(type.returnType);
|
||||
if (t.target == TargetLanguage.sksl && name == t.entryPoint) {
|
||||
String returnTypeString = transpiler.resolveType(type.returnType);
|
||||
if (transpiler.target == TargetLanguage.sksl &&
|
||||
name == transpiler.entryPoint) {
|
||||
returnTypeString = 'half4';
|
||||
}
|
||||
final String nameString = t.resolveName(name);
|
||||
final String nameString = transpiler.resolveName(name);
|
||||
out.write('$returnTypeString $nameString(');
|
||||
|
||||
if (t.target == TargetLanguage.sksl && name == t.entryPoint) {
|
||||
if (transpiler.target == TargetLanguage.sksl &&
|
||||
name == transpiler.entryPoint) {
|
||||
const String fragParam = 'float2 $_fragParamName';
|
||||
out.write(fragParam);
|
||||
}
|
||||
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
final String typeString = t.resolveType(type.params[i]);
|
||||
final String nameString = t.resolveName(params[i]);
|
||||
final String typeString = transpiler.resolveType(type.params[i]);
|
||||
final String nameString = transpiler.resolveName(params[i]);
|
||||
out.write('$typeString $nameString');
|
||||
if (i < params.length - 1) {
|
||||
out.write(', ');
|
||||
@ -70,22 +111,28 @@ class _Function {
|
||||
|
||||
// SkSL needs to return a value from main, so we maintain a variable
|
||||
// that receives the value of gl_FragColor and returns it at the end.
|
||||
if (t.target == TargetLanguage.sksl && name == t.entryPoint) {
|
||||
if (t.fragCoord > 0) {
|
||||
final String fragName = t.resolveName(t.fragCoord);
|
||||
if (transpiler.target == TargetLanguage.sksl &&
|
||||
name == transpiler.entryPoint) {
|
||||
if (transpiler.fragCoord > 0) {
|
||||
final String fragName = transpiler.resolveName(transpiler.fragCoord);
|
||||
out.writeln(' float4 $fragName = float4($_fragParamName, 0, 0);');
|
||||
}
|
||||
out.writeln(' float4 $_colorVariableName;');
|
||||
}
|
||||
|
||||
// write the actual function body
|
||||
entry?.write(t, out, 1);
|
||||
entry?._preprocess();
|
||||
|
||||
if (t.target == TargetLanguage.sksl && name == t.entryPoint) {
|
||||
// write the actual function body
|
||||
entry?.write(_BlockContext(
|
||||
out: out,
|
||||
indent: 1,
|
||||
));
|
||||
|
||||
if (transpiler.target == TargetLanguage.sksl &&
|
||||
name == transpiler.entryPoint) {
|
||||
out.writeln(' return $_colorVariableName;');
|
||||
}
|
||||
out.writeln('}');
|
||||
out.writeln();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,33 +1,286 @@
|
||||
part of spirv;
|
||||
|
||||
class _BlockContext {
|
||||
_BlockContext({
|
||||
required this.out,
|
||||
required this.indent,
|
||||
this.merge = 0,
|
||||
this.continueBlock = 0,
|
||||
this.loopHeader = 0,
|
||||
this.loopMerge = 0,
|
||||
});
|
||||
|
||||
final StringBuffer out;
|
||||
final int indent;
|
||||
|
||||
/// The most local merge block id, or zero.
|
||||
final int merge;
|
||||
|
||||
/// The most local continue block id, or zero.
|
||||
final int continueBlock;
|
||||
|
||||
/// The most local loop-construct header block id.
|
||||
final int loopHeader;
|
||||
|
||||
/// The most local loop-construct merge block id.
|
||||
/// This is different from [merge] when the context is inside an if-statement
|
||||
/// inside of a for-loop, for example.
|
||||
final int loopMerge;
|
||||
|
||||
/// Return a new [_BlockContext] that is a copy of the current [_BlockContext]
|
||||
/// with an increased indent and any parameters specified here overwritten.
|
||||
_BlockContext child({
|
||||
int? merge,
|
||||
int? continueBlock,
|
||||
int? loopHeader,
|
||||
int? loopMerge,
|
||||
}) =>
|
||||
_BlockContext(
|
||||
out: out,
|
||||
indent: indent + 1,
|
||||
merge: merge ?? this.merge,
|
||||
continueBlock: continueBlock ?? this.continueBlock,
|
||||
loopHeader: loopHeader ?? this.loopHeader,
|
||||
loopMerge: loopMerge ?? this.loopMerge,
|
||||
);
|
||||
|
||||
void writeIndent() {
|
||||
out.write(' ' * indent);
|
||||
}
|
||||
}
|
||||
|
||||
class _Block {
|
||||
_Block(this.id, this.function);
|
||||
|
||||
final int id;
|
||||
final _Function function;
|
||||
|
||||
List<_Instruction> instructions = <_Instruction>[];
|
||||
|
||||
void add(_Instruction i) {
|
||||
// control flow
|
||||
int branch = 0;
|
||||
int mergeBlock = 0;
|
||||
int condition = 0;
|
||||
int truthyBlock = 0;
|
||||
int falseyBlock = 0;
|
||||
|
||||
// structured loop
|
||||
_Store? loopInitializer;
|
||||
int continueBlock = 0;
|
||||
|
||||
// true if this block has been processed by [liftLoopVariables].
|
||||
bool scanned = false;
|
||||
|
||||
_Transpiler get transpiler => function.transpiler;
|
||||
|
||||
bool get hasSelectionStructure => mergeBlock != 0 && continueBlock == 0;
|
||||
bool get hasLoopStructure => continueBlock != 0;
|
||||
|
||||
void _add(_Instruction i) {
|
||||
instructions.add(i);
|
||||
}
|
||||
|
||||
void writeIndent(StringBuffer out, int indent) {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
out.write(' ');
|
||||
void _writeContinue(_BlockContext ctx) {
|
||||
final List<_CompoundAssignment> assignments =
|
||||
instructions.whereType<_CompoundAssignment>().toList();
|
||||
if (assignments.isEmpty) {
|
||||
throw TranspileException._(
|
||||
_opLoopMerge, 'loop continue block $id has no compound asignments.');
|
||||
}
|
||||
if (assignments.length > 1) {
|
||||
throw TranspileException._(_opLoopMerge,
|
||||
'loop continue block $id has multiple compound assignments.');
|
||||
}
|
||||
assignments[0].write(transpiler, ctx.out);
|
||||
}
|
||||
|
||||
void write(_BlockContext ctx) {
|
||||
for (final _Instruction inst in instructions) {
|
||||
if (inst is _Store) {
|
||||
final _Variable? v = function.variables[inst.pointer];
|
||||
if (v != null && inst.shouldDeclare && v.liftToBlock != 0) {
|
||||
function.block(v.liftToBlock).loopInitializer = inst;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!inst.isResult) {
|
||||
ctx.writeIndent();
|
||||
inst.write(transpiler, ctx.out);
|
||||
ctx.out.writeln(';');
|
||||
} else if (inst.refCount > 1) {
|
||||
ctx.writeIndent();
|
||||
final String typeString = transpiler.resolveType(inst.type);
|
||||
final String nameString = transpiler.resolveName(inst.id);
|
||||
ctx.out.write('$typeString $nameString = ');
|
||||
inst.write(transpiler, ctx.out);
|
||||
ctx.out.writeln(';');
|
||||
}
|
||||
}
|
||||
|
||||
if (hasSelectionStructure) {
|
||||
_writeSelectionStructure(ctx);
|
||||
} else if (hasLoopStructure) {
|
||||
_writeLoopStructure(ctx);
|
||||
}
|
||||
|
||||
if (mergeBlock != 0) {
|
||||
function.block(mergeBlock).write(ctx);
|
||||
} else if (branch != 0) {
|
||||
if (branch == ctx.merge) {
|
||||
return;
|
||||
}
|
||||
if (branch == ctx.continueBlock) {
|
||||
if (ctx.merge != ctx.loopMerge) {
|
||||
ctx.writeIndent();
|
||||
ctx.out.writeln('continue;');
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (branch == ctx.loopMerge) {
|
||||
ctx.writeIndent();
|
||||
ctx.out.writeln('break;');
|
||||
}
|
||||
function.block(branch).write(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
void write(_Transpiler t, StringBuffer out, int indent) {
|
||||
for (final _Instruction inst in instructions) {
|
||||
if (!inst.isResult) {
|
||||
writeIndent(out, indent);
|
||||
inst.write(t, out);
|
||||
out.writeln(';');
|
||||
} else if (inst.refCount > 1) {
|
||||
writeIndent(out, indent);
|
||||
final String typeString = t.resolveType(inst.type);
|
||||
final String nameString = t.resolveName(inst.id);
|
||||
out.write('$typeString $nameString = ');
|
||||
inst.write(t, out);
|
||||
out.writeln(';');
|
||||
/// Scans through the entire Control-Flow graph to collecting parts of
|
||||
/// for-loop structures.
|
||||
void _preprocess() {
|
||||
if (scanned) {
|
||||
return;
|
||||
}
|
||||
scanned = true;
|
||||
|
||||
// SkSL has specific needs for for-loops - they must define a single
|
||||
// index variable to a constant value, they must compare that value
|
||||
// against a constant value, and they must be modified in place with
|
||||
// a constant value. SPIR-V represents all these operations in different
|
||||
// blocks, so we scan here to collect them so they can be written together.
|
||||
if (hasLoopStructure) {
|
||||
int conditionId = condition;
|
||||
if (condition == 0) {
|
||||
final _Block branchBlock = function.block(branch);
|
||||
if (!branchBlock._isSimple() || branchBlock.condition == 0) {
|
||||
throw TranspileException._(
|
||||
_opBranch,
|
||||
'block $id has a loop structure but does not immediately '
|
||||
'branch to a single-expression conditional block.');
|
||||
}
|
||||
conditionId = branchBlock.condition;
|
||||
}
|
||||
final List<_Variable> deps = function.variableDeps(conditionId);
|
||||
if (deps.length != 1) {
|
||||
throw TranspileException._(
|
||||
_opLoopMerge,
|
||||
'block $id has a loop structure with a condition '
|
||||
'using more or fewer than one local variable.');
|
||||
}
|
||||
deps[0].liftToBlock = id;
|
||||
}
|
||||
|
||||
// Scan all blocks that can be reached from this block.
|
||||
if (branch != 0) {
|
||||
function.block(branch)._preprocess();
|
||||
}
|
||||
if (condition != 0) {
|
||||
if (truthyBlock != 0) {
|
||||
function.block(truthyBlock)._preprocess();
|
||||
}
|
||||
if (falseyBlock != 0) {
|
||||
function.block(falseyBlock)._preprocess();
|
||||
}
|
||||
}
|
||||
if (mergeBlock != 0) {
|
||||
function.block(mergeBlock)._preprocess();
|
||||
}
|
||||
}
|
||||
|
||||
void _writeSelectionStructure(_BlockContext ctx) {
|
||||
final _BlockContext childCtx = ctx.child(merge: mergeBlock);
|
||||
ctx.writeIndent();
|
||||
final String conditionString = transpiler.resolveResult(condition);
|
||||
ctx.out.writeln('if ($conditionString) {');
|
||||
function.block(truthyBlock).write(childCtx);
|
||||
if (falseyBlock != 0 && falseyBlock != mergeBlock) {
|
||||
ctx.writeIndent();
|
||||
ctx.out.writeln('} else {');
|
||||
function.block(falseyBlock).write(childCtx);
|
||||
}
|
||||
ctx.writeIndent();
|
||||
ctx.out.writeln('}');
|
||||
}
|
||||
|
||||
void _writeLoopStructure(_BlockContext ctx) {
|
||||
final _BlockContext childCtx = ctx.child(
|
||||
merge: mergeBlock,
|
||||
continueBlock: continueBlock,
|
||||
loopHeader: id,
|
||||
loopMerge: mergeBlock,
|
||||
);
|
||||
|
||||
String conditionString;
|
||||
int loopBody = 0;
|
||||
if (condition != 0) {
|
||||
conditionString = transpiler.resolveResult(condition);
|
||||
if (truthyBlock == mergeBlock) {
|
||||
conditionString = '!' + conditionString;
|
||||
loopBody = falseyBlock;
|
||||
} else if (falseyBlock == mergeBlock) {
|
||||
loopBody = truthyBlock;
|
||||
}
|
||||
} else {
|
||||
final _Block branchBlock = function.block(branch);
|
||||
if (!branchBlock._isSimple() || branchBlock.condition == 0) {
|
||||
throw TranspileException._(
|
||||
_opBranch,
|
||||
'block $id has a loop structure but does not immediately '
|
||||
'branch to a single-expression conditional block.');
|
||||
}
|
||||
|
||||
conditionString = transpiler.resolveResult(branchBlock.condition);
|
||||
if (branchBlock.truthyBlock == mergeBlock) {
|
||||
conditionString = '!' + conditionString;
|
||||
loopBody = branchBlock.falseyBlock;
|
||||
} else if (branchBlock.falseyBlock == mergeBlock) {
|
||||
loopBody = branchBlock.truthyBlock;
|
||||
}
|
||||
}
|
||||
|
||||
if (loopBody == 0) {
|
||||
throw TranspileException._(
|
||||
_opLoopMerge,
|
||||
'block $id does not conditionally branch to its '
|
||||
'loop merge block.');
|
||||
}
|
||||
|
||||
ctx.writeIndent();
|
||||
ctx.out.write('for(');
|
||||
loopInitializer!.write(transpiler, ctx.out);
|
||||
ctx.out.write('; ');
|
||||
ctx.out.write(conditionString);
|
||||
ctx.out.write('; ');
|
||||
function.block(continueBlock)._writeContinue(ctx);
|
||||
ctx.out.writeln(') {');
|
||||
function.block(loopBody).write(childCtx);
|
||||
ctx.writeIndent();
|
||||
ctx.out.writeln('}');
|
||||
}
|
||||
|
||||
/// Returns true if this block has no stateful expressions
|
||||
/// and can be written as a single expression.
|
||||
bool _isSimple() {
|
||||
int statements = 0;
|
||||
for (final _Instruction inst in instructions) {
|
||||
if (!inst.isResult) {
|
||||
return false;
|
||||
}
|
||||
if (inst.refCount > 1) {
|
||||
statements++;
|
||||
}
|
||||
}
|
||||
return statements == 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,6 +291,8 @@ abstract class _Instruction {
|
||||
|
||||
bool get isResult => id != 0;
|
||||
|
||||
List<int> get deps => <int>[];
|
||||
|
||||
// How many times this instruction is referenced, a value
|
||||
// of 2 or greater means that it will be stored into a variable.
|
||||
int refCount = 0;
|
||||
@ -46,6 +301,8 @@ abstract class _Instruction {
|
||||
}
|
||||
|
||||
class _FunctionCall extends _Instruction {
|
||||
_FunctionCall(this.type, this.id, this.function, this.args);
|
||||
|
||||
@override
|
||||
final int type;
|
||||
|
||||
@ -55,7 +312,8 @@ class _FunctionCall extends _Instruction {
|
||||
final String function;
|
||||
final List<int> args;
|
||||
|
||||
_FunctionCall(this.type, this.id, this.function, this.args);
|
||||
@override
|
||||
List<int> get deps => args;
|
||||
|
||||
@override
|
||||
void write(_Transpiler t, StringBuffer out) {
|
||||
@ -70,18 +328,16 @@ class _FunctionCall extends _Instruction {
|
||||
}
|
||||
}
|
||||
|
||||
class _StringInstruction extends _Instruction {
|
||||
final String value;
|
||||
|
||||
_StringInstruction(this.value);
|
||||
|
||||
class _Return extends _Instruction {
|
||||
@override
|
||||
void write(_Transpiler t, StringBuffer out) {
|
||||
out.write(value);
|
||||
out.write('return');
|
||||
}
|
||||
}
|
||||
|
||||
class _Select extends _Instruction {
|
||||
_Select(this.type, this.id, this.condition, this.a, this.b);
|
||||
|
||||
@override
|
||||
final int type;
|
||||
|
||||
@ -92,32 +348,74 @@ class _Select extends _Instruction {
|
||||
final int a;
|
||||
final int b;
|
||||
|
||||
_Select(this.type, this.id, this.condition, this.a, this.b);
|
||||
@override
|
||||
List<int> get deps => <int>[condition, a, b];
|
||||
|
||||
@override
|
||||
void write(_Transpiler t, StringBuffer out) {
|
||||
final String typeName = t.resolveType(type);
|
||||
final String aName = t.resolveResult(a);
|
||||
final String bName = t.resolveResult(b);
|
||||
final String conditionName = t.resolveResult(condition);
|
||||
out.write('mix($bName, $aName, $typeName($conditionName))');
|
||||
out.write('$conditionName ? $aName : $bName');
|
||||
}
|
||||
}
|
||||
|
||||
class _Store extends _Instruction {
|
||||
class _CompoundAssignment extends _Instruction {
|
||||
_CompoundAssignment(this.pointer, this.op, this.object);
|
||||
|
||||
final int pointer;
|
||||
final _Operator op;
|
||||
final int object;
|
||||
_Store(this.pointer, this.object);
|
||||
|
||||
@override
|
||||
void write(_Transpiler t, StringBuffer out) {
|
||||
final String pointerName = t.resolveResult(pointer);
|
||||
final String objectName = t.resolveResult(object);
|
||||
out.write('$pointerName = $objectName');
|
||||
final String operatorString = _operatorString(op);
|
||||
out.write('$pointerName $operatorString= $objectName');
|
||||
}
|
||||
}
|
||||
|
||||
class _Store extends _Instruction {
|
||||
_Store(
|
||||
this.pointer,
|
||||
this.object, {
|
||||
this.shouldDeclare = false,
|
||||
this.declarationType = 0,
|
||||
});
|
||||
|
||||
final int pointer;
|
||||
final int object;
|
||||
|
||||
final bool shouldDeclare;
|
||||
final int declarationType;
|
||||
|
||||
int selfModifyObject = 0;
|
||||
String selfModifyOperator = '';
|
||||
|
||||
@override
|
||||
List<int> get deps => <int>[pointer, object];
|
||||
|
||||
@override
|
||||
void write(_Transpiler t, StringBuffer out) {
|
||||
final String pointerName = t.resolveResult(pointer);
|
||||
if (selfModifyObject > 0) {
|
||||
final String objectName = t.resolveResult(selfModifyObject);
|
||||
out.write('$pointerName $selfModifyOperator $objectName');
|
||||
} else {
|
||||
final String objectName = t.resolveResult(object);
|
||||
if (shouldDeclare) {
|
||||
final String typeString = t.resolveType(declarationType);
|
||||
out.write('$typeString ');
|
||||
}
|
||||
out.write('$pointerName = $objectName');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _AccessChain extends _Instruction {
|
||||
_AccessChain(this.type, this.id, this.base, this.indices);
|
||||
|
||||
@override
|
||||
final int type;
|
||||
|
||||
@ -127,7 +425,8 @@ class _AccessChain extends _Instruction {
|
||||
final int base;
|
||||
final List<int> indices;
|
||||
|
||||
_AccessChain(this.type, this.id, this.base, this.indices);
|
||||
@override
|
||||
List<int> get deps => <int>[base, ...indices];
|
||||
|
||||
@override
|
||||
void write(_Transpiler t, StringBuffer out) {
|
||||
@ -140,6 +439,8 @@ class _AccessChain extends _Instruction {
|
||||
}
|
||||
|
||||
class _VectorShuffle extends _Instruction {
|
||||
_VectorShuffle(this.type, this.id, this.vector, this.indices);
|
||||
|
||||
@override
|
||||
final int type;
|
||||
|
||||
@ -149,7 +450,8 @@ class _VectorShuffle extends _Instruction {
|
||||
final int vector;
|
||||
final List<int> indices;
|
||||
|
||||
_VectorShuffle(this.type, this.id, this.vector, this.indices);
|
||||
@override
|
||||
List<int> get deps => <int>[vector];
|
||||
|
||||
@override
|
||||
void write(_Transpiler t, StringBuffer out) {
|
||||
@ -168,6 +470,8 @@ class _VectorShuffle extends _Instruction {
|
||||
}
|
||||
|
||||
class _CompositeConstruct extends _Instruction {
|
||||
_CompositeConstruct(this.type, this.id, this.components);
|
||||
|
||||
@override
|
||||
final int type;
|
||||
|
||||
@ -176,7 +480,8 @@ class _CompositeConstruct extends _Instruction {
|
||||
|
||||
final List<int> components;
|
||||
|
||||
_CompositeConstruct(this.type, this.id, this.components);
|
||||
@override
|
||||
List<int> get deps => components;
|
||||
|
||||
@override
|
||||
void write(_Transpiler t, StringBuffer out) {
|
||||
@ -193,6 +498,8 @@ class _CompositeConstruct extends _Instruction {
|
||||
}
|
||||
|
||||
class _CompositeExtract extends _Instruction {
|
||||
_CompositeExtract(this.type, this.id, this.src, this.indices);
|
||||
|
||||
@override
|
||||
final int type;
|
||||
|
||||
@ -202,7 +509,8 @@ class _CompositeExtract extends _Instruction {
|
||||
final int src;
|
||||
final List<int> indices;
|
||||
|
||||
_CompositeExtract(this.type, this.id, this.src, this.indices);
|
||||
@override
|
||||
List<int> get deps => <int>[src];
|
||||
|
||||
@override
|
||||
void write(_Transpiler t, StringBuffer out) {
|
||||
@ -214,6 +522,9 @@ class _CompositeExtract extends _Instruction {
|
||||
}
|
||||
|
||||
class _ImageSampleImplicitLod extends _Instruction {
|
||||
_ImageSampleImplicitLod(
|
||||
this.type, this.id, this.sampledImage, this.coordinate);
|
||||
|
||||
@override
|
||||
final int type;
|
||||
|
||||
@ -223,42 +534,51 @@ class _ImageSampleImplicitLod extends _Instruction {
|
||||
final int sampledImage;
|
||||
final int coordinate;
|
||||
|
||||
_ImageSampleImplicitLod(this.type, this.id, this.sampledImage, this.coordinate);
|
||||
@override
|
||||
List<int> get deps => <int>[coordinate];
|
||||
|
||||
@override
|
||||
void write(_Transpiler t, StringBuffer out) {
|
||||
final String sampledImageString = t.resolveName(sampledImage);
|
||||
final String coordinateString = t.resolveResult(coordinate);
|
||||
if (t.target == TargetLanguage.sksl) {
|
||||
out.write('$sampledImageString.eval(${sampledImageString}_size * $coordinateString)');
|
||||
out.write(
|
||||
'$sampledImageString.eval(${sampledImageString}_size * $coordinateString)');
|
||||
} else {
|
||||
out.write('texture($sampledImageString, $coordinateString)');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _Negate extends _Instruction {
|
||||
class _UnaryOperator extends _Instruction {
|
||||
_UnaryOperator(this.type, this.id, this.op, this.operand);
|
||||
|
||||
@override
|
||||
final int type;
|
||||
|
||||
@override
|
||||
final int id;
|
||||
|
||||
final _Operator op;
|
||||
final int operand;
|
||||
|
||||
_Negate(this.type, this.id, this.operand);
|
||||
@override
|
||||
List<int> get deps => <int>[operand];
|
||||
|
||||
@override
|
||||
void write(_Transpiler t, StringBuffer out) {
|
||||
final String operandString = t.resolveResult(operand);
|
||||
out.write('-$operandString');
|
||||
out.write(_operatorString(op));
|
||||
out.write(t.resolveResult(operand));
|
||||
}
|
||||
}
|
||||
|
||||
class _ReturnValue extends _Instruction {
|
||||
_ReturnValue(this.value);
|
||||
|
||||
final int value;
|
||||
|
||||
_ReturnValue(this.value);
|
||||
@override
|
||||
List<int> get deps => <int>[value];
|
||||
|
||||
@override
|
||||
void write(_Transpiler t, StringBuffer out) {
|
||||
@ -267,28 +587,34 @@ class _ReturnValue extends _Instruction {
|
||||
}
|
||||
}
|
||||
|
||||
class _Operator extends _Instruction {
|
||||
class _BinaryOperator extends _Instruction {
|
||||
_BinaryOperator(this.type, this.id, this.op, this.a, this.b);
|
||||
|
||||
@override
|
||||
final int type;
|
||||
|
||||
@override
|
||||
final int id;
|
||||
|
||||
final String op;
|
||||
final _Operator op;
|
||||
final int a;
|
||||
final int b;
|
||||
|
||||
_Operator(this.type, this.id, this.op, this.a, this.b);
|
||||
@override
|
||||
List<int> get deps => <int>[a, b];
|
||||
|
||||
@override
|
||||
void write(_Transpiler t, StringBuffer out) {
|
||||
final String aStr = t.resolveResult(a);
|
||||
final String bStr = t.resolveResult(b);
|
||||
out.write('$aStr $op $bStr');
|
||||
final String opString = _operatorString(op);
|
||||
out.write('$aStr $opString $bStr');
|
||||
}
|
||||
}
|
||||
|
||||
class _BuiltinFunction extends _Instruction {
|
||||
_BuiltinFunction(this.type, this.id, this.function, this.args);
|
||||
|
||||
@override
|
||||
final int type;
|
||||
|
||||
@ -298,7 +624,8 @@ class _BuiltinFunction extends _Instruction {
|
||||
final String function;
|
||||
final List<int> args;
|
||||
|
||||
_BuiltinFunction(this.type, this.id, this.function, this.args);
|
||||
@override
|
||||
List<int> get deps => args;
|
||||
|
||||
@override
|
||||
void write(_Transpiler t, StringBuffer out) {
|
||||
@ -314,6 +641,8 @@ class _BuiltinFunction extends _Instruction {
|
||||
}
|
||||
|
||||
class _TypeCast extends _Instruction {
|
||||
_TypeCast(this.type, this.id, this.value);
|
||||
|
||||
@override
|
||||
final int type;
|
||||
|
||||
@ -322,7 +651,8 @@ class _TypeCast extends _Instruction {
|
||||
|
||||
final int value;
|
||||
|
||||
_TypeCast(this.type, this.id, this.value);
|
||||
@override
|
||||
List<int> get deps => <int>[value];
|
||||
|
||||
@override
|
||||
void write(_Transpiler t, StringBuffer out) {
|
||||
|
||||
@ -201,6 +201,23 @@ class _Transpiler {
|
||||
TranspileException failure(String why) =>
|
||||
TranspileException._(currentOp, why);
|
||||
|
||||
void collectDeps(Set<int> collectedDeps, int id) {
|
||||
if (alias.containsKey(id)) {
|
||||
id = alias[id]!;
|
||||
collectedDeps.add(id);
|
||||
}
|
||||
final _Instruction? result = results[id];
|
||||
if (result == null) {
|
||||
return;
|
||||
}
|
||||
for (final int i in result.deps) {
|
||||
if (!collectedDeps.contains(i)) {
|
||||
collectedDeps.add(i);
|
||||
collectDeps(collectedDeps, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void writeFunctionAndDeps(Set<int> visited, int function) {
|
||||
if (visited.contains(function)) {
|
||||
return;
|
||||
@ -210,7 +227,7 @@ class _Transpiler {
|
||||
for (final int dep in f.deps) {
|
||||
writeFunctionAndDeps(visited, dep);
|
||||
}
|
||||
f.write(this, src);
|
||||
f.write(src);
|
||||
}
|
||||
|
||||
void writeHeader() {
|
||||
@ -229,6 +246,13 @@ class _Transpiler {
|
||||
}
|
||||
}
|
||||
|
||||
int resolveId(int id) {
|
||||
if (alias.containsKey(id)) {
|
||||
return alias[id]!;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
String resolveName(int id) {
|
||||
if (alias.containsKey(id)) {
|
||||
return resolveName(alias[id]!);
|
||||
@ -239,7 +263,8 @@ class _Transpiler {
|
||||
return 'true';
|
||||
} else if (constantFalse > 0 && id == constantFalse) {
|
||||
return 'false';
|
||||
} if (id == colorOutput) {
|
||||
}
|
||||
if (id == colorOutput) {
|
||||
if (target == TargetLanguage.glslES) {
|
||||
return _glslESColorName;
|
||||
} else {
|
||||
@ -323,7 +348,7 @@ class _Transpiler {
|
||||
if (inst.isResult) {
|
||||
results[inst.id] = inst;
|
||||
}
|
||||
currentBlock!.add(inst);
|
||||
currentBlock!._add(inst);
|
||||
}
|
||||
|
||||
/// Read an instruction word, and handle the operation.
|
||||
@ -446,39 +471,81 @@ class _Transpiler {
|
||||
opImageSampleImplicitLod();
|
||||
break;
|
||||
case _opFNegate:
|
||||
opFNegate();
|
||||
parseUnaryOperator(_Operator.subtraction);
|
||||
break;
|
||||
case _opFAdd:
|
||||
parseOperatorInst('+');
|
||||
parseOperatorInst(_Operator.addition);
|
||||
break;
|
||||
case _opFSub:
|
||||
parseOperatorInst('-');
|
||||
parseOperatorInst(_Operator.negation);
|
||||
break;
|
||||
case _opFMul:
|
||||
parseOperatorInst('*');
|
||||
parseOperatorInst(_Operator.multiplication);
|
||||
break;
|
||||
case _opFDiv:
|
||||
parseOperatorInst('/');
|
||||
parseOperatorInst(_Operator.division);
|
||||
break;
|
||||
case _opFMod:
|
||||
parseBuiltinFunction('mod');
|
||||
break;
|
||||
case _opFUnordNotEqual:
|
||||
parseOperatorInst('!=');
|
||||
break;
|
||||
case _opVectorTimesScalar:
|
||||
case _opMatrixTimesScalar:
|
||||
case _opVectorTimesMatrix:
|
||||
case _opMatrixTimesVector:
|
||||
case _opMatrixTimesMatrix:
|
||||
parseOperatorInst('*');
|
||||
parseOperatorInst(_Operator.multiplication);
|
||||
break;
|
||||
case _opDot:
|
||||
parseBuiltinFunction('dot');
|
||||
break;
|
||||
case _opFOrdEqual:
|
||||
parseOperatorInst(_Operator.equality);
|
||||
break;
|
||||
case _opFUnordNotEqual:
|
||||
parseOperatorInst(_Operator.inequality);
|
||||
break;
|
||||
case _opFOrdLessThan:
|
||||
parseOperatorInst(_Operator.lessThan);
|
||||
break;
|
||||
case _opFOrdGreaterThan:
|
||||
parseOperatorInst(_Operator.greaterThan);
|
||||
break;
|
||||
case _opFOrdLessThanEqual:
|
||||
parseOperatorInst(_Operator.lessThanEqual);
|
||||
break;
|
||||
case _opFOrdGreaterThanEqual:
|
||||
parseOperatorInst(_Operator.greaterThanEqual);
|
||||
break;
|
||||
case _opLogicalEqual:
|
||||
parseOperatorInst(_Operator.equality);
|
||||
break;
|
||||
case _opLogicalNotEqual:
|
||||
parseOperatorInst(_Operator.inequality);
|
||||
break;
|
||||
case _opLogicalOr:
|
||||
parseOperatorInst(_Operator.or);
|
||||
break;
|
||||
case _opLogicalAnd:
|
||||
parseOperatorInst(_Operator.and);
|
||||
break;
|
||||
case _opLogicalNot:
|
||||
parseUnaryOperator(_Operator.not);
|
||||
break;
|
||||
case _opLabel:
|
||||
opLabel();
|
||||
break;
|
||||
case _opBranch:
|
||||
opBranch();
|
||||
break;
|
||||
case _opBranchConditional:
|
||||
opBranchConditional();
|
||||
break;
|
||||
case _opLoopMerge:
|
||||
opLoopMerge();
|
||||
break;
|
||||
case _opSelectionMerge:
|
||||
opSelectionMerge();
|
||||
break;
|
||||
case _opReturn:
|
||||
opReturn();
|
||||
break;
|
||||
@ -712,12 +779,12 @@ class _Transpiler {
|
||||
}
|
||||
|
||||
void opConstantTrue() {
|
||||
position++; // Skip type operand.
|
||||
position++; // Skip type operand.
|
||||
constantTrue = readWord();
|
||||
}
|
||||
|
||||
void opConstantFalse() {
|
||||
position++; // Skip type operand.
|
||||
position++; // Skip type operand.
|
||||
constantFalse = readWord();
|
||||
}
|
||||
|
||||
@ -767,7 +834,7 @@ class _Transpiler {
|
||||
throw failure('function $id has return type mismatch');
|
||||
}
|
||||
|
||||
final _Function f = _Function(functionType, id);
|
||||
final _Function f = _Function(this, functionType, id);
|
||||
functions[id] = f;
|
||||
currentFunction = f;
|
||||
}
|
||||
@ -841,7 +908,9 @@ class _Transpiler {
|
||||
}
|
||||
return;
|
||||
case _storageClassFunction:
|
||||
addToCurrentBlock(_StringInstruction('$type $name'));
|
||||
// function variables are declared the first time a value is
|
||||
// stored to them.
|
||||
currentFunction!.declareVariable(id, typeId);
|
||||
return;
|
||||
default:
|
||||
throw failure('$storageClass is an unsupported Storage Class');
|
||||
@ -872,6 +941,31 @@ class _Transpiler {
|
||||
final int pointer = readWord();
|
||||
final int object = readWord();
|
||||
ref(object);
|
||||
|
||||
// Variables belonging to the current function need to be declared if they
|
||||
// haven't been already.
|
||||
final _Variable? v = currentFunction!.variable(pointer);
|
||||
if (v != null && !v.initialized) {
|
||||
addToCurrentBlock(_Store(
|
||||
pointer,
|
||||
object,
|
||||
shouldDeclare: true,
|
||||
declarationType: v.type,
|
||||
));
|
||||
v.initialized = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Is this a compound assignment operation? (x += y)
|
||||
final _Instruction? objInstruction = results[object];
|
||||
if (objInstruction is _BinaryOperator &&
|
||||
resolveId(objInstruction.a) == pointer &&
|
||||
_isCompoundAssignment(objInstruction.op)) {
|
||||
addToCurrentBlock(
|
||||
_CompoundAssignment(pointer, objInstruction.op, objInstruction.b));
|
||||
return;
|
||||
}
|
||||
|
||||
addToCurrentBlock(_Store(pointer, object));
|
||||
}
|
||||
|
||||
@ -958,15 +1052,8 @@ class _Transpiler {
|
||||
final int sampledImage = readWord();
|
||||
final int coordinate = readWord();
|
||||
ref(coordinate);
|
||||
addToCurrentBlock(_ImageSampleImplicitLod(type, name, sampledImage, coordinate));
|
||||
}
|
||||
|
||||
void opFNegate() {
|
||||
final int type = readWord();
|
||||
final int name = readWord();
|
||||
final int operand = readWord();
|
||||
ref(operand);
|
||||
addToCurrentBlock(_Negate(type, name, operand));
|
||||
addToCurrentBlock(
|
||||
_ImageSampleImplicitLod(type, name, sampledImage, coordinate));
|
||||
}
|
||||
|
||||
void opLabel() {
|
||||
@ -974,11 +1061,33 @@ class _Transpiler {
|
||||
currentBlock = currentFunction!.addBlock(id);
|
||||
}
|
||||
|
||||
void opBranch() {
|
||||
currentBlock!.branch = readWord();
|
||||
currentBlock = null;
|
||||
}
|
||||
|
||||
void opBranchConditional() {
|
||||
final _Block b = currentBlock!;
|
||||
b.condition = readWord();
|
||||
b.truthyBlock = readWord();
|
||||
b.falseyBlock = readWord();
|
||||
}
|
||||
|
||||
void opLoopMerge() {
|
||||
final _Block b = currentBlock!;
|
||||
b.mergeBlock = readWord();
|
||||
b.continueBlock = readWord();
|
||||
}
|
||||
|
||||
void opSelectionMerge() {
|
||||
currentBlock!.mergeBlock = readWord();
|
||||
}
|
||||
|
||||
void opReturn() {
|
||||
if (currentFunction!.name == entryPoint) {
|
||||
return;
|
||||
} else {
|
||||
addToCurrentBlock(_StringInstruction('return'));
|
||||
addToCurrentBlock(_Return());
|
||||
}
|
||||
}
|
||||
|
||||
@ -988,14 +1097,22 @@ class _Transpiler {
|
||||
addToCurrentBlock(_ReturnValue(value));
|
||||
}
|
||||
|
||||
void parseOperatorInst(String op) {
|
||||
void parseUnaryOperator(_Operator op) {
|
||||
final int type = readWord();
|
||||
final int name = readWord();
|
||||
final int operand = readWord();
|
||||
ref(operand);
|
||||
addToCurrentBlock(_UnaryOperator(type, name, op, operand));
|
||||
}
|
||||
|
||||
void parseOperatorInst(_Operator op) {
|
||||
final int type = readWord();
|
||||
final int name = readWord();
|
||||
final int a = readWord();
|
||||
final int b = readWord();
|
||||
ref(a);
|
||||
ref(b);
|
||||
addToCurrentBlock(_Operator(type, name, op, a, b));
|
||||
addToCurrentBlock(_BinaryOperator(type, name, op, a, b));
|
||||
}
|
||||
|
||||
void parseBuiltinFunction(String functionName) {
|
||||
|
||||
@ -10,6 +10,8 @@ if (enable_unittests) {
|
||||
tool = "//flutter/lib/spirv/test:spirv_assembler"
|
||||
|
||||
sources = [
|
||||
"for_loop_does_not_branch_to_conditional.spvasm",
|
||||
"for_loop_does_not_branch_to_merge.spvasm",
|
||||
"image_type_arrayed_must_be_zero.spvasm",
|
||||
"image_type_depth_must_be_zero.spvasm",
|
||||
"image_type_dimensionality_must_be_2D.spvasm",
|
||||
@ -17,6 +19,9 @@ if (enable_unittests) {
|
||||
"image_type_must_be_float.spvasm",
|
||||
"image_type_previously_declared.spvasm",
|
||||
"image_type_sampled_must_be_one.spvasm",
|
||||
"multiple_statements_in_for_loop_continue_block.spvasm",
|
||||
"multiple_variables_in_for_loop_comparison.spvasm",
|
||||
"no_store_in_for_loop_continue.spvasm",
|
||||
"sampled_image_type_image_type_not_declared.spvasm",
|
||||
"sampled_image_type_invalid_image_type.spvasm",
|
||||
"sampled_image_type_previously_declared.spvasm",
|
||||
|
||||
@ -0,0 +1,74 @@
|
||||
; Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
; Use of this source code is governed by a BSD-style license that can be
|
||||
; found in the LICENSE file.
|
||||
;
|
||||
; SPIR-V
|
||||
; Version: 1.0
|
||||
; Generator: Khronos Glslang Reference Front End; 10
|
||||
; Bound: 38
|
||||
; Schema: 0
|
||||
;
|
||||
; Block %14 branches unconditionally to a block with no conditional-branch
|
||||
; despite declaring a LoopMerge.
|
||||
;
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %oColor
|
||||
OpExecutionMode %main OriginLowerLeft
|
||||
OpSource GLSL 450
|
||||
OpName %main "main"
|
||||
OpName %oColor "oColor"
|
||||
OpName %i "i"
|
||||
OpName %a "a"
|
||||
OpDecorate %oColor Location 0
|
||||
OpDecorate %a Location 0
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%oColor = OpVariable %_ptr_Output_v4float Output
|
||||
%float_0 = OpConstant %float 0
|
||||
%11 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
|
||||
%_ptr_Function_float = OpTypePointer Function %float
|
||||
%float_10 = OpConstant %float 10
|
||||
%bool = OpTypeBool
|
||||
%_ptr_UniformConstant_float = OpTypePointer UniformConstant %float
|
||||
%a = OpVariable %_ptr_UniformConstant_float UniformConstant
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_0 = OpConstant %uint 0
|
||||
%_ptr_Output_float = OpTypePointer Output %float
|
||||
%float_1 = OpConstant %float 1
|
||||
%uint_3 = OpConstant %uint 3
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%i = OpVariable %_ptr_Function_float Function
|
||||
OpStore %oColor %11
|
||||
OpStore %i %float_0
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
OpLoopMerge %16 %17 None
|
||||
OpBranch %16
|
||||
%18 = OpLabel
|
||||
%19 = OpLoad %float %i
|
||||
%22 = OpFOrdLessThan %bool %19 %float_10
|
||||
OpBranchConditional %22 %15 %16
|
||||
%15 = OpLabel
|
||||
%25 = OpLoad %float %a
|
||||
%29 = OpAccessChain %_ptr_Output_float %oColor %uint_0
|
||||
%30 = OpLoad %float %29
|
||||
%31 = OpFAdd %float %30 %25
|
||||
%32 = OpAccessChain %_ptr_Output_float %oColor %uint_0
|
||||
OpStore %32 %31
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
%33 = OpLoad %float %i
|
||||
%35 = OpFAdd %float %33 %float_1
|
||||
OpStore %i %35
|
||||
OpBranch %14
|
||||
%16 = OpLabel
|
||||
%37 = OpAccessChain %_ptr_Output_float %oColor %uint_3
|
||||
OpStore %37 %float_1
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
@ -0,0 +1,74 @@
|
||||
; Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
; Use of this source code is governed by a BSD-style license that can be
|
||||
; found in the LICENSE file.
|
||||
;
|
||||
; SPIR-V
|
||||
; Version: 1.0
|
||||
; Generator: Khronos Glslang Reference Front End; 10
|
||||
; Bound: 38
|
||||
; Schema: 0
|
||||
;
|
||||
; The conditional following the LoopMerge on line 56 does not branch
|
||||
; to the loop merge block %16.
|
||||
;
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %oColor
|
||||
OpExecutionMode %main OriginLowerLeft
|
||||
OpSource GLSL 450
|
||||
OpName %main "main"
|
||||
OpName %oColor "oColor"
|
||||
OpName %i "i"
|
||||
OpName %a "a"
|
||||
OpDecorate %oColor Location 0
|
||||
OpDecorate %a Location 0
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%oColor = OpVariable %_ptr_Output_v4float Output
|
||||
%float_0 = OpConstant %float 0
|
||||
%11 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
|
||||
%_ptr_Function_float = OpTypePointer Function %float
|
||||
%float_10 = OpConstant %float 10
|
||||
%bool = OpTypeBool
|
||||
%_ptr_UniformConstant_float = OpTypePointer UniformConstant %float
|
||||
%a = OpVariable %_ptr_UniformConstant_float UniformConstant
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_0 = OpConstant %uint 0
|
||||
%_ptr_Output_float = OpTypePointer Output %float
|
||||
%float_1 = OpConstant %float 1
|
||||
%uint_3 = OpConstant %uint 3
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%i = OpVariable %_ptr_Function_float Function
|
||||
OpStore %oColor %11
|
||||
OpStore %i %float_0
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
OpLoopMerge %16 %17 None
|
||||
OpBranch %18
|
||||
%18 = OpLabel
|
||||
%19 = OpLoad %float %i
|
||||
%22 = OpFOrdLessThan %bool %19 %float_10
|
||||
OpBranchConditional %22 %15 %17
|
||||
%15 = OpLabel
|
||||
%25 = OpLoad %float %a
|
||||
%29 = OpAccessChain %_ptr_Output_float %oColor %uint_0
|
||||
%30 = OpLoad %float %29
|
||||
%31 = OpFAdd %float %30 %25
|
||||
%32 = OpAccessChain %_ptr_Output_float %oColor %uint_0
|
||||
OpStore %32 %31
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
%33 = OpLoad %float %i
|
||||
%35 = OpFAdd %float %33 %float_1
|
||||
OpStore %i %35
|
||||
OpBranch %14
|
||||
%16 = OpLabel
|
||||
%37 = OpAccessChain %_ptr_Output_float %oColor %uint_3
|
||||
OpStore %37 %float_1
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
@ -0,0 +1,76 @@
|
||||
; Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
; Use of this source code is governed by a BSD-style license that can be
|
||||
; found in the LICENSE file.
|
||||
;
|
||||
; SPIR-V
|
||||
; Version: 1.0
|
||||
; Generator: Khronos Glslang Reference Front End; 10
|
||||
; Bound: 39
|
||||
; Schema: 0
|
||||
;
|
||||
; Continue block %18 contains more than one OpStore instruction.
|
||||
;
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %oColor
|
||||
OpExecutionMode %main OriginLowerLeft
|
||||
OpSource GLSL 450
|
||||
OpName %main "main"
|
||||
OpName %oColor "oColor"
|
||||
OpName %j "j"
|
||||
OpName %i "i"
|
||||
OpName %a "a"
|
||||
OpDecorate %oColor Location 0
|
||||
OpDecorate %a Location 0
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%oColor = OpVariable %_ptr_Output_v4float Output
|
||||
%float_0 = OpConstant %float 0
|
||||
%11 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
|
||||
%_ptr_Function_float = OpTypePointer Function %float
|
||||
%float_10 = OpConstant %float 10
|
||||
%bool = OpTypeBool
|
||||
%_ptr_UniformConstant_float = OpTypePointer UniformConstant %float
|
||||
%a = OpVariable %_ptr_UniformConstant_float UniformConstant
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_0 = OpConstant %uint 0
|
||||
%_ptr_Output_float = OpTypePointer Output %float
|
||||
%float_1 = OpConstant %float 1
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%j = OpVariable %_ptr_Function_float Function
|
||||
%i = OpVariable %_ptr_Function_float Function
|
||||
OpStore %oColor %11
|
||||
OpStore %j %float_0
|
||||
OpStore %i %float_0
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
OpLoopMerge %17 %18 None
|
||||
OpBranch %19
|
||||
%19 = OpLabel
|
||||
%20 = OpLoad %float %i
|
||||
%23 = OpFOrdLessThan %bool %20 %float_10
|
||||
OpBranchConditional %23 %16 %17
|
||||
%16 = OpLabel
|
||||
%26 = OpLoad %float %a
|
||||
%30 = OpAccessChain %_ptr_Output_float %oColor %uint_0
|
||||
%31 = OpLoad %float %30
|
||||
%32 = OpFAdd %float %31 %26
|
||||
%33 = OpAccessChain %_ptr_Output_float %oColor %uint_0
|
||||
OpStore %33 %32
|
||||
OpBranch %18
|
||||
%18 = OpLabel
|
||||
%34 = OpLoad %float %i
|
||||
%36 = OpFAdd %float %34 %float_1
|
||||
OpStore %i %36
|
||||
%37 = OpLoad %float %j
|
||||
%38 = OpFAdd %float %37 %float_1
|
||||
OpStore %j %38
|
||||
OpBranch %15
|
||||
%17 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
@ -0,0 +1,78 @@
|
||||
; Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
; Use of this source code is governed by a BSD-style license that can be
|
||||
; found in the LICENSE file.
|
||||
;
|
||||
; SPIR-V
|
||||
; Version: 1.0
|
||||
; Generator: Khronos Glslang Reference Front End; 10
|
||||
; Bound: 41
|
||||
; Schema: 0
|
||||
;
|
||||
; Condition %27 depends on more than one variable, but is used as a for-loop
|
||||
; condition.
|
||||
;
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %oColor
|
||||
OpExecutionMode %main OriginLowerLeft
|
||||
OpSource GLSL 450
|
||||
OpName %main "main"
|
||||
OpName %oColor "oColor"
|
||||
OpName %i "i"
|
||||
OpName %j "j"
|
||||
OpName %a "a"
|
||||
OpDecorate %oColor Location 0
|
||||
OpDecorate %a Location 0
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%oColor = OpVariable %_ptr_Output_v4float Output
|
||||
%float_0 = OpConstant %float 0
|
||||
%11 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
|
||||
%_ptr_Function_float = OpTypePointer Function %float
|
||||
%float_10 = OpConstant %float 10
|
||||
%bool = OpTypeBool
|
||||
%float_5 = OpConstant %float 5
|
||||
%_ptr_UniformConstant_float = OpTypePointer UniformConstant %float
|
||||
%a = OpVariable %_ptr_UniformConstant_float UniformConstant
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_0 = OpConstant %uint 0
|
||||
%_ptr_Output_float = OpTypePointer Output %float
|
||||
%float_1 = OpConstant %float 1
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%i = OpVariable %_ptr_Function_float Function
|
||||
%j = OpVariable %_ptr_Function_float Function
|
||||
OpStore %oColor %11
|
||||
OpStore %i %float_0
|
||||
OpStore %j %float_0
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
OpLoopMerge %17 %18 None
|
||||
OpBranch %19
|
||||
%19 = OpLabel
|
||||
%20 = OpLoad %float %i
|
||||
%23 = OpFOrdLessThan %bool %20 %float_10
|
||||
%24 = OpLoad %float %j
|
||||
%26 = OpFOrdLessThan %bool %24 %float_5
|
||||
%27 = OpLogicalAnd %bool %23 %26
|
||||
OpBranchConditional %27 %16 %17
|
||||
%16 = OpLabel
|
||||
%30 = OpLoad %float %a
|
||||
%34 = OpAccessChain %_ptr_Output_float %oColor %uint_0
|
||||
%35 = OpLoad %float %34
|
||||
%36 = OpFAdd %float %35 %30
|
||||
%37 = OpAccessChain %_ptr_Output_float %oColor %uint_0
|
||||
OpStore %37 %36
|
||||
OpBranch %18
|
||||
%18 = OpLabel
|
||||
%38 = OpLoad %float %i
|
||||
%40 = OpFAdd %float %38 %float_1
|
||||
OpStore %i %40
|
||||
OpBranch %15
|
||||
%17 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
@ -0,0 +1,66 @@
|
||||
; Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
; Use of this source code is governed by a BSD-style license that can be
|
||||
; found in the LICENSE file.
|
||||
;
|
||||
; SPIR-V
|
||||
; Version: 1.0
|
||||
; Generator: Khronos Glslang Reference Front End; 10
|
||||
; Bound: 33
|
||||
; Schema: 0
|
||||
;
|
||||
; Continue block %17 has no OpStore instruction.
|
||||
;
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %oColor
|
||||
OpExecutionMode %main OriginLowerLeft
|
||||
OpSource GLSL 450
|
||||
OpName %main "main"
|
||||
OpName %oColor "oColor"
|
||||
OpName %i "i"
|
||||
OpName %a "a"
|
||||
OpDecorate %oColor Location 0
|
||||
OpDecorate %a Location 0
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%oColor = OpVariable %_ptr_Output_v4float Output
|
||||
%float_0 = OpConstant %float 0
|
||||
%11 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
|
||||
%_ptr_Function_float = OpTypePointer Function %float
|
||||
%float_10 = OpConstant %float 10
|
||||
%bool = OpTypeBool
|
||||
%_ptr_UniformConstant_float = OpTypePointer UniformConstant %float
|
||||
%a = OpVariable %_ptr_UniformConstant_float UniformConstant
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_0 = OpConstant %uint 0
|
||||
%_ptr_Output_float = OpTypePointer Output %float
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%i = OpVariable %_ptr_Function_float Function
|
||||
OpStore %oColor %11
|
||||
OpStore %i %float_0
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
OpLoopMerge %16 %17 None
|
||||
OpBranch %18
|
||||
%18 = OpLabel
|
||||
%19 = OpLoad %float %i
|
||||
%22 = OpFOrdLessThan %bool %19 %float_10
|
||||
OpBranchConditional %22 %15 %16
|
||||
%15 = OpLabel
|
||||
%25 = OpLoad %float %a
|
||||
%29 = OpAccessChain %_ptr_Output_float %oColor %uint_0
|
||||
%30 = OpLoad %float %29
|
||||
%31 = OpFAdd %float %30 %25
|
||||
%32 = OpAccessChain %_ptr_Output_float %oColor %uint_0
|
||||
OpStore %32 %31
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
OpBranch %14
|
||||
%16 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
13
engine/src/flutter/lib/spirv/test/exception_shaders/src.glsl
Normal file
13
engine/src/flutter/lib/spirv/test/exception_shaders/src.glsl
Normal file
@ -0,0 +1,13 @@
|
||||
#version 450
|
||||
|
||||
layout (location = 0) out vec4 oColor;
|
||||
|
||||
layout (location = 0) uniform float a;
|
||||
|
||||
void main() {
|
||||
oColor = vec4(0);
|
||||
for (float i = 0; i < 10.0; i++) {
|
||||
oColor.r += a;
|
||||
}
|
||||
oColor.a = 1.0;
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
#version 320 es
|
||||
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
precision highp float;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(location = 0) uniform float a;
|
||||
|
||||
void main() {
|
||||
if (a >= 0.0 == a >= 1.0) {
|
||||
fragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
} else {
|
||||
fragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
#version 320 es
|
||||
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
precision highp float;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(location = 0) uniform float a;
|
||||
|
||||
void main() {
|
||||
if (a <= 0.0 != a >= 1.0) {
|
||||
fragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
} else {
|
||||
fragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
#version 320 es
|
||||
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
precision highp float;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(location = 0) uniform float a;
|
||||
|
||||
void main() {
|
||||
if (a <= 0.0 || a == 1.0) {
|
||||
fragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
} else {
|
||||
fragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
#version 320 es
|
||||
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
precision highp float;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(location = 0) uniform float a;
|
||||
|
||||
void main() {
|
||||
if (a != 0.0 && a == 1.0) {
|
||||
fragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
} else {
|
||||
fragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
#version 320 es
|
||||
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
precision highp float;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(location = 0) uniform float a;
|
||||
|
||||
void main() {
|
||||
if (!(a == 0.0)) {
|
||||
fragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
} else {
|
||||
fragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
#version 320 es
|
||||
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
precision highp float;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(location = 0) uniform float a;
|
||||
|
||||
void main() {
|
||||
if (a == 1.0) {
|
||||
fragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
} else {
|
||||
fragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
#version 320 es
|
||||
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
precision highp float;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(location = 0) uniform float a;
|
||||
|
||||
void main() {
|
||||
if (a != 0.0) {
|
||||
fragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
} else {
|
||||
fragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
#version 320 es
|
||||
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
precision highp float;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(location = 0) uniform float a;
|
||||
|
||||
void main() {
|
||||
if (a < 1.0) {
|
||||
fragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
} else {
|
||||
fragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
#version 320 es
|
||||
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
precision highp float;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(location = 0) uniform float a;
|
||||
|
||||
void main() {
|
||||
if (a > 0.0) {
|
||||
fragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
} else {
|
||||
fragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
#version 320 es
|
||||
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
precision highp float;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(location = 0) uniform float a;
|
||||
|
||||
void main() {
|
||||
if (a <= 2.0 && a <= 1.0) {
|
||||
fragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
} else {
|
||||
fragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
#version 320 es
|
||||
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
precision highp float;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(location = 0) uniform float a;
|
||||
|
||||
void main() {
|
||||
if (a >= 0.0 && a >= 1.0) {
|
||||
fragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
} else {
|
||||
fragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
#version 320 es
|
||||
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
precision highp float;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(location = 0) uniform float a;
|
||||
|
||||
void main() {
|
||||
float sum = 0.0;
|
||||
for (float i = 0.0; i < 6.0; i++) {
|
||||
if (i > a * 5.0) {
|
||||
break;
|
||||
}
|
||||
if (i < 1.0) {
|
||||
continue;
|
||||
}
|
||||
if (a > 0.0) {
|
||||
sum += a * 0.25;
|
||||
}
|
||||
}
|
||||
fragColor = vec4(0.0, sum, 0.0, 1.0);
|
||||
}
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
#version 320 es
|
||||
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
precision highp float;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(location = 0) uniform float a;
|
||||
|
||||
void main() {
|
||||
if (a > 0.0) {
|
||||
fragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
if (a < 0.5) {
|
||||
fragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
} else {
|
||||
fragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -19,12 +19,25 @@ if (enable_unittests) {
|
||||
"145_OpMatrixTimesVector.glsl",
|
||||
"146_OpMatrixTimesMatrix.glsl",
|
||||
"148_OpDot.glsl",
|
||||
"164_OpLogicalEqual.glsl",
|
||||
"165_OpLogicalNotEqual.glsl",
|
||||
"166_OpLogicalOr.glsl",
|
||||
"167_OpLogicalAnd.glsl",
|
||||
"168_OpLogicalNot.glsl",
|
||||
"180_OpFOrdEqual.glsl",
|
||||
"183_OpFUnordNotEqual.glsl",
|
||||
"184_OpFOrdLessThan.glsl",
|
||||
"186_OpFOrdGreaterThan.glsl",
|
||||
"188_OpFOrdLessThanEqual.glsl",
|
||||
"190_OpFOrdGreaterThanEqual.glsl",
|
||||
"19_OpTypeVoid.glsl",
|
||||
"20_OpTypeBool.glsl",
|
||||
"21_OpTypeInt.glsl",
|
||||
"22_OpTypeFloat.glsl",
|
||||
"23_OpTypeVector.glsl",
|
||||
"246_OpLoopMerge.glsl",
|
||||
"24_OpTypeMatrix.glsl",
|
||||
"250_OpBranchConditional.glsl",
|
||||
"33_OpTypeFunction.glsl",
|
||||
]
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user