diff --git a/BUILD.gn b/BUILD.gn index fe1135605fc13..f7f861a7e4a3e 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -132,6 +132,9 @@ group("flutter") { "//flutter/flow:flow_unittests", "//flutter/fml:fml_unittests", "//flutter/lib/spirv/test/exception_shaders:spirv_compile_exception_shaders", + "//flutter/lib/spirv/test/general_shaders:spirv_compile_general_shaders", + "//flutter/lib/spirv/test/supported_glsl_op_shaders:spirv_compile_supported_glsl_shaders", + "//flutter/lib/spirv/test/supported_op_shaders:spirv_compile_supported_op_shaders", "//flutter/lib/ui:ui_unittests", "//flutter/runtime:no_dart_plugin_registrant_unittests", "//flutter/runtime:runtime_unittests", diff --git a/ci/analyze.sh b/ci/analyze.sh index aaadc0e68ba15..1d5aabb5d09db 100755 --- a/ci/analyze.sh +++ b/ci/analyze.sh @@ -30,6 +30,7 @@ function follow_links() ( SCRIPT_DIR=$(follow_links "$(dirname -- "${BASH_SOURCE[0]}")") SRC_DIR="$(cd "$SCRIPT_DIR/../.."; pwd -P)" FLUTTER_DIR="$SRC_DIR/flutter" +SKY_ENGINE_DIR="$SRC_DIR/out/host_debug_unopt/gen/dart-pkg/sky_engine" DART_BIN="$SRC_DIR/out/host_debug_unopt/dart-sdk/bin" DART="$DART_BIN/dart" @@ -46,7 +47,8 @@ echo "Using dart from $DART_BIN" "$DART" --version echo "" -"$DART" analyze "$FLUTTER_DIR/lib/ui" +(cd $SKY_ENGINE_DIR && "$DART" pub get --offline) +"$DART" analyze "$SKY_ENGINE_DIR/lib/ui/ui.dart" "$DART" analyze "$FLUTTER_DIR/lib/spirv" diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 1373f6c8dbbd0..0600745f1713f 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -358,6 +358,8 @@ FILE: ../../../flutter/lib/ui/painting/color_filter.cc FILE: ../../../flutter/lib/ui/painting/color_filter.h FILE: ../../../flutter/lib/ui/painting/engine_layer.cc FILE: ../../../flutter/lib/ui/painting/engine_layer.h +FILE: ../../../flutter/lib/ui/painting/fragment_shader.cc +FILE: ../../../flutter/lib/ui/painting/fragment_shader.h FILE: ../../../flutter/lib/ui/painting/gradient.cc FILE: ../../../flutter/lib/ui/painting/gradient.h FILE: ../../../flutter/lib/ui/painting/image.cc diff --git a/ci/licenses_golden/tool_signature b/ci/licenses_golden/tool_signature index 10c876e21dff2..8547440888f5a 100644 --- a/ci/licenses_golden/tool_signature +++ b/ci/licenses_golden/tool_signature @@ -1,2 +1,2 @@ -Signature: 2b08c736bc3af2c5d770099c53112c83 +Signature: e892e715f8184778851c5efcb6a1323a diff --git a/lib/snapshot/libraries.json b/lib/snapshot/libraries.json index 6267363cdeb65..380c36cf1d698 100644 --- a/lib/snapshot/libraries.json +++ b/lib/snapshot/libraries.json @@ -146,6 +146,9 @@ "uri": "../../../third_party/dart/sdk/lib/typed_data/typed_data.dart", "patches": "../../../third_party/dart/sdk/lib/_internal/vm/lib/typed_data_patch.dart" }, + "_spirv": { + "uri": "../../lib/spirv/lib/spirv.dart" + }, "ui": { "uri": "../../lib/ui/ui.dart" }, diff --git a/lib/snapshot/libraries.yaml b/lib/snapshot/libraries.yaml index a0dfd15a382d0..3ae2e3eed3ea7 100644 --- a/lib/snapshot/libraries.yaml +++ b/lib/snapshot/libraries.yaml @@ -146,6 +146,9 @@ flutter: uri: "../../../third_party/dart/sdk/lib/typed_data/typed_data.dart" patches: "../../../third_party/dart/sdk/lib/_internal/vm/lib/typed_data_patch.dart" + _spirv: + uri: "../../lib/spirv/lib/spirv.dart" + ui: uri: "../../lib/ui/ui.dart" diff --git a/lib/spirv/README.md b/lib/spirv/README.md index 5f7cf05f2d557..6f72ca7a8b2b0 100644 --- a/lib/spirv/README.md +++ b/lib/spirv/README.md @@ -33,13 +33,40 @@ Support for textures, control flow, and structured types is planned, but not cur ## Testing -## Exception Tests +### Exception Tests These tests rely on the `.spvasm` (SPIR-V Assembly) and `.glsl` files contained under `test/exception_shaders` in this directory. They are compiled to binary SPIR-V using `spirv-asm`, from the SwiftShader dependency. They are tested by testing/dart/spirv_exception_test.dart as part of the normal suite of dart tests. The purpose of these tests is to exercise every explicit failure path for shader transpilation. Each `glsl` or `spvasm` file should include a comment describing the failure that it is testing. The given files should be valid apart from the single failure case they are testing. -## Pixel Tests +To test the exception tests directly: `./testing/run_tests.py --type dart --dart-filter spirv_exception_test.dart` -Pixel test are not yet checked in, and should run as part of unit-testing for each implementation of `dart:ui`. These tests aim to validate the correctness of transpilation to each target language. Each shader should render the color green #00FF00 for a correct transpilation, and any other color for failure. They will be a combination of `.spvasm` files and more-readable GLSL files that are compiled to SPIR-V via `glslang`, provided by the SwiftShader dependency. Information for pixel tests will be expanded in a follow-up PR. +### Pixel Tests -These tests will be able to be run alone by executing `./ui_unittests` in the build-output directory. +Pixel tests should run as part of unit-testing for each implementation of `dart:ui`. Currently, FragmentShader is only supported in C++. These tests aim to validate the correctness of transpilation to each target language. Each shader should render the color green for a correct transpilation, and any other color for failure. They will be a GLSL files that are compiled to SPIR-V via `shaderc`. Therefor, the `fragColor` should resolve to `vec4(0.0, 1.0, 0.0, 1.0)` +for all tests. +In each test, the uniform `a` is initialized with the value of 1.0. +This is important so that expressions are not simplified during GLSL to SPIR-V compilation, which may result in the removal of the op being tested. + +To test the pixel tests directly: `./testing/run_tests.py --type dart --dart-filter fragment_shader_test.dart` + +#### A Note on Test Isolation + +Even the simplest GLSL program tests several instructions, so no test us completely isolated +to a single op. Also, some of the GLSL 450 op tests will use addition in subtraction, along with the +actual op being tested. However, the GLSL program for each test file is kept as simple as possible, +to satisfy these conditions: pass if the op works, and fail if the op does not work. In some tests, +it is sufficient to only call the GLSL op once, while other may need more calls to more completelty +test the op. Many ops support scalars, vectors, or a combination as parameters. Most tests default +to using scalars as params, but vec2, vec3, and vec4 parameters are also tested. + +- vec2 is tested as a paramter in glsl_op_normalize.glsl +- vec3 is tested as a parameter in glsl_op_cross.glsl +- vec4 is tested as a parameter in glsl_op_length.glsl + +### Adding New Tests + +To add a new test, add a glsl (fragment shader tests) or spvasm (spirv exception tests) src file to a `lib/spirv/test/` subfolder, and add the file as a source to the corresponding `BUILD.gn`. + +- New files in `exception_shaders` are automatically tested in `testing/dart/spirv_exception_test`. +- New files in `supported_op_shaders` and `supported_glsl_op_shaders` are automatically tested in `testing/dart/fragment_shader_test`. +- New files in `general_shaders` are not automatically tested and must add a new manual test case in `testing/dart/fragment_shader_test`. diff --git a/lib/spirv/lib/src/constants.dart b/lib/spirv/lib/src/constants.dart index 0cae6c58c1a1a..21569d2430296 100644 --- a/lib/spirv/lib/src/constants.dart +++ b/lib/spirv/lib/src/constants.dart @@ -34,6 +34,14 @@ const int _decorationLocation = 30; // Explicitly supported builtin types const int _builtinFragCoord = 15; +// Ops that have no semantic meaning in output and can be safely ignored +const int _opSource = 3; +const int _opSourceExtension = 4; +const int _opName = 5; +const int _opMemberName = 6; +const int _opString = 7; +const int _opLine = 8; + // Supported instructions const int _opExtInstImport = 11; const int _opExtInst = 12; @@ -43,17 +51,21 @@ const int _opExecutionMode = 16; const int _opCapability = 17; const int _opTypeVoid = 19; const int _opTypeBool = 20; +const int _opTypeInt = 21; const int _opTypeFloat = 22; const int _opTypeVector = 23; const int _opTypeMatrix = 24; const int _opTypePointer = 32; const int _opTypeFunction = 33; +const int _opConstantTrue = 41; +const int _opConstantFalse = 42; const int _opConstant = 43; const int _opConstantComposite = 44; 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; @@ -62,6 +74,8 @@ const int _opDecorate = 71; const int _opVectorShuffle = 79; const int _opCompositeConstruct = 80; const int _opCompositeExtract = 81; +const int _opConvertFToS = 110; +const int _opConvertSToF = 111; const int _opFNegate = 127; const int _opFAdd = 129; const int _opFSub = 131; @@ -74,6 +88,7 @@ const int _opVectorTimesMatrix = 144; const int _opMatrixTimesVector = 145; const int _opMatrixTimesMatrix = 146; const int _opDot = 148; +const int _opSelect = 169; const int _opLabel = 248; const int _opReturn = 253; const int _opReturnValue = 254; @@ -85,7 +100,6 @@ const int _opReturnValue = 254; const String _glslStd450 = 'GLSL.std.450'; // Supported GLSL ops -const int _glslStd450Trunc = 3; const int _glslStd450FAbs = 4; const int _glslStd450FSign = 6; const int _glslStd450Floor = 8; @@ -121,7 +135,6 @@ const int _glslStd450FaceForward = 70; const int _glslStd450Reflect = 71; const Map _glslStd450OpNames = { - _glslStd450Trunc: 'trunc', _glslStd450FAbs: 'abs', _glslStd450FSign: 'sign', _glslStd450Floor: 'floor', @@ -158,7 +171,6 @@ const Map _glslStd450OpNames = { }; const Map _glslStd450OpArgc = { - _glslStd450Trunc: 1, _glslStd450FAbs: 1, _glslStd450FSign: 1, _glslStd450Floor: 1, @@ -174,7 +186,7 @@ const Map _glslStd450OpArgc = { _glslStd450Atan: 1, _glslStd450Atan2: 2, _glslStd450Pow: 2, - _glslStd450Exp: 2, + _glslStd450Exp: 1, _glslStd450Log: 1, _glslStd450Exp2: 1, _glslStd450Log2: 1, diff --git a/lib/spirv/lib/src/transpiler.dart b/lib/spirv/lib/src/transpiler.dart index 2ad5d9a888098..b9d37c42a11a6 100644 --- a/lib/spirv/lib/src/transpiler.dart +++ b/lib/spirv/lib/src/transpiler.dart @@ -69,6 +69,10 @@ class _Transpiler { /// Function ID mapped to source-code definition. final Map functionDefs = {}; + /// Function ID mapped to referenced functions. + /// This is used to ensure they are written in the right order. + final Map> functionDeps = >{}; + /// ID mapped to location decorator. /// See [opDecorate] for more information. final Map locations = {}; @@ -76,6 +80,14 @@ class _Transpiler { /// ID mapped to ID. Used by [OpLoad]. final Map alias = {}; + /// The ID for a constant true value. + /// See [opConstantTrue]. + int constantTrue = 0; + + /// The ID for a constant false value. + /// See [opConstantFalse]. + int constantFalse = 0; + /// The current word-index in the SPIR-V buffer. int position = 0; @@ -93,6 +105,10 @@ class _Transpiler { /// See [opEntryPoint]. int entryPoint = 0; + /// The ID of a 32-bit int type. + /// See [opTypeInt]. + int intType = 0; + /// The ID of a 32-bit float type. /// See [opTypeFloat]. int floatType = 0; @@ -115,7 +131,7 @@ class _Transpiler { /// Set by [opDecorate]. int fragCoord = 0; - /// The number of floats used by uniforms. + /// The number of floats used by uniform int uniformFloatCount = 0; /// Current indentation to prepend to new lines. @@ -139,14 +155,25 @@ class _Transpiler { } src.writeln(); - for (final StringBuffer def in functionDefs.values) { - src.write(def.toString()); - } + // TODO(antrob): Investigate if `List.filled(maxFunctionId, false)` can be used here instead. + final Set visited = {}; + writeFunctionAndDeps(visited, entryPoint); } TranspileException failure(String why) => TranspileException._(currentOp, why); + void writeFunctionAndDeps(Set visited, int function) { + if (visited.contains(function)) { + return; + } + visited.add(function); + for (final int dep in functionDeps[function]!) { + writeFunctionAndDeps(visited, dep); + } + src.write(functionDefs[function]!.toString()); + } + void writeHeader() { switch (target) { case TargetLanguage.glslES: @@ -167,7 +194,11 @@ class _Transpiler { if (alias.containsKey(id)) { return resolveName(alias[id]!); } - if (id == colorOutput) { + if (constantTrue > 0 && id == constantTrue) { + return 'true'; + } else if (constantFalse > 0 && id == constantFalse) { + return 'false'; + } if (id == colorOutput) { if (target == TargetLanguage.glslES) { return _glslESColorName; } else { @@ -222,6 +253,13 @@ class _Transpiler { throw failure('No null-terminating character found for string literal'); } + void typeCast() { + final String type = resolveType(readWord()); + final String name = resolveName(readWord()); + final String value = resolveName(readWord()); + out.writeln('$indent$type $name = $type($value);'); + } + /// Read an instruction word, and handle the operation. /// /// SPIR-V instructions contain an op-code as well as a @@ -251,12 +289,18 @@ class _Transpiler { case _opCapability: opCapability(); break; + case _opConvertSToF: + typeCast(); + break; case _opTypeVoid: opTypeVoid(); break; case _opTypeBool: opTypeBool(); break; + case _opTypeInt: + opTypeInt(); + break; case _opTypeFloat: opTypeFloat(); break; @@ -272,12 +316,21 @@ class _Transpiler { case _opTypeFunction: opTypeFunction(); break; + case _opConstantTrue: + opConstantTrue(); + break; + case _opConstantFalse: + opConstantFalse(); + break; case _opConstant: opConstant(); break; case _opConstantComposite: opConstantComposite(); break; + case _opConvertFToS: + typeCast(); + break; case _opFunction: opFunction(); break; @@ -296,6 +349,9 @@ class _Transpiler { case _opLoad: opLoad(); break; + case _opSelect: + opSelect(); + break; case _opStore: opStore(); break; @@ -332,6 +388,9 @@ class _Transpiler { case _opFMod: parseBuiltinFunction('mod'); break; + case _opFUnordNotEqual: + parseOperatorInst('!='); + break; case _opVectorTimesScalar: case _opMatrixTimesScalar: case _opVectorTimesMatrix: @@ -351,6 +410,14 @@ class _Transpiler { case _opReturnValue: opReturnValue(); break; + // Unsupported ops with no semantic meaning. + case _opSource: + case _opSourceExtension: + case _opName: + case _opMemberName: + case _opString: + case _opLine: + break; default: throw failure('Not a supported op.'); } @@ -420,6 +487,16 @@ class _Transpiler { types[readWord()] = _Type._bool; } + void opTypeInt() { + final int id = readWord(); + types[id] = _Type._int; + intType = id; + final int width = readWord(); + if (width != 32) { + throw failure('int width must be 32'); + } + } + void opTypeFloat() { final int id = readWord(); types[id] = _Type.float; @@ -503,6 +580,18 @@ class _Transpiler { functionTypes[id] = _FunctionType(returnType, params); } + void opConstantTrue() { + // Skip type operand. + position++; + constantTrue = readWord(); + } + + void opConstantFalse() { + // Skip type operand. + position++; + constantFalse = readWord(); + } + void opConstant() { final int type = readWord(); final String id = resolveName(readWord()); @@ -548,12 +637,10 @@ class _Transpiler { final String opening = '$returnType $name('; final StringBuffer def = StringBuffer(); def.write(opening); - src.write(opening); if (target == TargetLanguage.sksl && id == entryPoint) { const String fragParam = 'float2 $_fragParamName'; def.write(fragParam); - src.write(fragParam); } final int typeIndex = readWord(); @@ -564,7 +651,6 @@ class _Transpiler { if (functionType.params.isEmpty) { def.write(') '); - src.writeln(');'); } currentFunction = id; @@ -572,6 +658,7 @@ class _Transpiler { declaredParams = 0; out = def; functionDefs[id] = def; + functionDeps[id] = []; } void opFunctionParameter() { @@ -609,7 +696,12 @@ class _Transpiler { void opFunctionCall() { final String type = resolveType(readWord()); final String name = resolveName(readWord()); - final String functionName = resolveName(readWord()); + final int functionId = readWord(); + final String functionName = resolveName(functionId); + + // Make the current function depend on this function. + functionDeps[currentFunction]!.add(functionId); + final List args = List.generate(nextPosition - position, (int i) { return resolveName(readWord()); @@ -667,6 +759,15 @@ class _Transpiler { alias[id] = pointer; } + void opSelect() { + final String type = resolveType(readWord()); + final String name = resolveName(readWord()); + final String condition = resolveName(readWord()); + final String a = resolveName(readWord()); + final String b = resolveName(readWord()); + out.writeln('$indent$type $name = mix($b, $a, $type($condition));'); + } + void opStore() { final String pointer = resolveName(readWord()); final String object = resolveName(readWord()); @@ -815,7 +916,10 @@ class _Transpiler { } void parseGLSLInst(int id, int type) { - final int inst = readWord(); + int inst = readWord(); + if (inst == _glslStd450Atan2 && target == TargetLanguage.sksl) { + inst = _glslStd450Atan; + } final String? opName = _glslStd450OpNames[inst]; if (opName == null) { throw failure('$id is not a supported GLSL instruction.'); diff --git a/lib/spirv/test/BUILD.gn b/lib/spirv/test/BUILD.gn index ab3ba5b008486..bcf82bfc5a339 100644 --- a/lib/spirv/test/BUILD.gn +++ b/lib/spirv/test/BUILD.gn @@ -1,6 +1,7 @@ # 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. + import("//flutter/testing/testing.gni") if (enable_unittests) { @@ -14,4 +15,12 @@ if (enable_unittests) { "//third_party/swiftshader_flutter:spvtools_val", ] } + + executable("glsl_to_spirv") { + sources = [ "glsl_to_spirv.cc" ] + + configs += [ "//third_party/shaderc_flutter:shaderc_util_config" ] + + deps = [ "//third_party/shaderc_flutter" ] + } } diff --git a/lib/spirv/test/exception_shaders/BUILD.gn b/lib/spirv/test/exception_shaders/BUILD.gn index 17e371e5f3261..8cdc9b8fa3bd6 100644 --- a/lib/spirv/test/exception_shaders/BUILD.gn +++ b/lib/spirv/test/exception_shaders/BUILD.gn @@ -1,6 +1,7 @@ # 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. + import("//build/compiled_action.gni") import("//flutter/testing/testing.gni") diff --git a/lib/spirv/test/exception_shaders/unassigned_function_type.spvasm b/lib/spirv/test/exception_shaders/unassigned_function_type.spvasm index a757977bcd9d8..a2853611a31d3 100644 --- a/lib/spirv/test/exception_shaders/unassigned_function_type.spvasm +++ b/lib/spirv/test/exception_shaders/unassigned_function_type.spvasm @@ -1,3 +1,7 @@ +; 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; 8 diff --git a/lib/spirv/test/exception_shaders/unassigned_pointer_type.spvasm b/lib/spirv/test/exception_shaders/unassigned_pointer_type.spvasm index 35b644e8e6342..7b59ea47d97e7 100644 --- a/lib/spirv/test/exception_shaders/unassigned_pointer_type.spvasm +++ b/lib/spirv/test/exception_shaders/unassigned_pointer_type.spvasm @@ -1,3 +1,7 @@ +; 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; 8 diff --git a/lib/spirv/test/exception_shaders/unassigned_type.spvasm b/lib/spirv/test/exception_shaders/unassigned_type.spvasm index c9bf556c135c0..c1c0329e7f35a 100644 --- a/lib/spirv/test/exception_shaders/unassigned_type.spvasm +++ b/lib/spirv/test/exception_shaders/unassigned_type.spvasm @@ -1,3 +1,7 @@ +; 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; 8 diff --git a/lib/spirv/test/exception_shaders/unassigned_variable_type.spvasm b/lib/spirv/test/exception_shaders/unassigned_variable_type.spvasm index 5905010d615a8..c811b90c30655 100644 --- a/lib/spirv/test/exception_shaders/unassigned_variable_type.spvasm +++ b/lib/spirv/test/exception_shaders/unassigned_variable_type.spvasm @@ -1,3 +1,7 @@ +; 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; 8 diff --git a/lib/spirv/test/exception_shaders/unsupported_addressing_model.spvasm b/lib/spirv/test/exception_shaders/unsupported_addressing_model.spvasm index 42db7acd64fdb..d8e129445a25e 100644 --- a/lib/spirv/test/exception_shaders/unsupported_addressing_model.spvasm +++ b/lib/spirv/test/exception_shaders/unsupported_addressing_model.spvasm @@ -1,3 +1,7 @@ +; 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; 8 diff --git a/lib/spirv/test/exception_shaders/unsupported_capability.spvasm b/lib/spirv/test/exception_shaders/unsupported_capability.spvasm index 3653af6987844..9692c538d8ba6 100644 --- a/lib/spirv/test/exception_shaders/unsupported_capability.spvasm +++ b/lib/spirv/test/exception_shaders/unsupported_capability.spvasm @@ -1,3 +1,7 @@ +; 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; 8 diff --git a/lib/spirv/test/exception_shaders/unsupported_execution_mode.spvasm b/lib/spirv/test/exception_shaders/unsupported_execution_mode.spvasm index 00abb481689b8..496ac8fabfb3d 100644 --- a/lib/spirv/test/exception_shaders/unsupported_execution_mode.spvasm +++ b/lib/spirv/test/exception_shaders/unsupported_execution_mode.spvasm @@ -1,3 +1,7 @@ +; 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; 8 diff --git a/lib/spirv/test/exception_shaders/unsupported_ext_inst_import.spvasm b/lib/spirv/test/exception_shaders/unsupported_ext_inst_import.spvasm index 722ff319bdfeb..7017ae51e4ef3 100644 --- a/lib/spirv/test/exception_shaders/unsupported_ext_inst_import.spvasm +++ b/lib/spirv/test/exception_shaders/unsupported_ext_inst_import.spvasm @@ -1,3 +1,7 @@ +; 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; 8 diff --git a/lib/spirv/test/exception_shaders/unsupported_float_width.spvasm b/lib/spirv/test/exception_shaders/unsupported_float_width.spvasm index 4fabcfbf2e779..78205e3351faf 100644 --- a/lib/spirv/test/exception_shaders/unsupported_float_width.spvasm +++ b/lib/spirv/test/exception_shaders/unsupported_float_width.spvasm @@ -1,3 +1,7 @@ +; 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; 8 diff --git a/lib/spirv/test/exception_shaders/unsupported_glsl_inst.spvasm b/lib/spirv/test/exception_shaders/unsupported_glsl_inst.spvasm index 23e3d1a0fdea6..1e2f62ad996e3 100644 --- a/lib/spirv/test/exception_shaders/unsupported_glsl_inst.spvasm +++ b/lib/spirv/test/exception_shaders/unsupported_glsl_inst.spvasm @@ -1,3 +1,7 @@ +; 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; 8 diff --git a/lib/spirv/test/exception_shaders/unsupported_matrix_column_count.spvasm b/lib/spirv/test/exception_shaders/unsupported_matrix_column_count.spvasm index b773de2b1cf66..0f04f812d6237 100644 --- a/lib/spirv/test/exception_shaders/unsupported_matrix_column_count.spvasm +++ b/lib/spirv/test/exception_shaders/unsupported_matrix_column_count.spvasm @@ -1,3 +1,7 @@ +; 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; 8 diff --git a/lib/spirv/test/exception_shaders/unsupported_matrix_non_square.spvasm b/lib/spirv/test/exception_shaders/unsupported_matrix_non_square.spvasm index d5ff3c432d432..4560e01baa753 100644 --- a/lib/spirv/test/exception_shaders/unsupported_matrix_non_square.spvasm +++ b/lib/spirv/test/exception_shaders/unsupported_matrix_non_square.spvasm @@ -1,3 +1,7 @@ +; 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; 8 diff --git a/lib/spirv/test/exception_shaders/unsupported_memory_model.spvasm b/lib/spirv/test/exception_shaders/unsupported_memory_model.spvasm index ae6e51e97cbd7..2766191df8784 100644 --- a/lib/spirv/test/exception_shaders/unsupported_memory_model.spvasm +++ b/lib/spirv/test/exception_shaders/unsupported_memory_model.spvasm @@ -1,3 +1,7 @@ +; 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; 8 diff --git a/lib/spirv/test/exception_shaders/unsupported_variable_storage_class.spvasm b/lib/spirv/test/exception_shaders/unsupported_variable_storage_class.spvasm index fa8574767c903..952833a5f0cb9 100644 --- a/lib/spirv/test/exception_shaders/unsupported_variable_storage_class.spvasm +++ b/lib/spirv/test/exception_shaders/unsupported_variable_storage_class.spvasm @@ -1,3 +1,7 @@ +; 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; 8 diff --git a/lib/spirv/test/exception_shaders/unsupported_vector_component_count.spvasm b/lib/spirv/test/exception_shaders/unsupported_vector_component_count.spvasm index 317ec226ee716..c0294011cbb25 100644 --- a/lib/spirv/test/exception_shaders/unsupported_vector_component_count.spvasm +++ b/lib/spirv/test/exception_shaders/unsupported_vector_component_count.spvasm @@ -1,3 +1,7 @@ +; 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; 8 diff --git a/lib/spirv/test/exception_shaders/unsupported_vector_type.spvasm b/lib/spirv/test/exception_shaders/unsupported_vector_type.spvasm index 8126cec49cd4b..77aacc674256f 100644 --- a/lib/spirv/test/exception_shaders/unsupported_vector_type.spvasm +++ b/lib/spirv/test/exception_shaders/unsupported_vector_type.spvasm @@ -1,3 +1,7 @@ +; 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; 8 diff --git a/lib/spirv/test/general_shaders/BUILD.gn b/lib/spirv/test/general_shaders/BUILD.gn new file mode 100644 index 0000000000000..73fedf24a7590 --- /dev/null +++ b/lib/spirv/test/general_shaders/BUILD.gn @@ -0,0 +1,24 @@ +# 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. + +import("//build/compiled_action.gni") +import("//flutter/testing/testing.gni") + +if (enable_unittests) { + compiled_action_foreach("spirv_compile_general_shaders") { + tool = "//flutter/lib/spirv/test:glsl_to_spirv" + + sources = [ + "simple.glsl", + "uniforms.glsl", + ] + + outputs = [ "$target_gen_dir/{{source_name_part}}.spv" ] + + args = [ + "{{source}}", + rebase_path(target_gen_dir, root_build_dir) + "/{{source_name_part}}.spv", + ] + } +} diff --git a/lib/spirv/test/general_shaders/simple.glsl b/lib/spirv/test/general_shaders/simple.glsl new file mode 100644 index 0000000000000..a221a4f8c2b94 --- /dev/null +++ b/lib/spirv/test/general_shaders/simple.glsl @@ -0,0 +1,15 @@ +#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() { + fragColor = vec4(0.0, a, 0.0, 1.0); +} diff --git a/lib/spirv/test/general_shaders/uniforms.glsl b/lib/spirv/test/general_shaders/uniforms.glsl new file mode 100644 index 0000000000000..c03032c97b156 --- /dev/null +++ b/lib/spirv/test/general_shaders/uniforms.glsl @@ -0,0 +1,17 @@ +#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 oColor; + +layout ( location = 0 ) uniform float iFloatUniform; +layout ( location = 1 ) uniform vec2 iVec2Uniform; +layout ( location = 2 ) uniform mat2 iMat2Uniform; + +void main() { + oColor = vec4(iFloatUniform, iVec2Uniform, iMat2Uniform[1][1]); +} diff --git a/lib/spirv/test/glsl_to_spirv.cc b/lib/spirv/test/glsl_to_spirv.cc new file mode 100644 index 0000000000000..25a05cf2e6fda --- /dev/null +++ b/lib/spirv/test/glsl_to_spirv.cc @@ -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. + +#include +#include +#include +#include +#include + +#include "third_party/shaderc/libshaderc/include/shaderc/shaderc.hpp" + +namespace fs = std::filesystem; + +int main(int argc, const char* argv[]) { + if (argc != 3) { + std::cerr << "Invalid argument count." << std::endl; + return -1; + } + + fs::path path(argv[1]); + if (!fs::is_regular_file(path)) { + std::cerr << "File is not a regular file." << std::endl; + return -1; + } + + std::fstream input; + input.open(argv[1]); + input.seekg(0, std::ios::end); + std::streampos size = input.tellg(); + input.seekg(0, std::ios::beg); + std::vector buf(static_cast(size) + 1); + input.read(buf.data(), size); + buf[size] = 0; // make sure the string is null terminated. + input.close(); + + shaderc::Compiler compiler; + shaderc::CompileOptions options; + options.SetOptimizationLevel(shaderc_optimization_level_zero); + options.SetTargetEnvironment(shaderc_target_env_opengl, 0); + shaderc::SpvCompilationResult result = compiler.CompileGlslToSpv( + buf.data(), shaderc_glsl_default_fragment_shader, argv[1], options); + + if (result.GetCompilationStatus() != shaderc_compilation_status_success) { + std::cerr << "Failed to transpile: " + result.GetErrorMessage() << argv[1] + << std::endl; + return -1; + } + + std::vector spirv = + std::vector(result.cbegin(), result.cend()); + + std::fstream output; + output.open(argv[2], std::fstream::out | std::fstream::trunc); + + if (!output.is_open()) { + output.close(); + std::cerr << "failed to open output file" << std::endl; + return -1; + } + + output.write(reinterpret_cast(spirv.data()), + sizeof(uint32_t) * spirv.size()); + output.close(); + return 0; +} diff --git a/lib/spirv/test/supported_glsl_op_shaders/10_fract.glsl b/lib/spirv/test/supported_glsl_op_shaders/10_fract.glsl new file mode 100644 index 0000000000000..bdf14300f07f1 --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/10_fract.glsl @@ -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() { + fragColor = vec4( + fract(a), + // 0.25 + 0.75 = 1.0 + fract(a + 1.25) + fract(3.75), + 0.0, + 1.0 + ); +} diff --git a/lib/spirv/test/supported_glsl_op_shaders/11_radians.glsl b/lib/spirv/test/supported_glsl_op_shaders/11_radians.glsl new file mode 100644 index 0000000000000..1a8fd54311ddc --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/11_radians.glsl @@ -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() { + fragColor = vec4( + 0.0, + // 57.2957795131 * pi / 180.0 = 1.0 + float(radians(a * 57.2957795131)), + 0.0, + 1.0 + ); +} diff --git a/lib/spirv/test/supported_glsl_op_shaders/12_degrees.glsl b/lib/spirv/test/supported_glsl_op_shaders/12_degrees.glsl new file mode 100644 index 0000000000000..ca185e63435cf --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/12_degrees.glsl @@ -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() { + fragColor = vec4( + 0.0, + // 0.01745329251 * 180.0 / pi = 1.0 + degrees(a * 0.01745329251), + 0.0, + 1.0 + ); +} diff --git a/lib/spirv/test/supported_glsl_op_shaders/13_sin.glsl b/lib/spirv/test/supported_glsl_op_shaders/13_sin.glsl new file mode 100644 index 0000000000000..6c89587ea5fc5 --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/13_sin.glsl @@ -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() { + fragColor = vec4( + /* sin(0.0) = 0.0 */ + sin(0.0), + // sin(1.57079632679) = sin(pi / 2.0) = 1.0 + sin(a * 1.57079632679), + 0.0, + 1.0); +} diff --git a/lib/spirv/test/supported_glsl_op_shaders/14_cos.glsl b/lib/spirv/test/supported_glsl_op_shaders/14_cos.glsl new file mode 100644 index 0000000000000..52600b964e2a3 --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/14_cos.glsl @@ -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() { + fragColor = vec4( + /* cos(1.57079632679) = cos(pi / 2.0) = 0.0 */ + cos(a * 1.57079632679), + // cos(0.0) = 0.0 + cos(0.0), + 0.0, + 1.0); +} diff --git a/lib/spirv/test/supported_glsl_op_shaders/15_tan.glsl b/lib/spirv/test/supported_glsl_op_shaders/15_tan.glsl new file mode 100644 index 0000000000000..c5cbbd406369b --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/15_tan.glsl @@ -0,0 +1,22 @@ +#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() { + fragColor = vec4( + // tan(0.0) = 0.0 + tan(0.0), + // tan(1.57079632679) = tan(pi / 4.0) = 1.0 + tan(a * 0.785398163), + 0.0, + 1.0 + ); +} diff --git a/lib/spirv/test/supported_glsl_op_shaders/16_asin.glsl b/lib/spirv/test/supported_glsl_op_shaders/16_asin.glsl new file mode 100644 index 0000000000000..92880cda929ab --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/16_asin.glsl @@ -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() { + fragColor = vec4( + /* sin(0.0) = 0.0 */ + asin(0.0), + // sin(1.0) = 0.8414709848 + asin(a * 0.8414709848), + 0.0, + 1.0); +} diff --git a/lib/spirv/test/supported_glsl_op_shaders/17_acos.glsl b/lib/spirv/test/supported_glsl_op_shaders/17_acos.glsl new file mode 100644 index 0000000000000..6d0f7eb05f98a --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/17_acos.glsl @@ -0,0 +1,22 @@ +#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() { + fragColor = vec4( + // cos(0.0) = 1.0 + acos(1.0), + // cos(1.0) = 0.54030230586 + acos(a * 0.54030230586), + 0.0, + 1.0 + ); +} diff --git a/lib/spirv/test/supported_glsl_op_shaders/18_atan.glsl b/lib/spirv/test/supported_glsl_op_shaders/18_atan.glsl new file mode 100644 index 0000000000000..68f5b4968a863 --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/18_atan.glsl @@ -0,0 +1,22 @@ +#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() { + fragColor = vec4( + // tan(0.0) = 0.0 + atan(0.0), + // tan(1.0) = 1.55740772465 + atan(a * 1.55740772465), + 0.0, + 1.0 + ); +} diff --git a/lib/spirv/test/supported_glsl_op_shaders/25_atan2.glsl b/lib/spirv/test/supported_glsl_op_shaders/25_atan2.glsl new file mode 100644 index 0000000000000..2e42d9fd9c349 --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/25_atan2.glsl @@ -0,0 +1,22 @@ +#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() { + fragColor = vec4( + // tan(0.0 / 1.0) = tan(0.0) = 0.0 + atan(0.0, 1.0), + // tan(3.1148154493 / 2.0) = tan(1.55740772465) = 1.0 + atan(a * 3.1148154493, 2.0), + 0.0, + 1.0 + ); +} diff --git a/lib/spirv/test/supported_glsl_op_shaders/26_pow.glsl b/lib/spirv/test/supported_glsl_op_shaders/26_pow.glsl new file mode 100644 index 0000000000000..ea808bd7a5794 --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/26_pow.glsl @@ -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() { + fragColor = vec4( + pow(2.0, a-1.0) - 1.0, + pow(a * 3.14, 0.0), + 0.0, + 1.0 + ); +} + diff --git a/lib/spirv/test/supported_glsl_op_shaders/27_exp.glsl b/lib/spirv/test/supported_glsl_op_shaders/27_exp.glsl new file mode 100644 index 0000000000000..61f476c7c54ca --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/27_exp.glsl @@ -0,0 +1,22 @@ +#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() { + fragColor = vec4( + 0.0, + // e^0.0 = 1.0 + exp(a * 0.0), + 0.0, + // e^2.0 - 6.38905609893 = 7.38905609893 - 6.38905609893 = 1.0 + exp(a * 2.0) - 6.38905609893 + ); +} diff --git a/lib/spirv/test/supported_glsl_op_shaders/28_log.glsl b/lib/spirv/test/supported_glsl_op_shaders/28_log.glsl new file mode 100644 index 0000000000000..c4f3b9955cbeb --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/28_log.glsl @@ -0,0 +1,22 @@ +#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() { + fragColor = vec4( + // e^0.0 = 1.0 + log(a), + // e^1.0 = e + log(a * 2.718281828459), + 0.0, + 1.0 + ); +} diff --git a/lib/spirv/test/supported_glsl_op_shaders/29_exp2.glsl b/lib/spirv/test/supported_glsl_op_shaders/29_exp2.glsl new file mode 100644 index 0000000000000..d6c4251a892bc --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/29_exp2.glsl @@ -0,0 +1,23 @@ +#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() { + fragColor = vec4( + 0.0, + // 2.0^0.0 = 1.0 + exp2(a - 1.0), + 0.0, + // 2.0^3.0 - 7.0 = 8.0 - 7.0 = 1.0 + exp2(a * 3.0) - 7.0 + ); +} + diff --git a/lib/spirv/test/supported_glsl_op_shaders/30_log2.glsl b/lib/spirv/test/supported_glsl_op_shaders/30_log2.glsl new file mode 100644 index 0000000000000..5a1e8579831c1 --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/30_log2.glsl @@ -0,0 +1,22 @@ +#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() { + fragColor = vec4( + // 2.0^0.0 = 1.0 + log2(a), + // 2.0^1.0 = 2.0 + log2(a * 2.0), + 0.0, + 1.0 + ); +} diff --git a/lib/spirv/test/supported_glsl_op_shaders/31_sqrt.glsl b/lib/spirv/test/supported_glsl_op_shaders/31_sqrt.glsl new file mode 100644 index 0000000000000..59892ab260199 --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/31_sqrt.glsl @@ -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() { + fragColor = vec4( + sqrt(a - 1.0), + sqrt(a), + sqrt(a * 9.0) - 3.0, + 1.0 + ); +} + diff --git a/lib/spirv/test/supported_glsl_op_shaders/32_inversesqrt.glsl b/lib/spirv/test/supported_glsl_op_shaders/32_inversesqrt.glsl new file mode 100644 index 0000000000000..d84c38910bda2 --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/32_inversesqrt.glsl @@ -0,0 +1,22 @@ +#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() { + fragColor = vec4( + 0.0, + // 1.0 / sqrt(1.0) = 1.0 + inversesqrt(a), + 0.0, + // 1.0 / sqrt(4.0) + 0.5 = 1.0 / 2.0 + 0.5 = 1.0 + inversesqrt(a * 4.0) + 0.5 + ); +} diff --git a/lib/spirv/test/supported_glsl_op_shaders/37_fmin.glsl b/lib/spirv/test/supported_glsl_op_shaders/37_fmin.glsl new file mode 100644 index 0000000000000..9dbea871c9a80 --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/37_fmin.glsl @@ -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() { + fragColor = vec4( + 0.0, + 1.0 - min(1.0, 1.0-a), + 0.0, + 1.0 + ); +} diff --git a/lib/spirv/test/supported_glsl_op_shaders/40_fmax.glsl b/lib/spirv/test/supported_glsl_op_shaders/40_fmax.glsl new file mode 100644 index 0000000000000..621d56ae0ca4d --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/40_fmax.glsl @@ -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() { + fragColor = vec4( + 0.0, + max(a, 0.5), + 0.0, + 1.0); +} + diff --git a/lib/spirv/test/supported_glsl_op_shaders/43_fclamp.glsl b/lib/spirv/test/supported_glsl_op_shaders/43_fclamp.glsl new file mode 100644 index 0000000000000..62674d91d0e62 --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/43_fclamp.glsl @@ -0,0 +1,22 @@ +#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; + +// clamp(x, a, b) is equivalent to min(max(x, a), b) +void main() { + fragColor = vec4( + 0.0, + clamp(10.0, 0.0, a), + 0.0, + clamp(-1.0, a, 10.0) + ); +} + diff --git a/lib/spirv/test/supported_glsl_op_shaders/46_fmix.glsl b/lib/spirv/test/supported_glsl_op_shaders/46_fmix.glsl new file mode 100644 index 0000000000000..2176d0126da94 --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/46_fmix.glsl @@ -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() { + fragColor = vec4( + 0.0, + mix(0.0, 1.0, a), + 0.0, + mix(1.0, 0.0, 1.0 - a)); +} + diff --git a/lib/spirv/test/supported_glsl_op_shaders/48_step.glsl b/lib/spirv/test/supported_glsl_op_shaders/48_step.glsl new file mode 100644 index 0000000000000..2a550e664cfae --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/48_step.glsl @@ -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; + +// 0.0 is returned if x (second param) < edge (first param), and 1.0 is returned otherwise. +void main() { + fragColor = vec4( + 0.0, + step(0.5, a), + 0.0, + 1.0 + ); +} diff --git a/lib/spirv/test/supported_glsl_op_shaders/49_smoothstep.glsl b/lib/spirv/test/supported_glsl_op_shaders/49_smoothstep.glsl new file mode 100644 index 0000000000000..2863ed92a8838 --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/49_smoothstep.glsl @@ -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; + +// performs Hermite interpolation between two values: +// +// smoothstep(edge0, edge1, 0) { +// t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0); +// return t * t * (3.0 - 2.0 * t); +// } +void main() { + fragColor = vec4( + // smoothstep(1.0, 5.0, 3.0) is 0.5, subtract to get 0.0 + smoothstep(a, 5.0, 3.0) - 0.5, + // smoothstep(0.0, 2.0, 1.0) is 0.5, add 0.5 to get 1.0 + smoothstep(0.0, 2.0, a) + 0.5, + 0.0, + 1.0 + ); +} diff --git a/lib/spirv/test/supported_glsl_op_shaders/4_abs.glsl b/lib/spirv/test/supported_glsl_op_shaders/4_abs.glsl new file mode 100644 index 0000000000000..0a6fc2c8facd0 --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/4_abs.glsl @@ -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() { + fragColor = vec4( + 0.0, + abs(-a), + 0.0, + 1.0 + ); +} diff --git a/lib/spirv/test/supported_glsl_op_shaders/66_length.glsl b/lib/spirv/test/supported_glsl_op_shaders/66_length.glsl new file mode 100644 index 0000000000000..bbd56ad93025c --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/66_length.glsl @@ -0,0 +1,23 @@ +#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() { + fragColor = vec4( + // length of a zero vector is 0.0 + length(vec3(a - 1.0, 0.0, 0.0)), + // sqrt(3.0^2.0 + 4.0^2.0) - 4.0 = 5.0 - 4.0 = 1.0 + length(vec2(a * 3.0, 4.0)) - 4.0, + 0.0, + // sqrt(4.0^2.0 + (-4.0)^2.0 + (-4.0)^2.0) + 4.0^2.0) - 7.0 = sqrt(16.0 + 16.0 + 16.0 + 16.0) - 7.0 = sqrt(64.0) - 7.0 = 8.0 - 7.0 = 1.0 + length(vec4(a * 4.0, -4.0, -4.0, 4.0)) - 7.0 + ); +} diff --git a/lib/spirv/test/supported_glsl_op_shaders/67_distance.glsl b/lib/spirv/test/supported_glsl_op_shaders/67_distance.glsl new file mode 100644 index 0000000000000..f0dfa2d7656d8 --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/67_distance.glsl @@ -0,0 +1,23 @@ +#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() { + fragColor = vec4( + // distance between same value is 0.0 + distance(a * 7.0, 7.0), + // 7.0 - 6.0 = 1.0 + distance(a * 7.0, 6.0), + 0.0, + // sqrt(7.0 * 7.0 - 6.0 * 8.0) = sqrt(49.0 - 48.0) = sqrt(1.0) = 1.0 + distance(vec2(a * 7.0, 6.0), vec2(7.0, 8.0)) + ); +} diff --git a/lib/spirv/test/supported_glsl_op_shaders/68_cross.glsl b/lib/spirv/test/supported_glsl_op_shaders/68_cross.glsl new file mode 100644 index 0000000000000..d3ddabbe4c9bd --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/68_cross.glsl @@ -0,0 +1,22 @@ +#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() { + fragColor = vec4( + /* cross product of parallel vectors is a zero vector */ + cross(vec3(a, 2.0, 3.0), vec3(2.0, 4.0, 6.0))[0], + 1.0, + // cross product of parallel vectors is a zero vector + cross(vec3(a, 2.0, 3.0), vec3(2.0, 4.0, 6.0))[2], + 1.0); +} + diff --git a/lib/spirv/test/supported_glsl_op_shaders/69_normalize.glsl b/lib/spirv/test/supported_glsl_op_shaders/69_normalize.glsl new file mode 100644 index 0000000000000..4c6dae16d54a4 --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/69_normalize.glsl @@ -0,0 +1,22 @@ +#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() { + fragColor = vec4( + 0.0, + // normalized result is x = [3/5, 4/5], so add 2/5 to x1 to make 1.0 + normalize(vec2(a * 3.0, 4.0))[0] + 0.4, + 0.0, + // normalized result is x = [3/5, 4/5], so add 1/5 to x2 to make 1.0 + normalize(vec2(a * 3.0, 4.0))[1] + 0.2 + ); +} diff --git a/lib/spirv/test/supported_glsl_op_shaders/6_sign.glsl b/lib/spirv/test/supported_glsl_op_shaders/6_sign.glsl new file mode 100644 index 0000000000000..491b85deb7514 --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/6_sign.glsl @@ -0,0 +1,23 @@ +#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() { + fragColor = vec4( + // sign is negative which results to -1.0, and -1.0 + 1.0 is 0.0 + sign(-72.45) + a, + // sign is negative which results to -1.0, and -1.0 + 2.0 is 1.0 + sign(-12.34) + 2.0 * a, + 0.0, + // sign is positive which results to 1.0 + sign(a * 0.1234)); +} + diff --git a/lib/spirv/test/supported_glsl_op_shaders/70_faceforward.glsl b/lib/spirv/test/supported_glsl_op_shaders/70_faceforward.glsl new file mode 100644 index 0000000000000..6f6e5ccee4b13 --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/70_faceforward.glsl @@ -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() { + fragColor = vec4( + 0.0, + // dot product of incident vector (2nd param) and reference vector (3rd param) is non-negative, + // so the negated first param is returned, and its first value is 1.0. + faceforward(vec2(-a, 5.0), vec2(1.0, 2.0), vec2(3.0, 4.0))[0], + 0.0, + // dot product of incident vector (2nd param) and reference vector (3rd param) is negative, + // so the original first param is returned, and its second value is 5.0, so subtract 4.0 to get 1.0. + faceforward(vec2(a, 5.0), vec2(1.0, -2.0), vec2(3.0, 4.0))[1] - 4.0 + ); +} diff --git a/lib/spirv/test/supported_glsl_op_shaders/71_reflect.glsl b/lib/spirv/test/supported_glsl_op_shaders/71_reflect.glsl new file mode 100644 index 0000000000000..a02e8af0b97ae --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/71_reflect.glsl @@ -0,0 +1,30 @@ +#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; + +// For a given incident vector I and surface normal N reflect returns the reflection direction calculated as I - 2.0 * dot(N, I) * N. +void main() { + // To get [0.0, 1.0] as the output, choose [0.6, 0.8] as N, and solve for I. + // Since the reflection is symmetric: + // I’ = reflect(I) + // I’ = I - 2 dot(N, I) N + // I = I’ - 2 dot(N, I’) N + // N = [0.6, 0.8] + // I’ = [0, 1] + // I = [0, 1] - 2 * 0.8 [0.6, 0.8] + // I = [-0.96, -0.28] + fragColor = vec4( + reflect(vec2(a * -0.96, -0.28), vec2(0.6, 0.8))[0], + reflect(vec2(a * -0.96, -0.28), vec2(0.6, 0.8))[1], + 0.0, + 1.0 + ); +} diff --git a/lib/spirv/test/supported_glsl_op_shaders/8_floor.glsl b/lib/spirv/test/supported_glsl_op_shaders/8_floor.glsl new file mode 100644 index 0000000000000..900e206b6a75b --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/8_floor.glsl @@ -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() { + fragColor = vec4( + floor(a * 0.25), + floor(a * 1.25), + floor(a * 0.75), + floor(a * 1.75) + ); +} diff --git a/lib/spirv/test/supported_glsl_op_shaders/9_ceil.glsl b/lib/spirv/test/supported_glsl_op_shaders/9_ceil.glsl new file mode 100644 index 0000000000000..c9039aa3e0309 --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/9_ceil.glsl @@ -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() { + fragColor = vec4( + ceil(a * -0.25), + ceil(a * 0.25), + ceil(a * -0.75), + ceil(a * 0.75) + ); +} + diff --git a/lib/spirv/test/supported_glsl_op_shaders/BUILD.gn b/lib/spirv/test/supported_glsl_op_shaders/BUILD.gn new file mode 100644 index 0000000000000..88c806a28a157 --- /dev/null +++ b/lib/spirv/test/supported_glsl_op_shaders/BUILD.gn @@ -0,0 +1,55 @@ +# 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. + +import("//build/compiled_action.gni") +import("//flutter/testing/testing.gni") + +if (enable_unittests) { + compiled_action_foreach("spirv_compile_supported_glsl_shaders") { + tool = "//flutter/lib/spirv/test:glsl_to_spirv" + + sources = [ + "10_fract.glsl", + "11_radians.glsl", + "12_degrees.glsl", + "13_sin.glsl", + "14_cos.glsl", + "15_tan.glsl", + "16_asin.glsl", + "17_acos.glsl", + "18_atan.glsl", + "25_atan2.glsl", + "26_pow.glsl", + "27_exp.glsl", + "28_log.glsl", + "29_exp2.glsl", + "30_log2.glsl", + "31_sqrt.glsl", + "32_inversesqrt.glsl", + "37_fmin.glsl", + "40_fmax.glsl", + "43_fclamp.glsl", + "46_fmix.glsl", + "48_step.glsl", + "49_smoothstep.glsl", + "4_abs.glsl", + "66_length.glsl", + "67_distance.glsl", + "68_cross.glsl", + "69_normalize.glsl", + "6_sign.glsl", + "70_faceforward.glsl", + "71_reflect.glsl", + "8_floor.glsl", + "9_ceil.glsl", + ] + + outputs = [ "$target_gen_dir/{{source_name_part}}.spv" ] + + args = [ + "{{source}}", + rebase_path(target_gen_dir, root_build_dir) + "/{{source_name_part}}.spv", + ] + } +} diff --git a/lib/spirv/test/supported_op_shaders/127_OpFNegate.glsl b/lib/spirv/test/supported_op_shaders/127_OpFNegate.glsl new file mode 100644 index 0000000000000..9548e6862e97a --- /dev/null +++ b/lib/spirv/test/supported_op_shaders/127_OpFNegate.glsl @@ -0,0 +1,16 @@ +#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() { + fragColor = vec4(0.0, -(0.0-a), 0.0, 1.0); +} + diff --git a/lib/spirv/test/supported_op_shaders/129_OpFAdd.glsl b/lib/spirv/test/supported_op_shaders/129_OpFAdd.glsl new file mode 100644 index 0000000000000..f82ccc9c26831 --- /dev/null +++ b/lib/spirv/test/supported_op_shaders/129_OpFAdd.glsl @@ -0,0 +1,16 @@ +#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() { + fragColor = vec4(0.0, 0.5 * a + 0.5, 0.0, 1.0); +} + diff --git a/lib/spirv/test/supported_op_shaders/131_OpFSub.glsl b/lib/spirv/test/supported_op_shaders/131_OpFSub.glsl new file mode 100644 index 0000000000000..2eef92f4d7b27 --- /dev/null +++ b/lib/spirv/test/supported_op_shaders/131_OpFSub.glsl @@ -0,0 +1,16 @@ +#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() { + fragColor = vec4(0.0, 2.0 - a, 0.0, 1.0); +} + diff --git a/lib/spirv/test/supported_op_shaders/142_OpVectorTimesScalar.glsl b/lib/spirv/test/supported_op_shaders/142_OpVectorTimesScalar.glsl new file mode 100644 index 0000000000000..ccde0f99120bd --- /dev/null +++ b/lib/spirv/test/supported_op_shaders/142_OpVectorTimesScalar.glsl @@ -0,0 +1,16 @@ +#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() { + fragColor = vec4(0.0, 1.0, 0.0, 1.0) * a; +} + diff --git a/lib/spirv/test/supported_op_shaders/143_OpMatrixTimesScalar.glsl b/lib/spirv/test/supported_op_shaders/143_OpMatrixTimesScalar.glsl new file mode 100644 index 0000000000000..aab64dea92736 --- /dev/null +++ b/lib/spirv/test/supported_op_shaders/143_OpMatrixTimesScalar.glsl @@ -0,0 +1,18 @@ +#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() { + mat4 m = mat4(1.0); + m *= a; + fragColor = vec4(0.0, 1.0, 0.0, 1.0) * m; +} + diff --git a/lib/spirv/test/supported_op_shaders/144_OpVectorTimesMatrix.glsl b/lib/spirv/test/supported_op_shaders/144_OpVectorTimesMatrix.glsl new file mode 100644 index 0000000000000..b9a9ccb4bd69b --- /dev/null +++ b/lib/spirv/test/supported_op_shaders/144_OpVectorTimesMatrix.glsl @@ -0,0 +1,16 @@ +#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() { + mat4 identity = mat4(a); + fragColor = vec4(0.0, 1.0, 0.0, 1.0) * identity; +} diff --git a/lib/spirv/test/supported_op_shaders/145_OpMatrixTimesVector.glsl b/lib/spirv/test/supported_op_shaders/145_OpMatrixTimesVector.glsl new file mode 100644 index 0000000000000..67365c49284ed --- /dev/null +++ b/lib/spirv/test/supported_op_shaders/145_OpMatrixTimesVector.glsl @@ -0,0 +1,17 @@ +#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() { + mat4 identity = mat4(a); + fragColor = identity * vec4(0.0, 1.0, 0.0, 1.0); +} + diff --git a/lib/spirv/test/supported_op_shaders/146_OpMatrixTimesMatrix.glsl b/lib/spirv/test/supported_op_shaders/146_OpMatrixTimesMatrix.glsl new file mode 100644 index 0000000000000..2536d21b9f030 --- /dev/null +++ b/lib/spirv/test/supported_op_shaders/146_OpMatrixTimesMatrix.glsl @@ -0,0 +1,17 @@ +#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() { + mat4 m = mat4(1.0) * mat4(a); + fragColor = vec4(0.0, 1.0, 0.0, 1.0) * m; +} + diff --git a/lib/spirv/test/supported_op_shaders/148_OpDot.glsl b/lib/spirv/test/supported_op_shaders/148_OpDot.glsl new file mode 100644 index 0000000000000..cc755d0a232fa --- /dev/null +++ b/lib/spirv/test/supported_op_shaders/148_OpDot.glsl @@ -0,0 +1,16 @@ +#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 one = dot(vec2(1.0), vec2(0.0, a)); + fragColor = vec4(0.0, one, 0.0, 1.0); +} diff --git a/lib/spirv/test/supported_op_shaders/19_OpTypeVoid.glsl b/lib/spirv/test/supported_op_shaders/19_OpTypeVoid.glsl new file mode 100644 index 0000000000000..a221a4f8c2b94 --- /dev/null +++ b/lib/spirv/test/supported_op_shaders/19_OpTypeVoid.glsl @@ -0,0 +1,15 @@ +#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() { + fragColor = vec4(0.0, a, 0.0, 1.0); +} diff --git a/lib/spirv/test/supported_op_shaders/20_OpTypeBool.glsl b/lib/spirv/test/supported_op_shaders/20_OpTypeBool.glsl new file mode 100644 index 0000000000000..ce1ef4c3cd26c --- /dev/null +++ b/lib/spirv/test/supported_op_shaders/20_OpTypeBool.glsl @@ -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() { + bool f = false; + bool t = bool(a); + float zero = float(f); + float one = float(t); + fragColor = vec4(zero, one, zero, one); +} + diff --git a/lib/spirv/test/supported_op_shaders/21_OpTypeInt.glsl b/lib/spirv/test/supported_op_shaders/21_OpTypeInt.glsl new file mode 100644 index 0000000000000..39b6b48ff2e73 --- /dev/null +++ b/lib/spirv/test/supported_op_shaders/21_OpTypeInt.glsl @@ -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() { + int zeroInt = 0; + int oneInt = int(a); + float zero = float(zeroInt); + float one = float(oneInt); + fragColor = vec4(zero, one, zero, one); +} + diff --git a/lib/spirv/test/supported_op_shaders/22_OpTypeFloat.glsl b/lib/spirv/test/supported_op_shaders/22_OpTypeFloat.glsl new file mode 100644 index 0000000000000..ffc779c0ff737 --- /dev/null +++ b/lib/spirv/test/supported_op_shaders/22_OpTypeFloat.glsl @@ -0,0 +1,17 @@ +#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 zero = 0.0; + fragColor = vec4(zero, a, zero, a); +} + diff --git a/lib/spirv/test/supported_op_shaders/23_OpTypeVector.glsl b/lib/spirv/test/supported_op_shaders/23_OpTypeVector.glsl new file mode 100644 index 0000000000000..9137ccdb20564 --- /dev/null +++ b/lib/spirv/test/supported_op_shaders/23_OpTypeVector.glsl @@ -0,0 +1,17 @@ +#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() { + vec2 ones = vec2(a); + vec3 zeros = vec3(0.0, 0.0, 0.0); + fragColor = vec4(zeros[0], ones[0], zeros[2], ones[1]); +} diff --git a/lib/spirv/test/supported_op_shaders/24_OpTypeMatrix.glsl b/lib/spirv/test/supported_op_shaders/24_OpTypeMatrix.glsl new file mode 100644 index 0000000000000..8b2032d99360e --- /dev/null +++ b/lib/spirv/test/supported_op_shaders/24_OpTypeMatrix.glsl @@ -0,0 +1,22 @@ +#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() { + mat2 zeros = mat2(0.0); + mat3 ones = mat3(a); + mat4 identity = mat4( + a, 0.0, 0.0, 0.0, + 0.0, a, 0.0, 0.0, + 0.0, 0.0, a, 0.0, + 0.0, 0.0, 0.0, a); + fragColor = vec4(zeros[1][1], ones[2][2], identity[3][1], identity[3][3]); +} diff --git a/lib/spirv/test/supported_op_shaders/33_OpTypeFunction.glsl b/lib/spirv/test/supported_op_shaders/33_OpTypeFunction.glsl new file mode 100644 index 0000000000000..eb468e82aa0d1 --- /dev/null +++ b/lib/spirv/test/supported_op_shaders/33_OpTypeFunction.glsl @@ -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; + +float zero() { + return 0.0; +} + +float one() { + return a; +} + +void main() { + fragColor = vec4(zero(), one(), zero(), one()); +} + diff --git a/lib/spirv/test/supported_op_shaders/BUILD.gn b/lib/spirv/test/supported_op_shaders/BUILD.gn new file mode 100644 index 0000000000000..b6751f67c0f0d --- /dev/null +++ b/lib/spirv/test/supported_op_shaders/BUILD.gn @@ -0,0 +1,38 @@ +# 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. + +import("//build/compiled_action.gni") +import("//flutter/testing/testing.gni") + +if (enable_unittests) { + compiled_action_foreach("spirv_compile_supported_op_shaders") { + tool = "//flutter/lib/spirv/test:glsl_to_spirv" + + sources = [ + "127_OpFNegate.glsl", + "129_OpFAdd.glsl", + "131_OpFSub.glsl", + "142_OpVectorTimesScalar.glsl", + "143_OpMatrixTimesScalar.glsl", + "144_OpVectorTimesMatrix.glsl", + "145_OpMatrixTimesVector.glsl", + "146_OpMatrixTimesMatrix.glsl", + "148_OpDot.glsl", + "19_OpTypeVoid.glsl", + "20_OpTypeBool.glsl", + "21_OpTypeInt.glsl", + "22_OpTypeFloat.glsl", + "23_OpTypeVector.glsl", + "24_OpTypeMatrix.glsl", + "33_OpTypeFunction.glsl", + ] + + outputs = [ "$target_gen_dir/{{source_name_part}}.spv" ] + + args = [ + "{{source}}", + rebase_path(target_gen_dir, root_build_dir) + "/{{source_name_part}}.spv", + ] + } +} diff --git a/lib/ui/BUILD.gn b/lib/ui/BUILD.gn index 917cacdd56d81..e062f23bb1806 100644 --- a/lib/ui/BUILD.gn +++ b/lib/ui/BUILD.gn @@ -30,6 +30,8 @@ source_set("ui") { "painting/color_filter.h", "painting/engine_layer.cc", "painting/engine_layer.h", + "painting/fragment_shader.cc", + "painting/fragment_shader.h", "painting/gradient.cc", "painting/gradient.h", "painting/image.cc", diff --git a/lib/ui/dart_ui.cc b/lib/ui/dart_ui.cc index d2958c838420c..91e2c5b0d65c9 100644 --- a/lib/ui/dart_ui.cc +++ b/lib/ui/dart_ui.cc @@ -13,6 +13,7 @@ #include "flutter/lib/ui/painting/codec.h" #include "flutter/lib/ui/painting/color_filter.h" #include "flutter/lib/ui/painting/engine_layer.h" +#include "flutter/lib/ui/painting/fragment_shader.h" #include "flutter/lib/ui/painting/gradient.h" #include "flutter/lib/ui/painting/image.h" #include "flutter/lib/ui/painting/image_descriptor.h" @@ -66,6 +67,7 @@ void DartUI::InitForGlobal() { DartRuntimeHooks::RegisterNatives(g_natives); EngineLayer::RegisterNatives(g_natives); FontCollection::RegisterNatives(g_natives); + FragmentShader::RegisterNatives(g_natives); ImageDescriptor::RegisterNatives(g_natives); ImageFilter::RegisterNatives(g_natives); ImageShader::RegisterNatives(g_natives); diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 086b2df63e5c5..a9717844ab553 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -3746,6 +3746,110 @@ class ImageShader extends Shader { void _initWithImage(_Image image, int tmx, int tmy, int filterQualityIndex, Float64List matrix4) native 'ImageShader_initWithImage'; } +/// A shader (as used by [Paint.shader]) that runs provided SPIR-V code. +/// +/// This API is in beta and does not yet work on web. +/// See https://github.com/flutter/flutter/projects/207 for roadmap. +/// +/// [A current specification of valid SPIR-V is here.](https://github.com/flutter/engine/blob/master/lib/spirv/README.md) +/// +/// When initializing or updating the `floatUniforms`, the length of float +/// uniforms must match the total number of floats defined as uniforms in +/// the shader. They will be updated in the order that they are defined. +/// +/// For example, if there are 3 uniforms: 1 of type float, 1 type float2/vec2, +/// and 1 of type vec3/float3, and 1 mat2x2 then the length of `floatUniforms` +/// must be 10. +/// +/// The uniforms could be updated as follows: +/// +/// Consider the following snippit of GLSL code. +/// +/// ``` +/// layout (location = 0) uniform float a; +/// layout (location = 1) uniform vec2 b; +/// layout (location = 2) uniform vec3 c; +/// layout (location = 3) uniform mat2x2 d; +/// ``` +/// +/// After being compiled to SPIR-V using [shaderc](https://github.com/google/shaderc) +/// and provided to the constructor, `floatUniforms` must always have a length +/// of 10. One per float-component of each uniform. +/// +/// Dart code to update uniforms. +/// +/// `shader.update(floatUniforms: Float32List.fromList([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]));` +/// +/// Results of shader uniforms. +/// +/// a: 1 +/// b: [2, 3] +/// c: [4, 5, 6] +/// d: [7, 8, 9, 10] // 2x2 matrix in column-major order +/// +class FragmentShader extends Shader { + + // TODO(chriscraws): Add `List? children` as a parameter to the + // constructor and to [update]. + // https://github.com/flutter/flutter/issues/85240 + + /// Creates a fragment shader from SPIR-V byte data as an input. + /// + /// [A current specification of valid SPIR-V is here.](https://github.com/flutter/engine/blob/master/lib/spirv/README.md) + /// SPIR-V not meeting this specification will throw an exception. + /// + /// `floatUniforms` can be passed optionally to initialize the shader's + /// uniforms. If they are not initially set, they will default + /// to 0. They can later be updated by invoking the [update] method. + /// + /// `floatUniforms` must be sized correctly, or an [ArgumentError] will + /// be thrown. See [FragmentShader] docs for details. + /// + /// The compilation of a shader gets more expensive the more complicated the source is. + /// Because of this, it is reccommended to construct a FragmentShader asynchrounously, + /// outside of a widget's `build` method, to minimize the chance of UI jank. + @pragma('vm:entry-point') + FragmentShader({ + required ByteBuffer spirv, + Float32List? floatUniforms, + bool debugPrint = false, + }) : super._() { + _constructor(); + final spv.TranspileResult result = spv.transpile( + spirv, + spv.TargetLanguage.sksl, + ); + _uniformFloatCount = result.uniformFloatCount; + _init(result.src, debugPrint); + update(floatUniforms: floatUniforms ?? Float32List(_uniformFloatCount)); + } + + late final int _uniformFloatCount; + + void _constructor() native 'FragmentShader_constructor'; + void _init(String sksl, bool debugPrint) native 'FragmentShader_init'; + + /// Updates the uniform values that are supplied to the [FragmentShader] + /// and refreshes the shader. + /// + /// `floatUniforms` must be sized correctly, or an [ArgumentError] will + /// be thrown. See [FragmentShader] docs for details. + /// + /// This method will aquire additional fields as [FragmentShader] is + /// implemented further. + void update({ + required Float32List floatUniforms, + }) { + if (floatUniforms.length != _uniformFloatCount) { + throw ArgumentError( + 'FragmentShader floatUniforms size: ${floatUniforms.length} must match given shader uniform count: $_uniformFloatCount.'); + } + _update(floatUniforms); + } + + void _update(Float32List floatUniforms) native 'FragmentShader_update'; +} + /// Defines how a list of points is interpreted when drawing a set of triangles. /// /// Used by [Canvas.drawVertices]. diff --git a/lib/ui/painting/fragment_shader.cc b/lib/ui/painting/fragment_shader.cc new file mode 100644 index 0000000000000..a9a59e399b408 --- /dev/null +++ b/lib/ui/painting/fragment_shader.cc @@ -0,0 +1,79 @@ +// 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. + +#include + +#include "flutter/lib/ui/painting/fragment_shader.h" + +#include "flutter/lib/ui/dart_wrapper.h" +#include "flutter/lib/ui/ui_dart_state.h" +#include "third_party/skia/include/core/SkString.h" +#include "third_party/tonic/converter/dart_converter.h" +#include "third_party/tonic/dart_args.h" +#include "third_party/tonic/dart_binding_macros.h" +#include "third_party/tonic/dart_library_natives.h" +#include "third_party/tonic/typed_data/typed_list.h" + +using tonic::ToDart; + +namespace flutter { + +static void FragmentShader_constructor(Dart_NativeArguments args) { + DartCallConstructor(&FragmentShader::Create, args); +} + +IMPLEMENT_WRAPPERTYPEINFO(ui, FragmentShader); + +#define FOR_EACH_BINDING(V) \ + V(FragmentShader, init) \ + V(FragmentShader, update) + +FOR_EACH_BINDING(DART_NATIVE_CALLBACK) + +void FragmentShader::RegisterNatives(tonic::DartLibraryNatives* natives) { + natives->Register( + {{"FragmentShader_constructor", FragmentShader_constructor, 1, true}, + FOR_EACH_BINDING(DART_REGISTER_NATIVE)}); +} + +sk_sp FragmentShader::shader(SkSamplingOptions sampling) { + // TODO(antrob): Use sampling? + // https://github.com/flutter/flutter/issues/88303 + return shader_; +} + +void FragmentShader::init(std::string sksl, bool debugPrintSksl) { + SkRuntimeEffect::Result result = + SkRuntimeEffect::MakeForShader(SkString(sksl)); + runtime_effect_ = result.effect; + + if (runtime_effect_ == nullptr) { + Dart_ThrowException(tonic::ToDart( + std::string("Invalid SkSL:\n") + sksl.c_str() + + std::string("\nSkSL Error:\n") + result.errorText.c_str())); + return; + } + if (debugPrintSksl) { + FML_DLOG(INFO) << std::string("debugPrintSksl:\n") + sksl.c_str(); + } +} + +// TODO(https://github.com/flutter/flutter/issues/85240): +// Add `Dart_Handle children` as a paramter. +void FragmentShader::update(const tonic::Float32List& uniforms) { + shader_ = runtime_effect_->makeShader( + SkData::MakeWithCopy(uniforms.data(), + uniforms.num_elements() * sizeof(float)), + 0, 0, nullptr, false); +} + +fml::RefPtr FragmentShader::Create() { + return fml::MakeRefCounted(); +} + +FragmentShader::FragmentShader() = default; + +FragmentShader::~FragmentShader() = default; + +} // namespace flutter diff --git a/lib/ui/painting/fragment_shader.h b/lib/ui/painting/fragment_shader.h new file mode 100644 index 0000000000000..8a1a12e4e2959 --- /dev/null +++ b/lib/ui/painting/fragment_shader.h @@ -0,0 +1,57 @@ +// 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. + +#ifndef FLUTTER_LIB_UI_PAINTING_FRAGMENT_SHADER_H_ +#define FLUTTER_LIB_UI_PAINTING_FRAGMENT_SHADER_H_ + +#include "flutter/lib/ui/dart_wrapper.h" +#include "flutter/lib/ui/painting/image.h" +#include "flutter/lib/ui/painting/image_shader.h" +#include "flutter/lib/ui/painting/shader.h" +#include "third_party/skia/include/core/SkShader.h" +#include "third_party/skia/include/effects/SkRuntimeEffect.h" +#include "third_party/tonic/dart_library_natives.h" +#include "third_party/tonic/typed_data/typed_list.h" + +#include +#include + +namespace tonic { +class DartLibraryNatives; +} // namespace tonic + +namespace flutter { + +class FragmentShader : public Shader { + DEFINE_WRAPPERTYPEINFO(); + FML_FRIEND_MAKE_REF_COUNTED(FragmentShader); + + public: + ~FragmentShader() override; + static fml::RefPtr Create(); + + sk_sp shader(SkSamplingOptions) override; + + void init(std::string sksl, bool debugPrintSksl); + + void update(const tonic::Float32List& uniforms); + + static void RegisterNatives(tonic::DartLibraryNatives* natives); + + private: + FragmentShader(); + + void setShader(); + + // Since the shader source cannot be updated, the effect can be + // created once and re-used. + sk_sp runtime_effect_; + + // A new shader is created every time update is called. + sk_sp shader_; +}; + +} // namespace flutter + +#endif // FLUTTER_LIB_UI_PAINTING_FRAGMENT_SHADER_H_ diff --git a/lib/ui/ui.dart b/lib/ui/ui.dart index 23d85835c1d92..743c2310650e1 100644 --- a/lib/ui/ui.dart +++ b/lib/ui/ui.dart @@ -12,6 +12,7 @@ // @dart = 2.12 library dart.ui; +import 'dart:_spirv' as spv; import 'dart:async'; import 'dart:collection' as collection; import 'dart:convert'; @@ -19,7 +20,7 @@ import 'dart:developer' as developer; import 'dart:io'; // ignore: unused_import import 'dart:isolate' show SendPort; import 'dart:math' as math; -import 'dart:nativewrappers'; +import 'dart:nativewrappers'; // ignore: unused_import import 'dart:typed_data'; part 'annotations.dart'; diff --git a/lib/web_ui/lib/src/ui/painting.dart b/lib/web_ui/lib/src/ui/painting.dart index cf6c5928b97ad..bb8f5e05269e8 100644 --- a/lib/web_ui/lib/src/ui/painting.dart +++ b/lib/web_ui/lib/src/ui/painting.dart @@ -785,3 +785,17 @@ class ImageDescriptor { return _createBmp(_data!, width, height, _rowBytes ?? width, _format!); } } + +class FragmentShader extends Shader { + FragmentShader({ + required ByteBuffer spirv, // ignore: avoid_unused_constructor_parameters + Float32List? floatUniforms, // ignore: avoid_unused_constructor_parameters + bool debugPrint = false, // ignore: avoid_unused_constructor_parameters + }) : super._() { + throw UnsupportedError('FragmentShader is not supported for the CanvasKit or HTML renderers.'); + } + + void update({Float32List? floatUniforms}) => + throw UnsupportedError('FragmentShader is not supported for the CanvasKit or HTML renderers.'); +} + diff --git a/shell/platform/fuchsia/flutter/kernel/libraries.json b/shell/platform/fuchsia/flutter/kernel/libraries.json index 77ea8972e26c9..a23782c67912c 100644 --- a/shell/platform/fuchsia/flutter/kernel/libraries.json +++ b/shell/platform/fuchsia/flutter/kernel/libraries.json @@ -1,6 +1,6 @@ { "comment:0": "NOTE: THIS FILE IS GENERATED. DO NOT EDIT.", - "comment:1": "Instead modify './flutter/shell/platform/fuchsia/flutter/kernel/libraries.yaml' and follow the instructions therein.", + "comment:1": "Instead modify 'flutter/shell/platform/fuchsia/flutter/kernel/libraries.yaml' and follow the instructions therein.", "flutter_runner": { "libraries": { "_builtin": { @@ -146,6 +146,9 @@ "uri": "../../../../../../third_party/dart/sdk/lib/typed_data/typed_data.dart", "patches": "../../../../../../third_party/dart/sdk/lib/_internal/vm/lib/typed_data_patch.dart" }, + "_spirv": { + "uri": "../../../../../lib/spirv/lib/spirv.dart" + }, "fuchsia.builtin": { "uri": "../../dart_runner/embedder/builtin.dart" }, @@ -169,4 +172,4 @@ } } } -} +} \ No newline at end of file diff --git a/shell/platform/fuchsia/flutter/kernel/libraries.yaml b/shell/platform/fuchsia/flutter/kernel/libraries.yaml index 37f480d71da68..c2aa9151078d8 100644 --- a/shell/platform/fuchsia/flutter/kernel/libraries.yaml +++ b/shell/platform/fuchsia/flutter/kernel/libraries.yaml @@ -145,6 +145,8 @@ flutter_runner: typed_data: uri: "../../../../../../third_party/dart/sdk/lib/typed_data/typed_data.dart" patches: "../../../../../../third_party/dart/sdk/lib/_internal/vm/lib/typed_data_patch.dart" + _spirv: + uri: "../../../../../lib/spirv/lib/spirv.dart" fuchsia.builtin: uri: "../../dart_runner/embedder/builtin.dart" diff --git a/sky/packages/sky_engine/BUILD.gn b/sky/packages/sky_engine/BUILD.gn index 89ff158dbcd47..c587ad8e53f15 100644 --- a/sky/packages/sky_engine/BUILD.gn +++ b/sky/packages/sky_engine/BUILD.gn @@ -137,6 +137,11 @@ copy("math") { [ "$root_gen_dir/dart-pkg/sky_engine/lib/math/{{source_file_part}}" ] } +copy("spirv") { + sources = [ "//flutter/lib/spirv/lib" ] + outputs = [ "$root_gen_dir/dart-pkg/sky_engine/lib/spirv" ] +} + copy("typed_data") { lib_path = rebase_path("typed_data", "", dart_sdk_lib_path) sources = rebase_path(typed_data_sdk_sources, "", lib_path) @@ -177,6 +182,7 @@ group("copy_dart_sdk") { ":js", ":js_util", ":math", + ":spirv", ":typed_data", ] } @@ -209,6 +215,7 @@ generated_file("_embedder_yaml") { " # public API, e.g. List being Iterable by virtue of implementing", " # EfficientLengthIterable. Not including this library yields analysis errors.", " \"dart:_internal\": \"internal/internal.dart\"", + " \"dart:_spirv\": \"spirv/spirv.dart\"", " \"dart:nativewrappers\": \"_empty.dart\"", ] } diff --git a/testing/dart/BUILD.gn b/testing/dart/BUILD.gn index 7e201e718fd9f..ec3d8d6a69a44 100644 --- a/testing/dart/BUILD.gn +++ b/testing/dart/BUILD.gn @@ -13,6 +13,7 @@ tests = [ "compositing_test.dart", "dart_test.dart", "encoding_test.dart", + "fragment_shader_test.dart", "geometry_test.dart", "gesture_settings_test.dart", "gradient_test.dart", diff --git a/testing/dart/fragment_shader_test.dart b/testing/dart/fragment_shader_test.dart new file mode 100644 index 0000000000000..859fb0ec61fdb --- /dev/null +++ b/testing/dart/fragment_shader_test.dart @@ -0,0 +1,185 @@ +// 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. + +import 'dart:async'; +import 'dart:collection'; +import 'dart:io'; +import 'dart:typed_data'; +import 'dart:ui'; + +import 'package:litetest/litetest.dart'; +import 'package:path/path.dart' as path; + +import 'shader_test_file_utils.dart'; + +void main() { + test('throws exception for invalid shader', () { + final ByteBuffer invalidBytes = Uint8List.fromList([1, 2, 3, 4, 5]).buffer; + expect(() => FragmentShader(spirv: invalidBytes), throws); + }); + + test('simple shader renders correctly', () async { + final Uint8List shaderBytes = await spvFile('general_shaders', 'simple.spv').readAsBytes(); + _expectShaderRendersGreen(shaderBytes.buffer.asUint32List()); + }); + + test('shader with uniforms renders and updates correctly', () async { + final Uint8List shaderBytes = await spvFile('general_shaders', 'uniforms.spv').readAsBytes(); + final FragmentShader shader = FragmentShader(spirv: shaderBytes.buffer); + + shader.update(floatUniforms: Float32List.fromList([ + 0.0, // iFloatUniform + 0.25, // iVec2Uniform.x + 0.75, // iVec2Uniform.y + 0.0, // iMat2Uniform[0][0] + 0.0, // iMat2Uniform[0][1] + 0.0, // iMat2Uniform[1][0] + 1.0, // iMat2Uniform[1][1] + ])); + + final ByteData renderedBytes = (await _imageByteDataFromShader( + shader: shader, + ))!; + + expect(toFloat(renderedBytes.getUint8(0)), closeTo(0.0, epsilon)); + expect(toFloat(renderedBytes.getUint8(1)), closeTo(0.25, epsilon)); + expect(toFloat(renderedBytes.getUint8(2)), closeTo(0.75, epsilon)); + expect(toFloat(renderedBytes.getUint8(3)), closeTo(1.0, epsilon)); + }); + + // Test all supported GLSL ops. See lib/spirv/lib/src/constants.dart + final Map supportedGLSLOpShaders = + _loadSpv('supported_glsl_op_shaders'); + expect(supportedGLSLOpShaders.isNotEmpty, true); + _expectShadersRenderGreen(supportedGLSLOpShaders); + _expectShadersHaveOp(supportedGLSLOpShaders, true /* glsl ops */); + + // Test all supported instructions. See lib/spirv/lib/src/constants.dart + final Map supportedOpShaders = + _loadSpv('supported_op_shaders'); + expect(supportedOpShaders.isNotEmpty, true); + _expectShadersRenderGreen(supportedOpShaders); + _expectShadersHaveOp(supportedOpShaders, false /* glsl ops */); +} + +// Expect that all of the spirv shaders in this folder render green. +// Keeping the outer loop of the test synchronous allows for easy printing +// of the file name within the test case. +void _expectShadersRenderGreen(Map shaders) { + for (final String key in shaders.keys) { + test('$key renders green', () { + _expectShaderRendersGreen(shaders[key]!); + }); + } +} + +void _expectShadersHaveOp(Map shaders, bool glsl) { + for (final String key in shaders.keys) { + test('$key contains opcode', () { + _expectShaderHasOp(shaders[key]!, key, glsl); + }); + } +} + +const int _opExtInst = 12; + +// Expects that a spirv shader has the op code identified by its file name. +void _expectShaderHasOp(Uint32List words, String filename, bool glsl) { + final List sections = filename.split('_'); + expect(sections.length, greaterThan(1)); + final int op = int.parse(sections.first); + + // skip the header + int position = 5; + + bool found = false; + while (position < words.length) { + final int word = words[position]; + final int currentOpCode = word & 0xFFFF; + if (glsl) { + if (currentOpCode == _opExtInst && words[position+4] == op) { + found = true; + break; + } + } else { + if (currentOpCode == op) { + found = true; + break; + } + } + final int advance = word >> 16; + if (advance <= 0) { + break; + } + position += advance; + } + + expect(found, true); +} + +// Expects that a spirv shader only outputs the color green. +Future _expectShaderRendersGreen(Uint32List spirv) async { + final FragmentShader shader = FragmentShader( + spirv: spirv.buffer, + floatUniforms: Float32List.fromList([1]), + ); + final ByteData renderedBytes = (await _imageByteDataFromShader( + shader: shader, + imageDimension: _shaderImageDimension, + ))!; + for (final int color in renderedBytes.buffer.asUint32List()) { + expect(toHexString(color), toHexString(_greenColor.value)); + } +} + +Future _imageByteDataFromShader({ + required FragmentShader shader, + int imageDimension = 100, +}) async { + final PictureRecorder recorder = PictureRecorder(); + final Canvas canvas = Canvas(recorder); + final Paint paint = Paint()..shader = shader; + canvas.drawPaint(paint); + final Picture picture = recorder.endRecording(); + final Image image = await picture.toImage( + imageDimension, + imageDimension, + ); + return image.toByteData(); +} + +// Loads the path and spirv content of the files at +// $FLUTTER_BUILD_DIRECTORY/gen/flutter/lib/spirv/test/$leafFolderName +// This is synchronous so that tests can be inside of a loop with +// the proper test name. +Map _loadSpv(String leafFolderName) { + final Map out = SplayTreeMap(); + + final Directory directory = spvDirectory(leafFolderName); + if (!directory.existsSync()) { + return out; + } + + directory.listSync() + .where((FileSystemEntity entry) => path.extension(entry.path) == '.spv') + .forEach((FileSystemEntity entry) { + final String key = path.basenameWithoutExtension(entry.path); + out[key] = (entry as File).readAsBytesSync().buffer.asUint32List(); + }); + return out; +} + + +// Arbitrary, but needs to be greater than 1 for frag coord tests. +const int _shaderImageDimension = 4; + +const Color _greenColor = Color(0xFF00FF00); + +// Precision for checking uniform values. +const double epsilon = 0.5 / 255.0; + +// Maps an int value from 0-255 to a double value of 0.0 to 1.0. +double toFloat(int v) => v.toDouble() / 255.0; + +String toHexString(int color) => '#${color.toRadixString(16)}'; diff --git a/testing/dart/shader_test_file_utils.dart b/testing/dart/shader_test_file_utils.dart new file mode 100644 index 0000000000000..ebc5b35a40ade --- /dev/null +++ b/testing/dart/shader_test_file_utils.dart @@ -0,0 +1,40 @@ +// 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. + +import 'dart:io'; + +import 'package:path/path.dart' as path; + +String _flutterBuildDirectoryPath() { + assert(Platform.environment.containsKey('FLUTTER_BUILD_DIRECTORY')); + + return Platform.environment['FLUTTER_BUILD_DIRECTORY']!; +} + +const String _testPath = 'gen/flutter/lib/spirv/test'; + +/// Gets the [Directory] of .spv files that are generated by `lib/spirv/test`. +/// +/// `folderName` is a leaf folder within the generated directory. +Directory spvDirectory(String leafFolderName) { + return Directory(path.joinAll([ + ...path.split(_flutterBuildDirectoryPath()), + ...path.split(_testPath), + leafFolderName, + ])); +} + +/// Gets a specific .spv [File] that is generated by `lib/spirv/test`. +/// +/// `folderName` is the leaf folder within the generated directory. +/// +/// `fileName` is the name of the filer within `folderName`. +File spvFile(String folderName, String fileName) { + return File(path.joinAll([ + ...path.split(_flutterBuildDirectoryPath()), + ...path.split(_testPath), + folderName, + fileName, + ])); +} \ No newline at end of file diff --git a/testing/dart/spirv_exception_test.dart b/testing/dart/spirv_exception_test.dart index e67c7b0136f76..5d96e34220d7f 100644 --- a/testing/dart/spirv_exception_test.dart +++ b/testing/dart/spirv_exception_test.dart @@ -9,6 +9,8 @@ import 'package:litetest/litetest.dart'; import 'package:path/path.dart' as path; import 'package:spirv/spirv.dart' as spirv; +import 'shader_test_file_utils.dart'; + const List targets = [ spirv.TargetLanguage.sksl, spirv.TargetLanguage.glslES, @@ -18,7 +20,7 @@ const List targets = [ void main() { test('spirv transpiler throws exceptions', () async { int count = 0; - await for (final Uint8List shader in exceptionShaders()) { + await for (final Uint8List shader in _exceptionShaders()) { for (final spirv.TargetLanguage target in targets) { expect(() => spirv.transpile(shader.buffer, target), throwsException); } @@ -30,17 +32,8 @@ void main() { }); } -Stream exceptionShaders() async* { - final Directory dir = Directory(path.joinAll([ - 'out', - 'host_debug_unopt', - 'gen', - 'flutter', - 'lib', - 'spirv', - 'test', - 'exception_shaders', - ])); +Stream _exceptionShaders() async* { + final Directory dir = spvDirectory('exception_shaders'); await for (final FileSystemEntity entry in dir.list()) { if (entry is! File) { continue; diff --git a/testing/run_tests.py b/testing/run_tests.py index ae34497fc094c..9224aace01459 100755 --- a/testing/run_tests.py +++ b/testing/run_tests.py @@ -135,6 +135,10 @@ def RunEngineExecutable(build_dir, executable_name, filter, flags=[], else: test_command = [ executable ] + flags + if not env: + env = os.environ.copy() + env['FLUTTER_BUILD_DIRECTORY'] = build_dir + try: RunCmd(test_command, cwd=cwd, forbidden_output=forbidden_output, expect_failure=expect_failure, env=env) except: diff --git a/tools/licenses/lib/filesystem.dart b/tools/licenses/lib/filesystem.dart index 20385626c3834..4cd01fcdc8fa0 100644 --- a/tools/licenses/lib/filesystem.dart +++ b/tools/licenses/lib/filesystem.dart @@ -177,6 +177,9 @@ FileType identifyFile(String name, Reader reader) { // Machine code case '.so': return FileType.binary; // ELF shared object case '.xpt': return FileType.binary; // XPCOM Type Library + // Graphics code + case '.glsl': return FileType.text; + case '.spvasm': return FileType.text; // Documentation case '.md': return FileType.text; case '.txt': return FileType.text; diff --git a/web_sdk/test/api_conform_test.dart b/web_sdk/test/api_conform_test.dart index 1c6f6132518b9..929e0aa7902e8 100644 --- a/web_sdk/test/api_conform_test.dart +++ b/web_sdk/test/api_conform_test.dart @@ -54,7 +54,7 @@ void main() { print('Checking ${uiClasses.length} public classes.'); for (final String className in uiClasses.keys) { final ClassDeclaration uiClass = uiClasses[className]!; - final ClassDeclaration webClass = webClasses[className]!; + final ClassDeclaration? webClass = webClasses[className]; // If the web class is missing there isn't much left to do here. Print a // warning and move along. if (webClass == null) {