aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Ethan Nicholas <ethannicholas@google.com>2017-06-27 09:56:09 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-06-27 14:20:05 +0000
commitccf59917d3fe7aaf59de714acfbd0596503f324f (patch)
treecc97719c47276c9dcbf0ec09effd580c4e7450dd
parentc3aef18419c1bb16951370e11758c7ef131fa10b (diff)
sksl fragment processor support
Bug: skia: Change-Id: Ia3b0305c2b0c78074303831f628fb01852b90d34 Reviewed-on: https://skia-review.googlesource.com/17843 Commit-Queue: Ethan Nicholas <ethannicholas@google.com> Reviewed-by: Ben Wagner <benjaminwagner@google.com> Reviewed-by: Mike Klein <mtklein@google.com>
-rw-r--r--BUILD.gn77
-rw-r--r--gn/BUILD.gn278
-rw-r--r--gn/BUILDCONFIG.gn20
-rwxr-xr-xgn/compile_processors.py19
-rw-r--r--gn/sksl.gni5
-rw-r--r--gn/tests.gni1
-rw-r--r--gn/toolchain/BUILD.gn301
-rw-r--r--src/sksl/README56
-rw-r--r--src/sksl/SkSLCFGGenerator.cpp2
-rw-r--r--src/sksl/SkSLCPP.h25
-rw-r--r--src/sksl/SkSLCPPCodeGenerator.cpp597
-rw-r--r--src/sksl/SkSLCPPCodeGenerator.h78
-rw-r--r--src/sksl/SkSLCodeGenerator.h1
-rw-r--r--src/sksl/SkSLCompiler.cpp41
-rw-r--r--src/sksl/SkSLCompiler.h20
-rw-r--r--src/sksl/SkSLContext.h16
-rw-r--r--src/sksl/SkSLGLSLCodeGenerator.cpp111
-rw-r--r--src/sksl/SkSLGLSLCodeGenerator.h26
-rw-r--r--src/sksl/SkSLHCodeGenerator.cpp236
-rw-r--r--src/sksl/SkSLHCodeGenerator.h60
-rw-r--r--src/sksl/SkSLIRGenerator.cpp164
-rw-r--r--src/sksl/SkSLIRGenerator.h41
-rw-r--r--src/sksl/SkSLMain.cpp68
-rw-r--r--src/sksl/SkSLParser.cpp158
-rw-r--r--src/sksl/SkSLParser.h21
-rw-r--r--src/sksl/SkSLSPIRVCodeGenerator.cpp4
-rw-r--r--src/sksl/SkSLSectionAndParameterHelper.h111
-rw-r--r--src/sksl/SkSLString.cpp7
-rw-r--r--src/sksl/SkSLStringStream.h31
-rw-r--r--src/sksl/SkSLToken.h6
-rw-r--r--src/sksl/SkSLUtil.cpp2
-rw-r--r--src/sksl/SkSLUtil.h4
-rw-r--r--src/sksl/ast/SkSLASTDeclaration.h3
-rw-r--r--src/sksl/ast/SkSLASTFunction.h2
-rw-r--r--src/sksl/ast/SkSLASTSection.h43
-rw-r--r--src/sksl/ir/SkSLExpression.h1
-rw-r--r--src/sksl/ir/SkSLFunctionDeclaration.h4
-rw-r--r--src/sksl/ir/SkSLLayout.h39
-rw-r--r--src/sksl/ir/SkSLPrefixExpression.h5
-rw-r--r--src/sksl/ir/SkSLProgram.h46
-rw-r--r--src/sksl/ir/SkSLProgramElement.h3
-rw-r--r--src/sksl/ir/SkSLSection.h43
-rw-r--r--src/sksl/ir/SkSLSetting.cpp22
-rw-r--r--src/sksl/ir/SkSLSetting.h51
-rw-r--r--src/sksl/ir/SkSLSwizzle.h6
-rw-r--r--src/sksl/ir/SkSLVarDeclarations.h2
-rw-r--r--src/sksl/ir/SkSLVariableReference.h7
-rw-r--r--src/sksl/layout.flex2
-rw-r--r--src/sksl/lex.layout.c577
-rw-r--r--src/sksl/lex.layout.cpp4
-rw-r--r--src/sksl/lex.sksl.c498
-rw-r--r--src/sksl/sksl.flex10
-rw-r--r--src/sksl/sksl_fp.include23
-rw-r--r--tests/SkSLFPTest.cpp381
54 files changed, 3321 insertions, 1038 deletions
diff --git a/BUILD.gn b/BUILD.gn
index bb5122a2b3..6ead044ff4 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -139,6 +139,7 @@ config("skia_private") {
"src/utils/win",
"src/xml",
"third_party/gif",
+ "$target_gen_dir",
]
defines = [ "SK_GAMMA_APPLY_TO_A8" ]
@@ -345,6 +346,9 @@ template("optional") {
optional("effects") {
enabled = skia_enable_effects
+ deps = [
+ ":compile_processors",
+ ]
sources =
skia_effects_sources + [ "src/ports/SkGlobalInitialization_default.cpp" ]
sources_when_disabled = [ "src/ports/SkGlobalInitialization_none.cpp" ]
@@ -410,12 +414,68 @@ optional("fontmgr_fuchsia") {
]
}
+if (skia_enable_gpu && skia_gpu_processor_sources != []) {
+ executable("skslc") {
+ defines = [ "SKSL_STANDALONE" ]
+ sources = [
+ "src/sksl/SkSLMain.cpp",
+ ]
+ sources += skia_sksl_sources
+ include_dirs = [
+ "src/gpu",
+ "src/sksl",
+ ]
+ deps = [
+ "//third_party/spirv-tools",
+ ]
+ }
+
+ skia_gpu_processor_outputs = []
+ foreach(src, skia_gpu_processor_sources) {
+ name = get_path_info(src, "name")
+ skia_gpu_processor_outputs += [
+ "$target_gen_dir/effects/$name.h",
+ "$target_gen_dir/effects/$name.cpp",
+ ]
+ }
+
+ action("compile_processors") {
+ script = "gn/compile_processors.py"
+ deps = [
+ ":skslc(//gn/toolchain:$host_toolchain)",
+ ]
+ sources = skia_gpu_processor_sources
+ outputs = skia_gpu_processor_outputs
+ skslc_path = "$root_out_dir/"
+ if (host_toolchain != default_toolchain_name) {
+ skslc_path += "$host_toolchain/"
+ }
+ skslc_path += "skslc"
+ if (host_os == "win") {
+ skslc_path = ".exe"
+ }
+ args = [
+ rebase_path(skslc_path),
+ rebase_path("$target_gen_dir/effects"),
+ ]
+ args += rebase_path(skia_gpu_processor_sources)
+ }
+} else {
+ skia_gpu_processor_outputs = []
+ group("compile_processors") {
+ }
+}
+
optional("gpu") {
enabled = skia_enable_gpu
+ deps = [
+ ":compile_processors",
+ ]
public_defines = []
sources = skia_gpu_sources + skia_sksl_sources +
- [ "src/gpu/gl/GrGLDefaultInterface_native.cpp" ]
+ [ "src/gpu/gl/GrGLDefaultInterface_native.cpp" ] +
+ skia_gpu_processor_outputs
# These paths need to be absolute to match the ones produced by shared_sources.gni.
sources -= get_path_info([
@@ -454,9 +514,7 @@ optional("gpu") {
}
}
if (skia_enable_spirv_validation) {
- deps = [
- "//third_party/spirv-tools",
- ]
+ deps += [ "//third_party/spirv-tools" ]
public_defines += [ "SK_ENABLE_SPIRV_VALIDATION" ]
}
}
@@ -1525,15 +1583,4 @@ if (skia_enable_tools) {
]
}
}
-
- if (skia_enable_gpu) {
- test_app("skslc") {
- defines = [ "SKSL_STANDALONE" ]
- sources = [
- "src/sksl/SkSLMain.cpp",
- ]
- sources += skia_sksl_sources
- include_dirs = [ "src/sksl" ]
- }
- }
}
diff --git a/gn/BUILD.gn b/gn/BUILD.gn
index 96da6775ec..cbac9759e4 100644
--- a/gn/BUILD.gn
+++ b/gn/BUILD.gn
@@ -4,48 +4,14 @@
# found in the LICENSE file.
declare_args() {
- ar = "ar"
- cc = "cc"
- cxx = "c++"
-
- if (is_android) {
- if (host_os == "win") {
- ar = "$ndk/toolchains/$ndk_gccdir-4.9/prebuilt/$ndk_host/$ndk_target/bin/ar.exe"
- cc = "$ndk/toolchains/llvm/prebuilt/$ndk_host/bin/clang.exe"
- cxx = "$ndk/toolchains/llvm/prebuilt/$ndk_host/bin/clang++.exe"
- } else {
- ar = "$ndk/toolchains/$ndk_gccdir-4.9/prebuilt/$ndk_host/$ndk_target/bin/ar"
- cc = "$ndk/toolchains/llvm/prebuilt/$ndk_host/bin/clang"
- cxx = "$ndk/toolchains/llvm/prebuilt/$ndk_host/bin/clang++"
- }
- }
-
- msvc = 2015
-
extra_asmflags = []
extra_cflags = []
extra_cflags_c = []
extra_cflags_cc = []
extra_ldflags = []
- cc_wrapper = ""
malloc = ""
}
-declare_args() {
- if (msvc == 2015) {
- windk = "C:/Program Files (x86)/Microsoft Visual Studio 14.0"
- } else {
- windk = "C:/Program Files (x86)/Microsoft Visual Studio/2017/Professional"
- }
-}
-
-if (host_os == "win") {
- python = "python.bat"
- stamp = "cmd.exe /c echo >"
-} else {
- python = "python"
- stamp = "touch"
-}
is_clang = is_android || is_ios || is_mac || (cc == "clang" && cxx == "clang++")
if (!is_clang && !is_win) {
@@ -476,247 +442,3 @@ config("executable") {
]
}
}
-
-toolchain("msvc") {
- lib_dir_switch = "/LIBPATH:"
-
- if (msvc == 2015) {
- bin = "$windk/VC/bin/amd64"
- env_setup = ""
- if (target_cpu == "x86") {
- bin += "_x86"
- env_setup = "cmd /c $windk/win_sdk/bin/SetEnv.cmd /x86 && "
- }
- } else {
- bin = "$windk/VC/Tools/MSVC/14.10.25017/bin/HostX64/$target_cpu"
- env_setup = ""
- if (target_cpu == "x86") {
- print("Be sure to run")
- print("$windk/VC/Auxiliary/Build/vcvarsall.bat amd64_x86")
- print("to set up your environment before running ninja.")
- }
- }
-
- tool("asm") {
- _ml = "ml"
- if (target_cpu == "x64") {
- _ml += "64"
- }
- command = "$env_setup$bin/$_ml.exe /nologo /c /Fo {{output}} {{source}}"
- outputs = [
- "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj",
- ]
- description = "assemble {{source}}"
- }
-
- tool("cc") {
- rspfile = "{{output}}.rsp"
- precompiled_header_type = "msvc"
- pdbname = "{{target_out_dir}}/{{label_name}}_c.pdb"
-
- # Label names may have spaces so pdbname must be quoted.
- command = "$env_setup$bin/cl.exe /nologo /showIncludes /FC @$rspfile /c {{source}} /Fo{{output}} /Fd\"$pdbname\""
- depsformat = "msvc"
- outputs = [
- "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj",
- ]
- rspfile_content = "{{defines}} {{include_dirs}} {{cflags}} {{cflags_c}}"
- description = "compile {{source}}"
- }
-
- tool("cxx") {
- rspfile = "{{output}}.rsp"
- precompiled_header_type = "msvc"
- pdbname = "{{target_out_dir}}/{{label_name}}_c.pdb"
-
- # Label names may have spaces so pdbname must be quoted.
- command = "$env_setup$bin/cl.exe /nologo /showIncludes /FC @$rspfile /c {{source}} /Fo{{output}} /Fd\"$pdbname\""
- depsformat = "msvc"
- outputs = [
- "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj",
- ]
- rspfile_content = "{{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}}"
- description = "compile {{source}}"
- }
-
- tool("alink") {
- rspfile = "{{output}}.rsp"
-
- command = "$env_setup$bin/lib.exe /nologo /ignore:4221 {{arflags}} /OUT:{{output}} @$rspfile"
- outputs = [
- # Ignore {{output_extension}} and always use .lib, there's no reason to
- # allow targets to override this extension on Windows.
- "{{root_out_dir}}/{{target_output_name}}{{output_extension}}",
- ]
- default_output_extension = ".lib"
- default_output_dir = "{{target_out_dir}}"
-
- # inputs_newline works around a fixed per-line buffer size in the linker.
- rspfile_content = "{{inputs_newline}}"
- description = "link {{output}}"
- }
-
- tool("solink") {
- dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
- libname = "${dllname}.lib"
- pdbname = "${dllname}.pdb"
- rspfile = "${dllname}.rsp"
-
- command = "$env_setup$bin/link.exe /nologo /IMPLIB:$libname /DLL /OUT:$dllname /PDB:$pdbname @$rspfile"
- outputs = [
- dllname,
- libname,
- pdbname,
- ]
- default_output_extension = ".dll"
- default_output_dir = "{{root_out_dir}}"
-
- link_output = libname
- depend_output = libname
- runtime_outputs = [
- dllname,
- pdbname,
- ]
-
- # I don't quite understand this. Aping Chrome's toolchain/win/BUILD.gn.
- restat = true
-
- # inputs_newline works around a fixed per-line buffer size in the linker.
- rspfile_content = "{{inputs_newline}} {{libs}} {{solibs}} {{ldflags}}"
- description = "link {{output}}"
- }
-
- tool("link") {
- exename = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"
- pdbname = "$exename.pdb"
- rspfile = "$exename.rsp"
-
- command =
- "$env_setup$bin/link.exe /nologo /OUT:$exename /PDB:$pdbname @$rspfile"
-
- default_output_extension = ".exe"
- default_output_dir = "{{root_out_dir}}"
- outputs = [
- exename,
- ]
-
- # inputs_newline works around a fixed per-line buffer size in the linker.
- rspfile_content = "{{inputs_newline}} {{libs}} {{solibs}} {{ldflags}}"
- description = "link {{output}}"
- }
-
- tool("stamp") {
- command = "$stamp {{output}}"
- description = "stamp {{output}}"
- }
-
- tool("copy") {
- cp_py = rebase_path("cp.py")
- command = "$python $cp_py {{source}} {{output}}"
- description = "copy {{source}} {{output}}"
- }
-}
-
-toolchain("gcc_like") {
- lib_switch = "-l"
- lib_dir_switch = "-L"
-
- tool("cc") {
- depfile = "{{output}}.d"
- command = "$cc_wrapper $cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
- depsformat = "gcc"
- outputs = [
- "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
- ]
- description = "compile {{source}}"
- }
-
- tool("cxx") {
- depfile = "{{output}}.d"
- command = "$cc_wrapper $cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}"
- depsformat = "gcc"
- outputs = [
- "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
- ]
- description = "compile {{source}}"
- }
-
- tool("objc") {
- depfile = "{{output}}.d"
- command = "$cc_wrapper $cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_objc}} -c {{source}} -o {{output}}"
- depsformat = "gcc"
- outputs = [
- "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
- ]
- description = "compile {{source}}"
- }
-
- tool("objcxx") {
- depfile = "{{output}}.d"
- command = "$cc_wrapper $cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} {{cflags_objc}} -c {{source}} -o {{output}}"
- depsformat = "gcc"
- outputs = [
- "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
- ]
- description = "compile {{source}}"
- }
-
- tool("asm") {
- depfile = "{{output}}.d"
- command = "$cc_wrapper $cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}"
- depsformat = "gcc"
- outputs = [
- "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
- ]
- description = "assemble {{source}}"
- }
-
- tool("alink") {
- rspfile = "{{output}}.rsp"
- rspfile_content = "{{inputs}}"
- ar_py = rebase_path("ar.py")
- command = "$python $ar_py $ar {{output}} $rspfile"
- outputs = [
- "{{root_out_dir}}/{{target_output_name}}{{output_extension}}",
- ]
- default_output_extension = ".a"
- output_prefix = "lib"
- description = "link {{output}}"
- }
-
- tool("solink") {
- soname = "{{target_output_name}}{{output_extension}}"
-
- rpath = "-Wl,-soname,$soname"
- if (is_mac) {
- rpath = "-Wl,-install_name,@rpath/$soname"
- }
-
- command = "$cc_wrapper $cxx -shared {{ldflags}} {{inputs}} {{solibs}} {{libs}} $rpath -o {{output}}"
- outputs = [
- "{{root_out_dir}}/$soname",
- ]
- output_prefix = "lib"
- default_output_extension = ".so"
- description = "link {{output}}"
- }
-
- tool("link") {
- command = "$cc_wrapper $cxx {{ldflags}} {{inputs}} {{solibs}} {{libs}} -o {{output}}"
- outputs = [
- "{{root_out_dir}}/{{target_output_name}}{{output_extension}}",
- ]
- description = "link {{output}}"
- }
-
- tool("stamp") {
- command = "$stamp {{output}}"
- description = "stamp {{output}}"
- }
-
- tool("copy") {
- cp_py = rebase_path("cp.py")
- command = "$python $cp_py {{source}} {{output}}"
- description = "copy {{source}} {{output}}"
- }
-}
diff --git a/gn/BUILDCONFIG.gn b/gn/BUILDCONFIG.gn
index 2b3ae33292..43f66f8832 100644
--- a/gn/BUILDCONFIG.gn
+++ b/gn/BUILDCONFIG.gn
@@ -17,9 +17,21 @@ declare_args() {
ndk_api = 21
}
sanitize = ""
+
+ ar = "ar"
+ cc = "cc"
+ cxx = "c++"
+
+ msvc = 2015
}
declare_args() {
is_debug = !is_official_build
+
+ if (msvc == 2015) {
+ windk = "C:/Program Files (x86)/Microsoft Visual Studio 14.0"
+ } else {
+ windk = "C:/Program Files (x86)/Microsoft Visual Studio/2017/Professional"
+ }
}
assert(!(is_debug && is_official_build))
@@ -164,8 +176,12 @@ set_defaults("component") {
if (is_win) {
# Windows tool chain
- set_default_toolchain("//gn:msvc")
+ set_default_toolchain("//gn/toolchain:msvc")
+ default_toolchain_name = "msvc"
+ host_toolchain = "msvc"
} else {
# GCC-like toolchains, including Clang.
- set_default_toolchain("//gn:gcc_like")
+ set_default_toolchain("//gn/toolchain:gcc_like")
+ default_toolchain_name = "gcc_like"
+ host_toolchain = "gcc_like_host"
}
diff --git a/gn/compile_processors.py b/gn/compile_processors.py
new file mode 100755
index 0000000000..72f23febdd
--- /dev/null
+++ b/gn/compile_processors.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+#
+# Copyright 2017 Google Inc.
+#
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import subprocess
+import sys
+
+skslc = sys.argv[1]
+dst = sys.argv[2]
+processors = sys.argv[3:]
+for p in processors:
+ path, _ = os.path.splitext(p)
+ filename = os.path.split(path)[1]
+ subprocess.check_call([skslc, p, os.path.join(dst, filename + ".h")])
+ subprocess.check_call([skslc, p, os.path.join(dst, filename + ".cpp")])
diff --git a/gn/sksl.gni b/gn/sksl.gni
index a1cab827ff..d13393025c 100644
--- a/gn/sksl.gni
+++ b/gn/sksl.gni
@@ -11,11 +11,16 @@ skia_sksl_sources = [
"$_src/sksl/SkSLCompiler.cpp",
"$_src/sksl/SkSLIRGenerator.cpp",
"$_src/sksl/SkSLParser.cpp",
+ "$_src/sksl/SkSLCPPCodeGenerator.cpp",
+ "$_src/sksl/SkSLHCodeGenerator.cpp",
"$_src/sksl/SkSLGLSLCodeGenerator.cpp",
"$_src/sksl/SkSLSPIRVCodeGenerator.cpp",
"$_src/sksl/SkSLString.cpp",
"$_src/sksl/SkSLUtil.cpp",
"$_src/sksl/lex.layout.cpp",
"$_src/sksl/ir/SkSLSymbolTable.cpp",
+ "$_src/sksl/ir/SkSLSetting.cpp",
"$_src/sksl/ir/SkSLType.cpp",
]
+
+skia_gpu_processor_sources = []
diff --git a/gn/tests.gni b/gn/tests.gni
index 6843a6f555..fde7df64eb 100644
--- a/gn/tests.gni
+++ b/gn/tests.gni
@@ -216,6 +216,7 @@ tests_sources = [
"$_tests/SkResourceCacheTest.cpp",
"$_tests/SkSharedMutexTest.cpp",
"$_tests/SkSLErrorTest.cpp",
+ "$_tests/SkSLFPTest.cpp",
"$_tests/SkSLGLSLTest.cpp",
"$_tests/SkSLMemoryLayoutTest.cpp",
"$_tests/SkSLSPIRVTest.cpp",
diff --git a/gn/toolchain/BUILD.gn b/gn/toolchain/BUILD.gn
new file mode 100644
index 0000000000..a4c13a7d69
--- /dev/null
+++ b/gn/toolchain/BUILD.gn
@@ -0,0 +1,301 @@
+declare_args() {
+ host_ar = ar
+ host_cc = cc
+ host_cxx = cxx
+
+ if (is_android) {
+ if (host_os == "win") {
+ target_ar = "$ndk/toolchains/$ndk_gccdir-4.9/prebuilt/$ndk_host/$ndk_target/bin/ar.exe"
+ target_cc = "$ndk/toolchains/llvm/prebuilt/$ndk_host/bin/clang.exe"
+ target_cxx = "$ndk/toolchains/llvm/prebuilt/$ndk_host/bin/clang++.exe"
+ } else {
+ target_ar = "$ndk/toolchains/$ndk_gccdir-4.9/prebuilt/$ndk_host/$ndk_target/bin/ar"
+ target_cc = "$ndk/toolchains/llvm/prebuilt/$ndk_host/bin/clang"
+ target_cxx = "$ndk/toolchains/llvm/prebuilt/$ndk_host/bin/clang++"
+ }
+ } else {
+ target_ar = ar
+ target_cc = cc
+ target_cxx = cxx
+ }
+
+ cc_wrapper = ""
+}
+
+if (host_os == "win") {
+ python = "python.bat"
+ stamp = "cmd.exe /c echo >"
+} else {
+ python = "python"
+ stamp = "touch"
+}
+
+toolchain("msvc") {
+ lib_dir_switch = "/LIBPATH:"
+
+ if (msvc == 2015) {
+ bin = "$windk/VC/bin/amd64"
+ env_setup = ""
+ if (target_cpu == "x86") {
+ bin += "_x86"
+ env_setup = "cmd /c $windk/win_sdk/bin/SetEnv.cmd /x86 && "
+ }
+ } else {
+ bin = "$windk/VC/Tools/MSVC/14.10.25017/bin/HostX64/$target_cpu"
+ env_setup = ""
+ if (target_cpu == "x86") {
+ print("Be sure to run")
+ print("$windk/VC/Auxiliary/Build/vcvarsall.bat amd64_x86")
+ print("to set up your environment before running ninja.")
+ }
+ }
+
+ tool("asm") {
+ _ml = "ml"
+ if (target_cpu == "x64") {
+ _ml += "64"
+ }
+ command = "$env_setup$bin/$_ml.exe /nologo /c /Fo {{output}} {{source}}"
+ outputs = [
+ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj",
+ ]
+ description = "assemble {{source}}"
+ }
+
+ tool("cc") {
+ rspfile = "{{output}}.rsp"
+ precompiled_header_type = "msvc"
+ pdbname = "{{target_out_dir}}/{{label_name}}_c.pdb"
+
+ # Label names may have spaces so pdbname must be quoted.
+ command = "$env_setup$bin/cl.exe /nologo /showIncludes /FC @$rspfile /c {{source}} /Fo{{output}} /Fd\"$pdbname\""
+ depsformat = "msvc"
+ outputs = [
+ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj",
+ ]
+ rspfile_content = "{{defines}} {{include_dirs}} {{cflags}} {{cflags_c}}"
+ description = "compile {{source}}"
+ }
+
+ tool("cxx") {
+ rspfile = "{{output}}.rsp"
+ precompiled_header_type = "msvc"
+ pdbname = "{{target_out_dir}}/{{label_name}}_c.pdb"
+
+ # Label names may have spaces so pdbname must be quoted.
+ command = "$env_setup$bin/cl.exe /nologo /showIncludes /FC @$rspfile /c {{source}} /Fo{{output}} /Fd\"$pdbname\""
+ depsformat = "msvc"
+ outputs = [
+ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj",
+ ]
+ rspfile_content = "{{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}}"
+ description = "compile {{source}}"
+ }
+
+ tool("alink") {
+ rspfile = "{{output}}.rsp"
+
+ command = "$env_setup$bin/lib.exe /nologo /ignore:4221 {{arflags}} /OUT:{{output}} @$rspfile"
+ outputs = [
+ # Ignore {{output_extension}} and always use .lib, there's no reason to
+ # allow targets to override this extension on Windows.
+ "{{root_out_dir}}/{{target_output_name}}{{output_extension}}",
+ ]
+ default_output_extension = ".lib"
+ default_output_dir = "{{target_out_dir}}"
+
+ # inputs_newline works around a fixed per-line buffer size in the linker.
+ rspfile_content = "{{inputs_newline}}"
+ description = "link {{output}}"
+ }
+
+ tool("solink") {
+ dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
+ libname = "${dllname}.lib"
+ pdbname = "${dllname}.pdb"
+ rspfile = "${dllname}.rsp"
+
+ command = "$env_setup$bin/link.exe /nologo /IMPLIB:$libname /DLL /OUT:$dllname /PDB:$pdbname @$rspfile"
+ outputs = [
+ dllname,
+ libname,
+ pdbname,
+ ]
+ default_output_extension = ".dll"
+ default_output_dir = "{{root_out_dir}}"
+
+ link_output = libname
+ depend_output = libname
+ runtime_outputs = [
+ dllname,
+ pdbname,
+ ]
+
+ # I don't quite understand this. Aping Chrome's toolchain/win/BUILD.gn.
+ restat = true
+
+ # inputs_newline works around a fixed per-line buffer size in the linker.
+ rspfile_content = "{{inputs_newline}} {{libs}} {{solibs}} {{ldflags}}"
+ description = "link {{output}}"
+ }
+
+ tool("link") {
+ exename = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"
+ pdbname = "$exename.pdb"
+ rspfile = "$exename.rsp"
+
+ command =
+ "$env_setup$bin/link.exe /nologo /OUT:$exename /PDB:$pdbname @$rspfile"
+
+ default_output_extension = ".exe"
+ default_output_dir = "{{root_out_dir}}"
+ outputs = [
+ exename,
+ ]
+
+ # inputs_newline works around a fixed per-line buffer size in the linker.
+ rspfile_content = "{{inputs_newline}} {{libs}} {{solibs}} {{ldflags}}"
+ description = "link {{output}}"
+ }
+
+ tool("stamp") {
+ command = "$stamp {{output}}"
+ description = "stamp {{output}}"
+ }
+
+ tool("copy") {
+ cp_py = rebase_path("../cp.py")
+ command = "$python $cp_py {{source}} {{output}}"
+ description = "copy {{source}} {{output}}"
+ }
+}
+
+template("gcc_like_toolchain") {
+ toolchain(target_name) {
+ ar = invoker.ar
+ cc = invoker.cc
+ cxx = invoker.cxx
+ lib_switch = "-l"
+ lib_dir_switch = "-L"
+
+ tool("cc") {
+ depfile = "{{output}}.d"
+ command = "$cc_wrapper $cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
+ depsformat = "gcc"
+ outputs = [
+ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+ ]
+ description = "compile {{source}}"
+ }
+
+ tool("cxx") {
+ depfile = "{{output}}.d"
+ command = "$cc_wrapper $cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}"
+ depsformat = "gcc"
+ outputs = [
+ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+ ]
+ description = "compile {{source}}"
+ }
+
+ tool("objc") {
+ depfile = "{{output}}.d"
+ command = "$cc_wrapper $cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_objc}} -c {{source}} -o {{output}}"
+ depsformat = "gcc"
+ outputs = [
+ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+ ]
+ description = "compile {{source}}"
+ }
+
+ tool("objcxx") {
+ depfile = "{{output}}.d"
+ command = "$cc_wrapper $cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} {{cflags_objc}} -c {{source}} -o {{output}}"
+ depsformat = "gcc"
+ outputs = [
+ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+ ]
+ description = "compile {{source}}"
+ }
+
+ tool("asm") {
+ depfile = "{{output}}.d"
+ command = "$cc_wrapper $cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}"
+ depsformat = "gcc"
+ outputs = [
+ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+ ]
+ description = "assemble {{source}}"
+ }
+
+ tool("alink") {
+ rspfile = "{{output}}.rsp"
+ rspfile_content = "{{inputs}}"
+ ar_py = rebase_path("../ar.py")
+ command = "$python $ar_py $ar {{output}} $rspfile"
+ outputs = [
+ "{{root_out_dir}}/{{target_output_name}}{{output_extension}}",
+ ]
+ default_output_extension = ".a"
+ output_prefix = "lib"
+ description = "link {{output}}"
+ }
+
+ tool("solink") {
+ soname = "{{target_output_name}}{{output_extension}}"
+
+ rpath = "-Wl,-soname,$soname"
+ if (is_mac) {
+ rpath = "-Wl,-install_name,@rpath/$soname"
+ }
+
+ command = "$cc_wrapper $cxx -shared {{ldflags}} {{inputs}} {{solibs}} {{libs}} $rpath -o {{output}}"
+ outputs = [
+ "{{root_out_dir}}/$soname",
+ ]
+ output_prefix = "lib"
+ default_output_extension = ".so"
+ description = "link {{output}}"
+ }
+
+ tool("link") {
+ command = "$cc_wrapper $cxx {{ldflags}} {{inputs}} {{solibs}} {{libs}} -o {{output}}"
+ outputs = [
+ "{{root_out_dir}}/{{target_output_name}}{{output_extension}}",
+ ]
+ description = "link {{output}}"
+ }
+
+ tool("stamp") {
+ command = "$stamp {{output}}"
+ description = "stamp {{output}}"
+ }
+
+ tool("copy") {
+ cp_py = rebase_path("../cp.py")
+ command = "$python $cp_py {{source}} {{output}}"
+ description = "copy {{source}} {{output}}"
+ }
+
+ toolchain_args = {
+ current_cpu = invoker.cpu
+ current_os = invoker.os
+ }
+ }
+}
+
+gcc_like_toolchain("gcc_like") {
+ cpu = current_cpu
+ os = current_os
+ ar = target_ar
+ cc = target_cc
+ cxx = target_cxx
+}
+
+gcc_like_toolchain("gcc_like_host") {
+ cpu = host_cpu
+ os = host_os
+ ar = host_ar
+ cc = host_cc
+ cxx = host_cxx
+}
diff --git a/src/sksl/README b/src/sksl/README
index a16dd80858..0c1712dc08 100644
--- a/src/sksl/README
+++ b/src/sksl/README
@@ -9,6 +9,7 @@ in GLSL "in the wild", but it does bring a few of its own changes to the table.
Skia uses the SkSL compiler to convert SkSL code to GLSL, GLSL ES, or SPIR-V
before handing it over to the graphics driver.
+
Differences from GLSL
=====================
@@ -56,3 +57,58 @@ following differences between SkSL and GLSL:
SkSL is still under development, and is expected to diverge further from GLSL
over time.
+
+
+SkSL Fragment Processors
+========================
+
+An extension of SkSL allows for the creation of fragment processors in pure
+SkSL. The program defines its inputs similarly to a normal SkSL program (with
+'in' and 'uniform' variables), but the 'main()' function represents only this
+fragment processor's portion of the overall fragment shader.
+
+Within an '.fp' fragment processor file:
+
+* C++ code can be embedded in sections of the form:
+
+ @section_name { <arbitrary C++ code> }
+
+ Supported section are:
+ @header (in the .h file, outside the class declaration)
+ @class (in the .h file, inside the class declaration)
+ @cpp (in the .cpp file)
+ @constructorParams (extra parameters to the constructor, comma-separated)
+ @constructor (replaces the default constructor)
+ @initializers (constructor initializer list, comma-separated)
+ @emitCode (extra code for the emitCode function)
+ @fields (extra private fields, each terminated with a semicolon)
+ @make (replaces the default Make function)
+ @setData(<pdman>) (extra code for the setData function, where <pdman> is
+ the name of the GrGLSLProgramDataManager)
+ @test(<testData>) (the body of the TestCreate function, where <testData> is
+ the name of the GrProcessorTestData* parameter)
+* global 'in' variables represent data passed to the fragment processor at
+ construction time. These variables become constructor parameters and are
+ stored in fragment processor fields. vec2s map to SkPoints, and vec4s map to
+ SkRects (in x, y, width, height) order.
+* 'uniform' variables become, as one would expect, top-level uniforms. By
+ default they do not have any data provided to them; you will need to provide
+ them with data via the @setData section.
+* 'in uniform' variables are uniforms that are automatically wired up to
+ fragment processor constructor parameters
+* the 'sk_TransformedCoords2D' array provides access to 2D transformed
+ coordinates. sk_TransformedCoords2D[0] is equivalent to calling
+ fragBuilder->ensureCoords2D(args.fTransformedCoords[0]) (and the result is
+ cached, so you need not worry about using the value repeatedly).
+* 'colorSpaceXform' is a supported type. It is reflected within SkSL as a mat4,
+ and on the C++ side as sk_sp<GrColorSpaceXform>.
+* the texture() function can be passed a colorSpaceXform as an additional
+ parameter
+* Uniform variables support an additional 'when' layout key.
+ 'layout(when=foo) uniform int x;' means that this uniform will only be
+ emitted when the 'foo' expression is true.
+* 'in' variables support an additional 'key' layout key.
+ 'layout(key) uniform int x;' means that this uniform should be included in
+ the program's key. Matrix variables additionally support 'key=identity',
+ which causes the key to consider only whether or not the matrix is an
+ identity matrix.
diff --git a/src/sksl/SkSLCFGGenerator.cpp b/src/sksl/SkSLCFGGenerator.cpp
index df10c62b7a..e8964db0bc 100644
--- a/src/sksl/SkSLCFGGenerator.cpp
+++ b/src/sksl/SkSLCFGGenerator.cpp
@@ -231,6 +231,7 @@ bool BasicBlock::tryRemoveExpression(std::vector<BasicBlock::Node>::iterator* it
case Expression::kBoolLiteral_Kind: // fall through
case Expression::kFloatLiteral_Kind: // fall through
case Expression::kIntLiteral_Kind: // fall through
+ case Expression::kSetting_Kind: // fall through
case Expression::kVariableReference_Kind:
*iter = fNodes.erase(*iter);
return true;
@@ -380,6 +381,7 @@ void CFGGenerator::addExpression(CFG& cfg, std::unique_ptr<Expression>* e, bool
case Expression::kBoolLiteral_Kind: // fall through
case Expression::kFloatLiteral_Kind: // fall through
case Expression::kIntLiteral_Kind: // fall through
+ case Expression::kSetting_Kind: // fall through
case Expression::kVariableReference_Kind:
cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
constantPropagate, e, nullptr });
diff --git a/src/sksl/SkSLCPP.h b/src/sksl/SkSLCPP.h
new file mode 100644
index 0000000000..47f8a4080b
--- /dev/null
+++ b/src/sksl/SkSLCPP.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SKSL_CPP
+#define SKSL_CPP
+
+// functions used by CPP programs created by skslc
+
+#include "SkPoint.h"
+
+// macros to make sk_Caps.<cap name> work from C++ code
+#define sk_Caps (*args.fShaderCaps)
+
+#define floatPrecisionVaries floatPrecisionVaries()
+
+// functions to make GLSL constructors work from C++ code
+inline SkPoint vec2(float xy) { return SkPoint::Make(xy, xy); }
+
+inline SkPoint vec2(float x, float y) { return SkPoint::Make(x, y); }
+
+#endif
diff --git a/src/sksl/SkSLCPPCodeGenerator.cpp b/src/sksl/SkSLCPPCodeGenerator.cpp
new file mode 100644
index 0000000000..c317b4ec66
--- /dev/null
+++ b/src/sksl/SkSLCPPCodeGenerator.cpp
@@ -0,0 +1,597 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkSLCPPCodeGenerator.h"
+
+#include "SkSLCompiler.h"
+#include "SkSLHCodeGenerator.h"
+
+namespace SkSL {
+
+static bool needs_uniform_var(const Variable& var) {
+ return (var.fModifiers.fFlags & Modifiers::kUniform_Flag) &&
+ strcmp(var.fType.fName.c_str(), "colorSpaceXform");
+}
+
+CPPCodeGenerator::CPPCodeGenerator(const Context* context, const Program* program,
+ ErrorReporter* errors, String name, OutputStream* out)
+: INHERITED(context, program, errors, out)
+, fName(std::move(name))
+, fFullName(String::printf("Gr%s", fName.c_str()))
+, fSectionAndParameterHelper(*program, *errors) {
+ fLineEnding = "\\n";
+}
+
+void CPPCodeGenerator::writef(const char* s, va_list va) {
+ static constexpr int BUFFER_SIZE = 1024;
+ char buffer[BUFFER_SIZE];
+ int length = vsnprintf(buffer, BUFFER_SIZE, s, va);
+ if (length < BUFFER_SIZE) {
+ fOut->write(buffer, length);
+ } else {
+ std::unique_ptr<char[]> heap(new char[length + 1]);
+ vsprintf(heap.get(), s, va);
+ fOut->write(heap.get(), length);
+ }
+}
+
+void CPPCodeGenerator::writef(const char* s, ...) {
+ va_list va;
+ va_start(va, s);
+ this->writef(s, va);
+ va_end(va);
+}
+
+void CPPCodeGenerator::writeHeader() {
+}
+
+void CPPCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
+ Precedence parentPrecedence) {
+ if (b.fOperator == Token::PERCENT) {
+ // need to use "%%" instead of "%" b/c the code will be inside of a printf
+ Precedence precedence = GetBinaryPrecedence(b.fOperator);
+ if (precedence >= parentPrecedence) {
+ this->write("(");
+ }
+ this->writeExpression(*b.fLeft, precedence);
+ this->write(" %% ");
+ this->writeExpression(*b.fRight, precedence);
+ if (precedence >= parentPrecedence) {
+ this->write(")");
+ }
+ } else {
+ INHERITED::writeBinaryExpression(b, parentPrecedence);
+ }
+}
+
+void CPPCodeGenerator::writeIndexExpression(const IndexExpression& i) {
+ const Expression& base = *i.fBase;
+ if (base.fKind == Expression::kVariableReference_Kind) {
+ int builtin = ((VariableReference&) base).fVariable.fModifiers.fLayout.fBuiltin;
+ if (SK_TRANSFORMEDCOORDS2D_BUILTIN == builtin) {
+ this->write("%s");
+ if (i.fIndex->fKind != Expression::kIntLiteral_Kind) {
+ fErrors.error(i.fIndex->fPosition,
+ "index into sk_TransformedCoords2D must be an integer literal");
+ return;
+ }
+ int64_t index = ((IntLiteral&) *i.fIndex).fValue;
+ String name = "sk_TransformedCoords2D_" + to_string(index);
+ fFormatArgs.push_back(name + ".c_str()");
+ if (fWrittenTransformedCoords.find(index) == fWrittenTransformedCoords.end()) {
+ fExtraEmitCodeCode += " SkSL::String " + name +
+ " = fragBuilder->ensureCoords2D(args.fTransformedCoords[" +
+ to_string(index) + "]);\n";
+ fWrittenTransformedCoords.insert(index);
+ }
+ return;
+ } else if (SK_TEXTURESAMPLERS_BUILTIN == builtin) {
+ this->write("%s");
+ if (i.fIndex->fKind != Expression::kIntLiteral_Kind) {
+ fErrors.error(i.fIndex->fPosition,
+ "index into sk_TextureSamplers must be an integer literal");
+ return;
+ }
+ int64_t index = ((IntLiteral&) *i.fIndex).fValue;
+ fFormatArgs.push_back(" fragBuilder->getProgramBuilder()->samplerVariable("
+ "args.fTexSamplers[" + to_string(index) + "]).c_str()");
+ return;
+ }
+ }
+ INHERITED::writeIndexExpression(i);
+}
+
+static const char* default_value(const Type& type) {
+ const char* name = type.name().c_str();
+ if (!strcmp(name, "float")) {
+ return "0.0";
+ } else if (!strcmp(name, "vec2")) {
+ return "vec2(0.0)";
+ } else if (!strcmp(name, "vec3")) {
+ return "vec3(0.0)";
+ } else if (!strcmp(name, "vec4")) {
+ return "vec4(0.0)";
+ } else if (!strcmp(name, "mat4") || !strcmp(name, "colorSpaceXform")) {
+ return "mat4(1.0)";
+ }
+ ABORT("unsupported default_value type\n");
+}
+
+static bool is_private(const Variable& var) {
+ return !(var.fModifiers.fFlags & Modifiers::kUniform_Flag) &&
+ !(var.fModifiers.fFlags & Modifiers::kIn_Flag) &&
+ var.fStorage == Variable::kGlobal_Storage &&
+ var.fModifiers.fLayout.fBuiltin == -1;
+}
+
+void CPPCodeGenerator::writeRuntimeValue(const Type& type, const String& cppCode) {
+ if (type == *fContext.fFloat_Type) {
+ this->write("%f");
+ fFormatArgs.push_back(cppCode);
+ } else if (type == *fContext.fInt_Type) {
+ this->write("%d");
+ fFormatArgs.push_back(cppCode);
+ } else if (type == *fContext.fBool_Type) {
+ this->write("%s");
+ fFormatArgs.push_back("(" + cppCode + " ? \"true\" : \"false\")");
+ } else if (type == *fContext.fVec2_Type) {
+ this->write("vec2(%f, %f)");
+ fFormatArgs.push_back(cppCode + ".fX");
+ fFormatArgs.push_back(cppCode + ".fY");
+ } else {
+ printf("%s\n", type.name().c_str());
+ ABORT("unsupported runtime value type\n");
+ }
+}
+
+void CPPCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
+ if (is_private(var)) {
+ this->writeRuntimeValue(var.fType, var.fName);
+ } else {
+ this->writeExpression(value, kTopLevel_Precedence);
+ }
+}
+
+void CPPCodeGenerator::writeVariableReference(const VariableReference& ref) {
+ switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
+ case SK_INCOLOR_BUILTIN:
+ this->write("%s");
+ fFormatArgs.push_back(String("args.fInputColor ? args.fInputColor : \"vec4(1)\""));
+ break;
+ case SK_OUTCOLOR_BUILTIN:
+ this->write("%s");
+ fFormatArgs.push_back(String("args.fOutputColor"));
+ break;
+ default:
+ if (ref.fVariable.fType.kind() == Type::kSampler_Kind) {
+ int samplerCount = 0;
+ for (const auto param : fSectionAndParameterHelper.fParameters) {
+ if (&ref.fVariable == param) {
+ this->write("%s");
+ fFormatArgs.push_back("fragBuilder->getProgramBuilder()->samplerVariable("
+ "args.fTexSamplers[" + to_string(samplerCount) +
+ "]).c_str()");
+ return;
+ }
+ if (param->fType.kind() == Type::kSampler_Kind) {
+ ++samplerCount;
+ }
+ }
+ ABORT("should have found sampler in parameters\n");
+ }
+ if (ref.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag) {
+ this->write("%s");
+ String name = ref.fVariable.fName;
+ String var;
+ if (ref.fVariable.fType == *fContext.fColorSpaceXform_Type) {
+ ASSERT(fNeedColorSpaceHelper);
+ var = String::printf("fColorSpaceHelper.isValid() ? "
+ "args.fUniformHandler->getUniformCStr("
+ "fColorSpaceHelper.gamutXformUniform()) : \"%s\"",
+ default_value(ref.fVariable.fType));
+ } else {
+ var = String::printf("args.fUniformHandler->getUniformCStr(%sVar)",
+ HCodeGenerator::FieldName(name.c_str()).c_str());
+ }
+ String code;
+ if (ref.fVariable.fModifiers.fLayout.fWhen.size()) {
+ code = String::printf("%sVar.isValid() ? %s : \"%s\"",
+ HCodeGenerator::FieldName(name.c_str()).c_str(),
+ var.c_str(),
+ default_value(ref.fVariable.fType));
+ } else {
+ code = var;
+ }
+ fFormatArgs.push_back(code);
+ } else if (SectionAndParameterHelper::IsParameter(ref.fVariable)) {
+ const char* name = ref.fVariable.fName.c_str();
+ this->writeRuntimeValue(ref.fVariable.fType,
+ String::printf("_outer.%s()", name).c_str());
+ } else {
+ this->write(ref.fVariable.fName.c_str());
+ }
+ }
+}
+
+void CPPCodeGenerator::writeFunction(const FunctionDefinition& f) {
+ if (f.fDeclaration.fName == "main") {
+ fFunctionHeader = "";
+ OutputStream* oldOut = fOut;
+ StringStream buffer;
+ fOut = &buffer;
+ for (const auto& s : ((Block&) *f.fBody).fStatements) {
+ this->writeStatement(*s);
+ this->writeLine();
+ }
+
+ fOut = oldOut;
+ this->write(fFunctionHeader);
+ this->write(buffer.str());
+ } else {
+ INHERITED::writeFunction(f);
+ }
+}
+
+void CPPCodeGenerator::writeSetting(const Setting& s) {
+ static constexpr const char* kPrefix = "sk_Args.";
+ if (!strncmp(s.fName.c_str(), kPrefix, strlen(kPrefix))) {
+ const char* name = s.fName.c_str() + strlen(kPrefix);
+ this->writeRuntimeValue(s.fType, HCodeGenerator::FieldName(name).c_str());
+ } else {
+ this->write(s.fName.c_str());
+ }
+}
+
+void CPPCodeGenerator::writeSection(const char* name, const char* prefix) {
+ const auto found = fSectionAndParameterHelper.fSections.find(String(name));
+ if (found != fSectionAndParameterHelper.fSections.end()) {
+ this->writef("%s%s", prefix, found->second->fText.c_str());
+ }
+}
+
+void CPPCodeGenerator::writeProgramElement(const ProgramElement& p) {
+ if (p.fKind == ProgramElement::kSection_Kind) {
+ return;
+ }
+ if (p.fKind == ProgramElement::kVar_Kind) {
+ const VarDeclarations& decls = (const VarDeclarations&) p;
+ if (!decls.fVars.size()) {
+ return;
+ }
+ const Variable& var = *((VarDeclaration&) *decls.fVars[0]).fVar;
+ if (var.fModifiers.fFlags & (Modifiers::kIn_Flag | Modifiers::kUniform_Flag) ||
+ -1 != var.fModifiers.fLayout.fBuiltin) {
+ return;
+ }
+ }
+ INHERITED::writeProgramElement(p);
+}
+
+void CPPCodeGenerator::addUniform(const Variable& var) {
+ if (!needs_uniform_var(var)) {
+ return;
+ }
+ const char* precision;
+ if (var.fModifiers.fFlags & Modifiers::kHighp_Flag) {
+ precision = "kHigh_GrSLPrecision";
+ } else if (var.fModifiers.fFlags & Modifiers::kMediump_Flag) {
+ precision = "kMedium_GrSLPrecision";
+ } else if (var.fModifiers.fFlags & Modifiers::kLowp_Flag) {
+ precision = "kLow_GrSLPrecision";
+ } else {
+ precision = "kDefault_GrSLPrecision";
+ }
+ const char* type;
+ if (var.fType == *fContext.fFloat_Type) {
+ type = "kFloat_GrSLType";
+ } else if (var.fType == *fContext.fVec2_Type) {
+ type = "kVec2f_GrSLType";
+ } else if (var.fType == *fContext.fVec4_Type) {
+ type = "kVec4f_GrSLType";
+ } else if (var.fType == *fContext.fMat4x4_Type ||
+ var.fType == *fContext.fColorSpaceXform_Type) {
+ type = "kMat44f_GrSLType";
+ } else {
+ ABORT("unsupported uniform type: %s %s;\n", var.fType.name().c_str(), var.fName.c_str());
+ }
+ if (var.fModifiers.fLayout.fWhen.size()) {
+ this->writef(" if (%s) {\n ", var.fModifiers.fLayout.fWhen.c_str());
+ }
+ const char* name = var.fName.c_str();
+ this->writef(" %sVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, %s, "
+ "%s, \"%s\");\n", HCodeGenerator::FieldName(name).c_str(), type, precision, name);
+ if (var.fModifiers.fLayout.fWhen.size()) {
+ this->write(" }\n");
+ }
+}
+
+void CPPCodeGenerator::writePrivateVars() {
+ for (const auto& p : fProgram.fElements) {
+ if (ProgramElement::kVar_Kind == p->fKind) {
+ const VarDeclarations* decls = (const VarDeclarations*) p.get();
+ for (const auto& raw : decls->fVars) {
+ VarDeclaration& decl = (VarDeclaration&) *raw;
+ if (is_private(*decl.fVar)) {
+ this->writef("%s %s;\n",
+ HCodeGenerator::FieldType(decl.fVar->fType).c_str(),
+ decl.fVar->fName.c_str());
+ }
+ }
+ }
+ }
+}
+
+void CPPCodeGenerator::writePrivateVarValues() {
+ for (const auto& p : fProgram.fElements) {
+ if (ProgramElement::kVar_Kind == p->fKind) {
+ const VarDeclarations* decls = (const VarDeclarations*) p.get();
+ for (const auto& raw : decls->fVars) {
+ VarDeclaration& decl = (VarDeclaration&) *raw;
+ if (is_private(*decl.fVar) && decl.fValue) {
+ this->writef("%s = %s;\n",
+ decl.fVar->fName.c_str(),
+ decl.fValue->description().c_str());
+ }
+ }
+ }
+ }
+}
+
+bool CPPCodeGenerator::writeEmitCode(std::vector<const Variable*>& uniforms) {
+ this->write(" void emitCode(EmitArgs& args) override {\n"
+ " GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;\n");
+ this->writef(" const %s& _outer = args.fFp.cast<%s>();\n"
+ " (void) _outer;\n",
+ fFullName.c_str(), fFullName.c_str());
+ this->writePrivateVarValues();
+ for (const auto u : uniforms) {
+ this->addUniform(*u);
+ if (u->fType == *fContext.fColorSpaceXform_Type) {
+ if (fNeedColorSpaceHelper) {
+ fErrors.error(u->fPosition, "only a single ColorSpaceXform is supported");
+ }
+ fNeedColorSpaceHelper = true;
+ this->writef(" fColorSpaceHelper.emitCode(args.fUniformHandler, "
+ "_outer.%s().get());\n",
+ u->fName.c_str());
+ }
+ }
+ this->writeSection(EMIT_CODE_SECTION);
+ OutputStream* old = fOut;
+ StringStream mainBuffer;
+ fOut = &mainBuffer;
+ bool result = INHERITED::generateCode();
+ fOut = old;
+ this->writef("%s fragBuilder->codeAppendf(\"%s\"", fExtraEmitCodeCode.c_str(),
+ mainBuffer.str().c_str());
+ for (const auto& s : fFormatArgs) {
+ this->writef(", %s", s.c_str());
+ }
+ this->write(");\n"
+ " }\n");
+ return result;
+}
+
+void CPPCodeGenerator::writeSetData(std::vector<const Variable*>& uniforms) {
+ const char* fullName = fFullName.c_str();
+ auto section = fSectionAndParameterHelper.fSections.find(String(SET_DATA_SECTION));
+ const char* pdman = section != fSectionAndParameterHelper.fSections.end() ?
+ section->second->fArgument.c_str() :
+ "pdman";
+ this->writef(" void onSetData(const GrGLSLProgramDataManager& %s, "
+ "const GrFragmentProcessor& _proc) override {\n",
+ pdman);
+ bool wroteProcessor = false;
+ for (const auto u : uniforms) {
+ if (u->fModifiers.fFlags & Modifiers::kIn_Flag) {
+ if (!wroteProcessor) {
+ this->writef(" const %s& _outer = _proc.cast<%s>();\n", fullName, fullName);
+ wroteProcessor = true;
+ this->writef(" {\n");
+ }
+ const char* name = u->fName.c_str();
+ if (u->fType == *fContext.fVec4_Type) {
+ this->writef(" const SkRect %sValue = _outer.%s();\n"
+ " %s.set4fv(%sVar, 4, (float*) &%sValue);\n",
+ name, name, pdman, HCodeGenerator::FieldName(name).c_str(), name);
+ } else if (u->fType == *fContext.fMat4x4_Type) {
+ this->writef(" float %sValue[16];\n"
+ " _outer.%s().asColMajorf(%sValue);\n"
+ " %s.setMatrix4f(%sVar, %sValue);\n",
+ name, name, name, pdman, HCodeGenerator::FieldName(name).c_str(),
+ name);
+ } else if (u->fType == *fContext.fColorSpaceXform_Type) {
+ ASSERT(fNeedColorSpaceHelper);
+ this->writef(" if (fColorSpaceHelper.isValid()) {\n"
+ " fColorSpaceHelper.setData(%s, _outer.%s().get());\n"
+ " }\n",
+ pdman, name);
+ } else {
+ this->writef(" %s.set1f(%sVar, _outer.%s());\n",
+ pdman, HCodeGenerator::FieldName(name).c_str(), name);
+ }
+ }
+ }
+ if (wroteProcessor) {
+ this->writef(" }\n");
+ }
+ if (section != fSectionAndParameterHelper.fSections.end()) {
+ for (const auto& p : fProgram.fElements) {
+ if (ProgramElement::kVar_Kind == p->fKind) {
+ const VarDeclarations* decls = (const VarDeclarations*) p.get();
+ for (const auto& raw : decls->fVars) {
+ VarDeclaration& decl = (VarDeclaration&) *raw;
+ if (needs_uniform_var(*decl.fVar)) {
+ const char* name = decl.fVar->fName.c_str();
+ this->writef(" UniformHandle& %s = %sVar;\n"
+ " (void) %s;\n",
+ name, HCodeGenerator::FieldName(name).c_str(), name);
+ } else if (SectionAndParameterHelper::IsParameter(*decl.fVar)) {
+ const char* name = decl.fVar->fName.c_str();
+ if (!wroteProcessor) {
+ this->writef(" const %s& _outer = _proc.cast<%s>();\n", fullName,
+ fullName);
+ wroteProcessor = true;
+ }
+ this->writef(" auto %s = _outer.%s();\n"
+ " (void) %s;\n",
+ name, name, name);
+ }
+ }
+ }
+ }
+ this->writeSection(SET_DATA_SECTION);
+ }
+ this->write(" }\n");
+}
+
+void CPPCodeGenerator::writeTest() {
+ const auto found = fSectionAndParameterHelper.fSections.find(TEST_CODE_SECTION);
+ if (found == fSectionAndParameterHelper.fSections.end()) {
+ return;
+ }
+ const Section* test = found->second;
+ this->writef("GR_DEFINE_FRAGMENT_PROCESSOR_TEST(%s);\n"
+ "#if GR_TEST_UTILS\n"
+ "sk_sp<GrFragmentProcessor> %s::TestCreate(GrProcessorTestData* %s) {\n",
+ fFullName.c_str(),
+ fFullName.c_str(),
+ test->fArgument.c_str());
+ this->writeSection(TEST_CODE_SECTION);
+ this->write("}\n"
+ "#endif\n");
+}
+
+void CPPCodeGenerator::writeGetKey() {
+ this->writef("void %s::onGetGLSLProcessorKey(const GrShaderCaps& caps, "
+ "GrProcessorKeyBuilder* b) const {\n",
+ fFullName.c_str());
+ for (const auto& param : fSectionAndParameterHelper.fParameters) {
+ const char* name = param->fName.c_str();
+ if (param->fType == *fContext.fColorSpaceXform_Type) {
+ this->writef(" b->add32(GrColorSpaceXform::XformKey(%s.get()));\n",
+ HCodeGenerator::FieldName(name).c_str());
+ continue;
+ }
+ if (param->fModifiers.fLayout.fKey != Layout::kNo_Key &&
+ (param->fModifiers.fFlags & Modifiers::kUniform_Flag)) {
+ fErrors.error(param->fPosition,
+ "layout(key) may not be specified on uniforms");
+ }
+ switch (param->fModifiers.fLayout.fKey) {
+ case Layout::kKey_Key:
+ if (param->fType == *fContext.fMat4x4_Type) {
+ ABORT("no automatic key handling for mat4\n");
+ } else if (param->fType == *fContext.fVec2_Type) {
+ this->writef(" b->add32(%s.fX);\n",
+ HCodeGenerator::FieldName(name).c_str());
+ this->writef(" b->add32(%s.fY);\n",
+ HCodeGenerator::FieldName(name).c_str());
+ } else if (param->fType == *fContext.fVec4_Type) {
+ this->writef(" b->add32(%s.x());\n",
+ HCodeGenerator::FieldName(name).c_str());
+ this->writef(" b->add32(%s.y());\n",
+ HCodeGenerator::FieldName(name).c_str());
+ this->writef(" b->add32(%s.width());\n",
+ HCodeGenerator::FieldName(name).c_str());
+ this->writef(" b->add32(%s.height());\n",
+ HCodeGenerator::FieldName(name).c_str());
+ } else {
+ this->writef(" b->add32(%s);\n",
+ HCodeGenerator::FieldName(name).c_str());
+ }
+ break;
+ case Layout::kIdentity_Key:
+ if (param->fType.kind() != Type::kMatrix_Kind) {
+ fErrors.error(param->fPosition,
+ "layout(key=identity) requires matrix type");
+ }
+ this->writef(" b->add32(%s.isIdentity() ? 1 : 0);\n",
+ HCodeGenerator::FieldName(name).c_str());
+ break;
+ case Layout::kNo_Key:
+ break;
+ }
+ }
+ this->write("}\n");
+}
+
+bool CPPCodeGenerator::generateCode() {
+ std::vector<const Variable*> uniforms;
+ for (const auto& p : fProgram.fElements) {
+ if (ProgramElement::kVar_Kind == p->fKind) {
+ const VarDeclarations* decls = (const VarDeclarations*) p.get();
+ for (const auto& raw : decls->fVars) {
+ VarDeclaration& decl = (VarDeclaration&) *raw;
+ if ((decl.fVar->fModifiers.fFlags & Modifiers::kUniform_Flag) &&
+ decl.fVar->fType.kind() != Type::kSampler_Kind) {
+ uniforms.push_back(decl.fVar);
+ }
+ }
+ }
+ }
+ const char* baseName = fName.c_str();
+ const char* fullName = fFullName.c_str();
+ this->writef("/*\n"
+ " * This file was autogenerated from %s.fp.\n"
+ " */\n"
+ "#include \"%s.h\"\n"
+ "#include \"glsl/GrGLSLColorSpaceXformHelper.h\"\n"
+ "#include \"glsl/GrGLSLFragmentProcessor.h\"\n"
+ "#include \"glsl/GrGLSLFragmentShaderBuilder.h\"\n"
+ "#include \"glsl/GrGLSLProgramBuilder.h\"\n"
+ "#include \"GrResourceProvider.h\"\n"
+ "#include \"SkSLCPP.h\"\n"
+ "#include \"SkSLUtil.h\"\n"
+ "class GrGLSL%s : public GrGLSLFragmentProcessor {\n"
+ "public:\n"
+ " GrGLSL%s() {}\n",
+ fullName, fullName, baseName, baseName);
+ bool result = this->writeEmitCode(uniforms);
+ this->write("private:\n");
+ this->writeSetData(uniforms);
+ this->writePrivateVars();
+ for (const auto& u : uniforms) {
+ const char* name = u->fName.c_str();
+ if (needs_uniform_var(*u) && !(u->fModifiers.fFlags & Modifiers::kIn_Flag)) {
+ this->writef(" UniformHandle %sVar;\n", HCodeGenerator::FieldName(name).c_str());
+ }
+ }
+ for (const auto& param : fSectionAndParameterHelper.fParameters) {
+ const char* name = param->fName.c_str();
+ if (needs_uniform_var(*param)) {
+ this->writef(" UniformHandle %sVar;\n", HCodeGenerator::FieldName(name).c_str());
+ }
+ }
+ if (fNeedColorSpaceHelper) {
+ this->write(" GrGLSLColorSpaceXformHelper fColorSpaceHelper;\n");
+ }
+ this->writef("};\n"
+ "GrGLSLFragmentProcessor* %s::onCreateGLSLInstance() const {\n"
+ " return new GrGLSL%s();\n"
+ "}\n",
+ fullName, baseName);
+ this->writeGetKey();
+ this->writef("bool %s::onIsEqual(const GrFragmentProcessor& other) const {\n"
+ " const %s& that = other.cast<%s>();\n"
+ " (void) that;\n",
+ fullName, fullName, fullName);
+ for (const auto& param : fSectionAndParameterHelper.fParameters) {
+ const char* name = param->fName.c_str();
+ this->writef(" if (%s != that.%s) return false;\n",
+ HCodeGenerator::FieldName(name).c_str(),
+ HCodeGenerator::FieldName(name).c_str());
+ }
+ this->write(" return true;\n"
+ "}\n");
+ this->writeSection(CPP_SECTION);
+ this->writeTest();
+ result &= 0 == fErrors.errorCount();
+ return result;
+}
+
+} // namespace
diff --git a/src/sksl/SkSLCPPCodeGenerator.h b/src/sksl/SkSLCPPCodeGenerator.h
new file mode 100644
index 0000000000..74ee8f6289
--- /dev/null
+++ b/src/sksl/SkSLCPPCodeGenerator.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SKSL_CPPCODEGENERATOR
+#define SKSL_CPPCODEGENERATOR
+
+#include "SkSLGLSLCodeGenerator.h"
+#include "SkSLSectionAndParameterHelper.h"
+
+#include <set>
+
+namespace SkSL {
+
+class CPPCodeGenerator : public GLSLCodeGenerator {
+public:
+ CPPCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors,
+ String name, OutputStream* out);
+
+ bool generateCode() override;
+
+private:
+ void writef(const char* s, va_list va) SKSL_PRINTF_LIKE(2, 0);
+
+ void writef(const char* s, ...) SKSL_PRINTF_LIKE(2, 3);
+
+ void writeSection(const char* name, const char* prefix = "");
+
+ void writeHeader() override;
+
+ void writeBinaryExpression(const BinaryExpression& b, Precedence parentPrecedence) override;
+
+ void writeIndexExpression(const IndexExpression& i) override;
+
+ void writeVariableReference(const VariableReference& ref) override;
+
+ void writeFunction(const FunctionDefinition& f) override;
+
+ void writeSetting(const Setting& s) override;
+
+ void writeProgramElement(const ProgramElement& p) override;
+
+ void addUniform(const Variable& var);
+
+ // writes a printf escape that will be filled in at runtime by the given C++ expression string
+ void writeRuntimeValue(const Type& type, const String& cppCode);
+
+ void writeVarInitializer(const Variable& var, const Expression& value) override;
+
+ void writePrivateVars();
+
+ void writePrivateVarValues();
+
+ bool writeEmitCode(std::vector<const Variable*>& uniforms);
+
+ void writeSetData(std::vector<const Variable*>& uniforms);
+
+ void writeGetKey();
+
+ void writeTest();
+
+ String fName;
+ String fFullName;
+ SectionAndParameterHelper fSectionAndParameterHelper;
+ String fExtraEmitCodeCode;
+ std::vector<String> fFormatArgs;
+ std::set<int> fWrittenTransformedCoords;
+ bool fNeedColorSpaceHelper = false;
+
+ typedef GLSLCodeGenerator INHERITED;
+};
+
+}
+
+#endif
diff --git a/src/sksl/SkSLCodeGenerator.h b/src/sksl/SkSLCodeGenerator.h
index f6f990503c..1f577b58b1 100644
--- a/src/sksl/SkSLCodeGenerator.h
+++ b/src/sksl/SkSLCodeGenerator.h
@@ -9,6 +9,7 @@
#define SKSL_CODEGENERATOR
#include "ir/SkSLProgram.h"
+#include "SkSLOutputStream.h"
namespace SkSL {
diff --git a/src/sksl/SkSLCompiler.cpp b/src/sksl/SkSLCompiler.cpp
index 39ac31532e..593397bd2a 100644
--- a/src/sksl/SkSLCompiler.cpp
+++ b/src/sksl/SkSLCompiler.cpp
@@ -8,7 +8,9 @@
#include "SkSLCompiler.h"
#include "SkSLCFGGenerator.h"
+#include "SkSLCPPCodeGenerator.h"
#include "SkSLGLSLCodeGenerator.h"
+#include "SkSLHCodeGenerator.h"
#include "SkSLIRGenerator.h"
#include "SkSLSPIRVCodeGenerator.h"
#include "ir/SkSLExpression.h"
@@ -45,6 +47,11 @@ static const char* SKSL_GEOM_INCLUDE =
#include "sksl_geom.include"
;
+static const char* SKSL_FP_INCLUDE =
+#include "sksl_fp.include"
+;
+
+
namespace SkSL {
Compiler::Compiler()
@@ -146,12 +153,18 @@ Compiler::Compiler()
ADD_TYPE(SamplerCubeArrayShadow);
ADD_TYPE(GSampler2DArrayShadow);
ADD_TYPE(GSamplerCubeArrayShadow);
+ ADD_TYPE(ColorSpaceXform);
String skCapsName("sk_Caps");
Variable* skCaps = new Variable(Position(), Modifiers(), skCapsName,
*fContext.fSkCaps_Type, Variable::kGlobal_Storage);
fIRGenerator->fSymbolTable->add(skCapsName, std::unique_ptr<Symbol>(skCaps));
+ String skArgsName("sk_Args");
+ Variable* skArgs = new Variable(Position(), Modifiers(), skArgsName,
+ *fContext.fSkArgs_Type, Variable::kGlobal_Storage);
+ fIRGenerator->fSymbolTable->add(skArgsName, std::unique_ptr<Symbol>(skArgs));
+
Modifiers::Flag ignored1;
std::vector<std::unique_ptr<ProgramElement>> ignored2;
fIRGenerator->convertProgram(String(SKSL_INCLUDE), *fTypes, &ignored1, &ignored2);
@@ -778,7 +791,6 @@ void Compiler::simplifyExpression(DefinitionMap& definitions,
}
}
-
// returns true if this statement could potentially execute a break at the current level (we ignore
// nested loops and switches, since any breaks inside of them will merely break the loop / switch)
static bool contains_break(Statement& s) {
@@ -1097,6 +1109,9 @@ std::unique_ptr<Program> Compiler::convertProgram(Program::Kind kind, String tex
case Program::kGeometry_Kind:
fIRGenerator->convertProgram(String(SKSL_GEOM_INCLUDE), *fTypes, &ignored, &elements);
break;
+ case Program::kFragmentProcessor_Kind:
+ fIRGenerator->convertProgram(String(SKSL_FP_INCLUDE), *fTypes, &ignored, &elements);
+ break;
}
fIRGenerator->fSymbolTable->markAllFunctionsBuiltin();
Modifiers::Flag defaultPrecision;
@@ -1127,15 +1142,16 @@ bool Compiler::toSPIRV(const Program& program, OutputStream& out) {
bool result = cg.generateCode();
if (result) {
spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
- ASSERT(0 == buffer.size() % 4);
+ const String& data = buffer.str();
+ ASSERT(0 == data.size() % 4);
auto dumpmsg = [](spv_message_level_t, const char*, const spv_position_t&, const char* m) {
SkDebugf("SPIR-V validation error: %s\n", m);
};
tools.SetMessageConsumer(dumpmsg);
// Verify that the SPIR-V we produced is valid. If this assert fails, check the logs prior
// to the failure to see the validation errors.
- ASSERT_RESULT(tools.Validate((const uint32_t*) buffer.data(), buffer.size() / 4));
- out.write(buffer.data(), buffer.size());
+ ASSERT_RESULT(tools.Validate((const uint32_t*) data.c_str(), data.size() / 4));
+ out.write(data.c_str(), data.size());
}
#else
SPIRVCodeGenerator cg(&fContext, &program, this, &out);
@@ -1149,7 +1165,7 @@ bool Compiler::toSPIRV(const Program& program, String* out) {
StringStream buffer;
bool result = this->toSPIRV(program, buffer);
if (result) {
- *out = String(buffer.data(), buffer.size());
+ *out = buffer.str();
}
return result;
}
@@ -1165,11 +1181,24 @@ bool Compiler::toGLSL(const Program& program, String* out) {
StringStream buffer;
bool result = this->toGLSL(program, buffer);
if (result) {
- *out = String(buffer.data(), buffer.size());
+ *out = buffer.str();
}
return result;
}
+bool Compiler::toCPP(const Program& program, String name, OutputStream& out) {
+ CPPCodeGenerator cg(&fContext, &program, this, name, &out);
+ bool result = cg.generateCode();
+ this->writeErrorCount();
+ return result;
+}
+
+bool Compiler::toH(const Program& program, String name, OutputStream& out) {
+ HCodeGenerator cg(&program, this, name, &out);
+ bool result = cg.generateCode();
+ this->writeErrorCount();
+ return result;
+}
void Compiler::error(Position position, String msg) {
fErrorCount++;
diff --git a/src/sksl/SkSLCompiler.h b/src/sksl/SkSLCompiler.h
index bc9a1964ac..2acb55958f 100644
--- a/src/sksl/SkSLCompiler.h
+++ b/src/sksl/SkSLCompiler.h
@@ -18,12 +18,16 @@
#include "SkSLErrorReporter.h"
#include "SkSLIRGenerator.h"
-#define SK_FRAGCOLOR_BUILTIN 10001
-#define SK_IN_BUILTIN 10002
-#define SK_FRAGCOORD_BUILTIN 15
-#define SK_VERTEXID_BUILTIN 5
-#define SK_CLIPDISTANCE_BUILTIN 3
-#define SK_INVOCATIONID_BUILTIN 8
+#define SK_FRAGCOLOR_BUILTIN 10001
+#define SK_IN_BUILTIN 10002
+#define SK_INCOLOR_BUILTIN 10003
+#define SK_OUTCOLOR_BUILTIN 10004
+#define SK_TRANSFORMEDCOORDS2D_BUILTIN 10005
+#define SK_TEXTURESAMPLERS_BUILTIN 10006
+#define SK_FRAGCOORD_BUILTIN 15
+#define SK_VERTEXID_BUILTIN 5
+#define SK_CLIPDISTANCE_BUILTIN 3
+#define SK_INVOCATIONID_BUILTIN 8
namespace SkSL {
@@ -54,6 +58,10 @@ public:
bool toGLSL(const Program& program, String* out);
+ bool toCPP(const Program& program, String name, OutputStream& out);
+
+ bool toH(const Program& program, String name, OutputStream& out);
+
void error(Position position, String msg) override;
String errorText();
diff --git a/src/sksl/SkSLContext.h b/src/sksl/SkSLContext.h
index 53e5ea0954..1155af4817 100644
--- a/src/sksl/SkSLContext.h
+++ b/src/sksl/SkSLContext.h
@@ -66,8 +66,7 @@ public:
, fSamplerExternalOES_Type(new Type(String("samplerExternalOES"), SpvDim2D, false, false,
false, true))
, fSamplerCube_Type(new Type(String("samplerCube"), SpvDimCube, false, false, false, true))
- , fSampler2DRect_Type(new Type(String("sampler2DRect"), SpvDimRect, false, false, false,
- true))
+ , fSampler2DRect_Type(new Type(String("sampler2DRect"), SpvDimRect, false, false, false, true))
, fSampler1DArray_Type(new Type(String("sampler1DArray")))
, fSampler2DArray_Type(new Type(String("sampler2DArray")))
, fSamplerCubeArray_Type(new Type(String("samplerCubeArray")))
@@ -151,6 +150,8 @@ public:
, fBVec_Type(new Type(String("$bvec"), { fInvalid_Type.get(), fBVec2_Type.get(),
fBVec3_Type.get(), fBVec4_Type.get() }))
, fSkCaps_Type(new Type(String("$sk_Caps")))
+ , fSkArgs_Type(new Type(String("$sk_Args")))
+ , fColorSpaceXform_Type(new Type(String("colorSpaceXform"), *fFloat_Type, 4, 4))
, fDefined_Expression(new Defined(*fInvalid_Type)) {}
static std::vector<const Type*> static_type(const Type& t) {
@@ -225,7 +226,6 @@ public:
const std::unique_ptr<Type> fSampler2DArrayShadow_Type;
const std::unique_ptr<Type> fSamplerCubeArrayShadow_Type;
-
const std::unique_ptr<Type> fISampler2D_Type;
const std::unique_ptr<Type> fImage2D_Type;
@@ -269,6 +269,8 @@ public:
const std::unique_ptr<Type> fBVec_Type;
const std::unique_ptr<Type> fSkCaps_Type;
+ const std::unique_ptr<Type> fSkArgs_Type;
+ const std::unique_ptr<Type> fColorSpaceXform_Type;
// dummy expression used to mark that a variable has a value during dataflow analysis (when it
// could have several different values, or the analyzer is otherwise unable to assign it a
@@ -281,14 +283,14 @@ private:
Defined(const Type& type)
: INHERITED(Position(), kDefined_Kind, type) {}
- virtual String description() const override {
- return String("<defined>");
- }
-
bool hasSideEffects() const override {
return false;
}
+ String description() const override {
+ return String("<defined>");
+ }
+
typedef Expression INHERITED;
};
};
diff --git a/src/sksl/SkSLGLSLCodeGenerator.cpp b/src/sksl/SkSLGLSLCodeGenerator.cpp
index 4326f4c794..36a43cf927 100644
--- a/src/sksl/SkSLGLSLCodeGenerator.cpp
+++ b/src/sksl/SkSLGLSLCodeGenerator.cpp
@@ -34,7 +34,7 @@ void GLSLCodeGenerator::write(const char* s) {
void GLSLCodeGenerator::writeLine(const char* s) {
this->write(s);
- fOut->write8('\n');
+ fOut->writeText(fLineEnding);
fAtLineStart = true;
}
@@ -108,6 +108,9 @@ void GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence paren
case Expression::kPostfix_Kind:
this->writePostfixExpression((PostfixExpression&) expr, parentPrecedence);
break;
+ case Expression::kSetting_Kind:
+ this->writeSetting((Setting&) expr);
+ break;
case Expression::kSwizzle_Kind:
this->writeSwizzle((Swizzle&) expr);
break;
@@ -371,7 +374,7 @@ void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
}
}
-static GLSLCodeGenerator::Precedence get_binary_precedence(Token::Kind op) {
+GLSLCodeGenerator::Precedence GLSLCodeGenerator::GetBinaryPrecedence(Token::Kind op) {
switch (op) {
case Token::STAR: // fall through
case Token::SLASH: // fall through
@@ -413,7 +416,7 @@ static GLSLCodeGenerator::Precedence get_binary_precedence(Token::Kind op) {
void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
Precedence parentPrecedence) {
- Precedence precedence = get_binary_precedence(b.fOperator);
+ Precedence precedence = GetBinaryPrecedence(b.fOperator);
if (precedence >= parentPrecedence) {
this->write("(");
}
@@ -480,6 +483,10 @@ void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
this->write(to_string(f.fValue));
}
+void GLSLCodeGenerator::writeSetting(const Setting& s) {
+ ABORT("internal error; setting was not folded to a constant during compilation\n");
+}
+
void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
this->writeType(f.fDeclaration.fReturnType);
this->write(" " + f.fDeclaration.fName + "(");
@@ -517,7 +524,7 @@ void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
fOut = oldOut;
this->write(fFunctionHeader);
- this->write(String(buffer.data(), buffer.size()));
+ this->write(buffer.str());
}
void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
@@ -617,6 +624,10 @@ void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
this->writeLine(";");
}
+void GLSLCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
+ this->writeExpression(value, kTopLevel_Precedence);
+}
+
void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
ASSERT(decl.fVars.size() > 0);
bool wroteType = false;
@@ -640,7 +651,7 @@ void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool g
}
if (var.fValue) {
this->write(" = ");
- this->writeExpression(*var.fValue, kTopLevel_Precedence);
+ this->writeVarInitializer(*var.fVar, *var.fValue);
}
if (!fFoundImageDecl && var.fVar->fType == *fContext.fImage2D_Type) {
if (fProgram.fSettings.fCaps->imageLoadStoreExtensionString()) {
@@ -797,10 +808,7 @@ void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
this->write(";");
}
-bool GLSLCodeGenerator::generateCode() {
- OutputStream* rawOut = fOut;
- fOut = &fHeader;
- fProgramKind = fProgram.fKind;
+void GLSLCodeGenerator::writeHeader() {
this->write(fProgram.fSettings.fCaps->versionDeclString());
this->writeLine();
for (const auto& e : fProgram.fElements) {
@@ -808,8 +816,6 @@ bool GLSLCodeGenerator::generateCode() {
this->writeExtension((Extension&) *e);
}
}
- StringStream body;
- fOut = &body;
if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
this->write("precision ");
switch (fProgram.fDefaultPrecision) {
@@ -828,47 +834,58 @@ bool GLSLCodeGenerator::generateCode() {
}
this->writeLine(" float;");
}
- for (const auto& e : fProgram.fElements) {
- switch (e->fKind) {
- case ProgramElement::kExtension_Kind:
- break;
- case ProgramElement::kVar_Kind: {
- VarDeclarations& decl = (VarDeclarations&) *e;
- if (decl.fVars.size() > 0) {
- ASSERT(decl.fVars[0]->fKind == Statement::kVarDeclaration_Kind);
- int builtin =
- ((VarDeclaration&) *decl.fVars[0]).fVar->fModifiers.fLayout.fBuiltin;
- if (builtin == -1) {
- // normal var
- this->writeVarDeclarations(decl, true);
- this->writeLine();
- } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
- fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
- this->write("out ");
- if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
- this->write("mediump ");
- }
- this->writeLine("vec4 sk_FragColor;");
+}
+
+void GLSLCodeGenerator::writeProgramElement(const ProgramElement& e) {
+ switch (e.fKind) {
+ case ProgramElement::kExtension_Kind:
+ break;
+ case ProgramElement::kVar_Kind: {
+ VarDeclarations& decl = (VarDeclarations&) e;
+ if (decl.fVars.size() > 0) {
+ int builtin = ((VarDeclaration&) *decl.fVars[0]).fVar->fModifiers.fLayout.fBuiltin;
+ if (builtin == -1) {
+ // normal var
+ this->writeVarDeclarations(decl, true);
+ this->writeLine();
+ } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
+ fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
+ this->write("out ");
+ if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
+ this->write("mediump ");
}
+ this->writeLine("vec4 sk_FragColor;");
}
- break;
}
- case ProgramElement::kInterfaceBlock_Kind:
- this->writeInterfaceBlock((InterfaceBlock&) *e);
- break;
- case ProgramElement::kFunction_Kind:
- this->writeFunction((FunctionDefinition&) *e);
- break;
- case ProgramElement::kModifiers_Kind:
- this->writeModifiers(((ModifiersDeclaration&) *e).fModifiers, true);
- this->writeLine(";");
- break;
- default:
- printf("%s\n", e->description().c_str());
- ABORT("unsupported program element");
+ break;
}
+ case ProgramElement::kInterfaceBlock_Kind:
+ this->writeInterfaceBlock((InterfaceBlock&) e);
+ break;
+ case ProgramElement::kFunction_Kind:
+ this->writeFunction((FunctionDefinition&) e);
+ break;
+ case ProgramElement::kModifiers_Kind:
+ this->writeModifiers(((ModifiersDeclaration&) e).fModifiers, true);
+ this->writeLine(";");
+ break;
+ default:
+ printf("%s\n", e.description().c_str());
+ ABORT("unsupported program element");
+ }
+}
+
+bool GLSLCodeGenerator::generateCode() {
+ OutputStream* rawOut = fOut;
+ fOut = &fHeader;
+ fProgramKind = fProgram.fKind;
+ this->writeHeader();
+ StringStream body;
+ fOut = &body;
+ for (const auto& e : fProgram.fElements) {
+ this->writeProgramElement(*e);
}
- fOut = nullptr;
+ fOut = rawOut;
write_stringstream(fHeader, *rawOut);
write_stringstream(body, *rawOut);
diff --git a/src/sksl/SkSLGLSLCodeGenerator.h b/src/sksl/SkSLGLSLCodeGenerator.h
index 032b70eea1..c0a638797b 100644
--- a/src/sksl/SkSLGLSLCodeGenerator.h
+++ b/src/sksl/SkSLGLSLCodeGenerator.h
@@ -13,6 +13,7 @@
#include <unordered_map>
#include "SkSLCodeGenerator.h"
+#include "SkSLStringStream.h"
#include "ir/SkSLBinaryExpression.h"
#include "ir/SkSLBoolLiteral.h"
#include "ir/SkSLConstructor.h"
@@ -32,6 +33,7 @@
#include "ir/SkSLPostfixExpression.h"
#include "ir/SkSLProgramElement.h"
#include "ir/SkSLReturnStatement.h"
+#include "ir/SkSLSetting.h"
#include "ir/SkSLStatement.h"
#include "ir/SkSLSwitchStatement.h"
#include "ir/SkSLSwizzle.h"
@@ -74,11 +76,12 @@ public:
GLSLCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors,
OutputStream* out)
: INHERITED(program, errors, out)
+ , fLineEnding("\n")
, fContext(*context) {}
- virtual bool generateCode() override;
+ bool generateCode() override;
-private:
+protected:
void write(const char* s);
void writeLine();
@@ -89,6 +92,8 @@ private:
void writeLine(const String& s);
+ virtual void writeHeader();
+
void writeType(const Type& type);
void writeExtension(const Extension& ext);
@@ -99,7 +104,7 @@ private:
void writeFunctionDeclaration(const FunctionDeclaration& f);
- void writeFunction(const FunctionDefinition& f);
+ virtual void writeFunction(const FunctionDefinition& f);
void writeLayout(const Layout& layout);
@@ -107,11 +112,13 @@ private:
void writeGlobalVars(const VarDeclaration& vs);
+ virtual void writeVarInitializer(const Variable& var, const Expression& value);
+
void writeVarDeclarations(const VarDeclarations& decl, bool global);
void writeFragCoord();
- void writeVariableReference(const VariableReference& ref);
+ virtual void writeVariableReference(const VariableReference& ref);
void writeExpression(const Expression& expr, Precedence parentPrecedence);
@@ -127,11 +134,13 @@ private:
void writeSwizzle(const Swizzle& swizzle);
- void writeBinaryExpression(const BinaryExpression& b, Precedence parentPrecedence);
+ static Precedence GetBinaryPrecedence(Token::Kind op);
+
+ virtual void writeBinaryExpression(const BinaryExpression& b, Precedence parentPrecedence);
void writeTernaryExpression(const TernaryExpression& t, Precedence parentPrecedence);
- void writeIndexExpression(const IndexExpression& expr);
+ virtual void writeIndexExpression(const IndexExpression& expr);
void writePrefixExpression(const PrefixExpression& p, Precedence parentPrecedence);
@@ -143,6 +152,8 @@ private:
void writeFloatLiteral(const FloatLiteral& f);
+ virtual void writeSetting(const Setting& s);
+
void writeStatement(const Statement& s);
void writeStatements(const std::vector<std::unique_ptr<Statement>>& statements);
@@ -161,6 +172,9 @@ private:
void writeReturnStatement(const ReturnStatement& r);
+ virtual void writeProgramElement(const ProgramElement& e);
+
+ const char* fLineEnding;
const Context& fContext;
StringStream fHeader;
String fFunctionHeader;
diff --git a/src/sksl/SkSLHCodeGenerator.cpp b/src/sksl/SkSLHCodeGenerator.cpp
new file mode 100644
index 0000000000..0eb43df046
--- /dev/null
+++ b/src/sksl/SkSLHCodeGenerator.cpp
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkSLHCodeGenerator.h"
+
+#include "SkSLUtil.h"
+#include "ir/SkSLFunctionDeclaration.h"
+#include "ir/SkSLFunctionDefinition.h"
+#include "ir/SkSLSection.h"
+#include "ir/SkSLVarDeclarations.h"
+
+namespace SkSL {
+
+HCodeGenerator::HCodeGenerator(const Program* program, ErrorReporter* errors, String name,
+ OutputStream* out)
+: INHERITED(program, errors, out)
+, fName(std::move(name))
+, fFullName(String::printf("Gr%s", fName.c_str()))
+, fSectionAndParameterHelper(*program, *errors) {}
+
+String HCodeGenerator::ParameterType(const Type& type) {
+ if (type.fName == "vec2") {
+ return "SkPoint";
+ } else if (type.fName == "ivec4") {
+ return "SkIRect";
+ } else if (type.fName == "vec4") {
+ return "SkRect";
+ } else if (type.fName == "mat4") {
+ return "SkMatrix44";
+ } else if (type.kind() == Type::kSampler_Kind) {
+ return "sk_sp<GrTextureProxy>";
+ } else if (type.fName == "colorSpaceXform") {
+ return "sk_sp<GrColorSpaceXform>";
+ }
+ return type.name();
+}
+
+String HCodeGenerator::FieldType(const Type& type) {
+ if (type.kind() == Type::kSampler_Kind) {
+ return "TextureSampler";
+ }
+ return ParameterType(type);
+}
+
+void HCodeGenerator::writef(const char* s, va_list va) {
+ static constexpr int BUFFER_SIZE = 1024;
+ char buffer[BUFFER_SIZE];
+ int length = vsnprintf(buffer, BUFFER_SIZE, s, va);
+ if (length < BUFFER_SIZE) {
+ fOut->write(buffer, length);
+ } else {
+ std::unique_ptr<char[]> heap(new char[length + 1]);
+ vsprintf(heap.get(), s, va);
+ fOut->write(heap.get(), length);
+ }
+}
+
+void HCodeGenerator::writef(const char* s, ...) {
+ va_list va;
+ va_start(va, s);
+ this->writef(s, va);
+ va_end(va);
+}
+
+bool HCodeGenerator::writeSection(const char* name, const char* prefix) {
+ const auto found = fSectionAndParameterHelper.fSections.find(String(name));
+ if (found != fSectionAndParameterHelper.fSections.end()) {
+ this->writef("%s%s", prefix, found->second->fText.c_str());
+ return true;
+ }
+ return false;
+}
+
+void HCodeGenerator::writeExtraConstructorParams(const char* separator) {
+ // super-simple parse, just assume the last token before a comma is the name of a parameter
+ // (which is true as long as there are no multi-parameter template types involved). Will replace
+ // this with something more robust if the need arises.
+ const auto found = fSectionAndParameterHelper.fSections.find(
+ String(CONSTRUCTOR_PARAMS_SECTION));
+ if (found != fSectionAndParameterHelper.fSections.end()) {
+ const char* s = found->second->fText.c_str();
+ #define BUFFER_SIZE 64
+ char lastIdentifier[BUFFER_SIZE];
+ int lastIdentifierLength = 0;
+ bool foundBreak = false;
+ while (*s) {
+ char c = *s;
+ ++s;
+ if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
+ c == '_') {
+ if (foundBreak) {
+ lastIdentifierLength = 0;
+ foundBreak = false;
+ }
+ ASSERT(lastIdentifierLength < BUFFER_SIZE);
+ lastIdentifier[lastIdentifierLength] = c;
+ ++lastIdentifierLength;
+ } else {
+ foundBreak = true;
+ if (c == ',') {
+ ASSERT(lastIdentifierLength < BUFFER_SIZE);
+ lastIdentifier[lastIdentifierLength] = 0;
+ this->writef("%s%s", separator, lastIdentifier);
+ separator = ", ";
+ } else if (c != ' ' && c != '\t' && c != '\n' && c != '\r') {
+ lastIdentifierLength = 0;
+ }
+ }
+ }
+ if (lastIdentifierLength) {
+ ASSERT(lastIdentifierLength < BUFFER_SIZE);
+ lastIdentifier[lastIdentifierLength] = 0;
+ this->writef("%s%s", separator, lastIdentifier);
+ }
+ }
+}
+
+void HCodeGenerator::writeMake() {
+ const char* separator;
+ if (!this->writeSection(MAKE_SECTION)) {
+ this->writef(" static sk_sp<GrFragmentProcessor> Make(");
+ separator = "";
+ for (const auto& param : fSectionAndParameterHelper.fParameters) {
+ this->writef("%s%s %s", separator, ParameterType(param->fType).c_str(),
+ param->fName.c_str());
+ separator = ", ";
+ }
+ this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator);
+ this->writef(") {\n"
+ " return sk_sp<GrFragmentProcessor>(new %s(",
+ fFullName.c_str());
+ separator = "";
+ for (const auto& param : fSectionAndParameterHelper.fParameters) {
+ this->writef("%s%s", separator, param->fName.c_str());
+ separator = ", ";
+ }
+ this->writeExtraConstructorParams(separator);
+ this->writef("));\n"
+ " }\n");
+ }
+}
+
+void HCodeGenerator::writeConstructor() {
+ if (this->writeSection(CONSTRUCTOR_SECTION)) {
+ return;
+ }
+ this->writef(" %s(", fFullName.c_str());
+ const char* separator = "";
+ for (const auto& param : fSectionAndParameterHelper.fParameters) {
+ this->writef("%s%s %s", separator, ParameterType(param->fType).c_str(),
+ param->fName.c_str());
+ separator = ", ";
+ }
+ this->writeSection(CONSTRUCTOR_PARAMS_SECTION, separator);
+ this->writef(")\n"
+ " : INHERITED(");
+ if (!this->writeSection(OPTIMIZATION_FLAGS_SECTION, "(OptimizationFlags) ")) {
+ this->writef("kNone_OptimizationFlags");
+ }
+ this->writef(")");
+ this->writeSection(INITIALIZERS_SECTION, "\n , ");
+ for (const auto& param : fSectionAndParameterHelper.fParameters) {
+ const char* name = param->fName.c_str();
+ if (param->fType.kind() == Type::kSampler_Kind) {
+ this->writef("\n , %s(resourceProvider, std::move(%s))", FieldName(name).c_str(),
+ name);
+ } else {
+ this->writef("\n , %s(%s)", FieldName(name).c_str(), name);
+ }
+ }
+ this->writef(" {\n");
+ this->writeSection(CONSTRUCTOR_CODE_SECTION);
+ for (const auto& param : fSectionAndParameterHelper.fParameters) {
+ if (param->fType.kind() == Type::kSampler_Kind) {
+ this->writef(" this->addTextureSampler(&%s);\n",
+ FieldName(param->fName.c_str()).c_str());
+ }
+ }
+ this->writef(" this->initClassID<%s>();\n"
+ " }\n",
+ fFullName.c_str());
+}
+
+void HCodeGenerator::writeFields() {
+ this->writeSection(FIELDS_SECTION);
+ for (const auto& param : fSectionAndParameterHelper.fParameters) {
+ const char* name = param->fName.c_str();
+ this->writef(" %s %s;\n", FieldType(param->fType).c_str(), FieldName(name).c_str());
+ }
+}
+
+bool HCodeGenerator::generateCode() {
+ this->writef("/*\n"
+ " * This file was autogenerated from %s.fp.\n"
+ " */\n"
+ "#ifndef %s_DEFINED\n"
+ "#define %s_DEFINED\n"
+ "#include \"GrFragmentProcessor.h\"\n"
+ "#include \"GrCoordTransform.h\"\n"
+ "#include \"effects/GrProxyMove.h\"\n",
+ fFullName.c_str(), fFullName.c_str(), fFullName.c_str());
+ this->writeSection(HEADER_SECTION);
+ this->writef("class %s : public GrFragmentProcessor {\n"
+ "public:\n",
+ fFullName.c_str());
+ this->writeSection(CLASS_SECTION);
+ for (const auto& param : fSectionAndParameterHelper.fParameters) {
+ if (param->fType.kind() == Type::kSampler_Kind) {
+ continue;
+ }
+ const char* name = param->fName.c_str();
+ this->writef("%s %s() const { return %s; }\n",
+ FieldType(param->fType).c_str(), name, FieldName(name).c_str());
+ }
+ this->writeMake();
+ this->writef(" const char* name() const override { return \"%s\"; }\n"
+ "private:\n",
+ fName.c_str());
+ this->writeConstructor();
+ this->writef(" GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;\n"
+ " void onGetGLSLProcessorKey(const GrShaderCaps&,"
+ "GrProcessorKeyBuilder*) const override;\n"
+ " bool onIsEqual(const GrFragmentProcessor&) const override;\n"
+ " GR_DECLARE_FRAGMENT_PROCESSOR_TEST;\n");
+ this->writeFields();
+ this->writef(" typedef GrFragmentProcessor INHERITED;\n"
+ "};\n"
+ "#endif\n");
+ return 0 == fErrors.errorCount();
+}
+
+} // namespace
diff --git a/src/sksl/SkSLHCodeGenerator.h b/src/sksl/SkSLHCodeGenerator.h
new file mode 100644
index 0000000000..1025d7f43c
--- /dev/null
+++ b/src/sksl/SkSLHCodeGenerator.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SKSL_HCODEGENERATOR
+#define SKSL_HCODEGENERATOR
+
+#include "SkSLCodeGenerator.h"
+#include "SkSLSectionAndParameterHelper.h"
+#include "ir/SkSLType.h"
+#include "ir/SkSLVariable.h"
+
+#include <cctype>
+
+namespace SkSL {
+
+class HCodeGenerator : public CodeGenerator {
+public:
+ HCodeGenerator(const Program* program, ErrorReporter* errors, String name, OutputStream* out);
+
+ bool generateCode() override;
+
+ static String ParameterType(const Type& type);
+
+ static String FieldType(const Type& type);
+
+ static String FieldName(const char* varName) {
+ return String::printf("f%c%s", toupper(varName[0]), varName + 1);
+ }
+
+private:
+ void writef(const char* s, va_list va) SKSL_PRINTF_LIKE(2, 0);
+
+ void writef(const char* s, ...) SKSL_PRINTF_LIKE(2, 3);
+
+ bool writeSection(const char* name, const char* prefix = "");
+
+ // given a @constructorParams section of e.g. 'int x, float y', writes out "<separator>x, y".
+ // Writes nothing (not even the separator) if there is no @constructorParams section.
+ void writeExtraConstructorParams(const char* separator);
+
+ void writeMake();
+
+ void writeConstructor();
+
+ void writeFields();
+
+ String fName;
+ String fFullName;
+ SectionAndParameterHelper fSectionAndParameterHelper;
+
+ typedef CodeGenerator INHERITED;
+};
+
+} // namespace SkSL
+
+#endif
diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp
index 159ede46e2..78672cb52e 100644
--- a/src/sksl/SkSLIRGenerator.cpp
+++ b/src/sksl/SkSLIRGenerator.cpp
@@ -42,6 +42,7 @@
#include "ir/SkSLPostfixExpression.h"
#include "ir/SkSLPrefixExpression.h"
#include "ir/SkSLReturnStatement.h"
+#include "ir/SkSLSetting.h"
#include "ir/SkSLSwitchCase.h"
#include "ir/SkSLSwitchStatement.h"
#include "ir/SkSLSwizzle.h"
@@ -104,9 +105,11 @@ IRGenerator::IRGenerator(const Context* context, std::shared_ptr<SymbolTable> sy
ErrorReporter& errorReporter)
: fContext(*context)
, fCurrentFunction(nullptr)
-, fSymbolTable(std::move(symbolTable))
+, fRootSymbolTable(symbolTable)
+, fSymbolTable(symbolTable)
, fLoopLevel(0)
, fSwitchLevel(0)
+, fTmpCount(0)
, fErrors(errorReporter) {}
void IRGenerator::pushSymbolTable() {
@@ -117,8 +120,10 @@ void IRGenerator::popSymbolTable() {
fSymbolTable = fSymbolTable->fParent;
}
-static void fill_caps(const SKSL_CAPS_CLASS& caps, std::unordered_map<String, CapValue>* capsMap) {
-#define CAP(name) capsMap->insert(std::make_pair(String(#name), CapValue(caps.name())));
+static void fill_caps(const SKSL_CAPS_CLASS& caps,
+ std::unordered_map<String, Program::Settings::Value>* capsMap) {
+#define CAP(name) capsMap->insert(std::make_pair(String(#name), \
+ Program::Settings::Value(caps.name())));
CAP(fbFetchSupport);
CAP(fbFetchNeedsCustomOutput);
CAP(bindlessTextureSupport);
@@ -135,6 +140,7 @@ static void fill_caps(const SKSL_CAPS_CLASS& caps, std::unordered_map<String, Ca
CAP(mustEnableSpecificAdvBlendEqs);
CAP(mustDeclareFragmentShaderOutput);
CAP(canUseAnyFunctionInShader);
+ CAP(floatPrecisionVaries);
#undef CAP
}
@@ -673,7 +679,12 @@ void IRGenerator::convertFunction(const ASTFunction& f,
bool needInvocationIDWorkaround = fSettings->fCaps &&
fSettings->fCaps->mustImplementGSInvocationsWithLoop() &&
fInvocations != -1 && f.fName == "main";
+ ASSERT(!fExtraVars.size());
std::unique_ptr<Block> body = this->convertBlock(*f.fBody);
+ for (auto& v : fExtraVars) {
+ body->fStatements.insert(body->fStatements.begin(), std::move(v));
+ }
+ fExtraVars.clear();
fCurrentFunction = nullptr;
if (!body) {
return;
@@ -845,6 +856,7 @@ std::unique_ptr<Expression> IRGenerator::convertIdentifier(const ASTIdentifier&
}
case Symbol::kVariable_Kind: {
const Variable* var = (const Variable*) result;
+#ifndef SKSL_STANDALONE
if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN) {
fInputs.fFlipY = true;
if (fSettings->fFlipY &&
@@ -853,6 +865,7 @@ std::unique_ptr<Expression> IRGenerator::convertIdentifier(const ASTIdentifier&
fInputs.fRTHeight = true;
}
}
+#endif
// default to kRead_RefKind; this will be corrected later if the variable is written to
return std::unique_ptr<VariableReference>(new VariableReference(
identifier.fPosition,
@@ -876,9 +889,13 @@ std::unique_ptr<Expression> IRGenerator::convertIdentifier(const ASTIdentifier&
default:
ABORT("unsupported symbol type %d\n", result->fKind);
}
+}
+std::unique_ptr<Section> IRGenerator::convertSection(const ASTSection& s) {
+ return std::unique_ptr<Section>(new Section(s.fPosition, s.fName, s.fArgument, s.fText));
}
+
std::unique_ptr<Expression> IRGenerator::coerce(std::unique_ptr<Expression> expr,
const Type& type) {
if (!expr) {
@@ -904,6 +921,9 @@ std::unique_ptr<Expression> IRGenerator::coerce(std::unique_ptr<Expression> expr
ASSERT(ctor);
return this->call(Position(), std::move(ctor), std::move(args));
}
+ if (type == *fContext.fColorSpaceXform_Type && expr->fType == *fContext.fMat4x4_Type) {
+ return expr;
+ }
std::vector<std::unique_ptr<Expression>> args;
args.push_back(std::move(expr));
return std::unique_ptr<Expression>(new Constructor(Position(), type, std::move(args)));
@@ -1332,7 +1352,7 @@ std::unique_ptr<Expression> IRGenerator::call(Position position,
return nullptr;
}
if (arguments[i] && (function.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag)) {
- this->markWrittenTo(*arguments[i],
+ this->markWrittenTo(*arguments[i],
function.fParameters[i]->fModifiers.fFlags & Modifiers::kIn_Flag);
}
}
@@ -1373,6 +1393,87 @@ bool IRGenerator::determineCallCost(const FunctionDeclaration& function,
return true;
}
+std::unique_ptr<Expression> IRGenerator::applyColorSpace(std::unique_ptr<Expression> texture,
+ const Variable* xform) {
+ // Before:
+ // vec4 color = texture(img, coords, xform);
+ // After:
+ // vec4 tmp;
+ // vec4 color = (tmp = texture(img, coords) ,
+ // xform != mat4(1) ?
+ // vec4(clamp((xform * vec4(tmp.rgb, 1.0)).rgb, 0.0, tmp.a), tmp.a) :
+ // tmp);
+
+ // a few macros to keep line lengths manageable
+ #define EXPR std::unique_ptr<Expression>
+ #define REF(v) EXPR(new VariableReference(p, *v))
+ #define FLOAT(x) EXPR(new FloatLiteral(fContext, p, x))
+ using std::move;
+ Position p = Position();
+ // vec4 tmp;
+ Variable* tmp = new Variable(p, Modifiers(), "_tmp" + to_string(fTmpCount++), texture->fType,
+ Variable::kLocal_Storage);
+ fRootSymbolTable->takeOwnership(tmp);
+ std::vector<std::unique_ptr<VarDeclaration>> decls;
+ decls.emplace_back(new VarDeclaration(tmp, std::vector<std::unique_ptr<Expression>>(),
+ nullptr));
+ const Type& type = texture->fType;
+ fExtraVars.emplace_back(new VarDeclarationsStatement(std::unique_ptr<VarDeclarations>(
+ new VarDeclarations(p, &type, move(decls)))));
+ // tmp = texture
+ EXPR assignment = EXPR(new BinaryExpression(p,
+ EXPR(new VariableReference(p, *tmp,
+ VariableReference::kWrite_RefKind)),
+ Token::EQ,
+ move(texture), type));
+ // 1.0
+ std::vector<EXPR> matArgs;
+ matArgs.push_back(FLOAT(1.0));
+ // mat4(1.0)
+ EXPR mat = EXPR(new Constructor(p, *fContext.fMat4x4_Type, move(matArgs)));
+ // <xform> != mat4(1.0)
+ EXPR matNeq = EXPR(new BinaryExpression(p, REF(xform), Token::NEQ, move(mat),
+ *fContext.fBool_Type));
+ // tmp.rgb
+ std::vector<int> rgb { 0, 1, 2 };
+ EXPR tmpRgb = EXPR(new Swizzle(fContext, REF(tmp), rgb));
+ // vec4(tmp.rgb, 1.0)
+ std::vector<EXPR> tmpVecArgs;
+ tmpVecArgs.push_back(move(tmpRgb));
+ tmpVecArgs.push_back(FLOAT(1.0));
+ EXPR tmpVec = EXPR(new Constructor(p, *fContext.fVec4_Type, move(tmpVecArgs)));
+ // xform * vec4(tmp.rgb, 1.0)
+ EXPR mul = EXPR(new BinaryExpression(p, REF(xform), Token::STAR, move(tmpVec),
+ *fContext.fVec4_Type));
+ // (xform * vec4(tmp.rgb, 1.0)).rgb
+ EXPR mulRGB = EXPR(new Swizzle(fContext, std::move(mul), rgb));
+ // tmp.a
+ std::vector<int> a { 3 };
+ EXPR tmpA = EXPR(new Swizzle(fContext, REF(tmp), a));
+ // clamp((xform * vec4(tmp.rgb, 1.0)).rgb, 0.0, tmp.a)
+ EXPR clamp = this->convertIdentifier(ASTIdentifier(p, "clamp"));
+ std::vector<EXPR> clampArgs;
+ clampArgs.push_back(move(mulRGB));
+ clampArgs.push_back(FLOAT(0));
+ clampArgs.push_back(move(tmpA));
+ EXPR clampCall = this->call(p, move(clamp), move(clampArgs));
+ // tmp.a
+ tmpA = EXPR(new Swizzle(fContext, REF(tmp), a));
+ // vec4(clamp((xform * vec4(tmp.rgb, 1.0)).rgb, 0.0, tmp.a), tmp.a)
+ std::vector<EXPR> finalVecArgs;
+ finalVecArgs.push_back(move(clampCall));
+ finalVecArgs.push_back(move(tmpA));
+ EXPR finalVec = EXPR(new Constructor(p, *fContext.fVec4_Type, move(finalVecArgs)));
+ // xform != mat4(1) ? vec4(clamp((xform * vec4(tmp.rgb, 1.0)).rgb, 0.0, tmp.a), tmp.a) : tmp)
+ EXPR ternary = EXPR(new TernaryExpression(p, move(matNeq), move(finalVec), REF(tmp)));
+ // (tmp = texture ,
+ // xform != mat4(1) ? vec4(clamp((xform * vec4(tmp.rgb, 1.0)).rgb, 0.0, tmp.a), tmp.a) : tmp))
+ return EXPR(new BinaryExpression(p, move(assignment), Token::COMMA, move(ternary), type));
+ #undef EXPR
+ #undef REF
+ #undef FLOAT
+}
+
std::unique_ptr<Expression> IRGenerator::call(Position position,
std::unique_ptr<Expression> functionValue,
std::vector<std::unique_ptr<Expression>> arguments) {
@@ -1386,6 +1487,17 @@ std::unique_ptr<Expression> IRGenerator::call(Position position,
return nullptr;
}
FunctionReference* ref = (FunctionReference*) functionValue.get();
+ if (ref->fFunctions[0]->fName == "texture" &&
+ arguments.back()->fType == *fContext.fColorSpaceXform_Type) {
+ std::unique_ptr<Expression> colorspace = std::move(arguments.back());
+ ASSERT(colorspace->fKind == Expression::kVariableReference_Kind);
+ arguments.pop_back();
+ return this->applyColorSpace(this->call(position,
+ std::move(functionValue),
+ std::move(arguments)),
+ &((VariableReference&) *colorspace).fVariable);
+ }
+
int bestCost = INT_MAX;
const FunctionDeclaration* best = nullptr;
if (ref->fFunctions.size() > 1) {
@@ -1451,7 +1563,7 @@ std::unique_ptr<Expression> IRGenerator::convertNumberConstructor(
args[0]->fType.description() + "')");
return nullptr;
}
- return std::unique_ptr<Expression>(new Constructor(position, std::move(type), std::move(args)));
+ return std::unique_ptr<Expression>(new Constructor(position, type, std::move(args)));
}
int component_count(const Type& type) {
@@ -1473,8 +1585,7 @@ std::unique_ptr<Expression> IRGenerator::convertCompoundConstructor(
if (type.kind() == Type::kMatrix_Kind && args.size() == 1 &&
args[0]->fType.kind() == Type::kMatrix_Kind) {
// matrix from matrix is always legal
- return std::unique_ptr<Expression>(new Constructor(position, std::move(type),
- std::move(args)));
+ return std::unique_ptr<Expression>(new Constructor(position, type, std::move(args)));
}
int actual = 0;
int expected = type.rows() * type.columns();
@@ -1511,7 +1622,7 @@ std::unique_ptr<Expression> IRGenerator::convertCompoundConstructor(
return nullptr;
}
}
- return std::unique_ptr<Expression>(new Constructor(position, std::move(type), std::move(args)));
+ return std::unique_ptr<Expression>(new Constructor(position, type, std::move(args)));
}
std::unique_ptr<Expression> IRGenerator::convertConstructor(
@@ -1534,8 +1645,7 @@ std::unique_ptr<Expression> IRGenerator::convertConstructor(
return nullptr;
}
}
- return std::unique_ptr<Expression>(new Constructor(position, std::move(type),
- std::move(args)));
+ return std::unique_ptr<Expression>(new Constructor(position, type, std::move(args)));
} else if (kind == Type::kVector_Kind || kind == Type::kMatrix_Kind) {
return this->convertCompoundConstructor(position, type, std::move(args));
} else {
@@ -1727,16 +1837,21 @@ std::unique_ptr<Expression> IRGenerator::getCap(Position position, String name)
fErrors.error(position, "unknown capability flag '" + name + "'");
return nullptr;
}
- switch (found->second.fKind) {
- case CapValue::kBool_Kind:
- return std::unique_ptr<Expression>(new BoolLiteral(fContext, position,
- (bool) found->second.fValue));
- case CapValue::kInt_Kind:
- return std::unique_ptr<Expression>(new IntLiteral(fContext, position,
- found->second.fValue));
+ String fullName = "sk_Caps." + name;
+ return std::unique_ptr<Expression>(new Setting(position, fullName,
+ found->second.literal(fContext, position)));
+}
+
+std::unique_ptr<Expression> IRGenerator::getArg(Position position, String name) {
+ auto found = fSettings->fArgs.find(name);
+ if (found == fSettings->fArgs.end()) {
+ fErrors.error(position, "unknown argument '" + name + "'");
+ return nullptr;
}
- ASSERT(false);
- return nullptr;
+ String fullName = "sk_Args." + name;
+ return std::unique_ptr<Expression>(new Setting(position,
+ fullName,
+ found->second.literal(fContext, position)));
}
std::unique_ptr<Expression> IRGenerator::convertSuffixExpression(
@@ -1780,6 +1895,10 @@ std::unique_ptr<Expression> IRGenerator::convertSuffixExpression(
return this->getCap(expression.fPosition,
((ASTFieldSuffix&) *expression.fSuffix).fField);
}
+ if (base->fType == *fContext.fSkArgs_Type) {
+ return this->getArg(expression.fPosition,
+ ((ASTFieldSuffix&) *expression.fSuffix).fField);
+ }
switch (base->fType.kind()) {
case Type::kVector_Kind:
return this->convertSwizzle(std::move(base),
@@ -1924,6 +2043,13 @@ void IRGenerator::convertProgram(String text,
}
break;
}
+ case ASTDeclaration::kSection_Kind: {
+ std::unique_ptr<Section> s = this->convertSection((ASTSection&) decl);
+ if (s) {
+ out->push_back(std::move(s));
+ }
+ break;
+ }
case ASTDeclaration::kPrecision_Kind: {
*defaultPrecision = ((ASTPrecision&) decl).fPrecision;
break;
diff --git a/src/sksl/SkSLIRGenerator.h b/src/sksl/SkSLIRGenerator.h
index 29513d8d34..3078a9e8df 100644
--- a/src/sksl/SkSLIRGenerator.h
+++ b/src/sksl/SkSLIRGenerator.h
@@ -27,6 +27,7 @@
#include "ast/SkSLASTModifiersDeclaration.h"
#include "ast/SkSLASTPrefixExpression.h"
#include "ast/SkSLASTReturnStatement.h"
+#include "ast/SkSLASTSection.h"
#include "ast/SkSLASTStatement.h"
#include "ast/SkSLASTSuffixExpression.h"
#include "ast/SkSLASTSwitchStatement.h"
@@ -42,6 +43,7 @@
#include "ir/SkSLModifiers.h"
#include "ir/SkSLModifiersDeclaration.h"
#include "ir/SkSLProgram.h"
+#include "ir/SkSLSection.h"
#include "ir/SkSLSymbolTable.h"
#include "ir/SkSLStatement.h"
#include "ir/SkSLType.h"
@@ -50,28 +52,6 @@
namespace SkSL {
-struct CapValue {
- CapValue()
- : fKind(kInt_Kind)
- , fValue(-1) {
- ASSERT(false);
- }
-
- CapValue(bool b)
- : fKind(kBool_Kind)
- , fValue(b) {}
-
- CapValue(int i)
- : fKind(kInt_Kind)
- , fValue(i) {}
-
- enum {
- kBool_Kind,
- kInt_Kind,
- } fKind;
- int fValue;
-};
-
/**
* Performs semantic analysis on an abstract syntax tree (AST) and produces the corresponding
* (unoptimized) intermediate representation (IR).
@@ -95,6 +75,7 @@ public:
Token::Kind op,
const Expression& right) const;
Program::Inputs fInputs;
+ const Program::Settings* fSettings;
const Context& fContext;
private:
@@ -160,7 +141,9 @@ private:
Modifiers convertModifiers(const Modifiers& m);
std::unique_ptr<Expression> convertPrefixExpression(const ASTPrefixExpression& expression);
std::unique_ptr<Statement> convertReturn(const ASTReturnStatement& r);
+ std::unique_ptr<Section> convertSection(const ASTSection& e);
std::unique_ptr<Expression> getCap(Position position, String name);
+ std::unique_ptr<Expression> getArg(Position position, String name);
std::unique_ptr<Expression> convertSuffixExpression(const ASTSuffixExpression& expression);
std::unique_ptr<Expression> convertField(std::unique_ptr<Expression> base,
const String& field);
@@ -173,16 +156,26 @@ private:
std::unique_ptr<Block> main,
std::vector<std::unique_ptr<ProgramElement>>* out);
+ /**
+ * Wraps an expression in code that applies a colorspace transformation to it. This is used
+ * to implement texture(sampler, coord, colorSpaceXForm).
+ */
+ std::unique_ptr<Expression> applyColorSpace(std::unique_ptr<Expression> texture,
+ const Variable* xform);
void fixRectSampling(std::vector<std::unique_ptr<Expression>>& arguments);
void checkValid(const Expression& expr);
void markWrittenTo(const Expression& expr, bool readWrite);
const FunctionDeclaration* fCurrentFunction;
- const Program::Settings* fSettings;
- std::unordered_map<String, CapValue> fCapsMap;
+ std::unordered_map<String, Program::Settings::Value> fCapsMap;
+ std::shared_ptr<SymbolTable> fRootSymbolTable;
std::shared_ptr<SymbolTable> fSymbolTable;
+ // holds extra temp variable declarations needed for the current function
+ std::vector<std::unique_ptr<Statement>> fExtraVars;
int fLoopLevel;
int fSwitchLevel;
+ // count of temporary variables we have created
+ int fTmpCount;
ErrorReporter& fErrors;
int fInvocations;
diff --git a/src/sksl/SkSLMain.cpp b/src/sksl/SkSLMain.cpp
index 1461bf9aae..ee868fb35e 100644
--- a/src/sksl/SkSLMain.cpp
+++ b/src/sksl/SkSLMain.cpp
@@ -5,11 +5,28 @@
* found in the LICENSE file.
*/
-#include "stdio.h"
#include <fstream>
#include "SkSLCompiler.h"
#include "SkSLFileOutputStream.h"
+// Given the path to a file (e.g. src/gpu/effects/GrFooFragmentProcessor.fp) and the expected
+// filename prefix and suffix (e.g. "Gr" and ".fp"), returns the "base name" of the
+// file (in this case, 'FooFragmentProcessor'). If no match, returns the empty string.
+static SkSL::String base_name(const char* fpPath, const char* prefix, const char* suffix) {
+ SkSL::String result;
+ const char* end = fpPath + strlen(fpPath);
+ const char* fileName = end;
+ // back up until we find a slash
+ while (fileName != fpPath && '/' != *(fileName - 1) && '\\' != *(fileName - 1)) {
+ --fileName;
+ }
+ if (!strncmp(fileName, prefix, strlen(prefix)) &&
+ !strncmp(end - strlen(suffix), suffix, strlen(suffix))) {
+ result.append(fileName + strlen(prefix), end - fileName - strlen(prefix) - strlen(suffix));
+ }
+ return result;
+}
+
/**
* Very simple standalone executable to facilitate testing.
*/
@@ -19,15 +36,17 @@ int main(int argc, const char** argv) {
exit(1);
}
SkSL::Program::Kind kind;
- size_t len = strlen(argv[1]);
- if (len > 5 && !strcmp(argv[1] + strlen(argv[1]) - 5, ".vert")) {
+ String input(argv[1]);
+ if (input.endsWith(".vert")) {
kind = SkSL::Program::kVertex_Kind;
- } else if (len > 5 && !strcmp(argv[1] + strlen(argv[1]) - 5, ".frag")) {
+ } else if (input.endsWith(".frag")) {
kind = SkSL::Program::kFragment_Kind;
- } else if (len > 5 && !strcmp(argv[1] + strlen(argv[1]) - 5, ".geom")) {
+ } else if (input.endsWith(".geom")) {
kind = SkSL::Program::kGeometry_Kind;
+ } else if (input.endsWith(".fp")) {
+ kind = SkSL::Program::kFragmentProcessor_Kind;
} else {
- printf("input filename must end in '.vert', '.frag', or '.geom'\n");
+ printf("input filename must end in '.vert', '.frag', '.geom', or '.fp'\n");
exit(1);
}
@@ -40,6 +59,7 @@ int main(int argc, const char** argv) {
exit(2);
}
SkSL::Program::Settings settings;
+ settings.fArgs.insert(std::make_pair("gpImplementsDistanceVector", 1));
SkSL::String name(argv[2]);
if (name.endsWith(".spirv")) {
SkSL::FileOutputStream out(argv[2]);
@@ -73,7 +93,41 @@ int main(int argc, const char** argv) {
printf("error writing '%s'\n", argv[2]);
exit(4);
}
+ } else if (name.endsWith(".h")) {
+ SkSL::FileOutputStream out(argv[2]);
+ SkSL::Compiler compiler;
+ if (!out.isValid()) {
+ printf("error writing '%s'\n", argv[2]);
+ exit(4);
+ }
+ settings.fReplaceSettings = false;
+ std::unique_ptr<SkSL::Program> program = compiler.convertProgram(kind, text, settings);
+ if (!program || !compiler.toH(*program, base_name(argv[1], "Gr", ".fp"), out)) {
+ printf("%s", compiler.errorText().c_str());
+ exit(3);
+ }
+ if (!out.close()) {
+ printf("error writing '%s'\n", argv[2]);
+ exit(4);
+ }
+ } else if (name.endsWith(".cpp")) {
+ SkSL::FileOutputStream out(argv[2]);
+ SkSL::Compiler compiler;
+ if (!out.isValid()) {
+ printf("error writing '%s'\n", argv[2]);
+ exit(4);
+ }
+ settings.fReplaceSettings = false;
+ std::unique_ptr<SkSL::Program> program = compiler.convertProgram(kind, text, settings);
+ if (!program || !compiler.toCPP(*program, base_name(argv[1], "Gr", ".fp"), out)) {
+ printf("%s", compiler.errorText().c_str());
+ exit(3);
+ }
+ if (!out.close()) {
+ printf("error writing '%s'\n", argv[2]);
+ exit(4);
+ }
} else {
- printf("expected output filename to end with '.spirv' or '.glsl'");
+ printf("expected output filename to end with '.spirv', '.glsl', '.cpp', or '.h'");
}
}
diff --git a/src/sksl/SkSLParser.cpp b/src/sksl/SkSLParser.cpp
index 5e8ec6398b..18ca311ee7 100644
--- a/src/sksl/SkSLParser.cpp
+++ b/src/sksl/SkSLParser.cpp
@@ -52,6 +52,7 @@ static_assert(YY_FLEX_MAJOR_VERSION * 10000 + YY_FLEX_MINOR_VERSION * 100 +
#include "ast/SkSLASTPrecision.h"
#include "ast/SkSLASTPrefixExpression.h"
#include "ast/SkSLASTReturnStatement.h"
+#include "ast/SkSLASTSection.h"
#include "ast/SkSLASTStatement.h"
#include "ast/SkSLASTSuffixExpression.h"
#include "ast/SkSLASTSwitchCase.h"
@@ -113,7 +114,7 @@ Parser::~Parser() {
layoutlex_destroy(fLayoutScanner);
}
-/* (precision | directive | declaration)* END_OF_FILE */
+/* (precision | directive | section | declaration)* END_OF_FILE */
std::vector<std::unique_ptr<ASTDeclaration>> Parser::file() {
std::vector<std::unique_ptr<ASTDeclaration>> result;
for (;;) {
@@ -134,6 +135,13 @@ std::vector<std::unique_ptr<ASTDeclaration>> Parser::file() {
}
break;
}
+ case Token::SECTION: {
+ std::unique_ptr<ASTDeclaration> section = this->section();
+ if (section) {
+ result.push_back(std::move(section));
+ }
+ break;
+ }
default: {
std::unique_ptr<ASTDeclaration> decl = this->declaration();
if (!decl) {
@@ -145,7 +153,7 @@ std::vector<std::unique_ptr<ASTDeclaration>> Parser::file() {
}
}
-Token Parser::nextToken() {
+Token Parser::nextRawToken() {
if (fPushback.fKind != Token::INVALID_TOKEN) {
Token result = fPushback;
fPushback.fKind = Token::INVALID_TOKEN;
@@ -153,25 +161,16 @@ Token Parser::nextToken() {
return result;
}
int token = sksllex(fScanner);
- String text;
- switch ((Token::Kind) token) {
- case Token::IDENTIFIER: // fall through
- case Token::INT_LITERAL: // fall through
- case Token::FLOAT_LITERAL: // fall through
- case Token::DIRECTIVE:
- text = String(skslget_text(fScanner));
- break;
- default:
-#ifdef SK_DEBUG
- text = String(skslget_text(fScanner));
-#endif
- break;
- }
- Position p = Position(skslget_lineno(fScanner), -1);
- if (token == Token::INVALID_TOKEN) {
- this->error(p, "invalid token: '" + text + "'");
- }
- return Token(p, (Token::Kind) token, text);
+ return Token(Position(skslget_lineno(fScanner), -1), (Token::Kind) token,
+ String(skslget_text(fScanner)));
+}
+
+Token Parser::nextToken() {
+ Token token;
+ do {
+ token = this->nextRawToken();
+ } while (token.fKind == Token::WHITESPACE);
+ return token;
}
void Parser::pushback(Token t) {
@@ -296,6 +295,56 @@ std::unique_ptr<ASTDeclaration> Parser::directive() {
}
}
+/* SECTION LBRACE (LPAREN IDENTIFIER RPAREN)? <any sequence of tokens with balanced braces>
+ RBRACE */
+std::unique_ptr<ASTDeclaration> Parser::section() {
+ Token start;
+ if (!this->expect(Token::SECTION, "a section token", &start)) {
+ return nullptr;
+ }
+ String argument;
+ if (this->peek().fKind == Token::LPAREN) {
+ this->nextToken();
+ Token argToken;
+ if (!this->expect(Token::IDENTIFIER, "an identifier", &argToken)) {
+ return nullptr;
+ }
+ argument = argToken.fText;
+ if (!this->expect(Token::RPAREN, "')'")) {
+ return nullptr;
+ }
+ }
+ if (!this->expect(Token::LBRACE, "'{'")) {
+ return nullptr;
+ }
+ String text;
+ int level = 1;
+ for (;;) {
+ Token next = this->nextRawToken();
+ switch (next.fKind) {
+ case Token::LBRACE:
+ ++level;
+ break;
+ case Token::RBRACE:
+ --level;
+ break;
+ case Token::END_OF_FILE:
+ this->error(start.fPosition, "reached end of file while parsing section");
+ return nullptr;
+ default:
+ break;
+ }
+ if (!level) {
+ break;
+ }
+ text += next.fText;
+ }
+ return std::unique_ptr<ASTDeclaration>(new ASTSection(start.fPosition,
+ String(start.fText.c_str() + 1),
+ argument,
+ text));
+}
+
/* modifiers (structVarDeclaration | type IDENTIFIER ((LPAREN parameter
(COMMA parameter)* RPAREN (block | SEMICOLON)) | SEMICOLON) | interfaceBlock) */
std::unique_ptr<ASTDeclaration> Parser::declaration() {
@@ -544,6 +593,61 @@ int Parser::layoutInt() {
return -1;
}
+/** EQ <any sequence of tokens with balanced parentheses and no top-level comma> */
+String Parser::layoutCode() {
+ if (!this->expect(Token::EQ, "'='")) {
+ return "";
+ }
+ Token start = this->peek();
+ String code;
+ int level = 1;
+ bool done = false;
+ while (!done) {
+ Token next = this->peek();
+ switch (next.fKind) {
+ case Token::LPAREN:
+ ++level;
+ break;
+ case Token::RPAREN:
+ --level;
+ break;
+ case Token::COMMA:
+ if (level == 1) {
+ done = true;
+ }
+ break;
+ case Token::END_OF_FILE:
+ this->error(start.fPosition, "reached end of file while parsing layout");
+ return nullptr;
+ default:
+ break;
+ }
+ if (!level) {
+ done = true;
+ }
+ if (!done) {
+ code += this->nextRawToken().fText;
+ }
+ }
+ return code;
+}
+
+/** (EQ IDENTIFIER('identity'))? */
+Layout::Key Parser::layoutKey() {
+ if (this->peek().fKind == Token::EQ) {
+ this->expect(Token::EQ, "'='");
+ Token key;
+ if (this->expect(Token::IDENTIFIER, "an identifer", &key)) {
+ if (key.fText == "identity") {
+ return Layout::kIdentity_Key;
+ } else {
+ this->error(key.fPosition, "unsupported layout key");
+ }
+ }
+ }
+ return Layout::kKey_Key;
+}
+
/* LAYOUT LPAREN IDENTIFIER (EQ INT_LITERAL)? (COMMA IDENTIFIER (EQ INT_LITERAL)?)* RPAREN */
Layout Parser::layout() {
int location = -1;
@@ -561,11 +665,13 @@ Layout Parser::layout() {
Layout::Primitive primitive = Layout::kUnspecified_Primitive;
int maxVertices = -1;
int invocations = -1;
+ String when;
+ Layout::Key key = Layout::kNo_Key;
if (this->checkNext(Token::LAYOUT)) {
if (!this->expect(Token::LPAREN, "'('")) {
return Layout(location, offset, binding, index, set, builtin, inputAttachmentIndex,
originUpperLeft, overrideCoverage, blendSupportAllEquations, format,
- pushConstant, primitive, maxVertices, invocations);
+ pushConstant, primitive, maxVertices, invocations, when, key);
}
for (;;) {
Token t = this->nextToken();
@@ -635,6 +741,12 @@ Layout Parser::layout() {
case Token::INVOCATIONS:
invocations = this->layoutInt();
break;
+ case Token::WHEN:
+ when = this->layoutCode();
+ break;
+ case Token::KEY:
+ key = this->layoutKey();
+ break;
}
} else if (Layout::ReadFormat(t.fText, &format)) {
// AST::ReadFormat stored the result in 'format'.
@@ -652,7 +764,7 @@ Layout Parser::layout() {
}
return Layout(location, offset, binding, index, set, builtin, inputAttachmentIndex,
originUpperLeft, overrideCoverage, blendSupportAllEquations, format,
- pushConstant, primitive, maxVertices, invocations);
+ pushConstant, primitive, maxVertices, invocations, when, key);
}
/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE |
diff --git a/src/sksl/SkSLParser.h b/src/sksl/SkSLParser.h
index 2f55b34986..e820484591 100644
--- a/src/sksl/SkSLParser.h
+++ b/src/sksl/SkSLParser.h
@@ -13,6 +13,7 @@
#include <unordered_map>
#include <unordered_set>
#include "SkSLErrorReporter.h"
+#include "ir/SkSLLayout.h"
#include "SkSLToken.h"
struct yy_buffer_state;
@@ -42,7 +43,6 @@ struct ASTSwitchStatement;
struct ASTType;
struct ASTWhileStatement;
struct ASTVarDeclarations;
-struct Layout;
struct Modifiers;
class SymbolTable;
@@ -64,7 +64,12 @@ public:
private:
/**
- * Return the next token from the parse stream.
+ * Return the next token, including whitespace tokens, from the parse stream.
+ */
+ Token nextRawToken();
+
+ /**
+ * Return the next non-whitespace token from the parse stream.
*/
Token nextToken();
@@ -76,7 +81,7 @@ private:
void pushback(Token t);
/**
- * Returns the next token without consuming it from the stream.
+ * Returns the next non-whitespace token without consuming it from the stream.
*/
Token peek();
@@ -87,8 +92,8 @@ private:
bool checkNext(Token::Kind kind, Token* result = nullptr);
/**
- * Reads the next token and generates an error if it is not the expected type. The 'expected'
- * string is part of the error message, which reads:
+ * Reads the next non-whitespace token and generates an error if it is not the expected type.
+ * The 'expected' string is part of the error message, which reads:
*
* "expected <expected>, but found '<actual text>'"
*
@@ -115,6 +120,8 @@ private:
std::unique_ptr<ASTDeclaration> directive();
+ std::unique_ptr<ASTDeclaration> section();
+
std::unique_ptr<ASTDeclaration> declaration();
std::unique_ptr<ASTVarDeclarations> varDeclarations();
@@ -131,6 +138,10 @@ private:
int layoutInt();
+ String layoutCode();
+
+ Layout::Key layoutKey();
+
Layout layout();
Modifiers modifiers();
diff --git a/src/sksl/SkSLSPIRVCodeGenerator.cpp b/src/sksl/SkSLSPIRVCodeGenerator.cpp
index fda98204c0..94e8a58e51 100644
--- a/src/sksl/SkSLSPIRVCodeGenerator.cpp
+++ b/src/sksl/SkSLSPIRVCodeGenerator.cpp
@@ -1906,7 +1906,7 @@ SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, O
Type intfStruct(Position(), name, fields);
Layout layout(-1, -1, 1, -1, -1, -1, -1, false, false, false,
Layout::Format::kUnspecified, false, Layout::kUnspecified_Primitive, -1,
- -1);
+ -1, "", Layout::kNo_Key);
Variable* intfVar = new Variable(Position(),
Modifiers(layout, Modifiers::kUniform_Flag),
name,
@@ -2948,6 +2948,8 @@ void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream&
case Program::kGeometry_Kind:
this->writeWord(SpvExecutionModelGeometry, out);
break;
+ default:
+ ABORT("cannot write this kind of program to SPIR-V\n");
}
this->writeWord(fFunctionMap[main], out);
this->writeString(main->fName.c_str(), out);
diff --git a/src/sksl/SkSLSectionAndParameterHelper.h b/src/sksl/SkSLSectionAndParameterHelper.h
new file mode 100644
index 0000000000..81e5f3b192
--- /dev/null
+++ b/src/sksl/SkSLSectionAndParameterHelper.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SKSL_SECTIONANDPARAMETERHELPER
+#define SKSL_SECTIONANDPARAMETERHELPER
+
+#include "SkSLErrorReporter.h"
+#include "ir/SkSLProgram.h"
+#include "ir/SkSLSection.h"
+#include "ir/SkSLVarDeclarations.h"
+#include <unordered_map>
+#include <vector>
+
+namespace SkSL {
+
+#define CLASS_SECTION "class"
+#define CPP_SECTION "cpp"
+#define HEADER_SECTION "header"
+#define CONSTRUCTOR_PARAMS_SECTION "constructorParams"
+#define CONSTRUCTOR_SECTION "constructor"
+#define CONSTRUCTOR_CODE_SECTION "constructorCode"
+#define INITIALIZERS_SECTION "initializers"
+#define EMIT_CODE_SECTION "emitCode"
+#define FIELDS_SECTION "fields"
+#define MAKE_SECTION "make"
+#define OPTIMIZATION_FLAGS_SECTION "optimizationFlags"
+#define SET_DATA_SECTION "setData"
+#define TEST_CODE_SECTION "test"
+
+class SectionAndParameterHelper {
+public:
+ SectionAndParameterHelper(const Program& program, ErrorReporter& errors) {
+ for (const auto& p : program.fElements) {
+ switch (p->fKind) {
+ case ProgramElement::kVar_Kind: {
+ const VarDeclarations* decls = (const VarDeclarations*) p.get();
+ for (const auto& raw : decls->fVars) {
+ const VarDeclaration& decl = (VarDeclaration&) *raw;
+ if (IsParameter(*decl.fVar)) {
+ fParameters.push_back(decl.fVar);
+ }
+ }
+ break;
+ }
+ case ProgramElement::kSection_Kind: {
+ const Section* s = (const Section*) p.get();
+ if (IsSupportedSection(s->fName.c_str())) {
+ if (SectionAcceptsArgument(s->fName.c_str())) {
+ if (!s->fArgument.size()) {
+ errors.error(s->fPosition,
+ ("section '@" + s->fName +
+ "' requires one parameter").c_str());
+ }
+ } else if (s->fArgument.size()) {
+ errors.error(s->fPosition,
+ ("section '@" + s->fName + "' has no parameters").c_str());
+ }
+ } else {
+ errors.error(s->fPosition,
+ ("unsupported section '@" + s->fName + "'").c_str());
+ }
+ if (fSections.find(s->fName) != fSections.end()) {
+ errors.error(s->fPosition,
+ ("duplicate section '@" + s->fName + "'").c_str());
+ }
+ fSections[s->fName] = s;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+
+ static bool IsParameter(const Variable& var) {
+ return (var.fModifiers.fFlags & Modifiers::kIn_Flag) &&
+ -1 == var.fModifiers.fLayout.fBuiltin;
+ }
+
+ static bool IsSupportedSection(const char* name) {
+ return !strcmp(name, CLASS_SECTION) ||
+ !strcmp(name, CPP_SECTION) ||
+ !strcmp(name, HEADER_SECTION) ||
+ !strcmp(name, CONSTRUCTOR_SECTION) ||
+ !strcmp(name, CONSTRUCTOR_CODE_SECTION) ||
+ !strcmp(name, CONSTRUCTOR_PARAMS_SECTION) ||
+ !strcmp(name, EMIT_CODE_SECTION) ||
+ !strcmp(name, FIELDS_SECTION) ||
+ !strcmp(name, INITIALIZERS_SECTION) ||
+ !strcmp(name, MAKE_SECTION) ||
+ !strcmp(name, OPTIMIZATION_FLAGS_SECTION) ||
+ !strcmp(name, SET_DATA_SECTION) ||
+ !strcmp(name, TEST_CODE_SECTION);
+ }
+
+ static bool SectionAcceptsArgument(const char* name) {
+ return !strcmp(name, SET_DATA_SECTION) ||
+ !strcmp(name, TEST_CODE_SECTION);
+ }
+
+ std::vector<const Variable*> fParameters;
+ std::unordered_map<String, const Section*> fSections;
+};
+
+} // namespace SkSL
+
+#endif
diff --git a/src/sksl/SkSLString.cpp b/src/sksl/SkSLString.cpp
index 9b2c1780f8..fb8fd56de8 100644
--- a/src/sksl/SkSLString.cpp
+++ b/src/sksl/SkSLString.cpp
@@ -40,15 +40,16 @@ void String::vappendf(const char* fmt, va_list args) {
#endif
#define BUFFER_SIZE 256
char buffer[BUFFER_SIZE];
+ va_list reuse;
+ va_copy(reuse, args);
size_t size = VSNPRINTF(buffer, BUFFER_SIZE, fmt, args);
if (BUFFER_SIZE >= size) {
this->append(buffer, size);
} else {
- auto newBuffer = std::unique_ptr<char[]>(new char[size]);
- VSNPRINTF(newBuffer.get(), size, fmt, args);
+ auto newBuffer = std::unique_ptr<char[]>(new char[size + 1]);
+ VSNPRINTF(newBuffer.get(), size + 1, fmt, reuse);
this->append(newBuffer.get(), size);
}
- va_end(args);
}
diff --git a/src/sksl/SkSLStringStream.h b/src/sksl/SkSLStringStream.h
index 9061432018..a8690668d2 100644
--- a/src/sksl/SkSLStringStream.h
+++ b/src/sksl/SkSLStringStream.h
@@ -28,12 +28,8 @@ public:
fBuffer.append((const char*) s, size);
}
- const char* data() const {
- return fBuffer.c_str();
- }
-
- size_t size() const {
- return fBuffer.size();
+ const String& str() const {
+ return fBuffer;
}
void reset() {
@@ -54,42 +50,33 @@ namespace SkSL {
class StringStream : public OutputStream {
public:
void write8(uint8_t b) override {
- SkASSERT(!fData);
fStream.write8(b);
}
void writeText(const char* s) override {
- SkASSERT(!fData);
fStream.writeText(s);
}
void write(const void* s, size_t size) override {
- SkASSERT(!fData);
fStream.write(s, size);
}
- const char* data() const {
- if (!fData) {
- fData = fStream.detachAsData();
- }
- return (const char*) fData->data();
- }
-
- size_t size() const {
- if (!fData) {
- fData = fStream.detachAsData();
+ const String& str() const {
+ if (!fString.size()) {
+ sk_sp<SkData> data = fStream.detachAsData();
+ fString = String((const char*) data->data(), data->size());
}
- return fData->size();
+ return fString;
}
void reset() {
fStream.reset();
- fData = nullptr;
+ fString = "";
}
private:
mutable SkDynamicMemoryWStream fStream;
- mutable sk_sp<SkData> fData;
+ mutable String fString;
};
#endif // SKSL_STANDALONE
diff --git a/src/sksl/SkSLToken.h b/src/sksl/SkSLToken.h
index 92193b9674..2857a82547 100644
--- a/src/sksl/SkSLToken.h
+++ b/src/sksl/SkSLToken.h
@@ -24,6 +24,7 @@ namespace SkSL {
struct Token {
enum Kind {
END_OF_FILE,
+ WHITESPACE,
IDENTIFIER,
INT_LITERAL,
FLOAT_LITERAL,
@@ -77,6 +78,8 @@ struct Token {
LOGICALXOREQ,
LOGICALANDEQ,
SEMICOLON,
+ ARROW,
+ COLONCOLON,
IF,
STATIC_IF,
ELSE,
@@ -111,6 +114,7 @@ struct Token {
STRUCT,
LAYOUT,
DIRECTIVE,
+ SECTION,
PRECISION,
LOCATION,
OFFSET,
@@ -132,6 +136,8 @@ struct Token {
TRIANGLES_ADJACENCY,
MAX_VERTICES,
INVOCATIONS,
+ WHEN,
+ KEY,
INVALID_TOKEN
};
diff --git a/src/sksl/SkSLUtil.cpp b/src/sksl/SkSLUtil.cpp
index c715cf1d09..49d37e3056 100644
--- a/src/sksl/SkSLUtil.cpp
+++ b/src/sksl/SkSLUtil.cpp
@@ -27,7 +27,7 @@ void sksl_abort() {
}
void write_stringstream(const StringStream& s, OutputStream& out) {
- out.write(s.data(), s.size());
+ out.write(s.str().c_str(), s.str().size());
}
} // namespace
diff --git a/src/sksl/SkSLUtil.h b/src/sksl/SkSLUtil.h
index b56ae16d2c..606d3e375f 100644
--- a/src/sksl/SkSLUtil.h
+++ b/src/sksl/SkSLUtil.h
@@ -135,6 +135,10 @@ public:
return false;
}
+ bool floatPrecisionVaries() const {
+ return false;
+ }
+
const char* shaderDerivativeExtensionString() const {
return nullptr;
}
diff --git a/src/sksl/ast/SkSLASTDeclaration.h b/src/sksl/ast/SkSLASTDeclaration.h
index 0395ef91b4..873c6b2208 100644
--- a/src/sksl/ast/SkSLASTDeclaration.h
+++ b/src/sksl/ast/SkSLASTDeclaration.h
@@ -22,7 +22,8 @@ struct ASTDeclaration : public ASTPositionNode {
kInterfaceBlock_Kind,
kExtension_Kind,
kPrecision_Kind,
- kModifiers_Kind
+ kModifiers_Kind,
+ kSection_Kind
};
ASTDeclaration(Position position, Kind kind)
diff --git a/src/sksl/ast/SkSLASTFunction.h b/src/sksl/ast/SkSLASTFunction.h
index 0dff3aeaa1..36d8a3af9f 100644
--- a/src/sksl/ast/SkSLASTFunction.h
+++ b/src/sksl/ast/SkSLASTFunction.h
@@ -20,7 +20,7 @@ namespace SkSL {
*/
struct ASTFunction : public ASTDeclaration {
ASTFunction(Position position, Modifiers modifiers, std::unique_ptr<ASTType> returnType,
- String name, std::vector<std::unique_ptr<ASTParameter>> parameters,
+ String name, std::vector<std::unique_ptr<ASTParameter>> parameters,
std::unique_ptr<ASTBlock> body)
: INHERITED(position, kFunction_Kind)
, fModifiers(modifiers)
diff --git a/src/sksl/ast/SkSLASTSection.h b/src/sksl/ast/SkSLASTSection.h
new file mode 100644
index 0000000000..d0887e20fe
--- /dev/null
+++ b/src/sksl/ast/SkSLASTSection.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SKSL_ASTSECTION
+#define SKSL_ASTSECTION
+
+#include "SkSLASTDeclaration.h"
+
+namespace SkSL {
+
+/**
+ * A section declaration (e.g. @body { body code here })..
+ */
+struct ASTSection : public ASTDeclaration {
+ ASTSection(Position position, String name, String arg, String text)
+ : INHERITED(position, kSection_Kind)
+ , fName(std::move(name))
+ , fArgument(std::move(arg))
+ , fText(std::move(text)) {}
+
+ String description() const override {
+ String result = "@" + fName;
+ if (fArgument.size()) {
+ result += "(" + fArgument + ")";
+ }
+ result += " { " + fText + " }";
+ return result;
+ }
+
+ const String fName;
+ const String fArgument;
+ const String fText;
+
+ typedef ASTDeclaration INHERITED;
+};
+
+} // namespace
+
+#endif
diff --git a/src/sksl/ir/SkSLExpression.h b/src/sksl/ir/SkSLExpression.h
index 07dad1d7df..89a1a1e84a 100644
--- a/src/sksl/ir/SkSLExpression.h
+++ b/src/sksl/ir/SkSLExpression.h
@@ -36,6 +36,7 @@ struct Expression : public IRNode {
kIndex_Kind,
kPrefix_Kind,
kPostfix_Kind,
+ kSetting_Kind,
kSwizzle_Kind,
kVariableReference_Kind,
kTernary_Kind,
diff --git a/src/sksl/ir/SkSLFunctionDeclaration.h b/src/sksl/ir/SkSLFunctionDeclaration.h
index 8704c9a5b0..64236d3980 100644
--- a/src/sksl/ir/SkSLFunctionDeclaration.h
+++ b/src/sksl/ir/SkSLFunctionDeclaration.h
@@ -71,7 +71,7 @@ struct FunctionDeclaration : public Symbol {
bool determineFinalTypes(const std::vector<std::unique_ptr<Expression>>& arguments,
std::vector<const Type*>* outParameterTypes,
const Type** outReturnType) const {
- assert(arguments.size() == fParameters.size());
+ ASSERT(arguments.size() == fParameters.size());
int genericIndex = -1;
for (size_t i = 0; i < arguments.size(); i++) {
if (fParameters[i]->fType.kind() == Type::kGeneric_Kind) {
@@ -93,7 +93,7 @@ struct FunctionDeclaration : public Symbol {
}
}
if (fReturnType.kind() == Type::kGeneric_Kind) {
- assert(genericIndex != -1);
+ ASSERT(genericIndex != -1);
*outReturnType = fReturnType.coercibleTypes()[genericIndex];
} else {
*outReturnType = &fReturnType;
diff --git a/src/sksl/ir/SkSLLayout.h b/src/sksl/ir/SkSLLayout.h
index 3a8416ac4e..8bf0472a95 100644
--- a/src/sksl/ir/SkSLLayout.h
+++ b/src/sksl/ir/SkSLLayout.h
@@ -8,6 +8,7 @@
#ifndef SKSL_LAYOUT
#define SKSL_LAYOUT
+#include "SkSLString.h"
#include "SkSLUtil.h"
namespace SkSL {
@@ -42,6 +43,16 @@ struct Layout {
kR8I,
};
+ // used by SkSL processors
+ enum Key {
+ // field is not a key
+ kNo_Key,
+ // field is a key
+ kKey_Key,
+ // key is 0 or 1 depending on whether the matrix is an identity matrix
+ kIdentity_Key,
+ };
+
static const char* FormatToStr(Format format) {
switch (format) {
case Format::kUnspecified: return "";
@@ -55,7 +66,6 @@ struct Layout {
case Format::kR8I: return "r8i";
}
ABORT("Unexpected format");
- return "";
}
static bool ReadFormat(String str, Format* format) {
@@ -90,7 +100,7 @@ struct Layout {
Layout(int location, int offset, int binding, int index, int set, int builtin,
int inputAttachmentIndex, bool originUpperLeft, bool overrideCoverage,
bool blendSupportAllEquations, Format format, bool pushconstant, Primitive primitive,
- int maxVertices, int invocations)
+ int maxVertices, int invocations, String when, Key key)
: fLocation(location)
, fOffset(offset)
, fBinding(binding)
@@ -105,7 +115,9 @@ struct Layout {
, fPushConstant(pushconstant)
, fPrimitive(primitive)
, fMaxVertices(maxVertices)
- , fInvocations(invocations) {}
+ , fInvocations(invocations)
+ , fWhen(when)
+ , fKey(key) {}
Layout()
: fLocation(-1)
@@ -122,7 +134,8 @@ struct Layout {
, fPushConstant(false)
, fPrimitive(kUnspecified_Primitive)
, fMaxVertices(-1)
- , fInvocations(-1) {}
+ , fInvocations(-1)
+ , fKey(kNo_Key) {}
String description() const {
String result;
@@ -215,6 +228,22 @@ struct Layout {
result += separator + "invocations = " + to_string(fInvocations);
separator = ", ";
}
+ if (fWhen.size()) {
+ result += separator + "when = " + fWhen;
+ separator = ", ";
+ }
+ switch (fKey) {
+ case kNo_Key:
+ break;
+ case kKey_Key:
+ result += separator + "key";
+ separator = ", ";
+ break;
+ case kIdentity_Key:
+ result += separator + "key=identity";
+ separator = ", ";
+ break;
+ }
if (result.size() > 0) {
result = "layout (" + result + ")";
}
@@ -261,6 +290,8 @@ struct Layout {
Primitive fPrimitive;
int fMaxVertices;
int fInvocations;
+ String fWhen;
+ Key fKey;
};
} // namespace
diff --git a/src/sksl/ir/SkSLPrefixExpression.h b/src/sksl/ir/SkSLPrefixExpression.h
index acab37ed88..5ac84c66b1 100644
--- a/src/sksl/ir/SkSLPrefixExpression.h
+++ b/src/sksl/ir/SkSLPrefixExpression.h
@@ -33,9 +33,8 @@ struct PrefixExpression : public Expression {
fOperand->hasSideEffects();
}
- virtual std::unique_ptr<Expression> constantPropagate(
- const IRGenerator& irGenerator,
- const DefinitionMap& definitions) override {
+ std::unique_ptr<Expression> constantPropagate(const IRGenerator& irGenerator,
+ const DefinitionMap& definitions) override {
if (fOperand->fKind == Expression::kFloatLiteral_Kind) {
return std::unique_ptr<Expression>(new FloatLiteral(
irGenerator.fContext,
diff --git a/src/sksl/ir/SkSLProgram.h b/src/sksl/ir/SkSLProgram.h
index 96bd5c4fbd..a3eeaa3612 100644
--- a/src/sksl/ir/SkSLProgram.h
+++ b/src/sksl/ir/SkSLProgram.h
@@ -11,7 +11,9 @@
#include <vector>
#include <memory>
-#include "SkSLContext.h"
+#include "SkSLBoolLiteral.h"
+#include "SkSLExpression.h"
+#include "SkSLIntLiteral.h"
#include "SkSLModifiers.h"
#include "SkSLProgramElement.h"
#include "SkSLSymbolTable.h"
@@ -21,11 +23,46 @@
namespace SkSL {
+class Context;
+
/**
* Represents a fully-digested program, ready for code generation.
*/
struct Program {
struct Settings {
+ struct Value {
+ Value(bool b)
+ : fKind(kBool_Kind)
+ , fValue(b) {}
+
+ Value(int i)
+ : fKind(kInt_Kind)
+ , fValue(i) {}
+
+ std::unique_ptr<Expression> literal(const Context& context, Position position) const {
+ switch (fKind) {
+ case Program::Settings::Value::kBool_Kind:
+ return std::unique_ptr<Expression>(new BoolLiteral(context,
+ position,
+ fValue));
+ case Program::Settings::Value::kInt_Kind:
+ return std::unique_ptr<Expression>(new IntLiteral(context,
+ position,
+ fValue));
+ default:
+ ASSERT(false);
+ return nullptr;
+ }
+ }
+
+ enum {
+ kBool_Kind,
+ kInt_Kind,
+ } fKind;
+
+ int fValue;
+ };
+
#ifdef SKSL_STANDALONE
const StandaloneShaderCaps* fCaps = &standaloneCaps;
#else
@@ -34,6 +71,10 @@ struct Program {
// if false, sk_FragCoord is exactly the same as gl_FragCoord. If true, the y coordinate
// must be flipped.
bool fFlipY = false;
+ // if true, Setting objects (e.g. sk_Caps.fbFetchSupport) should be replaced with their
+ // constant equivalents during compilation
+ bool fReplaceSettings = true;
+ std::unordered_map<String, Value> fArgs;
};
struct Inputs {
@@ -57,7 +98,8 @@ struct Program {
enum Kind {
kFragment_Kind,
kVertex_Kind,
- kGeometry_Kind
+ kGeometry_Kind,
+ kFragmentProcessor_Kind
};
Program(Kind kind,
diff --git a/src/sksl/ir/SkSLProgramElement.h b/src/sksl/ir/SkSLProgramElement.h
index ebb4e9a84d..1e2bb48641 100644
--- a/src/sksl/ir/SkSLProgramElement.h
+++ b/src/sksl/ir/SkSLProgramElement.h
@@ -21,7 +21,8 @@ struct ProgramElement : public IRNode {
kFunction_Kind,
kInterfaceBlock_Kind,
kExtension_Kind,
- kModifiers_Kind
+ kModifiers_Kind,
+ kSection_Kind
};
ProgramElement(Position position, Kind kind)
diff --git a/src/sksl/ir/SkSLSection.h b/src/sksl/ir/SkSLSection.h
new file mode 100644
index 0000000000..f9815b1caa
--- /dev/null
+++ b/src/sksl/ir/SkSLSection.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SKSL_SECTION
+#define SKSL_SECTION
+
+#include "SkSLProgramElement.h"
+
+namespace SkSL {
+
+/**
+ * A section declaration (e.g. @body { body code here })..
+ */
+struct Section : public ProgramElement {
+ Section(Position position, String name, String arg, String text)
+ : INHERITED(position, kSection_Kind)
+ , fName(std::move(name))
+ , fArgument(std::move(arg))
+ , fText(std::move(text)) {}
+
+ String description() const override {
+ String result = "@" + fName;
+ if (fArgument.size()) {
+ result += "(" + fArgument + ")";
+ }
+ result += " { " + fText + " }";
+ return result;
+ }
+
+ const String fName;
+ const String fArgument;
+ const String fText;
+
+ typedef ProgramElement INHERITED;
+};
+
+} // namespace
+
+#endif
diff --git a/src/sksl/ir/SkSLSetting.cpp b/src/sksl/ir/SkSLSetting.cpp
new file mode 100644
index 0000000000..2d4a8ba151
--- /dev/null
+++ b/src/sksl/ir/SkSLSetting.cpp
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkSLSetting.h"
+#include "SkSLIRGenerator.h"
+#include "SkSLVariableReference.h"
+
+namespace SkSL {
+
+std::unique_ptr<Expression> Setting::constantPropagate(const IRGenerator& irGenerator,
+ const DefinitionMap& definitions) {
+ if (irGenerator.fSettings->fReplaceSettings) {
+ return VariableReference::copy_constant(irGenerator, fValue.get());
+ }
+ return nullptr;
+ }
+} // namespace
+
diff --git a/src/sksl/ir/SkSLSetting.h b/src/sksl/ir/SkSLSetting.h
new file mode 100644
index 0000000000..995fcf55bf
--- /dev/null
+++ b/src/sksl/ir/SkSLSetting.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SKSL_SETTING
+#define SKSL_SETTING
+
+#include "SkSLContext.h"
+#include "SkSLExpression.h"
+
+namespace SkSL {
+
+/**
+ * Represents a compile-time constant setting, such as sk_Caps.fbFetchSupport. These are generally
+ * collapsed down to their constant representations during the compilation process.
+ */
+struct Setting : public Expression {
+ Setting(Position position, String name, std::unique_ptr<Expression> value)
+ : INHERITED(position, kSetting_Kind, value->fType)
+ , fName(std::move(name))
+ , fValue(std::move(value)) {
+ ASSERT(fValue->isConstant());
+ }
+
+ std::unique_ptr<Expression> constantPropagate(const IRGenerator& irGenerator,
+ const DefinitionMap& definitions) override;
+
+ String description() const override {
+ return fName;
+ }
+
+ bool hasSideEffects() const override {
+ return false;
+ }
+
+ bool isConstant() const override {
+ return true;
+ }
+
+ const String fName;
+ std::unique_ptr<Expression> fValue;
+
+ typedef Expression INHERITED;
+};
+
+} // namespace
+
+#endif
diff --git a/src/sksl/ir/SkSLSwizzle.h b/src/sksl/ir/SkSLSwizzle.h
index 1e36c41e41..442e92f348 100644
--- a/src/sksl/ir/SkSLSwizzle.h
+++ b/src/sksl/ir/SkSLSwizzle.h
@@ -71,10 +71,8 @@ struct Swizzle : public Expression {
ASSERT(fComponents.size() >= 1 && fComponents.size() <= 4);
}
- virtual std::unique_ptr<Expression> constantPropagate(
- const IRGenerator& irGenerator,
- const DefinitionMap& definitions) override {
-
+ std::unique_ptr<Expression> constantPropagate(const IRGenerator& irGenerator,
+ const DefinitionMap& definitions) override {
if (fBase->fKind == Expression::kConstructor_Kind && fBase->isConstant()) {
// we're swizzling a constant vector, e.g. vec4(1).x. Simplify it.
ASSERT(fBase->fKind == Expression::kConstructor_Kind);
diff --git a/src/sksl/ir/SkSLVarDeclarations.h b/src/sksl/ir/SkSLVarDeclarations.h
index c07fee87db..1eda87e979 100644
--- a/src/sksl/ir/SkSLVarDeclarations.h
+++ b/src/sksl/ir/SkSLVarDeclarations.h
@@ -55,7 +55,7 @@ struct VarDeclaration : public Statement {
* A variable declaration statement, which may consist of one or more individual variables.
*/
struct VarDeclarations : public ProgramElement {
- VarDeclarations(Position position, const Type* baseType,
+ VarDeclarations(Position position, const Type* baseType,
std::vector<std::unique_ptr<VarDeclaration>> vars)
: INHERITED(position, kVar_Kind)
, fBaseType(*baseType) {
diff --git a/src/sksl/ir/SkSLVariableReference.h b/src/sksl/ir/SkSLVariableReference.h
index 92aef94290..ba17437e24 100644
--- a/src/sksl/ir/SkSLVariableReference.h
+++ b/src/sksl/ir/SkSLVariableReference.h
@@ -14,6 +14,7 @@
#include "SkSLFloatLiteral.h"
#include "SkSLIRGenerator.h"
#include "SkSLIntLiteral.h"
+#include "SkSLSetting.h"
namespace SkSL {
@@ -104,6 +105,12 @@ struct VariableReference : public Expression {
return std::unique_ptr<Expression>(new Constructor(Position(), c->fType,
std::move(args)));
}
+ case Expression::kSetting_Kind: {
+ const Setting* s = (const Setting*) expr;
+ return std::unique_ptr<Expression>(new Setting(Position(), s->fName,
+ copy_constant(irGenerator,
+ s->fValue.get())));
+ }
default:
ABORT("unsupported constant\n");
}
diff --git a/src/sksl/layout.flex b/src/sksl/layout.flex
index 412bd4707b..4e6695cfdc 100644
--- a/src/sksl/layout.flex
+++ b/src/sksl/layout.flex
@@ -51,6 +51,8 @@
"triangles_adjacency" { return SkSL::Token::TRIANGLES_ADJACENCY; }
"max_vertices" { return SkSL::Token::MAX_VERTICES; }
"invocations" { return SkSL::Token::INVOCATIONS; }
+"when" { return SkSL::Token::WHEN; }
+"key" { return SkSL::Token::KEY; }
. { return SkSL::Token::INVALID_TOKEN; }
diff --git a/src/sksl/lex.layout.c b/src/sksl/lex.layout.c
index 42db0fe5ef..63369fe93b 100644
--- a/src/sksl/lex.layout.c
+++ b/src/sksl/lex.layout.c
@@ -5,7 +5,7 @@
* found in the LICENSE file.
*/
-#line 2 "lex.layout.c"
+#line 3 "lex.layout.c"
#define YY_INT_ALIGNED short int
@@ -14,81 +14,11 @@
#define FLEX_SCANNER
#define YY_FLEX_MAJOR_VERSION 2
#define YY_FLEX_MINOR_VERSION 6
-#define YY_FLEX_SUBMINOR_VERSION 3
+#define YY_FLEX_SUBMINOR_VERSION 1
#if YY_FLEX_SUBMINOR_VERSION > 0
#define FLEX_BETA
#endif
- #define yy_create_buffer layout_create_buffer
-
- #define yy_delete_buffer layout_delete_buffer
-
- #define yy_scan_buffer layout_scan_buffer
-
- #define yy_scan_string layout_scan_string
-
- #define yy_scan_bytes layout_scan_bytes
-
- #define yy_init_buffer layout_init_buffer
-
- #define yy_flush_buffer layout_flush_buffer
-
- #define yy_load_buffer_state layout_load_buffer_state
-
- #define yy_switch_to_buffer layout_switch_to_buffer
-
- #define yypush_buffer_state layoutpush_buffer_state
-
- #define yypop_buffer_state layoutpop_buffer_state
-
- #define yyensure_buffer_stack layoutensure_buffer_stack
-
- #define yylex layoutlex
-
- #define yyrestart layoutrestart
-
- #define yylex_init layoutlex_init
-
- #define yylex_init_extra layoutlex_init_extra
-
- #define yylex_destroy layoutlex_destroy
-
- #define yyget_debug layoutget_debug
-
- #define yyset_debug layoutset_debug
-
- #define yyget_extra layoutget_extra
-
- #define yyset_extra layoutset_extra
-
- #define yyget_in layoutget_in
-
- #define yyset_in layoutset_in
-
- #define yyget_out layoutget_out
-
- #define yyset_out layoutset_out
-
- #define yyget_leng layoutget_leng
-
- #define yyget_text layoutget_text
-
- #define yyget_lineno layoutget_lineno
-
- #define yyset_lineno layoutset_lineno
-
- #define yyget_column layoutget_column
-
- #define yyset_column layoutset_column
-
- #define yywrap layoutwrap
-
- #define yyalloc layoutalloc
-
- #define yyrealloc layoutrealloc
-
- #define yyfree layoutfree
-
/* First, we deal with platform-specific or compiler-specific issues. */
/* begin standard C headers. */
@@ -175,10 +105,12 @@ typedef unsigned int flex_uint32_t;
/* Returned upon end-of-file. */
#define YY_NULL 0
-/* Promotes a possibly negative, possibly signed char to an
- * integer in range [0..255] for use as an array index.
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
*/
-#define YY_SC_TO_UI(c) ((YY_CHAR) (c))
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
/* An opaque pointer. */
#ifndef YY_TYPEDEF_YY_SCANNER_T
@@ -202,16 +134,20 @@ typedef void* yyscan_t;
* definition of BEGIN.
*/
#define BEGIN yyg->yy_start = 1 + 2 *
+
/* Translate the current start state into a value that can be later handed
* to BEGIN to return to the state. The YYSTATE alias is for lex
* compatibility.
*/
#define YY_START ((yyg->yy_start - 1) / 2)
#define YYSTATE YY_START
+
/* Action number for EOF rule of a given start state. */
#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
/* Special action meaning "start processing a new file". */
#define YY_NEW_FILE layoutrestart(yyin ,yyscanner )
+
#define YY_END_OF_BUFFER_CHAR 0
/* Size of default input buffer. */
@@ -244,10 +180,10 @@ typedef size_t yy_size_t;
#define EOB_ACT_CONTINUE_SCAN 0
#define EOB_ACT_END_OF_FILE 1
#define EOB_ACT_LAST_MATCH 2
-
+
/* Note: We specifically omit the test for yy_rule_can_match_eol because it requires
* access to the local variable yy_act. Since yyless() is a macro, it would break
- * existing scanners that call yyless() from OUTSIDE layoutlex.
+ * existing scanners that call yyless() from OUTSIDE layoutlex.
* One obvious solution it to make yy_act a global. I tried that, and saw
* a 5% performance hit in a non-yylineno scanner, because yy_act is
* normally declared as a register variable-- so it is not worth it.
@@ -280,6 +216,7 @@ typedef size_t yy_size_t;
YY_DO_BEFORE_ACTION; /* set up yytext again */ \
} \
while ( 0 )
+
#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
#ifndef YY_STRUCT_YY_BUFFER_STATE
@@ -322,7 +259,7 @@ struct yy_buffer_state
int yy_bs_lineno; /**< The line count. */
int yy_bs_column; /**< The column count. */
-
+
/* Whether to try to fill the input buffer when we reach the
* end of it.
*/
@@ -356,33 +293,36 @@ struct yy_buffer_state
#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
: NULL)
+
/* Same as previous macro, but useful when we know that the buffer stack is not
* NULL or when we need an lvalue. For internal use only.
*/
#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
-void layoutrestart ( FILE *input_file , yyscan_t yyscanner );
-void layout_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
-YY_BUFFER_STATE layout_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
-void layout_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
-void layout_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
-void layoutpush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
-void layoutpop_buffer_state ( yyscan_t yyscanner );
-
-static void layoutensure_buffer_stack ( yyscan_t yyscanner );
-static void layout_load_buffer_state ( yyscan_t yyscanner );
-static void layout_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner );
+void layoutrestart (FILE *input_file ,yyscan_t yyscanner );
+void layout_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE layout_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void layout_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void layout_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void layoutpush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void layoutpop_buffer_state (yyscan_t yyscanner );
+
+static void layoutensure_buffer_stack (yyscan_t yyscanner );
+static void layout_load_buffer_state (yyscan_t yyscanner );
+static void layout_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+
#define YY_FLUSH_BUFFER layout_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
-YY_BUFFER_STATE layout_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
-YY_BUFFER_STATE layout_scan_string ( const char *yy_str , yyscan_t yyscanner );
-YY_BUFFER_STATE layout_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
+YY_BUFFER_STATE layout_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE layout_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE layout_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
-void *layoutalloc ( yy_size_t , yyscan_t yyscanner );
-void *layoutrealloc ( void *, yy_size_t , yyscan_t yyscanner );
-void layoutfree ( void * , yyscan_t yyscanner );
+void *layoutalloc (yy_size_t ,yyscan_t yyscanner );
+void *layoutrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void layoutfree (void * ,yyscan_t yyscanner );
#define yy_new_buffer layout_create_buffer
+
#define yy_set_interactive(is_interactive) \
{ \
if ( ! YY_CURRENT_BUFFER ){ \
@@ -392,6 +332,7 @@ void layoutfree ( void * , yyscan_t yyscanner );
} \
YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
}
+
#define yy_set_bol(at_bol) \
{ \
if ( ! YY_CURRENT_BUFFER ){\
@@ -401,19 +342,21 @@ void layoutfree ( void * , yyscan_t yyscanner );
} \
YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
}
+
#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
/* Begin user sect3 */
-typedef flex_uint8_t YY_CHAR;
+
+typedef unsigned char YY_CHAR;
typedef int yy_state_type;
#define yytext_ptr yytext_r
-static yy_state_type yy_get_previous_state ( yyscan_t yyscanner );
-static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner);
-static int yy_get_next_buffer ( yyscan_t yyscanner );
-static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner );
+static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner);
+static int yy_get_next_buffer (yyscan_t yyscanner );
+static void yynoreturn yy_fatal_error (yyconst char* msg ,yyscan_t yyscanner );
/* Done after the current pattern has been matched and before the
* corresponding action - sets up yytext.
@@ -424,8 +367,9 @@ static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner );
yyg->yy_hold_char = *yy_cp; \
*yy_cp = '\0'; \
yyg->yy_c_buf_p = yy_cp;
-#define YY_NUM_RULES 22
-#define YY_END_OF_BUFFER 23
+
+#define YY_NUM_RULES 24
+#define YY_END_OF_BUFFER 25
/* This struct is not used in this scanner,
but its presence is necessary. */
struct yy_trans_info
@@ -433,34 +377,34 @@ struct yy_trans_info
flex_int32_t yy_verify;
flex_int32_t yy_nxt;
};
-static const flex_int16_t yy_accept[204] =
+static yyconst flex_int16_t yy_accept[211] =
{ 0,
- 0, 0, 23, 21, 22, 21, 21, 21, 21, 21,
- 21, 21, 21, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 25, 23, 24, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 5, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 22, 0, 0,
+ 0, 0, 0, 0, 0, 0, 5, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 4, 0, 0, 0, 13, 0, 0, 0, 0,
+ 0, 0, 0, 0, 21, 0, 0, 0, 4, 0,
+ 0, 0, 13, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 2, 0, 0, 12, 0, 0, 3,
- 0, 6, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 0, 0, 12, 0, 0, 3, 0, 6, 0,
- 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 16, 0, 0, 0, 14, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 20, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 19, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 11,
- 0, 0, 0, 0, 0, 0, 0, 17, 0, 0,
- 0, 15, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 8, 9, 0, 0, 0, 0, 0, 0,
- 18, 0, 0, 0, 0, 0, 7, 0, 0, 0,
-
- 0, 10, 0
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 16, 0, 0, 0, 14, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 20, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 19, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 11, 0, 0, 0,
+ 0, 0, 0, 0, 17, 0, 0, 0, 15, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,
+ 9, 0, 0, 0, 0, 0, 0, 18, 0, 0,
+
+ 0, 0, 0, 7, 0, 0, 0, 0, 10, 0
} ;
-static const YY_CHAR yy_ec[256] =
+static yyconst YY_CHAR yy_ec[256] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -473,9 +417,9 @@ static const YY_CHAR yy_ec[256] =
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 3, 1, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 13, 1, 14, 15, 16,
- 17, 18, 19, 20, 21, 22, 23, 24, 1, 25,
- 26, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -492,134 +436,138 @@ static const YY_CHAR yy_ec[256] =
1, 1, 1, 1, 1
} ;
-static const YY_CHAR yy_meta[27] =
+static yyconst YY_CHAR yy_meta[29] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1
+ 1, 1, 1, 1, 1, 1, 1, 1
} ;
-static const flex_int16_t yy_base[205] =
+static yyconst flex_uint16_t yy_base[212] =
{ 0,
- 0, 21, 218, 219, 219, 17, 201, 7, 212, 21,
- 11, 207, 194, 197, 204, 199, 30, 194, 203, 183,
- 198, 194, 197, 192, 182, 180, 189, 193, 183, 184,
- 189, 173, 178, 186, 189, 189, 170, 180, 169, 172,
- 176, 219, 182, 173, 177, 161, 157, 159, 174, 4,
- 157, 154, 169, 164, 155, 152, 170, 156, 155, 167,
- 157, 219, 165, 163, 145, 162, 152, 155, 140, 145,
- 148, 138, 152, 147, 146, 134, 138, 149, 130, 129,
- 146, 132, 128, 219, 144, 139, 219, 128, 130, 219,
- 120, 219, 120, 129, 120, 132, 122, 115, 113, 127,
-
- 118, 125, 114, 109, 113, 117, 115, 219, 115, 108,
- 122, 103, 6, 105, 118, 105, 102, 115, 112, 99,
- 110, 93, 93, 110, 95, 105, 89, 219, 103, 100,
- 99, 89, 101, 82, 99, 82, 90, 219, 92, 78,
- 78, 73, 80, 75, 87, 71, 77, 75, 219, 87,
- 81, 66, 75, 73, 82, 76, 77, 68, 61, 219,
- 62, 75, 74, 61, 50, 67, 70, 219, 67, 58,
- 49, 219, 61, 59, 60, 53, 63, 43, 56, 47,
- 59, 49, 219, 219, 54, 51, 42, 31, 37, 48,
- 219, 30, 44, 47, 25, 27, 219, 35, 29, 28,
-
- 11, 219, 219, 0
+ 0, 25, 227, 228, 228, 5, 209, 217, 13, 220,
+ 24, 10, 215, 201, 210, 203, 211, 206, 17, 189,
+ 199, 209, 187, 204, 200, 203, 198, 187, 185, 195,
+ 198, 198, 187, 188, 194, 177, 182, 228, 191, 194,
+ 194, 174, 185, 173, 176, 181, 228, 187, 173, 177,
+ 181, 164, 159, 162, 178, 10, 160, 157, 173, 168,
+ 158, 155, 174, 159, 228, 158, 171, 161, 228, 169,
+ 167, 148, 166, 156, 159, 143, 148, 152, 141, 156,
+ 151, 150, 137, 141, 153, 133, 132, 150, 135, 131,
+ 228, 148, 143, 228, 131, 133, 228, 123, 228, 123,
+
+ 133, 123, 136, 125, 118, 116, 131, 121, 129, 117,
+ 112, 116, 121, 119, 228, 119, 111, 126, 106, 32,
+ 108, 122, 108, 105, 119, 116, 102, 114, 96, 96,
+ 114, 98, 109, 92, 228, 107, 104, 103, 92, 105,
+ 85, 103, 85, 94, 228, 96, 81, 81, 76, 83,
+ 78, 91, 74, 80, 78, 228, 91, 85, 69, 79,
+ 77, 86, 80, 81, 71, 64, 228, 65, 79, 78,
+ 64, 52, 71, 74, 228, 71, 61, 52, 228, 65,
+ 63, 64, 56, 67, 46, 60, 50, 63, 53, 228,
+ 228, 58, 55, 45, 33, 40, 52, 228, 34, 49,
+
+ 52, 28, 30, 228, 40, 32, 29, 16, 228, 228,
+ 0
} ;
-static const flex_int16_t yy_def[205] =
+static yyconst flex_int16_t yy_def[212] =
{ 0,
- 204, 204, 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
-
- 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
-
- 203, 203, 0, 203
+ 211, 211, 210, 210, 210, 210, 210, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 0,
+ 210
} ;
-static const flex_int16_t yy_nxt[246] =
+static yyconst flex_uint16_t yy_nxt[257] =
{ 0,
- 4, 5, 203, 203, 6, 203, 65, 203, 123, 203,
- 203, 7, 203, 8, 9, 203, 10, 11, 18, 203,
- 12, 13, 5, 19, 66, 6, 124, 24, 14, 21,
- 15, 202, 7, 25, 8, 9, 31, 10, 11, 16,
- 22, 12, 13, 201, 23, 200, 199, 32, 198, 197,
- 196, 195, 194, 33, 193, 192, 191, 190, 189, 188,
- 187, 186, 185, 184, 183, 182, 181, 180, 179, 178,
- 177, 176, 175, 174, 173, 172, 171, 170, 169, 168,
- 167, 166, 165, 164, 163, 162, 161, 160, 159, 158,
- 157, 156, 155, 154, 153, 152, 151, 150, 149, 148,
-
- 147, 146, 145, 144, 143, 142, 141, 140, 139, 138,
- 137, 136, 135, 134, 133, 132, 131, 130, 129, 128,
- 127, 126, 125, 122, 121, 120, 119, 118, 117, 116,
- 115, 114, 113, 112, 111, 110, 109, 108, 107, 106,
- 105, 104, 103, 102, 101, 100, 99, 98, 97, 96,
- 95, 94, 93, 92, 91, 90, 89, 88, 87, 86,
- 85, 84, 83, 82, 81, 80, 79, 78, 77, 76,
- 75, 74, 73, 72, 71, 70, 69, 68, 67, 64,
- 63, 62, 61, 60, 59, 58, 57, 56, 55, 54,
- 53, 52, 51, 50, 49, 48, 47, 46, 45, 44,
-
- 43, 42, 41, 40, 39, 38, 37, 36, 35, 34,
- 30, 29, 28, 27, 26, 20, 17, 203, 3, 203,
- 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203
+ 4, 5, 210, 210, 6, 210, 210, 210, 210, 210,
+ 210, 7, 72, 8, 9, 10, 16, 11, 12, 17,
+ 210, 13, 14, 35, 21, 15, 5, 27, 18, 6,
+ 22, 73, 24, 28, 130, 36, 7, 209, 8, 9,
+ 10, 37, 11, 12, 25, 208, 13, 14, 26, 207,
+ 15, 206, 205, 131, 204, 203, 202, 201, 200, 199,
+ 198, 197, 196, 195, 194, 193, 192, 191, 190, 189,
+ 188, 187, 186, 185, 184, 183, 182, 181, 180, 179,
+ 178, 177, 176, 175, 174, 173, 172, 171, 170, 169,
+ 168, 167, 166, 165, 164, 163, 162, 161, 160, 159,
+
+ 158, 157, 156, 155, 154, 153, 152, 151, 150, 149,
+ 148, 147, 146, 145, 144, 143, 142, 141, 140, 139,
+ 138, 137, 136, 135, 134, 133, 132, 129, 128, 127,
+ 126, 125, 124, 123, 122, 121, 120, 119, 118, 117,
+ 116, 115, 114, 113, 112, 111, 110, 109, 108, 107,
+ 106, 105, 104, 103, 102, 101, 100, 99, 98, 97,
+ 96, 95, 94, 93, 92, 91, 90, 89, 88, 87,
+ 86, 85, 84, 83, 82, 81, 80, 79, 78, 77,
+ 76, 75, 74, 71, 70, 69, 68, 67, 66, 65,
+ 64, 63, 62, 61, 60, 59, 58, 57, 56, 55,
+
+ 54, 53, 52, 51, 50, 49, 48, 47, 46, 45,
+ 44, 43, 42, 41, 40, 39, 38, 34, 33, 32,
+ 31, 30, 29, 23, 20, 19, 210, 3, 210, 210,
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210
} ;
-static const flex_int16_t yy_chk[246] =
+static yyconst flex_int16_t yy_chk[257] =
{ 0,
- 204, 1, 0, 0, 1, 0, 50, 0, 113, 0,
- 0, 1, 0, 1, 1, 0, 1, 1, 8, 0,
- 1, 1, 2, 8, 50, 2, 113, 11, 6, 10,
- 6, 201, 2, 11, 2, 2, 17, 2, 2, 6,
- 10, 2, 2, 200, 10, 199, 198, 17, 196, 195,
- 194, 193, 192, 17, 190, 189, 188, 187, 186, 185,
- 182, 181, 180, 179, 178, 177, 176, 175, 174, 173,
- 171, 170, 169, 167, 166, 165, 164, 163, 162, 161,
- 159, 158, 157, 156, 155, 154, 153, 152, 151, 150,
- 148, 147, 146, 145, 144, 143, 142, 141, 140, 139,
-
- 137, 136, 135, 134, 133, 132, 131, 130, 129, 127,
- 126, 125, 124, 123, 122, 121, 120, 119, 118, 117,
- 116, 115, 114, 112, 111, 110, 109, 107, 106, 105,
- 104, 103, 102, 101, 100, 99, 98, 97, 96, 95,
- 94, 93, 91, 89, 88, 86, 85, 83, 82, 81,
- 80, 79, 78, 77, 76, 75, 74, 73, 72, 71,
- 70, 69, 68, 67, 66, 65, 64, 63, 61, 60,
- 59, 58, 57, 56, 55, 54, 53, 52, 51, 49,
- 48, 47, 46, 45, 44, 43, 41, 40, 39, 38,
- 37, 36, 35, 34, 33, 32, 31, 30, 29, 28,
-
- 27, 26, 25, 24, 23, 22, 21, 20, 19, 18,
- 16, 15, 14, 13, 12, 9, 7, 3, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203
+ 211, 1, 0, 0, 1, 0, 0, 0, 0, 0,
+ 0, 1, 56, 1, 1, 1, 6, 1, 1, 6,
+ 0, 1, 1, 19, 9, 1, 2, 12, 6, 2,
+ 9, 56, 11, 12, 120, 19, 2, 208, 2, 2,
+ 2, 19, 2, 2, 11, 207, 2, 2, 11, 206,
+ 2, 205, 203, 120, 202, 201, 200, 199, 197, 196,
+ 195, 194, 193, 192, 189, 188, 187, 186, 185, 184,
+ 183, 182, 181, 180, 178, 177, 176, 174, 173, 172,
+ 171, 170, 169, 168, 166, 165, 164, 163, 162, 161,
+ 160, 159, 158, 157, 155, 154, 153, 152, 151, 150,
+
+ 149, 148, 147, 146, 144, 143, 142, 141, 140, 139,
+ 138, 137, 136, 134, 133, 132, 131, 130, 129, 128,
+ 127, 126, 125, 124, 123, 122, 121, 119, 118, 117,
+ 116, 114, 113, 112, 111, 110, 109, 108, 107, 106,
+ 105, 104, 103, 102, 101, 100, 98, 96, 95, 93,
+ 92, 90, 89, 88, 87, 86, 85, 84, 83, 82,
+ 81, 80, 79, 78, 77, 76, 75, 74, 73, 72,
+ 71, 70, 68, 67, 66, 64, 63, 62, 61, 60,
+ 59, 58, 57, 55, 54, 53, 52, 51, 50, 49,
+ 48, 46, 45, 44, 43, 42, 41, 40, 39, 37,
+
+ 36, 35, 34, 33, 32, 31, 30, 29, 28, 27,
+ 26, 25, 24, 23, 22, 21, 20, 18, 17, 16,
+ 15, 14, 13, 10, 8, 7, 3, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210
} ;
/* Table of booleans, true if rule could match eol. */
-static const flex_int32_t yy_rule_can_match_eol[23] =
+static yyconst flex_int32_t yy_rule_can_match_eol[25] =
{ 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, };
+ 0, 0, 0, 0, 0, };
/* The intent behind this definition is that it'll catch
* any uses of REJECT which flex missed.
@@ -651,8 +599,7 @@ static const flex_int32_t yy_rule_can_match_eol[23] =
#define YY_NO_UNISTD_H 1
#line 29 "layout.flex"
#include "SkSLToken.h"
-#line 648 "lex.layout.c"
-#line 649 "lex.layout.c"
+#line 597 "lex.layout.c"
#define INITIAL 0
@@ -702,44 +649,44 @@ struct yyguts_t
}; /* end struct yyguts_t */
-static int yy_init_globals ( yyscan_t yyscanner );
+static int yy_init_globals (yyscan_t yyscanner );
int layoutlex_init (yyscan_t* scanner);
-int layoutlex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
+int layoutlex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
/* Accessor methods to globals.
These are made visible to non-reentrant scanners for convenience. */
-int layoutlex_destroy ( yyscan_t yyscanner );
+int layoutlex_destroy (yyscan_t yyscanner );
-int layoutget_debug ( yyscan_t yyscanner );
+int layoutget_debug (yyscan_t yyscanner );
-void layoutset_debug ( int debug_flag , yyscan_t yyscanner );
+void layoutset_debug (int debug_flag ,yyscan_t yyscanner );
-YY_EXTRA_TYPE layoutget_extra ( yyscan_t yyscanner );
+YY_EXTRA_TYPE layoutget_extra (yyscan_t yyscanner );
-void layoutset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
+void layoutset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
-FILE *layoutget_in ( yyscan_t yyscanner );
+FILE *layoutget_in (yyscan_t yyscanner );
-void layoutset_in ( FILE * _in_str , yyscan_t yyscanner );
+void layoutset_in (FILE * _in_str ,yyscan_t yyscanner );
-FILE *layoutget_out ( yyscan_t yyscanner );
+FILE *layoutget_out (yyscan_t yyscanner );
-void layoutset_out ( FILE * _out_str , yyscan_t yyscanner );
+void layoutset_out (FILE * _out_str ,yyscan_t yyscanner );
- int layoutget_leng ( yyscan_t yyscanner );
+ int layoutget_leng (yyscan_t yyscanner );
-char *layoutget_text ( yyscan_t yyscanner );
+char *layoutget_text (yyscan_t yyscanner );
-int layoutget_lineno ( yyscan_t yyscanner );
+int layoutget_lineno (yyscan_t yyscanner );
-void layoutset_lineno ( int _line_number , yyscan_t yyscanner );
+void layoutset_lineno (int _line_number ,yyscan_t yyscanner );
-int layoutget_column ( yyscan_t yyscanner );
+int layoutget_column (yyscan_t yyscanner );
-void layoutset_column ( int _column_no , yyscan_t yyscanner );
+void layoutset_column (int _column_no ,yyscan_t yyscanner );
/* Macros after this point can all be overridden by user definitions in
* section 1.
@@ -747,31 +694,32 @@ void layoutset_column ( int _column_no , yyscan_t yyscanner );
#ifndef YY_SKIP_YYWRAP
#ifdef __cplusplus
-extern "C" int layoutwrap ( yyscan_t yyscanner );
+extern "C" int layoutwrap (yyscan_t yyscanner );
#else
-extern int layoutwrap ( yyscan_t yyscanner );
+extern int layoutwrap (yyscan_t yyscanner );
#endif
#endif
#ifndef YY_NO_UNPUT
- static void yyunput ( int c, char *buf_ptr , yyscan_t yyscanner);
+ static void yyunput (int c,char *buf_ptr ,yyscan_t yyscanner);
#endif
#ifndef yytext_ptr
-static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
#endif
#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
#endif
#ifndef YY_NO_INPUT
+
#ifdef __cplusplus
-static int yyinput ( yyscan_t yyscanner );
+static int yyinput (yyscan_t yyscanner );
#else
-static int input ( yyscan_t yyscanner );
+static int input (yyscan_t yyscanner );
#endif
#endif
@@ -802,7 +750,7 @@ static int input ( yyscan_t yyscanner );
if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
{ \
int c = '*'; \
- int n; \
+ size_t n; \
for ( n = 0; n < max_size && \
(c = getc( yyin )) != EOF && c != '\n'; ++n ) \
buf[n] = (char) c; \
@@ -815,7 +763,7 @@ static int input ( yyscan_t yyscanner );
else \
{ \
errno=0; \
- while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \
+ while ( (result = (int) fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
{ \
if( errno != EINTR) \
{ \
@@ -915,7 +863,7 @@ YY_DECL
#line 32 "layout.flex"
-#line 912 "lex.layout.c"
+#line 861 "lex.layout.c"
while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
{
@@ -942,13 +890,13 @@ yy_match:
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 204 )
- yy_c = yy_meta[yy_c];
+ if ( yy_current_state >= 211 )
+ yy_c = yy_meta[(unsigned int) yy_c];
}
- yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c];
++yy_cp;
}
- while ( yy_current_state != 203 );
+ while ( yy_current_state != 210 );
yy_cp = yyg->yy_last_accepting_cpos;
yy_current_state = yyg->yy_last_accepting_state;
@@ -959,10 +907,10 @@ yy_find_action:
if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
{
- int yyl;
+ yy_size_t yyl;
for ( yyl = 0; yyl < yyleng; ++yyl )
if ( yytext[yyl] == '\n' )
-
+
do{ yylineno++;
yycolumn=0;
}while(0)
@@ -1082,15 +1030,25 @@ YY_RULE_SETUP
YY_BREAK
case 21:
YY_RULE_SETUP
-#line 55 "layout.flex"
-{ return SkSL::Token::INVALID_TOKEN; }
+#line 54 "layout.flex"
+{ return SkSL::Token::WHEN; }
YY_BREAK
case 22:
YY_RULE_SETUP
+#line 55 "layout.flex"
+{ return SkSL::Token::KEY; }
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
#line 57 "layout.flex"
+{ return SkSL::Token::INVALID_TOKEN; }
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 59 "layout.flex"
ECHO;
YY_BREAK
-#line 1087 "lex.layout.c"
+#line 1046 "lex.layout.c"
case YY_STATE_EOF(INITIAL):
yyterminate();
@@ -1237,7 +1195,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
char *source = yyg->yytext_ptr;
- int number_to_move, i;
+ yy_size_t number_to_move, i;
int ret_val;
if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
@@ -1266,7 +1224,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
/* Try to read more data. */
/* First move last chars to start of buffer. */
- number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1);
+ number_to_move = (yy_size_t) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
for ( i = 0; i < number_to_move; ++i )
*(dest++) = *(source++);
@@ -1302,7 +1260,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
b->yy_ch_buf = (char *)
/* Include room in for 2 EOB chars. */
- layoutrealloc((void *) b->yy_ch_buf,(yy_size_t) (b->yy_buf_size + 2) ,yyscanner );
+ layoutrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner );
}
else
/* Can't grow it, we don't own it. */
@@ -1348,10 +1306,10 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
else
ret_val = EOB_ACT_CONTINUE_SCAN;
- if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ if ((int) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
/* Extend the array by 50%, plus the number we really need. */
int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
- YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) layoutrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,(yy_size_t) new_size ,yyscanner );
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) layoutrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
}
@@ -1386,10 +1344,10 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 204 )
- yy_c = yy_meta[yy_c];
+ if ( yy_current_state >= 211 )
+ yy_c = yy_meta[(unsigned int) yy_c];
}
- yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c];
}
return yy_current_state;
@@ -1415,11 +1373,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 204 )
- yy_c = yy_meta[yy_c];
+ if ( yy_current_state >= 211 )
+ yy_c = yy_meta[(unsigned int) yy_c];
}
- yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
- yy_is_jam = (yy_current_state == 203);
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c];
+ yy_is_jam = (yy_current_state == 210);
(void)yyg;
return yy_is_jam ? 0 : yy_current_state;
@@ -1496,7 +1454,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
else
{ /* need more input */
- int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr);
+ int offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
++yyg->yy_c_buf_p;
switch ( yy_get_next_buffer( yyscanner ) )
@@ -1543,7 +1501,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
yyg->yy_hold_char = *++yyg->yy_c_buf_p;
if ( c == '\n' )
-
+
do{ yylineno++;
yycolumn=0;
}while(0)
@@ -1631,12 +1589,12 @@ static void layout_load_buffer_state (yyscan_t yyscanner)
if ( ! b )
YY_FATAL_ERROR( "out of dynamic memory in layout_create_buffer()" );
- b->yy_buf_size = size;
+ b->yy_buf_size = (yy_size_t)size;
/* yy_ch_buf has to be 2 characters longer than the size given because
* we need to put in 2 end-of-buffer characters.
*/
- b->yy_ch_buf = (char *) layoutalloc((yy_size_t) (b->yy_buf_size + 2) ,yyscanner );
+ b->yy_ch_buf = (char *) layoutalloc(b->yy_buf_size + 2 ,yyscanner );
if ( ! b->yy_ch_buf )
YY_FATAL_ERROR( "out of dynamic memory in layout_create_buffer()" );
@@ -1783,7 +1741,7 @@ void layoutpop_buffer_state (yyscan_t yyscanner)
*/
static void layoutensure_buffer_stack (yyscan_t yyscanner)
{
- yy_size_t num_to_alloc;
+ int num_to_alloc;
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
if (!yyg->yy_buffer_stack) {
@@ -1798,9 +1756,9 @@ static void layoutensure_buffer_stack (yyscan_t yyscanner)
, yyscanner);
if ( ! yyg->yy_buffer_stack )
YY_FATAL_ERROR( "out of dynamic memory in layoutensure_buffer_stack()" );
-
+
memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
-
+
yyg->yy_buffer_stack_max = num_to_alloc;
yyg->yy_buffer_stack_top = 0;
return;
@@ -1829,7 +1787,7 @@ static void layoutensure_buffer_stack (yyscan_t yyscanner)
* @param base the character buffer
* @param size the size in bytes of the character buffer
* @param yyscanner The scanner object.
- * @return the newly allocated buffer state object.
+ * @return the newly allocated buffer state object.
*/
YY_BUFFER_STATE layout_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner)
{
@@ -1845,7 +1803,7 @@ YY_BUFFER_STATE layout_scan_buffer (char * base, yy_size_t size , yyscan_t yys
if ( ! b )
YY_FATAL_ERROR( "out of dynamic memory in layout_scan_buffer()" );
- b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
b->yy_buf_pos = b->yy_ch_buf = base;
b->yy_is_our_buffer = 0;
b->yy_input_file = NULL;
@@ -1868,7 +1826,7 @@ YY_BUFFER_STATE layout_scan_buffer (char * base, yy_size_t size , yyscan_t yys
* @note If you want to scan bytes that may contain NUL values, then use
* layout_scan_bytes() instead.
*/
-YY_BUFFER_STATE layout_scan_string (const char * yystr , yyscan_t yyscanner)
+YY_BUFFER_STATE layout_scan_string (yyconst char * yystr , yyscan_t yyscanner)
{
return layout_scan_bytes(yystr,(int) strlen(yystr) ,yyscanner);
@@ -1881,15 +1839,15 @@ YY_BUFFER_STATE layout_scan_string (const char * yystr , yyscan_t yyscanner)
* @param yyscanner The scanner object.
* @return the newly allocated buffer state object.
*/
-YY_BUFFER_STATE layout_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner)
+YY_BUFFER_STATE layout_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner)
{
YY_BUFFER_STATE b;
char *buf;
yy_size_t n;
- int i;
+ yy_size_t i;
/* Get memory for full buffer, including space for trailing EOB's. */
- n = (yy_size_t) (_yybytes_len + 2);
+ n = (yy_size_t) _yybytes_len + 2;
buf = (char *) layoutalloc(n ,yyscanner );
if ( ! buf )
YY_FATAL_ERROR( "out of dynamic memory in layout_scan_bytes()" );
@@ -1915,7 +1873,7 @@ YY_BUFFER_STATE layout_scan_bytes (const char * yybytes, int _yybytes_len , yy
#define YY_EXIT_FAILURE 2
#endif
-static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner)
+static void yynoreturn yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
{
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
(void)yyg;
@@ -1957,7 +1915,7 @@ YY_EXTRA_TYPE layoutget_extra (yyscan_t yyscanner)
int layoutget_lineno (yyscan_t yyscanner)
{
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
+
if (! YY_CURRENT_BUFFER)
return 0;
@@ -1970,7 +1928,7 @@ int layoutget_lineno (yyscan_t yyscanner)
int layoutget_column (yyscan_t yyscanner)
{
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
+
if (! YY_CURRENT_BUFFER)
return 0;
@@ -2092,7 +2050,9 @@ void layoutset_debug (int _bdebug , yyscan_t yyscanner)
* the ONLY reentrant function that doesn't take the scanner as the last argument.
* That's why we explicitly handle the declaration, instead of using our macros.
*/
+
int layoutlex_init(yyscan_t* ptr_yy_globals)
+
{
if (ptr_yy_globals == NULL){
errno = EINVAL;
@@ -2119,7 +2079,9 @@ int layoutlex_init(yyscan_t* ptr_yy_globals)
* The user defined value in the first argument will be available to layoutalloc in
* the yyextra field.
*/
+
int layoutlex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
+
{
struct yyguts_t dummy_yyguts;
@@ -2129,20 +2091,20 @@ int layoutlex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals
errno = EINVAL;
return 1;
}
-
+
*ptr_yy_globals = (yyscan_t) layoutalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
-
+
if (*ptr_yy_globals == NULL){
errno = ENOMEM;
return 1;
}
-
+
/* By setting to 0xAA, we expose bugs in
yy_init_globals. Leave at 0x00 for releases. */
memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
-
+
layoutset_extra (yy_user_defined, *ptr_yy_globals);
-
+
return yy_init_globals ( *ptr_yy_globals );
}
@@ -2214,7 +2176,7 @@ int layoutlex_destroy (yyscan_t yyscanner)
*/
#ifndef yytext_ptr
-static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner)
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
{
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
(void)yyg;
@@ -2226,7 +2188,7 @@ static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscann
#endif
#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (const char * s , yyscan_t yyscanner)
+static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
{
int n;
for ( n = 0; s[n]; ++n )
@@ -2267,7 +2229,8 @@ void layoutfree (void * ptr , yyscan_t yyscanner)
#define YYTABLES_NAME "yytables"
-#line 57 "layout.flex"
+#line 59 "layout.flex"
+
int layoutwrap(yyscan_t scanner) {
diff --git a/src/sksl/lex.layout.cpp b/src/sksl/lex.layout.cpp
index 4289b110d9..937c93190e 100644
--- a/src/sksl/lex.layout.cpp
+++ b/src/sksl/lex.layout.cpp
@@ -7,6 +7,6 @@
#include "disable_flex_warnings.h"
#include "lex.layout.c"
-static_assert(YY_FLEX_MAJOR_VERSION * 100 + YY_FLEX_MINOR_VERSION * 10 +
- YY_FLEX_SUBMINOR_VERSION >= 261,
+static_assert(YY_FLEX_MAJOR_VERSION * 10000 + YY_FLEX_MINOR_VERSION * 100 +
+ YY_FLEX_SUBMINOR_VERSION >= 20601,
"we require Flex 2.6.1 or better for security reasons");
diff --git a/src/sksl/lex.sksl.c b/src/sksl/lex.sksl.c
index ebf94edaf7..6e44f5aea7 100644
--- a/src/sksl/lex.sksl.c
+++ b/src/sksl/lex.sksl.c
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#line 3 "lex.sksl.c"
@@ -362,8 +368,8 @@ static void yynoreturn yy_fatal_error (yyconst char* msg ,yyscan_t yyscanner );
*yy_cp = '\0'; \
yyg->yy_c_buf_p = yy_cp;
-#define YY_NUM_RULES 96
-#define YY_END_OF_BUFFER 97
+#define YY_NUM_RULES 99
+#define YY_END_OF_BUFFER 100
/* This struct is not used in this scanner,
but its presence is necessary. */
struct yy_trans_info
@@ -371,39 +377,39 @@ struct yy_trans_info
flex_int32_t yy_verify;
flex_int32_t yy_nxt;
};
-static yyconst flex_int16_t yy_accept[285] =
+static yyconst flex_int16_t yy_accept[289] =
{ 0,
- 0, 0, 97, 95, 94, 94, 68, 95, 42, 58,
- 63, 44, 45, 56, 54, 51, 55, 50, 57, 4,
- 4, 70, 91, 75, 71, 74, 69, 95, 48, 49,
- 62, 42, 42, 42, 42, 42, 42, 42, 42, 42,
- 42, 42, 42, 42, 42, 42, 42, 42, 42, 46,
- 61, 47, 64, 94, 73, 43, 42, 82, 67, 87,
- 80, 52, 78, 53, 79, 1, 0, 92, 81, 2,
- 4, 0, 0, 59, 77, 72, 76, 60, 0, 0,
- 86, 66, 42, 42, 42, 42, 42, 42, 13, 42,
- 42, 42, 42, 42, 8, 22, 42, 42, 42, 42,
+ 0, 0, 100, 98, 95, 95, 69, 98, 42, 59,
+ 64, 45, 46, 57, 55, 52, 56, 51, 58, 4,
+ 4, 71, 92, 76, 72, 75, 70, 98, 49, 50,
+ 63, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42, 42, 42, 47,
+ 62, 48, 65, 95, 74, 43, 42, 83, 68, 88,
+ 81, 53, 79, 54, 80, 93, 1, 0, 96, 82,
+ 2, 4, 0, 0, 94, 60, 78, 73, 77, 61,
+ 44, 44, 44, 87, 67, 42, 42, 42, 42, 42,
+ 42, 13, 42, 42, 42, 42, 42, 8, 22, 42,
42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
- 42, 85, 65, 43, 90, 0, 0, 0, 92, 1,
- 0, 0, 3, 5, 83, 84, 9, 0, 89, 42,
- 42, 42, 42, 42, 42, 42, 42, 42, 42, 11,
- 42, 42, 42, 42, 42, 42, 23, 42, 42, 42,
- 42, 42, 42, 42, 42, 42, 42, 42, 42, 88,
- 0, 1, 93, 0, 0, 2, 0, 42, 42, 16,
- 42, 42, 42, 42, 42, 10, 42, 30, 42, 42,
- 42, 27, 42, 42, 42, 42, 42, 42, 42, 42,
- 42, 6, 42, 42, 42, 42, 0, 1, 0, 18,
-
- 42, 42, 26, 42, 42, 42, 7, 29, 24, 42,
- 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
- 42, 12, 42, 0, 37, 42, 42, 42, 42, 40,
- 42, 42, 42, 42, 42, 21, 42, 39, 14, 42,
- 42, 42, 15, 42, 42, 17, 20, 28, 42, 42,
- 42, 42, 42, 25, 42, 42, 34, 19, 42, 42,
- 32, 36, 42, 35, 42, 42, 41, 42, 33, 42,
- 42, 42, 42, 42, 42, 31, 42, 42, 42, 42,
- 42, 42, 38, 0
+ 42, 42, 42, 42, 86, 66, 43, 91, 0, 0,
+ 0, 96, 1, 0, 0, 3, 5, 84, 85, 44,
+ 9, 44, 90, 42, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 11, 42, 42, 42, 42, 42, 42,
+ 23, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 89, 0, 1, 97, 0, 0, 2,
+ 44, 42, 42, 16, 42, 42, 42, 42, 42, 10,
+ 42, 30, 42, 42, 42, 27, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 6, 42, 42, 42, 42,
+
+ 0, 1, 44, 18, 42, 42, 26, 42, 42, 42,
+ 7, 29, 24, 42, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 12, 42, 44, 37, 42,
+ 42, 42, 42, 40, 42, 42, 42, 42, 42, 21,
+ 42, 39, 14, 42, 42, 42, 15, 42, 42, 17,
+ 20, 28, 42, 42, 42, 42, 42, 25, 42, 42,
+ 34, 19, 42, 42, 32, 36, 42, 35, 42, 42,
+ 41, 42, 33, 42, 42, 42, 42, 42, 42, 31,
+ 42, 42, 42, 42, 42, 42, 38, 0
} ;
static yyconst YY_CHAR yy_ec[256] =
@@ -448,77 +454,81 @@ static yyconst YY_CHAR yy_meta[59] =
3, 3, 3, 3, 1, 1, 1, 1
} ;
-static yyconst flex_uint16_t yy_base[291] =
+static yyconst flex_uint16_t yy_base[297] =
{ 0,
- 0, 0, 353, 354, 57, 59, 330, 0, 0, 329,
- 55, 354, 354, 328, 52, 354, 51, 49, 59, 61,
- 65, 354, 354, 47, 327, 49, 354, 45, 354, 354,
- 64, 37, 57, 55, 306, 64, 307, 61, 58, 310,
- 300, 294, 296, 306, 58, 294, 296, 294, 65, 354,
- 86, 354, 354, 113, 354, 0, 0, 354, 316, 354,
- 354, 354, 354, 354, 354, 100, 326, 0, 354, 102,
- 107, 114, 0, 314, 354, 354, 354, 313, 297, 281,
- 354, 310, 295, 293, 281, 91, 291, 279, 0, 278,
- 283, 292, 276, 284, 0, 276, 266, 267, 283, 271,
-
- 267, 279, 91, 283, 266, 272, 261, 270, 267, 268,
- 267, 354, 284, 0, 354, 132, 294, 288, 0, 130,
- 141, 134, 143, 0, 354, 354, 354, 263, 354, 270,
- 264, 264, 263, 114, 266, 263, 260, 247, 245, 0,
- 254, 242, 246, 244, 249, 252, 0, 253, 251, 236,
- 234, 244, 232, 232, 244, 242, 246, 235, 227, 354,
- 147, 150, 354, 157, 155, 159, 226, 233, 237, 0,
- 225, 222, 230, 219, 236, 0, 231, 0, 220, 216,
- 214, 0, 213, 215, 221, 215, 212, 211, 225, 222,
- 221, 0, 209, 204, 216, 215, 161, 163, 216, 0,
-
- 202, 212, 0, 203, 204, 198, 0, 0, 0, 195,
- 200, 194, 193, 196, 199, 194, 189, 187, 196, 187,
- 193, 0, 187, 192, 0, 186, 179, 179, 192, 0,
- 180, 179, 184, 181, 188, 0, 190, 0, 0, 177,
- 177, 174, 354, 168, 180, 0, 0, 0, 179, 169,
- 159, 163, 163, 0, 174, 167, 0, 0, 174, 163,
- 0, 0, 166, 0, 151, 155, 0, 168, 0, 157,
- 147, 119, 125, 118, 109, 0, 104, 100, 97, 87,
- 64, 63, 0, 354, 179, 182, 185, 190, 195, 197
+ 0, 0, 360, 361, 57, 59, 337, 0, 0, 336,
+ 55, 361, 361, 335, 52, 361, 53, 48, 57, 54,
+ 65, 337, 361, 63, 333, 64, 361, 30, 361, 361,
+ 66, 44, 57, 59, 312, 61, 313, 61, 65, 316,
+ 306, 300, 302, 312, 59, 300, 302, 300, 70, 361,
+ 90, 361, 361, 111, 361, 0, 0, 361, 322, 361,
+ 361, 361, 361, 361, 361, 361, 98, 332, 0, 361,
+ 101, 105, 112, 0, 361, 320, 361, 361, 361, 319,
+ 0, 303, 287, 361, 316, 301, 299, 287, 92, 297,
+ 285, 0, 284, 289, 298, 282, 290, 0, 282, 272,
+
+ 273, 289, 277, 273, 285, 95, 289, 272, 278, 267,
+ 276, 273, 274, 273, 361, 290, 0, 361, 121, 300,
+ 294, 0, 130, 137, 135, 141, 0, 361, 361, 0,
+ 0, 269, 361, 276, 270, 270, 269, 112, 272, 269,
+ 266, 253, 251, 0, 260, 248, 252, 250, 255, 258,
+ 0, 259, 257, 242, 240, 250, 238, 238, 250, 248,
+ 252, 241, 233, 361, 145, 147, 361, 155, 153, 157,
+ 232, 239, 243, 0, 231, 228, 236, 225, 242, 0,
+ 237, 0, 226, 222, 220, 0, 219, 221, 227, 221,
+ 218, 217, 231, 228, 227, 0, 215, 210, 222, 221,
+
+ 159, 161, 222, 0, 208, 218, 0, 209, 210, 204,
+ 0, 0, 0, 201, 206, 200, 199, 202, 205, 200,
+ 195, 193, 202, 193, 199, 0, 193, 198, 0, 192,
+ 185, 185, 198, 0, 186, 185, 190, 187, 194, 0,
+ 196, 0, 0, 183, 183, 180, 0, 174, 186, 0,
+ 0, 0, 185, 175, 165, 169, 169, 0, 180, 173,
+ 0, 0, 180, 169, 0, 0, 172, 0, 157, 161,
+ 0, 174, 0, 168, 171, 147, 156, 145, 132, 0,
+ 119, 113, 109, 108, 91, 73, 0, 361, 177, 180,
+ 183, 186, 191, 196, 198, 201
+
} ;
-static yyconst flex_int16_t yy_def[291] =
+static yyconst flex_int16_t yy_def[297] =
{ 0,
- 284, 1, 284, 284, 284, 284, 284, 285, 286, 284,
- 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
- 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
- 284, 286, 286, 286, 286, 286, 286, 286, 286, 286,
- 286, 286, 286, 286, 286, 286, 286, 286, 286, 284,
- 284, 284, 284, 284, 284, 287, 286, 284, 284, 284,
- 284, 284, 284, 284, 284, 284, 288, 289, 284, 284,
- 284, 284, 290, 284, 284, 284, 284, 284, 284, 284,
- 284, 284, 286, 286, 286, 286, 286, 286, 286, 286,
- 286, 286, 286, 286, 286, 286, 286, 286, 286, 286,
-
- 286, 286, 286, 286, 286, 286, 286, 286, 286, 286,
- 286, 284, 284, 287, 284, 284, 288, 288, 289, 284,
- 284, 284, 284, 290, 284, 284, 284, 284, 284, 286,
- 286, 286, 286, 286, 286, 286, 286, 286, 286, 286,
- 286, 286, 286, 286, 286, 286, 286, 286, 286, 286,
- 286, 286, 286, 286, 286, 286, 286, 286, 286, 284,
- 284, 284, 284, 284, 284, 284, 284, 286, 286, 286,
- 286, 286, 286, 286, 286, 286, 286, 286, 286, 286,
- 286, 286, 286, 286, 286, 286, 286, 286, 286, 286,
- 286, 286, 286, 286, 286, 286, 284, 284, 284, 286,
-
- 286, 286, 286, 286, 286, 286, 286, 286, 286, 286,
- 286, 286, 286, 286, 286, 286, 286, 286, 286, 286,
- 286, 286, 286, 284, 286, 286, 286, 286, 286, 286,
- 286, 286, 286, 286, 286, 286, 286, 286, 286, 286,
- 286, 286, 284, 286, 286, 286, 286, 286, 286, 286,
- 286, 286, 286, 286, 286, 286, 286, 286, 286, 286,
- 286, 286, 286, 286, 286, 286, 286, 286, 286, 286,
- 286, 286, 286, 286, 286, 286, 286, 286, 286, 286,
- 286, 286, 286, 0, 284, 284, 284, 284, 284, 284
+ 288, 1, 288, 288, 288, 288, 288, 289, 290, 288,
+ 288, 288, 288, 288, 288, 288, 288, 288, 288, 288,
+ 288, 288, 288, 288, 288, 288, 288, 291, 288, 288,
+ 288, 290, 290, 290, 290, 290, 290, 290, 290, 290,
+ 290, 290, 290, 290, 290, 290, 290, 290, 290, 288,
+ 288, 288, 288, 288, 288, 292, 290, 288, 288, 288,
+ 288, 288, 288, 288, 288, 288, 288, 293, 294, 288,
+ 288, 288, 288, 295, 288, 288, 288, 288, 288, 288,
+ 296, 296, 296, 288, 288, 290, 290, 290, 290, 290,
+ 290, 290, 290, 290, 290, 290, 290, 290, 290, 290,
+
+ 290, 290, 290, 290, 290, 290, 290, 290, 290, 290,
+ 290, 290, 290, 290, 288, 288, 292, 288, 288, 293,
+ 293, 294, 288, 288, 288, 288, 295, 288, 288, 296,
+ 296, 296, 288, 290, 290, 290, 290, 290, 290, 290,
+ 290, 290, 290, 290, 290, 290, 290, 290, 290, 290,
+ 290, 290, 290, 290, 290, 290, 290, 290, 290, 290,
+ 290, 290, 290, 288, 288, 288, 288, 288, 288, 288,
+ 296, 290, 290, 290, 290, 290, 290, 290, 290, 290,
+ 290, 290, 290, 290, 290, 290, 290, 290, 290, 290,
+ 290, 290, 290, 290, 290, 290, 290, 290, 290, 290,
+
+ 288, 288, 296, 290, 290, 290, 290, 290, 290, 290,
+ 290, 290, 290, 290, 290, 290, 290, 290, 290, 290,
+ 290, 290, 290, 290, 290, 290, 290, 296, 290, 290,
+ 290, 290, 290, 290, 290, 290, 290, 290, 290, 290,
+ 290, 290, 290, 290, 290, 290, 296, 290, 290, 290,
+ 290, 290, 290, 290, 290, 290, 290, 290, 290, 290,
+ 290, 290, 290, 290, 290, 290, 290, 290, 290, 290,
+ 290, 290, 290, 290, 290, 290, 290, 290, 290, 290,
+ 290, 290, 290, 290, 290, 290, 290, 0, 288, 288,
+ 288, 288, 288, 288, 288, 288
+
} ;
-static yyconst flex_uint16_t yy_nxt[413] =
+static yyconst flex_uint16_t yy_nxt[420] =
{ 0,
4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
@@ -526,49 +536,49 @@ static yyconst flex_uint16_t yy_nxt[413] =
9, 9, 32, 33, 34, 35, 36, 9, 37, 38,
9, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 9, 9, 50, 51, 52, 53, 54, 54,
- 54, 54, 59, 62, 64, 66, 66, 74, 75, 67,
- 77, 78, 65, 63, 68, 70, 60, 71, 71, 70,
- 69, 71, 71, 83, 79, 81, 84, 72, 85, 97,
- 87, 72, 80, 82, 88, 91, 72, 95, 104, 89,
-
- 72, 86, 98, 110, 96, 92, 105, 112, 93, 106,
- 283, 111, 282, 73, 54, 54, 66, 66, 120, 120,
- 281, 70, 149, 71, 71, 122, 116, 122, 121, 133,
- 123, 123, 280, 72, 134, 116, 279, 121, 150, 151,
- 278, 113, 72, 161, 277, 161, 120, 120, 162, 162,
- 123, 123, 165, 276, 165, 275, 164, 166, 166, 123,
- 123, 172, 173, 162, 162, 164, 162, 162, 197, 274,
- 197, 166, 166, 198, 198, 166, 166, 198, 198, 198,
- 198, 56, 273, 56, 57, 57, 57, 114, 114, 114,
- 117, 117, 117, 117, 117, 119, 272, 119, 119, 119,
-
- 124, 124, 271, 270, 269, 268, 267, 266, 265, 264,
+ 54, 54, 59, 62, 67, 67, 64, 68, 71, 82,
+ 72, 72, 69, 63, 65, 66, 60, 83, 70, 71,
+ 73, 72, 72, 76, 77, 79, 80, 84, 88, 73,
+ 86, 73, 94, 87, 90, 85, 100, 98, 91, 107,
+
+ 73, 89, 95, 92, 99, 96, 74, 108, 113, 101,
+ 109, 115, 54, 54, 67, 67, 114, 123, 123, 71,
+ 287, 72, 72, 125, 119, 125, 153, 124, 126, 126,
+ 137, 73, 165, 119, 165, 138, 124, 166, 166, 286,
+ 73, 285, 154, 155, 284, 116, 123, 123, 169, 283,
+ 169, 126, 126, 170, 170, 282, 168, 126, 126, 176,
+ 177, 166, 166, 166, 166, 168, 201, 281, 201, 170,
+ 170, 202, 202, 170, 170, 202, 202, 202, 202, 56,
+ 280, 56, 57, 57, 57, 81, 279, 81, 117, 117,
+ 117, 120, 120, 120, 120, 120, 122, 278, 122, 122,
+
+ 122, 127, 127, 130, 130, 130, 277, 276, 275, 274,
+ 273, 272, 271, 270, 269, 268, 267, 266, 265, 264,
263, 262, 261, 260, 259, 258, 257, 256, 255, 254,
253, 252, 251, 250, 249, 248, 247, 246, 245, 244,
243, 242, 241, 240, 239, 238, 237, 236, 235, 234,
233, 232, 231, 230, 229, 228, 227, 226, 225, 224,
223, 222, 221, 220, 219, 218, 217, 216, 215, 214,
213, 212, 211, 210, 209, 208, 207, 206, 205, 204,
- 203, 202, 201, 200, 199, 196, 195, 194, 193, 192,
+ 203, 200, 199, 198, 197, 196, 195, 194, 193, 192,
191, 190, 189, 188, 187, 186, 185, 184, 183, 182,
- 181, 180, 179, 178, 177, 176, 175, 174, 171, 170,
-
- 169, 168, 167, 163, 118, 160, 159, 158, 157, 156,
- 155, 154, 153, 152, 148, 147, 146, 145, 144, 143,
- 142, 141, 140, 139, 138, 137, 136, 135, 132, 131,
- 130, 129, 128, 127, 126, 125, 118, 115, 109, 108,
- 107, 103, 102, 101, 100, 99, 94, 90, 76, 61,
- 58, 55, 284, 3, 284, 284, 284, 284, 284, 284,
- 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
- 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
- 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
- 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
-
- 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
- 284, 284
+
+ 181, 180, 179, 178, 175, 174, 173, 172, 171, 167,
+ 121, 164, 163, 162, 161, 160, 159, 158, 157, 156,
+ 152, 151, 150, 149, 148, 147, 146, 145, 144, 143,
+ 142, 141, 140, 139, 136, 135, 134, 133, 132, 131,
+ 129, 128, 121, 118, 112, 111, 110, 106, 105, 104,
+ 103, 102, 97, 93, 78, 75, 61, 58, 55, 288,
+ 3, 288, 288, 288, 288, 288, 288, 288, 288, 288,
+ 288, 288, 288, 288, 288, 288, 288, 288, 288, 288,
+ 288, 288, 288, 288, 288, 288, 288, 288, 288, 288,
+ 288, 288, 288, 288, 288, 288, 288, 288, 288, 288,
+
+ 288, 288, 288, 288, 288, 288, 288, 288, 288, 288,
+ 288, 288, 288, 288, 288, 288, 288, 288, 288
} ;
-static yyconst flex_int16_t yy_chk[413] =
+static yyconst flex_int16_t yy_chk[420] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -576,56 +586,57 @@ static yyconst flex_int16_t yy_chk[413] =
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 5, 5,
- 6, 6, 11, 15, 17, 18, 18, 24, 24, 19,
- 26, 26, 17, 15, 19, 20, 11, 20, 20, 21,
- 19, 21, 21, 32, 28, 31, 32, 20, 33, 39,
- 34, 21, 28, 31, 34, 36, 20, 38, 45, 34,
-
- 21, 33, 39, 49, 38, 36, 45, 51, 36, 45,
- 282, 49, 281, 20, 54, 54, 66, 66, 70, 70,
- 280, 71, 103, 71, 71, 72, 66, 72, 70, 86,
- 72, 72, 279, 71, 86, 66, 278, 70, 103, 103,
- 277, 51, 71, 116, 275, 116, 120, 120, 116, 116,
- 122, 122, 121, 274, 121, 273, 120, 121, 121, 123,
- 123, 134, 134, 161, 161, 120, 162, 162, 164, 272,
- 164, 165, 165, 164, 164, 166, 166, 197, 197, 198,
- 198, 285, 271, 285, 286, 286, 286, 287, 287, 287,
- 288, 288, 288, 288, 288, 289, 270, 289, 289, 289,
-
- 290, 290, 268, 266, 265, 263, 260, 259, 256, 255,
- 253, 252, 251, 250, 249, 245, 244, 242, 241, 240,
- 237, 235, 234, 233, 232, 231, 229, 228, 227, 226,
- 224, 223, 221, 220, 219, 218, 217, 216, 215, 214,
- 213, 212, 211, 210, 206, 205, 204, 202, 201, 199,
- 196, 195, 194, 193, 191, 190, 189, 188, 187, 186,
- 185, 184, 183, 181, 180, 179, 177, 175, 174, 173,
- 172, 171, 169, 168, 167, 159, 158, 157, 156, 155,
- 154, 153, 152, 151, 150, 149, 148, 146, 145, 144,
- 143, 142, 141, 139, 138, 137, 136, 135, 133, 132,
-
- 131, 130, 128, 118, 117, 113, 111, 110, 109, 108,
- 107, 106, 105, 104, 102, 101, 100, 99, 98, 97,
- 96, 94, 93, 92, 91, 90, 88, 87, 85, 84,
- 83, 82, 80, 79, 78, 74, 67, 59, 48, 47,
- 46, 44, 43, 42, 41, 40, 37, 35, 25, 14,
- 10, 7, 3, 284, 284, 284, 284, 284, 284, 284,
- 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
- 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
- 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
- 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
-
- 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
- 284, 284
+ 6, 6, 11, 15, 18, 18, 17, 19, 20, 28,
+ 20, 20, 19, 15, 17, 17, 11, 28, 19, 21,
+ 20, 21, 21, 24, 24, 26, 26, 31, 33, 20,
+ 32, 21, 36, 32, 34, 31, 39, 38, 34, 45,
+
+ 21, 33, 36, 34, 38, 36, 20, 45, 49, 39,
+ 45, 51, 54, 54, 67, 67, 49, 71, 71, 72,
+ 286, 72, 72, 73, 67, 73, 106, 71, 73, 73,
+ 89, 72, 119, 67, 119, 89, 71, 119, 119, 285,
+ 72, 284, 106, 106, 283, 51, 123, 123, 124, 282,
+ 124, 125, 125, 124, 124, 281, 123, 126, 126, 138,
+ 138, 165, 165, 166, 166, 123, 168, 279, 168, 169,
+ 169, 168, 168, 170, 170, 201, 201, 202, 202, 289,
+ 278, 289, 290, 290, 290, 291, 277, 291, 292, 292,
+ 292, 293, 293, 293, 293, 293, 294, 276, 294, 294,
+
+ 294, 295, 295, 296, 296, 296, 275, 274, 272, 270,
+ 269, 267, 264, 263, 260, 259, 257, 256, 255, 254,
+ 253, 249, 248, 246, 245, 244, 241, 239, 238, 237,
+ 236, 235, 233, 232, 231, 230, 228, 227, 225, 224,
+ 223, 222, 221, 220, 219, 218, 217, 216, 215, 214,
+ 210, 209, 208, 206, 205, 203, 200, 199, 198, 197,
+ 195, 194, 193, 192, 191, 190, 189, 188, 187, 185,
+ 184, 183, 181, 179, 178, 177, 176, 175, 173, 172,
+ 171, 163, 162, 161, 160, 159, 158, 157, 156, 155,
+ 154, 153, 152, 150, 149, 148, 147, 146, 145, 143,
+
+ 142, 141, 140, 139, 137, 136, 135, 134, 132, 121,
+ 120, 116, 114, 113, 112, 111, 110, 109, 108, 107,
+ 105, 104, 103, 102, 101, 100, 99, 97, 96, 95,
+ 94, 93, 91, 90, 88, 87, 86, 85, 83, 82,
+ 80, 76, 68, 59, 48, 47, 46, 44, 43, 42,
+ 41, 40, 37, 35, 25, 22, 14, 10, 7, 3,
+ 288, 288, 288, 288, 288, 288, 288, 288, 288, 288,
+ 288, 288, 288, 288, 288, 288, 288, 288, 288, 288,
+ 288, 288, 288, 288, 288, 288, 288, 288, 288, 288,
+ 288, 288, 288, 288, 288, 288, 288, 288, 288, 288,
+
+ 288, 288, 288, 288, 288, 288, 288, 288, 288, 288,
+ 288, 288, 288, 288, 288, 288, 288, 288, 288
} ;
/* Table of booleans, true if rule could match eol. */
-static yyconst flex_int32_t yy_rule_can_match_eol[97] =
+static yyconst flex_int32_t yy_rule_can_match_eol[100] =
{ 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, };
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0,
+ };
/* The intent behind this definition is that it'll catch
* any uses of REJECT which flex missed.
@@ -654,7 +665,7 @@ static yyconst flex_int32_t yy_rule_can_match_eol[97] =
*/
#define YY_NO_UNISTD_H 1
-#line 658 "lex.sksl.c"
+#line 663 "lex.sksl.c"
#define INITIAL 0
@@ -918,7 +929,7 @@ YY_DECL
#line 30 "sksl.flex"
-#line 922 "lex.sksl.c"
+#line 927 "lex.sksl.c"
while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
{
@@ -945,13 +956,13 @@ yy_match:
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 285 )
+ if ( yy_current_state >= 289 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c];
++yy_cp;
}
- while ( yy_current_state != 284 );
+ while ( yy_current_state != 288 );
yy_cp = yyg->yy_last_accepting_cpos;
yy_current_state = yyg->yy_last_accepting_state;
@@ -1201,271 +1212,286 @@ YY_RULE_SETUP
case 44:
YY_RULE_SETUP
#line 118 "sksl.flex"
-{ return SkSL::Token::LPAREN; }
+{ return SkSL::Token::SECTION; }
YY_BREAK
case 45:
YY_RULE_SETUP
#line 120 "sksl.flex"
-{ return SkSL::Token::RPAREN; }
+{ return SkSL::Token::LPAREN; }
YY_BREAK
case 46:
YY_RULE_SETUP
#line 122 "sksl.flex"
-{ return SkSL::Token::LBRACE; }
+{ return SkSL::Token::RPAREN; }
YY_BREAK
case 47:
YY_RULE_SETUP
#line 124 "sksl.flex"
-{ return SkSL::Token::RBRACE; }
+{ return SkSL::Token::LBRACE; }
YY_BREAK
case 48:
YY_RULE_SETUP
#line 126 "sksl.flex"
-{ return SkSL::Token::LBRACKET; }
+{ return SkSL::Token::RBRACE; }
YY_BREAK
case 49:
YY_RULE_SETUP
#line 128 "sksl.flex"
-{ return SkSL::Token::RBRACKET; }
+{ return SkSL::Token::LBRACKET; }
YY_BREAK
case 50:
YY_RULE_SETUP
#line 130 "sksl.flex"
-{ return SkSL::Token::DOT; }
+{ return SkSL::Token::RBRACKET; }
YY_BREAK
case 51:
YY_RULE_SETUP
#line 132 "sksl.flex"
-{ return SkSL::Token::COMMA; }
+{ return SkSL::Token::DOT; }
YY_BREAK
case 52:
YY_RULE_SETUP
#line 134 "sksl.flex"
-{ return SkSL::Token::PLUSPLUS; }
+{ return SkSL::Token::COMMA; }
YY_BREAK
case 53:
YY_RULE_SETUP
#line 136 "sksl.flex"
-{ return SkSL::Token::MINUSMINUS; }
+{ return SkSL::Token::PLUSPLUS; }
YY_BREAK
case 54:
YY_RULE_SETUP
#line 138 "sksl.flex"
-{ return SkSL::Token::PLUS; }
+{ return SkSL::Token::MINUSMINUS; }
YY_BREAK
case 55:
YY_RULE_SETUP
#line 140 "sksl.flex"
-{ return SkSL::Token::MINUS; }
+{ return SkSL::Token::PLUS; }
YY_BREAK
case 56:
YY_RULE_SETUP
#line 142 "sksl.flex"
-{ return SkSL::Token::STAR; }
+{ return SkSL::Token::MINUS; }
YY_BREAK
case 57:
YY_RULE_SETUP
#line 144 "sksl.flex"
-{ return SkSL::Token::SLASH; }
+{ return SkSL::Token::STAR; }
YY_BREAK
case 58:
YY_RULE_SETUP
#line 146 "sksl.flex"
-{ return SkSL::Token::PERCENT; }
+{ return SkSL::Token::SLASH; }
YY_BREAK
case 59:
YY_RULE_SETUP
#line 148 "sksl.flex"
-{ return SkSL::Token::SHL; }
+{ return SkSL::Token::PERCENT; }
YY_BREAK
case 60:
YY_RULE_SETUP
#line 150 "sksl.flex"
-{ return SkSL::Token::SHR; }
+{ return SkSL::Token::SHL; }
YY_BREAK
case 61:
YY_RULE_SETUP
#line 152 "sksl.flex"
-{ return SkSL::Token::BITWISEOR; }
+{ return SkSL::Token::SHR; }
YY_BREAK
case 62:
YY_RULE_SETUP
#line 154 "sksl.flex"
-{ return SkSL::Token::BITWISEXOR; }
+{ return SkSL::Token::BITWISEOR; }
YY_BREAK
case 63:
YY_RULE_SETUP
#line 156 "sksl.flex"
-{ return SkSL::Token::BITWISEAND; }
+{ return SkSL::Token::BITWISEXOR; }
YY_BREAK
case 64:
YY_RULE_SETUP
#line 158 "sksl.flex"
-{ return SkSL::Token::BITWISENOT; }
+{ return SkSL::Token::BITWISEAND; }
YY_BREAK
case 65:
YY_RULE_SETUP
#line 160 "sksl.flex"
-{ return SkSL::Token::LOGICALOR; }
+{ return SkSL::Token::BITWISENOT; }
YY_BREAK
case 66:
YY_RULE_SETUP
#line 162 "sksl.flex"
-{ return SkSL::Token::LOGICALXOR; }
+{ return SkSL::Token::LOGICALOR; }
YY_BREAK
case 67:
YY_RULE_SETUP
#line 164 "sksl.flex"
-{ return SkSL::Token::LOGICALAND; }
+{ return SkSL::Token::LOGICALXOR; }
YY_BREAK
case 68:
YY_RULE_SETUP
#line 166 "sksl.flex"
-{ return SkSL::Token::LOGICALNOT; }
+{ return SkSL::Token::LOGICALAND; }
YY_BREAK
case 69:
YY_RULE_SETUP
#line 168 "sksl.flex"
-{ return SkSL::Token::QUESTION; }
+{ return SkSL::Token::LOGICALNOT; }
YY_BREAK
case 70:
YY_RULE_SETUP
#line 170 "sksl.flex"
-{ return SkSL::Token::COLON; }
+{ return SkSL::Token::QUESTION; }
YY_BREAK
case 71:
YY_RULE_SETUP
#line 172 "sksl.flex"
-{ return SkSL::Token::EQ; }
+{ return SkSL::Token::COLON; }
YY_BREAK
case 72:
YY_RULE_SETUP
#line 174 "sksl.flex"
-{ return SkSL::Token::EQEQ; }
+{ return SkSL::Token::EQ; }
YY_BREAK
case 73:
YY_RULE_SETUP
#line 176 "sksl.flex"
-{ return SkSL::Token::NEQ; }
+{ return SkSL::Token::EQEQ; }
YY_BREAK
case 74:
YY_RULE_SETUP
#line 178 "sksl.flex"
-{ return SkSL::Token::GT; }
+{ return SkSL::Token::NEQ; }
YY_BREAK
case 75:
YY_RULE_SETUP
#line 180 "sksl.flex"
-{ return SkSL::Token::LT; }
+{ return SkSL::Token::GT; }
YY_BREAK
case 76:
YY_RULE_SETUP
#line 182 "sksl.flex"
-{ return SkSL::Token::GTEQ; }
+{ return SkSL::Token::LT; }
YY_BREAK
case 77:
YY_RULE_SETUP
#line 184 "sksl.flex"
-{ return SkSL::Token::LTEQ; }
+{ return SkSL::Token::GTEQ; }
YY_BREAK
case 78:
YY_RULE_SETUP
#line 186 "sksl.flex"
-{ return SkSL::Token::PLUSEQ; }
+{ return SkSL::Token::LTEQ; }
YY_BREAK
case 79:
YY_RULE_SETUP
#line 188 "sksl.flex"
-{ return SkSL::Token::MINUSEQ; }
+{ return SkSL::Token::PLUSEQ; }
YY_BREAK
case 80:
YY_RULE_SETUP
#line 190 "sksl.flex"
-{ return SkSL::Token::STAREQ; }
+{ return SkSL::Token::MINUSEQ; }
YY_BREAK
case 81:
YY_RULE_SETUP
#line 192 "sksl.flex"
-{ return SkSL::Token::SLASHEQ; }
+{ return SkSL::Token::STAREQ; }
YY_BREAK
case 82:
YY_RULE_SETUP
#line 194 "sksl.flex"
-{ return SkSL::Token::PERCENTEQ; }
+{ return SkSL::Token::SLASHEQ; }
YY_BREAK
case 83:
YY_RULE_SETUP
#line 196 "sksl.flex"
-{ return SkSL::Token::SHLEQ; }
+{ return SkSL::Token::PERCENTEQ; }
YY_BREAK
case 84:
YY_RULE_SETUP
#line 198 "sksl.flex"
-{ return SkSL::Token::SHREQ; }
+{ return SkSL::Token::SHLEQ; }
YY_BREAK
case 85:
YY_RULE_SETUP
#line 200 "sksl.flex"
-{ return SkSL::Token::BITWISEOREQ; }
+{ return SkSL::Token::SHREQ; }
YY_BREAK
case 86:
YY_RULE_SETUP
#line 202 "sksl.flex"
-{ return SkSL::Token::BITWISEXOREQ; }
+{ return SkSL::Token::BITWISEOREQ; }
YY_BREAK
case 87:
YY_RULE_SETUP
#line 204 "sksl.flex"
-{ return SkSL::Token::BITWISEANDEQ; }
+{ return SkSL::Token::BITWISEXOREQ; }
YY_BREAK
case 88:
YY_RULE_SETUP
#line 206 "sksl.flex"
-{ return SkSL::Token::LOGICALOREQ; }
+{ return SkSL::Token::BITWISEANDEQ; }
YY_BREAK
case 89:
YY_RULE_SETUP
#line 208 "sksl.flex"
-{ return SkSL::Token::LOGICALXOREQ; }
+{ return SkSL::Token::LOGICALOREQ; }
YY_BREAK
case 90:
YY_RULE_SETUP
#line 210 "sksl.flex"
-{ return SkSL::Token::LOGICALANDEQ; }
+{ return SkSL::Token::LOGICALXOREQ; }
YY_BREAK
case 91:
YY_RULE_SETUP
#line 212 "sksl.flex"
-{ return SkSL::Token::SEMICOLON; }
+{ return SkSL::Token::LOGICALANDEQ; }
YY_BREAK
case 92:
YY_RULE_SETUP
#line 214 "sksl.flex"
-/* line comment */
+{ return SkSL::Token::SEMICOLON; }
YY_BREAK
case 93:
-/* rule 93 can match eol */
YY_RULE_SETUP
#line 216 "sksl.flex"
-/* block comment */
+{ return SkSL::Token::ARROW; }
YY_BREAK
case 94:
-/* rule 94 can match eol */
YY_RULE_SETUP
#line 218 "sksl.flex"
-/* whitespace */
+{ return SkSL::Token::COLONCOLON; }
YY_BREAK
case 95:
+/* rule 95 can match eol */
YY_RULE_SETUP
#line 220 "sksl.flex"
-{ return SkSL::Token::INVALID_TOKEN; }
+{ return SkSL::Token::WHITESPACE; }
YY_BREAK
case 96:
YY_RULE_SETUP
#line 222 "sksl.flex"
+/* line comment */
+ YY_BREAK
+case 97:
+/* rule 97 can match eol */
+YY_RULE_SETUP
+#line 224 "sksl.flex"
+/* block comment */
+ YY_BREAK
+case 98:
+YY_RULE_SETUP
+#line 226 "sksl.flex"
+{ return SkSL::Token::INVALID_TOKEN; }
+ YY_BREAK
+case 99:
+YY_RULE_SETUP
+#line 228 "sksl.flex"
ECHO;
YY_BREAK
-#line 1469 "lex.sksl.c"
+#line 1489 "lex.sksl.c"
case YY_STATE_EOF(INITIAL):
yyterminate();
@@ -1761,7 +1787,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 285 )
+ if ( yy_current_state >= 289 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c];
@@ -1790,11 +1816,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 285 )
+ if ( yy_current_state >= 289 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c];
- yy_is_jam = (yy_current_state == 284);
+ yy_is_jam = (yy_current_state == 288);
(void)yyg;
return yy_is_jam ? 0 : yy_current_state;
@@ -2646,7 +2672,7 @@ void skslfree (void * ptr , yyscan_t yyscanner)
#define YYTABLES_NAME "yytables"
-#line 222 "sksl.flex"
+#line 228 "sksl.flex"
diff --git a/src/sksl/sksl.flex b/src/sksl/sksl.flex
index c5d5ec34d0..275a4e6633 100644
--- a/src/sksl/sksl.flex
+++ b/src/sksl/sksl.flex
@@ -115,6 +115,8 @@ precision { return SkSL::Token::PRECISION; }
"#"{LETTER}({DIGIT}|{LETTER})* { return SkSL::Token::DIRECTIVE; }
+"@"{LETTER}({DIGIT}|{LETTER})* { return SkSL::Token::SECTION; }
+
"(" { return SkSL::Token::LPAREN; }
")" { return SkSL::Token::RPAREN; }
@@ -211,12 +213,16 @@ precision { return SkSL::Token::PRECISION; }
";" { return SkSL::Token::SEMICOLON; }
+"->" { return SkSL::Token::ARROW; }
+
+"::" { return SkSL::Token::COLONCOLON; }
+
+[ \t\r\n]+ { return SkSL::Token::WHITESPACE; }
+
"//".* /* line comment */
"/*"([^*]|"*"[^/])*"*/" /* block comment */
-[ \t\r\n]+ /* whitespace */
-
. { return SkSL::Token::INVALID_TOKEN; }
%%
diff --git a/src/sksl/sksl_fp.include b/src/sksl/sksl_fp.include
new file mode 100644
index 0000000000..566e441e30
--- /dev/null
+++ b/src/sksl/sksl_fp.include
@@ -0,0 +1,23 @@
+STRINGIFY(
+
+// defines built-in interfaces supported by SkiaSL fragment shaders
+
+layout(builtin=15) in vec4 sk_FragCoord;
+layout(builtin=3) float sk_ClipDistance[1];
+
+// 9999 is a temporary value that causes us to ignore these declarations beyond
+// adding them to the symbol table. This works fine in GLSL (where they do not
+// require any further handling) but will fail in SPIR-V. We'll have a better
+// solution for this soon.
+layout(builtin=9999) vec4 gl_LastFragData[1];
+layout(builtin=9999) vec4 gl_LastFragColor;
+layout(builtin=9999) vec4 gl_LastFragColorARM;
+layout(builtin=9999) int gl_SampleMaskIn[1];
+layout(builtin=9999) out int gl_SampleMask[1];
+layout(builtin=9999) vec4 gl_SecondaryFragColorEXT;
+
+layout(builtin=10003) vec4 sk_InColor;
+layout(builtin=10004) out vec4 sk_OutColor;
+layout(builtin=10005) vec2[] sk_TransformedCoords2D;
+layout(builtin=10006) sampler2D[] sk_TextureSamplers;
+)
diff --git a/tests/SkSLFPTest.cpp b/tests/SkSLFPTest.cpp
new file mode 100644
index 0000000000..6f1326d6f7
--- /dev/null
+++ b/tests/SkSLFPTest.cpp
@@ -0,0 +1,381 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkSLCompiler.h"
+
+#include "Test.h"
+
+#if SK_SUPPORT_GPU
+
+static void test(skiatest::Reporter* r, const char* src, const GrShaderCaps& caps,
+ std::vector<const char*> expectedH, std::vector<const char*> expectedCPP) {
+ SkSL::Program::Settings settings;
+ settings.fCaps = &caps;
+ SkSL::Compiler compiler;
+ SkSL::StringStream output;
+ std::unique_ptr<SkSL::Program> program = compiler.convertProgram(
+ SkSL::Program::kFragmentProcessor_Kind,
+ SkString(src),
+ settings);
+ if (!program) {
+ SkDebugf("Unexpected error compiling %s\n%s", src, compiler.errorText().c_str());
+ return;
+ }
+ REPORTER_ASSERT(r, program);
+ bool success = compiler.toH(*program, "Test", output);
+ if (!success) {
+ SkDebugf("Unexpected error compiling %s\n%s", src, compiler.errorText().c_str());
+ }
+ REPORTER_ASSERT(r, success);
+ if (success) {
+ for (const char* expected : expectedH) {
+ bool found = strstr(output.str().c_str(), expected);
+ if (!found) {
+ SkDebugf("HEADER MISMATCH:\nsource:\n%s\n\nexpected:\n'%s'\n\nreceived:\n'%s'", src,
+ expected, output.str().c_str());
+ }
+ REPORTER_ASSERT(r, found);
+ }
+ }
+ output.reset();
+ success = compiler.toCPP(*program, "Test", output);
+ if (!success) {
+ SkDebugf("Unexpected error compiling %s\n%s", src, compiler.errorText().c_str());
+ }
+ REPORTER_ASSERT(r, success);
+ if (success) {
+ for (const char* expected : expectedCPP) {
+ bool found = strstr(output.str().c_str(), expected);
+ if (!found) {
+ SkDebugf("CPP MISMATCH:\nsource:\n%s\n\nexpected:\n'%s'\n\nreceived:\n'%s'", src,
+ expected, output.str().c_str());
+ }
+ REPORTER_ASSERT(r, found);
+ }
+ }
+}
+
+DEF_TEST(SkSLFPHelloWorld, r) {
+ test(r,
+ "void main() {"
+ "sk_OutColor = vec4(1);"
+ "}",
+ *SkSL::ShaderCapsFactory::Default(),
+ {
+ "/*\n"
+ " * This file was autogenerated from GrTest.fp.\n"
+ " */\n"
+ "#ifndef GrTest_DEFINED\n"
+ "#define GrTest_DEFINED\n"
+ "#include \"GrFragmentProcessor.h\"\n"
+ "#include \"GrCoordTransform.h\"\n"
+ "#include \"effects/GrProxyMove.h\"\n"
+ "class GrTest : public GrFragmentProcessor {\n"
+ "public:\n"
+ " static sk_sp<GrFragmentProcessor> Make() {\n"
+ " return sk_sp<GrFragmentProcessor>(new GrTest());\n"
+ " }\n"
+ " const char* name() const override { return \"Test\"; }\n"
+ "private:\n"
+ " GrTest()\n"
+ " : INHERITED(kNone_OptimizationFlags) {\n"
+ " this->initClassID<GrTest>();\n"
+ " }\n"
+ " GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;\n"
+ " void onGetGLSLProcessorKey(const GrShaderCaps&,GrProcessorKeyBuilder*) "
+ "const override;\n"
+ " bool onIsEqual(const GrFragmentProcessor&) const override;\n"
+ " GR_DECLARE_FRAGMENT_PROCESSOR_TEST;\n"
+ " typedef GrFragmentProcessor INHERITED;\n"
+ "};\n"
+ "#endif\n"
+ },
+ {
+ "/*\n"
+ " * This file was autogenerated from GrTest.fp.\n"
+ " */\n"
+ "#include \"GrTest.h\"\n"
+ "#include \"glsl/GrGLSLColorSpaceXformHelper.h\"\n"
+ "#include \"glsl/GrGLSLFragmentProcessor.h\"\n"
+ "#include \"glsl/GrGLSLFragmentShaderBuilder.h\"\n"
+ "#include \"glsl/GrGLSLProgramBuilder.h\"\n"
+ "#include \"GrResourceProvider.h\"\n"
+ "#include \"SkSLCPP.h\"\n"
+ "#include \"SkSLUtil.h\"\n"
+ "class GrGLSLTest : public GrGLSLFragmentProcessor {\n"
+ "public:\n"
+ " GrGLSLTest() {}\n"
+ " void emitCode(EmitArgs& args) override {\n"
+ " GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;\n"
+ " const GrTest& _outer = args.fFp.cast<GrTest>();\n"
+ " (void) _outer;\n"
+ " fragBuilder->codeAppendf(\"%s = vec4(1.0);\\n\", args.fOutputColor);\n"
+ " }\n"
+ "private:\n"
+ " void onSetData(const GrGLSLProgramDataManager& pdman, "
+ "const GrFragmentProcessor& _proc) override {\n"
+ " }\n"
+ "};\n"
+ "GrGLSLFragmentProcessor* GrTest::onCreateGLSLInstance() const {\n"
+ " return new GrGLSLTest();\n"
+ "}\n"
+ "void GrTest::onGetGLSLProcessorKey(const GrShaderCaps& caps, "
+ "GrProcessorKeyBuilder* b) const {\n"
+ "}\n"
+ "bool GrTest::onIsEqual(const GrFragmentProcessor& other) const {\n"
+ " const GrTest& that = other.cast<GrTest>();\n"
+ " (void) that;\n"
+ " return true;\n"
+ "}\n"
+ });
+}
+
+DEF_TEST(SkSLFPInput, r) {
+ test(r,
+ "in vec2 point;"
+ "void main() {"
+ "sk_OutColor = vec4(point, point);"
+ "}",
+ *SkSL::ShaderCapsFactory::Default(),
+ {
+ "SkPoint point() const { return fPoint; }",
+ "static sk_sp<GrFragmentProcessor> Make(SkPoint point) {",
+ "return sk_sp<GrFragmentProcessor>(new GrTest(point));",
+ "GrTest(SkPoint point)",
+ ", fPoint(point)"
+ },
+ {
+ "fragBuilder->codeAppendf(\"%s = vec4(vec2(%f, %f), vec2(%f, %f));\\n\", "
+ "args.fOutputColor, _outer.point().fX, _outer.point().fY, "
+ "_outer.point().fX, _outer.point().fY);",
+ "if (fPoint != that.fPoint) return false;"
+ });
+}
+
+DEF_TEST(SkSLFPUniform, r) {
+ test(r,
+ "uniform vec4 color;"
+ "void main() {"
+ "sk_OutColor = color;"
+ "}",
+ *SkSL::ShaderCapsFactory::Default(),
+ {
+ "static sk_sp<GrFragmentProcessor> Make()"
+ },
+ {
+ "fColorVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kVec4f_GrSLType, "
+ "kDefault_GrSLPrecision, \"color\");",
+ });
+}
+
+DEF_TEST(SkSLFPInUniform, r) {
+ test(r,
+ "in uniform vec4 color;"
+ "void main() {"
+ "sk_OutColor = color;"
+ "}",
+ *SkSL::ShaderCapsFactory::Default(),
+ {
+ "static sk_sp<GrFragmentProcessor> Make(SkRect color) {",
+ },
+ {
+ "fColorVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kVec4f_GrSLType, "
+ "kDefault_GrSLPrecision, \"color\");",
+ "const SkRect colorValue = _outer.color();",
+ "pdman.set4fv(fColorVar, 4, (float*) &colorValue);"
+ });
+}
+
+DEF_TEST(SkSLFPSections, r) {
+ test(r,
+ "@header { header section }"
+ "void main() {"
+ "sk_OutColor = vec4(1);"
+ "}",
+ *SkSL::ShaderCapsFactory::Default(),
+ {
+ "header section class GrTest",
+ },
+ {});
+ test(r,
+ "@class { class section }"
+ "void main() {"
+ "sk_OutColor = vec4(1);"
+ "}",
+ *SkSL::ShaderCapsFactory::Default(),
+ {
+ "class GrTest : public GrFragmentProcessor {\n"
+ "public:\n"
+ " class section"
+ },
+ {});
+ test(r,
+ "@cpp { cpp section }"
+ "void main() {"
+ "sk_OutColor = vec4(1);"
+ "}",
+ *SkSL::ShaderCapsFactory::Default(),
+ {},
+ {"cpp section"});
+ test(r,
+ "@constructorParams { int x, float y, std::vector<float> z }"
+ "in float w;"
+ "void main() {"
+ "sk_OutColor = vec4(1);"
+ "}",
+ *SkSL::ShaderCapsFactory::Default(),
+ {
+ "Make(float w, int x, float y, std::vector<float> z )",
+ "return sk_sp<GrFragmentProcessor>(new GrTest(w, x, y, z));",
+ "GrTest(float w, int x, float y, std::vector<float> z )",
+ ", fW(w) {"
+ },
+ {});
+ test(r,
+ "@constructor { constructor section }"
+ "void main() {"
+ "sk_OutColor = vec4(1);"
+ "}",
+ *SkSL::ShaderCapsFactory::Default(),
+ {
+ "private:\n constructor section"
+ },
+ {});
+ test(r,
+ "@initializers { initializers section }"
+ "void main() {"
+ "sk_OutColor = vec4(1);"
+ "}",
+ *SkSL::ShaderCapsFactory::Default(),
+ {
+ ": INHERITED(kNone_OptimizationFlags)\n , initializers section"
+ },
+ {});
+ test(r,
+ "float x = 10;"
+ "@emitCode { fragBuilder->codeAppendf(\"float y = %d\\n\", x * 2); }"
+ "void main() {"
+ "sk_OutColor = vec4(1);"
+ "}",
+ *SkSL::ShaderCapsFactory::Default(),
+ {},
+ {
+ "x = 10.0;\n"
+ " fragBuilder->codeAppendf(\"float y = %d\\n\", x * 2);"
+ });
+ test(r,
+ "@fields { fields section }"
+ "void main() {"
+ "sk_OutColor = vec4(1);"
+ "}",
+ *SkSL::ShaderCapsFactory::Default(),
+ {
+ "GR_DECLARE_FRAGMENT_PROCESSOR_TEST;\n"
+ " fields section typedef GrFragmentProcessor INHERITED;"
+ },
+ {});
+ test(r,
+ "@make { make section }"
+ "void main() {"
+ "sk_OutColor = vec4(1);"
+ "}",
+ *SkSL::ShaderCapsFactory::Default(),
+ {
+ "public:\n"
+ " make section"
+ },
+ {});
+ test(r,
+ "uniform float calculated;"
+ "in float provided;"
+ "@setData(varName) { varName.set1f(calculated, provided * 2); }"
+ "void main() {"
+ "sk_OutColor = vec4(1);"
+ "}",
+ *SkSL::ShaderCapsFactory::Default(),
+ {},
+ {
+ "void onSetData(const GrGLSLProgramDataManager& varName, "
+ "const GrFragmentProcessor& _proc) override {\n",
+ "UniformHandle& calculated = fCalculatedVar;",
+ "auto provided = _outer.provided();",
+ "varName.set1f(calculated, provided * 2);"
+ });
+ test(r,
+ "@test(testDataName) { testDataName section }"
+ "void main() {"
+ "sk_OutColor = vec4(1);"
+ "}",
+ *SkSL::ShaderCapsFactory::Default(),
+ {},
+ {
+ "#if GR_TEST_UTILS\n"
+ "sk_sp<GrFragmentProcessor> GrTest::TestCreate(GrProcessorTestData* testDataName) {\n"
+ " testDataName section }\n"
+ "#endif"
+ });
+}
+
+DEF_TEST(SkSLFPColorSpaceXform, r) {
+ test(r,
+ "in uniform sampler2D image;"
+ "in uniform colorSpaceXform colorXform;"
+ "void main() {"
+ "sk_OutColor = sk_InColor * texture(image, vec2(0, 0), colorXform);"
+ "}",
+ *SkSL::ShaderCapsFactory::Default(),
+ {
+ "sk_sp<GrColorSpaceXform> colorXform() const { return fColorXform; }",
+ "GrTest(sk_sp<GrTextureProxy> image, sk_sp<GrColorSpaceXform> colorXform)",
+ "this->addTextureSampler(&fImage);",
+ "sk_sp<GrColorSpaceXform> fColorXform;"
+ },
+ {
+ "fragBuilder->codeAppendf(\"vec4 _tmp0;\\n%s = %s * "
+ "(_tmp0 = texture(%s, vec2(0.0, 0.0)) , %s != mat4(1.0) ? "
+ "vec4(clamp((%s * vec4(_tmp0.xyz, 1.0)).xyz, 0.0, _tmp0.w), _tmp0.w) : "
+ "_tmp0);\\n\", args.fOutputColor, args.fInputColor ? args.fInputColor : "
+ "\"vec4(1)\", fragBuilder->getProgramBuilder()->samplerVariable("
+ "args.fTexSamplers[0]).c_str(), fColorSpaceHelper.isValid() ? "
+ "args.fUniformHandler->getUniformCStr(fColorSpaceHelper.gamutXformUniform()) : "
+ "\"mat4(1.0)\", fColorSpaceHelper.isValid() ? "
+ "args.fUniformHandler->getUniformCStr(fColorSpaceHelper.gamutXformUniform()) : "
+ "\"mat4(1.0)\");"
+ });
+}
+
+DEF_TEST(SkSLFPTransformedCoords, r) {
+ test(r,
+ "void main() {"
+ "sk_OutColor = vec4(sk_TransformedCoords2D[0], sk_TransformedCoords2D[0]);"
+ "}",
+ *SkSL::ShaderCapsFactory::Default(),
+ {},
+ {
+ "SkSL::String sk_TransformedCoords2D_0 = "
+ "fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);",
+ "fragBuilder->codeAppendf(\"%s = vec4(%s, %s);\\n\", args.fOutputColor, "
+ "sk_TransformedCoords2D_0.c_str(), sk_TransformedCoords2D_0.c_str());"
+ });
+
+}
+
+DEF_TEST(SkSLFPLayoutWhen, r) {
+ test(r,
+ "layout(when=someExpression(someOtherExpression())) uniform float sometimes;"
+ "void main() {"
+ "}",
+ *SkSL::ShaderCapsFactory::Default(),
+ {},
+ {
+ "if (someExpression(someOtherExpression())) {\n"
+ " fSometimesVar = args.fUniformHandler->addUniform"
+ });
+
+}
+
+#endif