Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Add Dart SPIR-V transpiler #25480

Merged
merged 6 commits into from
May 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ group("flutter") {
public_deps += [
"//flutter/flow:flow_unittests",
"//flutter/fml:fml_unittests",
"//flutter/lib/spirv/test/exception_shaders:spirv_compile_exception_shaders",
"//flutter/lib/ui:ui_unittests",
"//flutter/runtime:no_dart_plugin_registrant_unittests",
"//flutter/runtime:runtime_unittests",
Expand Down
6 changes: 6 additions & 0 deletions ci/analyze.sh
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ analyze \
--options "$FLUTTER_DIR/analysis_options.yaml" \
"$SRC_DIR/out/host_debug_unopt/gen/sky/bindings/dart_ui/ui.dart"

echo "Analyzing spirv library..."
analyze \
--packages="$FLUTTER_DIR/lib/spirv/.dart_tool/package_config.json" \
--options "$FLUTTER_DIR/analysis_options.yaml" \
"$FLUTTER_DIR/lib/spirv"

echo "Analyzing ci/"
analyze \
--packages="$FLUTTER_DIR/ci/.dart_tool/package_config.json" \
Expand Down
4 changes: 4 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,10 @@ FILE: ../../../flutter/lib/io/dart_io.cc
FILE: ../../../flutter/lib/io/dart_io.h
FILE: ../../../flutter/lib/snapshot/libraries.json
FILE: ../../../flutter/lib/snapshot/snapshot.h
FILE: ../../../flutter/lib/spirv/lib/spirv.dart
FILE: ../../../flutter/lib/spirv/lib/src/constants.dart
FILE: ../../../flutter/lib/spirv/lib/src/transpiler.dart
FILE: ../../../flutter/lib/spirv/lib/src/types.dart
FILE: ../../../flutter/lib/ui/annotations.dart
FILE: ../../../flutter/lib/ui/channel_buffers.dart
FILE: ../../../flutter/lib/ui/compositing.dart
Expand Down
45 changes: 45 additions & 0 deletions lib/spirv/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# SPIR-V Transpiler

Note: This library is currently considered experimental until shader compilation is verified by engine unit tests, see the Testing section below for more details.

A dart library for transpiling a subset of SPIR-V to the shader languages used by Flutter internally.

- [SkSL](https://skia.org/docs/user/sksl/)
- [GLSL ES 100](https://www.khronos.org/files/opengles_shading_language.pdf)
- [GLSL ES 300](https://www.khronos.org/registry/OpenGL/specs/es/3.0/GLSL_ES_Specification_3.00.pdf)

All exported symbols are documented in `lib/spirv.dart`.

The supported subset of SPIR-V is specified in `lib/src/constants.dart`.

If you're using GLSL to generate SPIR-V with `glslangValidator` or `shaderc`,
the code will need to adhere to the following rules.

- There must be a single vec4 output at location 0.
- The output can only be written to from the main function.
- `gl_FragCoord` can only be read from the main function, and its z and w components
have no meaning.
- Control flow is prohibited aside from function calls and `return`.
`if`, `while`, `for`, `switch`, etc.
- No inputs from other shader stages.
- Only float, float-vector types, and square float-matrix types.
- Only square matrices are supported.
- Only built-in functions present in GLSL ES 100 are used.
- Debug symbols must be stripped, you can use the `spirv-opt` `--strip-debug` flag.

These rules may become less strict in future versions. Confirmant SPIR-V should succesfully transpile from the current version onwards. In other words, a spir-v shader you use now that meets these rules should keep working, but the output of the transpiler may change for that shader.

Support for textures, control flow, and structured types is planned, but not currently included.

## Testing

## 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

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.

These tests will be able to be run alone by executing `./ui_unittests` in the build-output directory.

70 changes: 70 additions & 0 deletions lib/spirv/lib/spirv.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// 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.

/// This library defines a transpiler for converting SPIR-V into SkSL or GLSL.
// @dart = 2.12
library spirv;

import 'dart:convert';
import 'dart:math';
import 'dart:typed_data';

// These parts only contain private members, all public
// members are in this file (spirv.dart)
part 'src/constants.dart';
part 'src/transpiler.dart';
part 'src/types.dart';

/// The language to transpile to.
enum TargetLanguage {
/// SkSL, for Skia.
sksl,

/// GLSL ES 1.00, for WebGL 1.
glslES,

/// GLSL ES 3.00, for WebGL 2.
glslES300,
}

/// The result of a transpilation.
class TranspileResult {
/// Source code string in [language].
final String src;

/// The shader language in [src].
final TargetLanguage language;

/// The number of float uniforms used in this shader.
final int uniformFloatCount;

TranspileResult._(this.src, this.uniformFloatCount, this.language);
}

/// Thrown during transpilation due to malformed or unsupported SPIR-V.
class TranspileException implements Exception {
/// The SPIR-V operator last read, or zero if there was none.
final int op;

/// Human readable message explaining the exception.
final String message;

@override
String toString() => '$op: $message';

TranspileException._(this.op, this.message);
}

/// Transpile the provided SPIR-V buffer into a string of the [target] lang.
/// Throws an instance of [TranspileException] for malformed or unsupported
/// SPIR-V.
TranspileResult transpile(ByteBuffer spirv, TargetLanguage target) {
final _Transpiler t = _Transpiler(spirv.asUint32List(), target);
t.transpile();
return TranspileResult._(
t.src.toString(),
t.uniformFloatCount,
target,
);
}
196 changes: 196 additions & 0 deletions lib/spirv/lib/src/constants.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
// 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.
// @dart = 2.12

part of spirv;

// This file contains a subset of SPIR-V constants defined at
// https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html

// Header constants
const int _magicNumber = 0x07230203;

// Supported ExecutionModes
const int _originLowerLeft = 8;

// Supported memory models
const int _addressingModelLogical = 0;
const int _memoryModelGLSL450 = 1;

// Supported capabilities
const int _capabilityMatrix = 0;
const int _capabilityShader = 1;

// Supported storage classes
const int _storageClassUniformConstant = 0;
const int _storageClassInput = 1;
const int _storageClassOutput = 3;
const int _storageClassFunction = 7;

// Explicity supported decorations, others are ignored
const int _decorationBuiltIn = 11;
const int _decorationLocation = 30;

// Explicitly supported builtin types
const int _builtinFragCoord = 15;

// Supported instructions
const int _opExtInstImport = 11;
const int _opExtInst = 12;
const int _opMemoryModel = 14;
const int _opEntryPoint = 15;
const int _opExecutionMode = 16;
const int _opCapability = 17;
const int _opTypeVoid = 19;
const int _opTypeBool = 20;
const int _opTypeFloat = 22;
const int _opTypeVector = 23;
const int _opTypeMatrix = 24;
const int _opTypePointer = 32;
const int _opTypeFunction = 33;
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 _opVariable = 59;
const int _opLoad = 61;
const int _opStore = 62;
const int _opAccessChain = 65;
const int _opDecorate = 71;
const int _opVectorShuffle = 79;
const int _opCompositeConstruct = 80;
const int _opCompositeExtract = 81;
const int _opFNegate = 127;
const int _opFAdd = 129;
const int _opFSub = 131;
const int _opFMul = 133;
const int _opFDiv = 136;
const int _opFMod = 141;
const int _opVectorTimesScalar = 142;
const int _opMatrixTimesScalar = 143;
const int _opVectorTimesMatrix = 144;
const int _opMatrixTimesVector = 145;
const int _opMatrixTimesMatrix = 146;
const int _opDot = 148;
const int _opLabel = 248;
const int _opReturn = 253;
const int _opReturnValue = 254;

// GLSL extension constants defined at
// https://www.khronos.org/registry/spir-v/specs/unified1/GLSL.std.450.html

// Supported GLSL extension name
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;
const int _glslStd450Ceil = 9;
const int _glslStd450Fract = 10;
const int _glslStd450Radians = 11;
const int _glslStd450Degrees = 12;
const int _glslStd450Sin = 13;
const int _glslStd450Cos = 14;
const int _glslStd450Tan = 15;
const int _glslStd450Asin = 16;
const int _glslStd450Acos = 17;
const int _glslStd450Atan = 18;
const int _glslStd450Atan2 = 25;
const int _glslStd450Pow = 26;
const int _glslStd450Exp = 27;
const int _glslStd450Log = 28;
const int _glslStd450Exp2 = 29;
const int _glslStd450Log2 = 30;
const int _glslStd450Sqrt = 31;
const int _glslStd450InverseSqrt = 32;
const int _glslStd450FMin = 37;
const int _glslStd450FMax = 40;
const int _glslStd450FClamp = 43;
const int _glslStd450FMix = 46;
const int _glslStd450Step = 48;
const int _glslStd450SmoothStep = 49;
const int _glslStd450Length = 66;
const int _glslStd450Distance = 67;
const int _glslStd450Cross = 68;
const int _glslStd450Normalize = 69;
const int _glslStd450FaceForward = 70;
const int _glslStd450Reflect = 71;

const Map<int, String> _glslStd450OpNames = <int, String>{
_glslStd450Trunc: 'trunc',
_glslStd450FAbs: 'abs',
_glslStd450FSign: 'sign',
_glslStd450Floor: 'floor',
_glslStd450Ceil: 'ceil',
_glslStd450Fract: 'fract',
_glslStd450Radians: 'radians',
_glslStd450Degrees: 'degrees',
_glslStd450Sin: 'sin',
_glslStd450Cos: 'cos',
_glslStd450Tan: 'tan',
_glslStd450Asin: 'asin',
_glslStd450Acos: 'acos',
_glslStd450Atan: 'atan',
_glslStd450Atan2: 'atan2',
_glslStd450Pow: 'pow',
_glslStd450Exp: 'exp',
_glslStd450Log: 'log',
_glslStd450Exp2: 'exp2',
_glslStd450Log2: 'log2',
_glslStd450Sqrt: 'sqrt',
_glslStd450InverseSqrt: 'inversesqrt',
_glslStd450FMin: 'min',
_glslStd450FMax: 'max',
_glslStd450FClamp: 'clamp',
_glslStd450FMix: 'mix',
_glslStd450Step: 'step',
_glslStd450SmoothStep: 'smoothstep',
_glslStd450Length: 'length',
_glslStd450Distance: 'distance',
_glslStd450Cross: 'cross',
_glslStd450Normalize: 'normalize',
_glslStd450FaceForward: 'faceforward',
_glslStd450Reflect: 'reflect',
};

const Map<int, int> _glslStd450OpArgc = <int, int>{
_glslStd450Trunc: 1,
_glslStd450FAbs: 1,
_glslStd450FSign: 1,
_glslStd450Floor: 1,
_glslStd450Ceil: 1,
_glslStd450Fract: 1,
_glslStd450Radians: 1,
_glslStd450Degrees: 1,
_glslStd450Sin: 1,
_glslStd450Cos: 1,
_glslStd450Tan: 1,
_glslStd450Asin: 1,
_glslStd450Acos: 1,
_glslStd450Atan: 1,
_glslStd450Atan2: 2,
_glslStd450Pow: 2,
_glslStd450Exp: 2,
_glslStd450Log: 1,
_glslStd450Exp2: 1,
_glslStd450Log2: 1,
_glslStd450Sqrt: 1,
_glslStd450InverseSqrt: 1,
_glslStd450FMin: 2,
_glslStd450FMax: 2,
_glslStd450FClamp: 3,
_glslStd450FMix: 3,
_glslStd450Step: 2,
_glslStd450SmoothStep: 3,
_glslStd450Length: 1,
_glslStd450Distance: 2,
_glslStd450Cross: 2,
_glslStd450Normalize: 1,
_glslStd450FaceForward: 3,
_glslStd450Reflect: 2,
};
Loading